[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)