2023-03-20 16:22:51 -07:00
|
|
|
#!/bin/relish
|
|
|
|
|
|
2023-03-17 13:06:27 -07:00
|
|
|
;; relish: versatile lisp shell
|
|
|
|
|
;; Copyright (C) 2021 Aidan Hahn
|
|
|
|
|
;;
|
|
|
|
|
;; This program is free software: you can redistribute it and/or modify
|
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
|
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
;; (at your option) any later version.
|
|
|
|
|
;;
|
|
|
|
|
;; This program is distributed in the hope that it will be useful,
|
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
;; GNU General Public License for more details.
|
|
|
|
|
;;
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
|
|
|
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2023-03-17 13:24:31 -07:00
|
|
|
|
2023-03-17 13:06:27 -07:00
|
|
|
;; USERLIB
|
2023-03-20 16:22:51 -07:00
|
|
|
;; This file contains useful features that are not shipped in the STL
|
2023-03-17 13:06:27 -07:00
|
|
|
|
2023-03-20 16:22:51 -07:00
|
|
|
;; this would be way faster as code in stl
|
|
|
|
|
;; but stl already suffers scope creep
|
2023-03-17 13:06:27 -07:00
|
|
|
(def prepend
|
|
|
|
|
'takes a list and appends an element to the back of it.
|
|
|
|
|
returns prepended list'
|
|
|
|
|
(elem list)
|
2023-03-20 16:22:51 -07:00
|
|
|
(reverse (cons (reverse list) elem)))
|
2023-03-17 13:06:27 -07:00
|
|
|
|
|
|
|
|
(def set
|
2023-03-20 16:22:51 -07:00
|
|
|
'sets an existing variable without touching its docstring.
|
|
|
|
|
|
2023-05-16 10:58:06 -07:00
|
|
|
WARNING:
|
2023-03-20 16:22:51 -07:00
|
|
|
If you find yourself struggling to debug a complex error in state access,
|
|
|
|
|
or you are having issues re-running commands in the shell consider the
|
|
|
|
|
following advice:
|
|
|
|
|
|
2023-05-16 10:58:06 -07:00
|
|
|
It is very much an anti pattern to mutate global variable that contain state.
|
2023-03-20 16:22:51 -07:00
|
|
|
refactor your program: put iterators, counters, procedurally generated code,
|
|
|
|
|
and all other mutable state into a let loop.
|
|
|
|
|
|
2023-05-16 10:58:06 -07:00
|
|
|
A cozy script in relish is one where each root level form (or eval at repl)
|
2023-03-20 16:22:51 -07:00
|
|
|
is self contained, and does not permanently modify any other one.
|
|
|
|
|
|
|
|
|
|
See the userlib tests for an easy to follow example of this.'
|
|
|
|
|
|
2023-03-17 13:06:27 -07:00
|
|
|
(var val)
|
|
|
|
|
(let ((doc (get-doc var)))
|
2023-03-20 16:22:51 -07:00
|
|
|
(def (eval var) doc val)))
|
|
|
|
|
|
2023-03-20 17:16:44 -07:00
|
|
|
(def map
|
2023-03-20 16:22:51 -07:00
|
|
|
'Takes two arguments: a function and a list.
|
|
|
|
|
for each element in the list, the function is applied and the
|
|
|
|
|
result is added to a new list. Returns the new list.'
|
|
|
|
|
(func list)
|
|
|
|
|
(let ((list-iter (pop list))
|
|
|
|
|
(result ()))
|
|
|
|
|
(while (gt? (len list-iter) 1)
|
|
|
|
|
(let ((current (car list-iter))
|
|
|
|
|
(remaining (cdr list-iter))
|
|
|
|
|
(current-res (func current)))
|
|
|
|
|
(set (q result) (cons result current-res))
|
|
|
|
|
(set (q list-iter) (pop remaining))))
|
|
|
|
|
result))
|
2023-03-20 21:07:16 -07:00
|
|
|
|
|
|
|
|
(def reduce
|
|
|
|
|
'Takes two arguments: a function and a list.
|
|
|
|
|
The function is expected to take two arguments:
|
|
|
|
|
* the current list item
|
|
|
|
|
* the previous result
|
|
|
|
|
Initially the function will take element1 and element2, outputting result1.
|
|
|
|
|
Then the function will take result1 and element3, outputting result2.
|
|
|
|
|
this will continue iuntil the list is exhausted.'
|
|
|
|
|
(func list)
|
|
|
|
|
(let ((list-iter (pop list))
|
|
|
|
|
(result (car list-iter)))
|
|
|
|
|
(set (q list-iter) (pop (cdr list-iter)))
|
|
|
|
|
(if (lt? (len list) 2)
|
|
|
|
|
(echo "list too short!")
|
|
|
|
|
(while (gt? (len list-iter) 1)
|
|
|
|
|
(let ((current (car list-iter))
|
|
|
|
|
(remaining (cdr list-iter)))
|
|
|
|
|
(set (q result) (func result current))
|
|
|
|
|
(set (q list-iter) (pop remaining)))))
|
|
|
|
|
result))
|
2023-03-20 22:03:10 -07:00
|
|
|
|
|
|
|
|
(def contains?
|
|
|
|
|
'Takes two arguments: a list and an element.
|
|
|
|
|
Returns true if the list contains the element.'
|
|
|
|
|
(list elem)
|
|
|
|
|
(let ((found false)
|
|
|
|
|
(list-iter (pop list)))
|
|
|
|
|
(while (and (gt? (len list-iter) 1)
|
|
|
|
|
(not found))
|
|
|
|
|
(let ((current (car list-iter))
|
|
|
|
|
(remaining (cdr list-iter)))
|
|
|
|
|
(if (eq? current elem)
|
|
|
|
|
(set (q found) true)
|
|
|
|
|
(set (q list-iter) (pop remaining)))))
|
|
|
|
|
found))
|
2023-03-23 12:07:28 -07:00
|
|
|
|
|
|
|
|
(def get-paths
|
|
|
|
|
'returns each individual directory in PATH'
|
|
|
|
|
() (split PATH ':'))
|
|
|
|
|
|
|
|
|
|
(def add-path
|
2023-03-24 18:14:33 -07:00
|
|
|
'Takes one argument.
|
|
|
|
|
adds a directory to PATH'
|
2023-03-23 12:07:28 -07:00
|
|
|
(path) (set (q PATH)
|
2023-04-17 22:11:49 -07:00
|
|
|
(concat PATH ':' path)))
|
|
|
|
|
|
|
|
|
|
(def display-paths
|
|
|
|
|
'prints out each element of $PATH one by one'
|
|
|
|
|
()
|
|
|
|
|
(let ((path-iter (pop (get-paths))))
|
|
|
|
|
(while (gt? (len path-iter) 1)
|
|
|
|
|
(let ((pat (car path-iter))
|
|
|
|
|
(rem (cdr path-iter)))
|
|
|
|
|
(echo pat)
|
|
|
|
|
(set (q path-iter) (pop rem))))))
|