Skip to content

Commit

Permalink
shell pass-through: remove Clesh, only on the terminal, always intera…
Browse files Browse the repository at this point in the history
…ctive

fixes #85
  • Loading branch information
vindarel committed Feb 3, 2025
1 parent 0dda8fe commit d88f771
Show file tree
Hide file tree
Showing 8 changed files with 27 additions and 272 deletions.
6 changes: 0 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@ ql-deps: check-asdf-version
# I asked for inclusion in Quicklisp.
$(call git-clone-pull,https://github.com/vindarel/termp)

# NOT in Quicklisp <2025-02-03>
# updated Clesh for a shell pass-through that handles all shell commands interactively.
# So we now see the output in real time (instead of at the end of the execution),
# and commands like "emacs -nw" now work, in addition of sudo, vim or htop that were handled separately.
$(call git-clone-pull,https://github.com/lisp-maintainers/clesh)

# 2023-11: The symbol SB-INT:TRULY-DYNAMIC-EXTENT is absent since at least
# SBCL v2.3.10, which was required in older versions of cl-environments
# and cl-form-types.
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,6 @@ small and trivial library, you can clone it into your

git clone https://github.com/vindarel/termp/ ~/quicklisp/local-projects/termp

As of writing, you also need [https://github.com/lisp-maintainers/clesh](https://github.com/lisp-maintainers/clesh), but we aim to remove this dependency.

For a number of other libraries we need the Quicklisp version of August, 2024, or later.

For those, you should either:
Expand Down
2 changes: 0 additions & 2 deletions ciel.asd
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@
;;; ;TODO: we don't want these dependencies when we build a binary.
;;;
:named-readtables
:clesh ;; shell pass-through
:quicksearch ;; search on GitHub, Cliki, Quickdocs.
)
:components ((:module "src"
Expand Down Expand Up @@ -180,7 +179,6 @@
:components ((:file "repl")
(:file "utils")
(:file "scripting")
(:file "shell-utils")
(:file "repl-utils")

;; I define them here, for good practice (for me),
Expand Down
1 change: 0 additions & 1 deletion docs/dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
- cl-ftp: send or receive files from FTP.
- cl-ppcre: Perl-compatible regular expression library
- cl-reexport: Reexport external symbols in other packages.
- clesh: Clesh is a very short program that provides
mechanisms for running and composing Unix shell commands and
constructs from Common Lisp.

Expand Down
42 changes: 3 additions & 39 deletions docs/repl.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,52 +45,16 @@ ciel-user> (dict ?

## Shell pass-through with "!"

Activate it with `(enable-shell-passthrough)`.

Use `!` to send a shell command:
Use `!` to send a shell command. All shell commands are run interactively, so you can run `htop`, `sudo`, `emacs -nw` etc.

```
!ls
!sudo emacs -nw /etc/
```

### Mixing Lisp code with "?"

You can mix shell commands and Lisp code. The `?` character is the
"lisp escape". For example:

* !echo ?(+ 2 3)

or:

* (defun factorial (x) (if (zerop x) 1 (* x (factorial (1- x)))))
* !echo "fact 3: " ?(factorial 3)

Escape the "?" with "\?" to write it in a shell command.

### Shell commands in Slime and limitations

The "!" shell pass-through is not enabled by default. You can enable both in the terminal REPL and in Slime:

CIEL-USER> (enable-shell-passthrough)

There are differences on how shell commands are handled in the terminal REPL and in Slime.

All shell commands in the terminal are run interactively. You can see
the program output as it goes. In Emacs and Slime, the commands are
run *synchronously*, the output (and error output) is captured and
displayed when the command is finished.

In the terminal REPL, you can use `sudo`, `emacs -nw` and other visual
and interactive commands, but not in Slime.

> Note: the shell-passthrough feature is experimental.
> Note: we encourage our users to use a good editor rather than a terminal!
We use our fork of the [Clesh](https://github.com/lisp-maintainers/clesh) library.
We provide TAB completion for shell commands that are in your PATH.

See also [Lish](https://github.com/nibbula/lish/) and [SHCL](https://github.com/bradleyjensen/shcl) for more unholy union of (posix) shells and Common Lisp.
See [Lish](https://github.com/nibbula/lish/) and [SHCL](https://github.com/bradleyjensen/shcl) for more unholy union of (posix) shells and Common Lisp.


## Syntax highlighting
Expand Down
53 changes: 24 additions & 29 deletions repl.lisp
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
;; #!/usr/bin/sbcl --script
(load "~/quicklisp/setup")

(let ((*standard-output* (make-broadcast-stream)))
(ql:quickload "cl-readline"))
(ql:quickload "cl-readline" :silent t)

;;; update <2024-09-04>: now all shell commands are run interactively.
;;; It works for htop, vim, sudo, emacs -nw…
;;;
;;; update <2025-02-03>: the "!" "pass-through" is disabled on Slime and "dumb" terminals.

(uiop:define-package :sbcli
(:use :common-lisp :trivial-package-local-nicknames)
(:use :common-lisp :trivial-package-local-nicknames)
(:import-from :magic-ed
:magic-ed)
:magic-ed)
(:export repl sbcli help what *repl-version* *repl-name* *prompt* *prompt2* *result-indicator* *init-file*
*quicklisp*
*hist-file* *special*
Expand Down Expand Up @@ -420,12 +425,10 @@ strings to match candidates against (for example in the form \"package:sym\")."
(select-completions "str:con" (list "str:containsp" "str:concat" "str:constant-case"))
:test #'string-equal)))

(defun shell-passthrough-p (arg)
"Return t if arg (string) starts with \"!\".
This is used to offer custom TAB completion, not to launch shell commands.
The Clesh readtable is responsible of that."
(str:starts-with-p "!" arg))
(defun shell-passthrough-p (s)
"Return t if s (string) starts with \"!\".
We also use it to offer custom TAB completion."
(str:starts-with-p "!" s))

(defun complete-filename-p (text start end &key (line-buffer rl:*line-buffer*))
"Return T if we should feed the tab completion candidates filenames, instead of the regular Lisp symbols.
Expand Down Expand Up @@ -543,6 +546,14 @@ strings to match candidates against (for example in the form \"package:sym\")."
(cl-ansi-text:green prompt)
prompt))))

(defun run-visual-command (text)
"Run this visual command (string, sans \"!\" prefix)."
(if (termp:termp)
(uiop:run-program (string-left-trim "!" text)
:output :interactive
:input :interactive)
(uiop:format! *error-output* "~&Cannot run this shell command: we are not inside a \"real\" terminal.~&")))

(defun sbcli (txt prompt)
"Read user input and evaluate it.
This function must be called from inside the CIEL-USER package."
Expand Down Expand Up @@ -577,11 +588,9 @@ strings to match candidates against (for example in the form \"package:sym\")."
(sbcli::symbol-documentation (last-nested-expr text)))

;; Interactive and visual shell command?
;; They are now handled by Clesh.
;; When on a non "dumb" terminal, all shell commands are run interactively.

;; No need to check for a "!" in the input here,
;; it's done with the clesh readtable when handling lisp.
;; All shell commands are run interactively.
((shell-passthrough-p text)
(run-visual-command text))

;; Default: run the lisp command (with the lisp-critic, the shell passthrough
;; and other add-ons).
Expand Down Expand Up @@ -664,20 +673,6 @@ strings to match candidates against (for example in the form \"package:sym\")."

(in-package :ciel-user)

;; Enable Clesh, only for the readline REPL,
;; part because we don't want to clutter the ciel-user package,
;; part because Clesh is buggy for us on Slime (!! and [...]).
;; We get the ! pass-through shell:
;; !ls
;; as well as [ ... ] on multilines.
;; Beware: the double bang !! doesn't work. See issues.
;;
;; <2025-01-29> disable Clesh altogether,
;; a ! anywhere in the function name fails.
;; https://github.com/ciel-lang/CIEL/issues/85
;; I also noticed other issues.
;; (named-readtables:in-readtable clesh:syntax)

(handler-case (sbcli::sbcli "" sbcli::*prompt*)
(error (c)
;; Normally lisp code is evaled and protected from errors in evaluate-lisp.
Expand Down
183 changes: 0 additions & 183 deletions shell-utils.lisp

This file was deleted.

10 changes: 0 additions & 10 deletions src/ciel.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -473,16 +473,6 @@ We currently only try this with serapeum. See *deps/serapeum/sequences-hashtable
(when *pretty-print-hash-tables*
(toggle-pretty-print-hash-table t))

(defun enable-shell-passthrough ()
"Enable the shell passthrough with \"!\" and \"[\". Enable Clesh's readtable."
(named-readtables:in-readtable clesh:syntax))

(defun disable-shell-passthrough ()
"(experimental) Disable the shell passthrough with \"!\" and \"[\". Disable Clesh's syntax."
(set-macro-character #\! (get-macro-character #\! (copy-readtable nil)))
(set-macro-character #\[ (get-macro-character #\[ (copy-readtable nil)))
(set-macro-character #\] (get-macro-character #\] (copy-readtable nil))))

(defun ciel-user-help ()
"Print a short welcome and help message."
(format t "CIEL version ~a~&" (asdf:system-version (asdf:find-system "ciel")))
Expand Down

0 comments on commit d88f771

Please sign in to comment.