PS: I look forward to trying this out! Since I don’t know much Common Lisp, are there particularly useful libraries that would make it easy to cover functionality commonly used through the shell? I’d love to see a tutorial with a compilation of examples. EDIT: Found some useful stuff in the CL cookbook (Eg. section on files & directories) https://lispcookbook.github.io/cl-cookbook/
I'm going to publish a few more libraries which should help with file manipulation (as I demoed it).
Stay tuned!
I have recently switched to Jupyter's qtconsole for my REPL needs - for me, it hits the sweet spot of supporting rich media and interaction without the overhead of running a full web browser stack. I could see it becoming the basis for a next-gen terminal.
What I find limiting for now is interactions with the shell process, in my case the Common Lisp compiler: no interactive stacktrace, no debugger, etc. This is very limiting. I don't know if there is a way around it, as this could be a limitation of the Jupyter design with its kernels. Please let me know if there is a way out! :)
For processes, I wrote something that is not finished, not polished, but if anyone want to steal from it, go ahead:
https://github.com/christophejunke/pipeline
This allows to spawn processes or threads to pipeline input/output, like done usually with | in shells
(with-pipeline ()
(program "ls" (namestring (merge-pathnames "bin/" (user-homedir-pathname))))
(program "sed" "s/a/aaaa/")
(tee/error) ;; "tee" and output a copy to error
(program "wc" "-c")
#'read)
https://github.com/christophejunke/pipeline/blob/master/test...The nmcli.lisp example starts an nmcli process and filters its output to build Lisp objects representing connections:
https://github.com/christophejunke/pipeline/blob/master/nmcl...
It's not Lisp but Scala so may not be the authors language of choice however it can be used as a Shell: https://ammonite.io/#Ammonite-Shell
I am personally using it and compared to a classical shell like Bash it's really nice for more structured data related tasks (exploring some API, checking some data, creating a bunch of PRs at once, ...).
It also makes use of Scala's adjustable syntax and functional concepts so you basically get shell piping but in a strongly typed fashion (e.g. `ls.! |? (_.ext == "txt") | (os.read)` would produce a list of strings representing the contents of all files ending in .txt of the current directory).
Also I am curious what people think of PowerShell which as of PowerShell Core is usable on all platforms as well.
Its hard to beat PowerShell tho given its integrated in infinite number of tools on Windows platform and growing number on Linux.
It does structured data, native support for extending it via .NET and native libraries and at least on Windows, can plug into OS Automation libraries.
What it misses is graphical display on the REPL.
I can easily see PowerShell Core replacing my uses of Python in what concerns Linux VMs.
From what I understand, Ammonite was designed as a "readline shell" as I wrote in the article. It perpetuates this approach that everything is a command.
The thesis of my article suggests we do the opposite: I'm suggesting to rethink shells by starting from the interface (here the SLY REPL) and then implement the shell features.
In particular, it seems that Ammonite does not support back-references and I'm not sure it has an interactive inspector.
While Ammonite seems to be a definite improvement over the _syntax_ of Bash, etc., I'm not sure it brings much novelty in terms of user interface. But again, I know very little about it so I may have missed some features :)
There are a couple of techniques:
1) Check for use of certain escape sequences in the output.
2) Check PTY terminal modes using tcgetattr, especially for raw mode
I think combining (1) and (2) you could come up with some heuristics that would work 99% of the time, without hardcoding names of fullscreen apps or anything else like that.
(Really this isn't "ncurses detection" per se, you can have a full-screen terminal app without using any curses library.)
Yes, apps can change terminal mode at any time. The solution the author went with is to have a list of "visual program" names, and when a visual program name is detected, launch it in an external terminal (xterm or Emacs vterm). That is making no attempt to handle mode switches during program execution, it is making a permanent decision before the program starts based on its name.
I think the solution here is to have a visual terminal "widget" that can be embedded into the graphical REPL, and the REPL constantly monitors the output and terminal mode of the subprocess, and when the REPL detects initiation of visual mode, start an embedded visual terminal widget, and then stop the visual terminal widget when it detects visual mode is completed.
On Linux, it is possible for the pty master to be immediately notified of any mode changes in the slave [0], using packet mode and EXTPROC. I don't think that facility exists in most other operating systems.
[0] https://stackoverflow.com/questions/21641754/when-pty-pseudo...
Not sure if I'm the only one though.
In other words, in Algol like languages you’re typically calling like(this) (or the dotted.equivalent(form)) and in lisp it’s (like this).
You do eventually take advantage of the fact that you’re writing an AST, when you get into macros. But that feels pretty simple once you’re used to the function syntax, since macros just manipulate the resulting structures.
What used to throw me off was the special syntax for lists - ‘(structures looking like this) - but once you get used to using the lisp structure for function calls it becomes clear why and when this kind of quoting is necessary (any time you want a list as data instead of a function call).
read-data -> push-to-rabbit -> read-from-rabbit -> send-ack -> push-to-http.
Turns out with functional composition + data structures you can do a lot.
With the idea of immutability or persistent data structure with say Clojure, a lot of idea start to make sense. Rich Hickey videos are pretty good at describing simpler programs. Even if you never use Clojure, or Lisp, or Scheme, these idea might make you a better programmer. At least they did for me. My Python code is now much simpler because I realized I didn't need everything I was doing.
I've only scratched the surface of Xonsh, so please correct me if I'm wrong.
From what I understand, Xonsh was designed as a "readline shell" as I wrote in the article. It perpetuates this approach that everything is a command.
The thesis of my article suggests we do the opposite: I'm suggesting to rethink shells by starting from the interface (here the SLY REPL) and then implement the shell features. In particular, it seems that Xonsh does not support back-references and I'm not sure it has an interactive inspector (or does Emacs python mode provide one?).
While Xonsh seems to be a definite improvement over the syntax of Bash, etc., I'm not sure it brings much novelty in terms of user interface. But again, I know very little about it so I may have missed some features, in particular regarding the Emacs integration :)
Outer most parens should be optional, if you're running ls you don't want to type (ls).
Grouping flags, files and options is difficult: ls -lh file could become (ls (h l) file) (ls (flags h l) (files file)) (ls -l -h file) (ls -lh file) none of the options are particularly good or lispy.
You need a full editor on the command line. Shells are designed for teletypes, lisps are designed for glass terminals.
All in all not I'm sure that an s-expression based system is the right fit for a low level interface to the computer. That said I did enjoy my experiments a lot more than I did using shells. Were I to try it again I would have it is a higher level language that compiles down to a shell.
A bit late on the uptake, but welcome to the party of realizing that the shell is not be all end all of computing.