mirror of
https://gitlab.com/vindarel/ciel.git
synced 2025-12-06 02:30:39 -08:00
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:
parent
f7a4f06335
commit
b23214917c
8 changed files with 98 additions and 33 deletions
2
Makefile
2
Makefile
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
2
ciel.asd
2
ciel.asd
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
22
repl.lisp
22
repl.lisp
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
35
utils.lisp
Normal 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))))
|
||||||
Loading…
Add table
Add a link
Reference in a new issue