2024-02-06 22:39:08 +00:00
|
|
|
#!/bin/flesh
|
2023-03-20 16:22:51 -07:00
|
|
|
|
2024-02-06 22:39:08 +00:00
|
|
|
;; Flesh: Flexible Shell
|
|
|
|
|
;; Copyright (C) 2021 Ava Affine
|
2023-03-17 13:06:27 -07:00
|
|
|
;;
|
|
|
|
|
;; 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-06-20 01:25:19 +00:00
|
|
|
;; TODO
|
|
|
|
|
;; dir-path
|
|
|
|
|
;; abs-path
|
|
|
|
|
;; rel-path
|
|
|
|
|
;; unique (make set)
|
|
|
|
|
;; set add
|
|
|
|
|
;; set del
|
|
|
|
|
;; superset
|
|
|
|
|
;; common-set
|
|
|
|
|
;; make-map
|
|
|
|
|
;; ins-mapping
|
|
|
|
|
;; del-mapping
|
|
|
|
|
;; get-mapping
|
|
|
|
|
;; mapped?
|
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.
|
|
|
|
|
|
2024-02-06 22:39:08 +00:00
|
|
|
A cozy script in flesh 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
|
|
|
|
2023-06-13 00:18:11 +02:00
|
|
|
(def cond
|
|
|
|
|
'Takes one argument: a list of pairs consisting of a form returning a bool and a form to execute
|
|
|
|
|
The function iterates over the list checking if the first form of a pair evaluates to true, in which
|
|
|
|
|
case it will execute the second form of the pair, returning its result, and stop the loop.'
|
|
|
|
|
(list)
|
|
|
|
|
(let ((iter list))
|
|
|
|
|
(while (gt? (len iter) 0)
|
|
|
|
|
(let ((current (car iter))
|
|
|
|
|
(remaining (pop iter)))
|
|
|
|
|
(if (eval (car current))
|
|
|
|
|
(car (pop ((set (q iter) ())
|
|
|
|
|
(eval (cdr current)))))
|
|
|
|
|
(set (q iter) (cdr remaining)))))))
|
|
|
|
|
|
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))))))
|
2024-06-01 08:55:53 -07:00
|
|
|
|
|
|
|
|
(def join
|
|
|
|
|
'concatenates list elements into a string, while
|
|
|
|
|
interspersing a provided delimiter in between elements'
|
|
|
|
|
(list delim)
|
|
|
|
|
(reduce (lambda (res elem)
|
|
|
|
|
(if (eq? (strlen res) 0)
|
|
|
|
|
(string elem)
|
|
|
|
|
(concat res delim elem)))
|
|
|
|
|
list))
|
2024-06-11 17:07:49 -07:00
|
|
|
|
|
|
|
|
(def extend
|
|
|
|
|
'adds all elements in set2 to set1'
|
|
|
|
|
(set1 set2)
|
|
|
|
|
(reduce (lambda (res elem) (cons res elem))
|
|
|
|
|
(prepend set1 set2)))
|