init file: add --no-userinit

and add --noinform that was missing in Clingon options.

Move the useful load-without-shebang in utils.lisp, now available for
all systems.

"make" alone calls make build
This commit is contained in:
vindarel 2023-05-04 16:53:40 +02:00
parent f7a4f06335
commit b23214917c
8 changed files with 98 additions and 33 deletions

View file

@ -1,5 +1,7 @@
LISP ?= sbcl LISP ?= sbcl
all: build
# Install some Quicklisp dependencies. # Install some Quicklisp dependencies.
ql-deps: ql-deps:
# 2023-03: we want str:ensure-suffix, not yet in Quicklisp. # 2023-03: we want str:ensure-suffix, not yet in Quicklisp.

View file

@ -210,6 +210,8 @@ This REPL is more user friendly than the default SBCL one:
%q => Ends the session. %q => Ends the session.
``` ```
The CIEL terminal REPL loads the `~/.cielrc` init file at start-up if present. Don't load with `--no-userinit`.
See more in [*the documentation*](https://ciel-lang.github.io/CIEL/#/). See more in [*the documentation*](https://ciel-lang.github.io/CIEL/#/).
# Usage # Usage

View file

@ -13,4 +13,9 @@
(in-package :ciel-user) (in-package :ciel-user)
;; XXX: we would like to read our ~/.cielrc init file when resuming the core
;; in Slime.
;; Currently we load it only when starting the terminal REPL.
;; See the :toplevel option.
(sb-ext:save-lisp-and-die "ciel-core") (sb-ext:save-lisp-and-die "ciel-core")

View file

@ -136,6 +136,7 @@
((:file "packages") ((:file "packages")
(:file "json-pointer-minus") (:file "json-pointer-minus")
(:file "ciel"))) (:file "ciel")))
(:file "utils")
(:module "src/more-docstrings" (:module "src/more-docstrings"
:components :components
((:file "docstrings")))) ((:file "docstrings"))))
@ -152,6 +153,7 @@
:lisp-critic ;; it would be nice to integrate it with Slime. :lisp-critic ;; it would be nice to integrate it with Slime.
:magic-ed) :magic-ed)
:components ((:file "repl") :components ((:file "repl")
(:file "utils")
(:file "scripting") (:file "scripting")
(:file "shell-utils") (:file "shell-utils")
(:file "repl-utils") (:file "repl-utils")

View file

@ -539,3 +539,27 @@ This allows you to have a dumb "live reload" workflow with a simple editor and a
(simple-auto-reload) (simple-auto-reload)
(sleep most-positive-fixnum)) (sleep most-positive-fixnum))
~~~ ~~~
## Misc
### Load your scripts in the REPL
Calling your scripts from the shell is pretty cool, what if you could
*also* have them available at your fingertips in a Lisp REPL?
TLDR;
```lisp
;; in ~/.cielrc
(ciel::load-without-shebang "~/path/to/yourscript.lisp")
```
As the name suggests, this `load` function works even if your file starts with a shebang line (which is not valid Lisp code, so the default `LOAD` function would fail).
Y'know, sometimes you live longer in a Lisp REPL than in a shell
without noticing. Or simply, manipulating real objects in a text
buffer can be more practical than copy-pasting text in a rigid
terminal (even though Emacs'
[vterm](https://github.com/akermu/emacs-libvterm) is an excellent improvement too).
> INFO: the `~/.cielrc` file is loaded at start-up of the terminal REPL (called with `ciel`), not yet when you start the core image in your IDE.

View file

@ -8,7 +8,7 @@
(:use :common-lisp :trivial-package-local-nicknames) (:use :common-lisp :trivial-package-local-nicknames)
(:import-from :magic-ed (:import-from :magic-ed
:magic-ed) :magic-ed)
(:export sbcli help what *repl-version* *repl-name* *prompt* *prompt2* *result-indicator* *config-file* (:export sbcli help what *repl-version* *repl-name* *prompt* *prompt2* *result-indicator* *init-file*
*hist-file* *special* *hist-file* *special*
*syntax-highlighting* *pygmentize* *pygmentize-options*)) *syntax-highlighting* *pygmentize* *pygmentize-options*))
@ -48,7 +48,7 @@
(defvar *prompt* (format nil "~a" (cl-ansi-text:green "ciel-user> "))) (defvar *prompt* (format nil "~a" (cl-ansi-text:green "ciel-user> ")))
(defvar *prompt2* "....> ") (defvar *prompt2* "....> ")
(defvar *result-indicator* "=> ") (defvar *result-indicator* "=> ")
(defvar *config-file* "~/.cielrc") (defvar *init-file* "~/.cielrc")
(defvar *hist-file* "~/.ciel_history") (defvar *hist-file* "~/.ciel_history")
(defvar *hist* (list)) (defvar *hist* (list))
(defvar *syntax-highlighting* nil) (defvar *syntax-highlighting* nil)
@ -87,6 +87,11 @@
:if-does-not-exist :create) :if-does-not-exist :create)
(write-line str out))) (write-line str out)))
(defun load-init-file (&optional (init-file *init-file*))
"Load the ~/.cielrc init file.
Defaults to `*init-file*'."
(load init-file))
(defun end () (defun end ()
"Ends the session." "Ends the session."
(format t "~%Bye!~&") (format t "~%Bye!~&")
@ -524,12 +529,13 @@ strings to match candidates against (for example in the form \"package:sym\")."
(rl:redisplay) (rl:redisplay)
)) ))
(defun repl (&key noinform) (defun repl (&key noinform no-usernit)
"Toplevel REPL. "Toplevel REPL.
CLI options: CLI options:
- -h, --help - -h, --help
- --noinform: don't print the welcome banner. - --noinform: don't print the welcome banner.
- --no-userinit: don't load the user's cielrc init file.
" "
(let ((argv (uiop:command-line-arguments))) (let ((argv (uiop:command-line-arguments)))
@ -556,10 +562,8 @@ strings to match candidates against (for example in the form \"package:sym\")."
(rl:bind-keyseq "\\C-x\\C-e" #'edit-current-input) (rl:bind-keyseq "\\C-x\\C-e" #'edit-current-input)
(rl:set-paren-blink-timeout 500) (rl:set-paren-blink-timeout 500)
(if (probe-file *config-file*)
(load *config-file*))
;; Print a banner and system info. ;; Print a banner and system info.
;; Checking a CLI arg this way is an old, done before our use of Clingon.
(unless (or noinform (unless (or noinform
(member "--noinform" (uiop:command-line-arguments) :test #'string-equal)) (member "--noinform" (uiop:command-line-arguments) :test #'string-equal))
(princ *banner*) (princ *banner*)
@ -570,6 +574,12 @@ strings to match candidates against (for example in the form \"package:sym\")."
(write-char #\linefeed) (write-char #\linefeed)
(finish-output nil)) (finish-output nil))
;; Load CIEL's user init file.
(unless (or no-usernit
(member "--no-userinit" (uiop:command-line-arguments) :test #'string-equal))
(when (uiop:file-exists-p *init-file*)
(load-init-file)))
(when *hist-file* (read-hist-file)) (when *hist-file* (read-hist-file))
(in-package :ciel-user) (in-package :ciel-user)

View file

@ -8,33 +8,6 @@
Hash-table: file name (sans extension) -> file content (string). Hash-table: file name (sans extension) -> file content (string).
The name is case-insensitive (it's easier for typing things in the terminal).") The name is case-insensitive (it's easier for typing things in the terminal).")
(defun maybe-ignore-shebang (in)
"If this file starts with #!, delete the shebang line,
so we can LOAD the file.
Return: a stream (it is LOADable)."
;; thanks Roswell for the trick.
(let ((first-line (read-line in)))
(make-concatenated-stream
;; remove shebang:
(make-string-input-stream
(format nil "~a"
(if (str:starts-with-p "#!" first-line)
""
first-line)))
;; rest of the file:
in)))
(defun load-without-shebang (file)
"LOAD this file, but exclude the first line if it is a shebang line."
(with-open-file (file-stream file)
(load
(maybe-ignore-shebang file-stream))))
(defun has-shebang (file)
"Return T if the first line of this file is a shell shebang line (starts with #!)."
(with-open-file (s file)
(str:starts-with-p "#!" (read-line s))))
;; eval ;; eval
(defun wrap-user-code (s) (defun wrap-user-code (s)
"Wrap this user code to handle common conditions, such as a C-c C-c to quit gracefully." "Wrap this user code to handle common conditions, such as a C-c C-c to quit gracefully."
@ -124,6 +97,16 @@
:long-name "scripts" :long-name "scripts"
:short-name #\z :short-name #\z
:key :scripts) :key :scripts)
(clingon:make-option
:flag
:description "Don't load the ~/.cielrc init file at start-up (for the CIEL terminal REPL)."
:long-name "no-userinit"
:key :no-userinit)
(clingon:make-option
:flag
:description "Don't print the welcome banner."
:long-name "noinform"
:key :noinform)
)) ))
#+(or) #+(or)
@ -259,6 +242,8 @@
;; default: run CIEL's REPL. ;; default: run CIEL's REPL.
(t (t
;; XXX: maybe pass all CLI options here, don't re-read them in the repl function.
;; (which was the old way).
(sbcli::repl))) (sbcli::repl)))
(error (c) (error (c)

35
utils.lisp Normal file
View file

@ -0,0 +1,35 @@
(in-package :ciel)
;;; Utilities that are useful enough to be available everywhere.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; These are used for the scripting capabilities.
;;; We can load a file with or without a shebang line.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun maybe-ignore-shebang (in)
"If this file starts with #!, delete the shebang line,
so we can LOAD the file.
Return: a stream (it is LOADable)."
;; thanks Roswell for the trick.
(let ((first-line (read-line in)))
(make-concatenated-stream
;; remove shebang:
(make-string-input-stream
(format nil "~a"
(if (str:starts-with-p "#!" first-line)
""
first-line)))
;; rest of the file:
in)))
(defun load-without-shebang (file)
"LOAD this file, but exclude the first line if it is a shebang line."
(with-open-file (file-stream file)
(load
(maybe-ignore-shebang file-stream))))
(defun has-shebang (file)
"Return T if the first line of this file is a shell shebang line (starts with #!)."
(with-open-file (s file)
(str:starts-with-p "#!" (read-line s))))