aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile17
-rwxr-xr-xbin/cl296
-rw-r--r--etc/lisp-cli/init.lisp26
-rw-r--r--etc/sh/rc1
4 files changed, 336 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index c1723b3..7384fb2 100644
--- a/Makefile
+++ b/Makefile
@@ -6,10 +6,11 @@ pod2man = \
derived-assets = \
- $(pod2man) \
- $(XDG_CONFIG_HOME)/ssh/id_rsa.pub \
- $(XDG_DATA_HOME)/common-lisp/source \
- $(XDG_DATA_HOME)/euandreh/e.list.txt \
+ $(pod2man) \
+ $(XDG_CONFIG_HOME)/ssh/id_rsa.pub \
+ $(XDG_DATA_HOME)/common-lisp/source \
+ $(XDG_DATA_HOME)/euandreh/e.list.txt \
+ $(XDG_DATA_HOME)/lisp-cli/clisp.image \
@@ -29,6 +30,14 @@ $(XDG_CONFIG_HOME)/ssh/id_rsa.pub:
$(XDG_DATA_HOME)/euandreh/e.list.txt: ~/Documents/txt/ opt/aux/gen-e-list.sh
sh opt/aux/gen-e-list.sh > $@
+$(XDG_DATA_HOME)/lisp-cli/clisp.image: $(XDG_CONFIG_HOME)/lisp-cli/init.lisp bin/cl
+ cl \
+ -I clisp \
+ -v \
+ -e '(ql:quickload :trivial-dump-core)' \
+ -e '(trivial-dump-core:dump-image "$@")' \
+ -e '(uiop:quit)'
+
check-shellcheck:
diff --git a/bin/cl b/bin/cl
new file mode 100755
index 0000000..1b9a659
--- /dev/null
+++ b/bin/cl
@@ -0,0 +1,296 @@
+#!/bin/sh
+set -eu
+
+
+uuid() {
+ od -xN20 /dev/urandom |
+ head -n1 |
+ awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}'
+}
+
+tmpname() {
+ echo "${TMPDIR:-/tmp}/cl.tmpfile.$(uuid)"
+}
+
+mkstemp() {
+ name="$(tmpname)"
+ touch "$name"
+ echo "$name"
+}
+
+escape_name() {
+ printf '%s' "$1" |
+ sed 's|"|\\"|g' |
+ printf '(load "%s")\n' "$(cat -)"
+}
+
+
+IMPLEMENTATIONS='
+abcl
+allegro
+ccl
+clasp
+clisp
+cmucl
+ecl
+jscl
+mkcl
+sbcl
+'
+
+usage() {
+ cat <<-'EOF'
+ Usage:
+ cl [-e EXP] [-f FILE] [-p] [-M IMAGE] [-I IMPL] [-n] [-v] [FILE...]
+ cl -l
+ cl -h
+ EOF
+}
+
+help() {
+ cat <<-'EOF'
+
+
+ Options:
+ -e EXP an sexp to be evaluated (can be given more than once)
+ -f FILE FIXME
+ -p print the value of the last given expression
+ -M IMAGE load the given Lisp image
+ -m disable looking for the default image under $XDG_DATA_HOME
+ -I IMPL use the given implementation (default: $LISP_CLI_IMPL)
+ -n skip loading the implementation's init file
+ -v verbose mode
+ -l list the known types of implementations
+ -h, --help show this message
+
+ FILE FIXME
+
+
+ Lauch the desired Lisp implementation, properly adapting the given
+ CLI options.
+
+ When the implementation is not explicited on the command line, and
+ the $LISP_CLI_IMPL environment variable in unset, implementations are
+ searched for alphabetically in $PATH, untill one is found, otherwise
+ an error is emitted.
+
+ The supported implementations are:
+ EOF
+
+
+ for i in $IMPLEMENTATIONS; do
+ printf '%s\n' "$i"
+ done
+
+ cat <<-'EOF'
+
+
+ Examples:
+
+ Launch CLISP REPL, when $LISP_CLI_IMPL is set to 'clisp':
+
+ $ cl
+
+
+ Lauch SBCL REPL, with the given Lisp image loaded, skipping the
+ loading of the '.sbclrc' file:
+
+ $ cl -n -Isbcl sbcl.image
+
+
+ Run file1.lisp with ABCL:
+
+ $ cl -Iabcl file1.lisp
+
+
+ Process STDIN:
+
+ $ cat <<-EOS > process.lisp
+
+ EOS
+ $ cat f1.txt f2.txt | cl -p process.lisp
+
+
+ Print a value on all types of implementations:
+
+ $ for i in `cl -l`; do cl -I$i -pe 'call-arguments-list'; done
+ EOF
+}
+
+
+for flag in "$@"; do
+ case "$flag" in
+ --)
+ break
+ ;;
+ --help)
+ usage
+ help
+ exit
+ ;;
+ *)
+ ;;
+ esac
+done
+
+NO_RC=false
+SCRIPT="$(mkstemp)"
+LISP_CLI_RC="${XDG_CONFIG_HOME:-$HOME/.config}/lisp-cli/init.lisp"
+VERBOSE=false
+IMAGE=''
+SKIP_DEFAULT_IMAGE=false
+IMPL="${LISP_CLI_IMPL:-}"
+while getopts 'e:f:pM:mI:nvlh' flag; do
+ case "$flag" in
+ e)
+ printf '%s\n' "$OPTARG" >> "$SCRIPT"
+ ;;
+ f)
+ escape_name "$OPTARG" >> "$SCRIPT"
+ ;;
+ M)
+ IMAGE="$OPTARG"
+ ;;
+ m)
+ SKIP_DEFAULT_IMAGE=true
+ ;;
+ I)
+ IMPL="$OPTARG"
+ ;;
+ n)
+ NO_RC=true
+ ;;
+ v)
+ VERBOSE=true
+ ;;
+ h)
+ usage
+ help
+ exit
+ ;;
+ *)
+ usage >&2
+ exit 2
+ ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+INTERACTIVE=true
+for f in "$@"; do
+ INTERACTIVE=false
+ escape_name "$f" >> "$SCRIPT"
+done
+
+MAIN="$(mkstemp)"
+if [ "$NO_RC" = false ] && [ -e "$LISP_CLI_RC" ]; then
+ escape_name "$LISP_CLI_RC" > "$MAIN"
+fi
+
+if [ "$INTERACTIVE" = true ]; then
+ escape_name "$SCRIPT" >> "$MAIN"
+else
+ cat <<-EOF >> "$MAIN"
+ (handler-case
+ (progn
+ (load "$SCRIPT"
+ :verbose NIL
+ :print NIL)
+ (uiop:quit 0))
+ (error (e)
+ (format *error-output* "~&~%ERROR: ~a" e)
+ (uiop:quit 1)))
+ EOF
+fi
+
+if [ -z "$IMPL" ]; then
+ for i in $IMPLEMENTATIONS; do
+ if command -v "$i" > /dev/null; then
+ IMPL="$i"
+ break
+ fi
+ done
+ if [ -z "$IMPL" ]; then
+ printf 'Could not find any implementation in $PATH.\n' >&2
+ exit 2
+ fi
+fi
+
+DEFAULT_IMAGE="${XDG_DATA_HOME:-$HOME/.local/share}/lisp-cli/$IMPL.image"
+if [ "$SKIP_DEFAULT_IMAGE" = false ] && [ -z "$IMAGE" ] &&
+ [ -e "$DEFAULT_IMAGE" ]; then
+ IMAGE="$DEFAULT_IMAGE"
+fi
+
+case "$IMPL" in
+ abcl)
+ exit 4
+ ;;
+ allegro)
+ exit 4
+ ;;
+ ccl)
+ exit 4
+ ;;
+ clasp)
+ exit 4
+ ;;
+ clisp)
+ ARGS="-ansi -i $MAIN"
+ if [ -n "$IMAGE" ]; then
+ set -- -M "$IMAGE"
+ fi
+ if [ "$NO_RC" = true ]; then
+ ARGS="$ARGS -norc"
+ fi
+ if [ "$VERBOSE" = false ]; then
+ ARGS="$ARGS -q -q"
+ else
+ set -x
+ fi
+ exec clisp $ARGS "$@"
+ ;;
+ cmucl)
+ exit 4
+ ;;
+ ecl)
+ exit 4
+ ;;
+ jscl)
+ exit 4
+ ;;
+ mkcl)
+ exit 4
+ ;;
+ sbcl)
+ ARGS="--disable-debugger --script $MAIN"
+ if [ "$VERBOSE" = false ]; then
+ ARGS="$ARGS --noinform"
+ fi
+ if [ "$NO_RC" = true ]; then
+ ARGS="$ARGS --no-sysinit --no-userinit"
+ fi
+ if [ -n "$IMAGE" ]; then
+ set -- --core "$IMAGE"
+ fi
+ exec sbcl $ARGS "$@"
+ ;;
+ *)
+ printf 'Unsupported implementation: "%s".\n\n' "$IMPL" >&2
+ usage >&2
+ exit 2
+ ;;
+esac
+
+exit
+
+# https://www.cliki.net/cl-launch
+# buildapp
+# https://github.com/memleaks/clbuild
+# https://www.cliki.net/roswell
+# https://github.com/shinmera/cl-all
+# https://fare.livejournal.com/184127.html
+# https://github.com/rolpereira/trivial-dump-core
+# FIXME: enable readline from CL itself
+when competing with roswell, add completion
+FIXME: implement the example from help string
diff --git a/etc/lisp-cli/init.lisp b/etc/lisp-cli/init.lisp
index 0f01d57..062446e 100644
--- a/etc/lisp-cli/init.lisp
+++ b/etc/lisp-cli/init.lisp
@@ -3,3 +3,29 @@
(user-homedir-pathname))))
(when (probe-file quicklisp-init)
(load quicklisp-init)))
+
+(defun load-once (p)
+ (let ((k (intern
+ (concatenate 'string
+ (string :ql/)
+ (string p))
+ "KEYWORD")))
+ (unless (member k *features*)
+ (ql:quickload p)
+ (pushnew k *features*))
+ k))
+
+(mapcar #'load-once
+ (list
+ :cl-ppcre
+ :cffi
+ :trivial-dump-core
+ :named-readtables
+ :rstring))
+
+(mapcar (lambda (p)
+ (pushnew (concatenate 'string p "/") cffi:*foreign-library-directories*
+ :test #'equal))
+ (cl-ppcre:split ":" (uiop:getenv "LIBRARY_PATH")))
+
+(load-once :cl-fswatch)
diff --git a/etc/sh/rc b/etc/sh/rc
index 0f0ed5d..d5801b8 100644
--- a/etc/sh/rc
+++ b/etc/sh/rc
@@ -87,6 +87,7 @@ export LEX=flex
export LDFLAGS='-flto'
export LISP='sbcl --eval'
export N_PROCS GUILE_EFFECTIVE_VERSION
+export LISP_CLI_IMPL=clisp
add_prefix() {
export GUILE_LOAD_PATH="$1/share/guile/site/$GUILE_EFFECTIVE_VERSION${GUILE_LOAD_PATH:+:}${GUILE_LOAD_PATH:-:}"