[HN Gopher] Schemesh: Fusion between Unix shell and Lisp REPL
___________________________________________________________________
Schemesh: Fusion between Unix shell and Lisp REPL
Author : cosmos0072
Score : 55 points
Date : 2025-02-15 19:00 UTC (3 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| dreamcompiler wrote:
| I'm curious as to how this differs from an older project that
| seems to solve the same problem:
|
| https://github.com/scheme/scsh
| cosmos0072 wrote:
| This is a common question :)
|
| Schemesh is intended as an _interactive_ shell and REPL: it
| supports line editing, autocompletion, searchable history,
| aliases, builtins, a customizable prompt, and automatic loading
| of `~ /.config/schemesh/repl_init.ss`.
|
| Most importantly, it has job control (CTRL+Z, `fg`, `bg` etc.)
| and recognizes and extends Unix shell syntax for starting,
| redirecting and composing jobs. An example:
|
| find (lisp-expression-returning-some-string) -type f | xargs ls
| 2>/dev/null >> ls.log &
|
| Scsh has none of the above features. As stated in
| https://scsh.net/docu/html/man-Z-H-2.html#node_sec_1.4
|
| > Scsh, in the current release, is primarily designed for the
| writing of shell scripts -- programming. It is not a very
| comfortable system for interactive command use: the current
| release lacks job control, command-line editing, a terse,
| convenient command syntax, and it does not read in an
| initialisation file analogous to .login or .profile
| sshine wrote:
| I really like how you don't sacrifice complete command-line
| first shell feel, and escaping into a sane language with real
| datastructures is literally one character away.
|
| Rather than the tclsh way of saying "we'll just make the Lisp
| seem really shelly" which is a dud to anyone who is not a
| lisper.
|
| Now, it'd be really cool if schemesh had a TUI library at the
| maturity level of Ratatui.
|
| So... it sacrifices sub-shell syntax with parentheses being
| hijacked for Scheme. Have you also lost $(...) shell
| interpolation as the saner alternative to `...`?
| cosmos0072 wrote:
| It does not sacrifice sub-shell syntax: it is fully
| supported, I just had to rename it from ( ... ) to [ ... ]
| to avoid conflicts with ( ... ) that switches to lisp
| syntax
|
| Also, both $(...) and `...` shell interpolation are fully
| supported.
|
| The only thing I intentionally sacrificed is shell flow
| control: schemesh shell syntax does not have the builtins
| 'case' 'for' 'if' 'while' etc.
|
| In practically all examples I tried, escaping to Scheme for
| loops and conditional code works better: it avoids the
| usual pitfalls related to shell string splitting, and
| usually results in more readable code too, at least for a
| Lisper
|
| Note: there's also some additional parsing logic to
| distinguish between sub-shell syntax [ ... ] and wildcard
| patterns that use [ ... ] as well
| lisper wrote:
| SCSH is a shell embedded in Scheme, i.e. it's a Scheme library
| that lets you easily create unix processes in Scheme. Schemesh
| is Scheme embedded in a shell, i.e. it's a shell that lets you
| easily call Scheme code.
|
| For example, if you type: ls
|
| in schemesh you will execute the "ls" command and get a
| directory listing, whereas in scsh you will get the value of a
| variable named "ls".
|
| [UPDATE] Also, as cosmos0072 notes in a sibling comment,
| schemesh has shell-like features like line editing,
| autocompletion, searchable history, aliases, builtins, etc.
| behnamoh wrote:
| speaking of shell pipelines, what is the "right" way of
| implementing pipes?
|
| - Elixir: data |> process(12) puts data as the FIRST arg of
| process (before 12).
|
| - Gleam: data |> process(12, _) puts data as the "hole" arg ("_")
| of process.
|
| So far so good, but these approaches are mainly just more
| convenient function calls - i.e., they don't have fancy error
| checking in them. Then you have Haskell:
|
| - Haskell: >>= "binds" actions to guarantee execution order (even
| for actions that don't depend on the previous action's output!).
| This is more fancy because it uses monads to encapsulate the
| computations at each step, and can shortcircuit on errors.
| rednafi wrote:
| So many shells, so little time.
| susam wrote:
| Excellent project! Thanks for sharing it here!
|
| I'd just like to share my joy of using the Emacs shell (Eshell),
| which I find to be a wonderful fusion of the Unix shell and a
| Lisp REPL. We can enter commands with or without parentheses. For
| example: ~ $ concat "foo" "bar" foobar
| ~ $ (concat "foo" "bar") foobar
|
| Or ~ $ * 123 456 56088 ~ $ (* 123
| 456) 56088
|
| It comes with several built-in commands implemented as Elisp
| functions. For example: ~ $ which cd echo ls
| which eshell/cd is a byte-compiled Lisp function in 'em-
| dirs.el'. eshell/echo is a byte-compiled Lisp function in
| 'em-basic.el'. eshell/ls is a byte-compiled Lisp function
| in 'em-ls.el'. eshell/which is a byte-compiled Lisp
| function in 'esh-cmd.el'. ~ $ ls -l /etc/h* -rw-r--r--
| 1 root wheel 446 2025-02-15 20:43 /etc/hosts
| -rw-r--r-- 1 root wheel 0 2024-10-01 2024
| /etc/ hosts.equiv ~ $ (eshell/ls "-l" (eshell-extended-glob
| "/etc/h*")) -rw-r--r-- 1 root wheel 446
| 2025-02-15 20:43 /etc/hosts -rw-r--r-- 1 root
| wheel 0 2024-10-01 2024 /etc/hosts.equiv
|
| At the same time, external commands are usable as usual:
| ~ $ which curl jq python3 rustc /usr/bin/curl
| /opt/homebrew/bin/jq /opt/homebrew/bin/python3
| /Users/susam/.cargo/bin/rustc ~ $ python3 -c
| "print('hello')" hello ~ $ curl -sS https://hacker-
| news.firebaseio.com/v0/item/43061183.json | jq -r .title
| Schemesh: Fusion between Unix shell and Lisp REPL
|
| The fact that TRAMP is an integral part of Emacs means I can
| switch between my local shell and remote shells transparently
| with simple 'cd' commands. For example: ~ $ echo
| local > /tmp/foo.txt ~ $ echo remote >
| /ssh:susam@susam.net:/tmp/foo.txt ~ $ cd /tmp/ /tmp $
| cat foo.txt local /tmp $ hostname mac.local
| ~ $ cd /ssh:susam@susam.net:/tmp/ /ssh:susam@susam.net:/tmp
| $ hostname susam.net /ssh:susam@susam.net:/tmp $ cat
| foo.txt remote
|
| See how in the second command, I redirected a file to a remote
| filesystem with the usual '>' redirection operator.
|
| Also, see how in the sixth command, I went from my local shell to
| a remote shell using a simple 'cd' command. With Eshell and
| TRAMP, working across multiple remote systems becomes
| transparent, seamless, and effortless! Best of all, I still have
| the full power of Emacs at my fingertips, making Eshell an
| incredibly smooth and powerful experience!
| cosmos0072 wrote:
| Eshell looks really powerful :)
|
| Does it also have job control, and jobs as first-class objects?
|
| In schemesh, you can do things like find /
| -xdev -type f | ls -l --sort=size CTRL+Z bg 1
|
| and also (define j {git log})
| (display j) (display (sh-run/string j))
| whartung wrote:
| Can this shell do this (in some form):
|
| (lisp expression) | <unix command> | (lisp expression)
___________________________________________________________________
(page generated 2025-02-15 23:00 UTC)