;; Copyright (c) 2003 Nikodemus Siivola ;; ;; Permission is hereby granted, free of charge, to any person obtaining ;; a copy of this software and associated documentation files (the ;; "Software"), to deal in the Software without restriction, including ;; without limitation the rights to use, copy, modify, merge, publish, ;; distribute, sublicense, and/or sell copies of the Software, and to ;; permit persons to whom the Software is furnished to do so, subject to ;; the following conditions: ;; ;; The above copyright notice and this permission notice shall be included ;; in all copies or substantial portions of the Software. ;; ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. (in-package readline) (defvar *whitespace* (list #\Space #\Tab)) (defun convert-and-free-foreign-string (foreign-string) (let ((lisp-string (convert-from-foreign-string foreign-string))) (free-foreign-object foreign-string) lisp-string)) (defmacro ignore-end-of-file (&body forms) `(catch 'end-of-file (handler-bind ((end-of-file (lambda (e) (declare (ignore e)) (throw 'end-of-file nil)))) ,@forms))) (def-function ("readline" c-readline) ((prompt :cstring)) :module "readline" :returning (* :char)) (def-function ("add_history" c-add-history) ((str :cstring)) :module "readline" :returning :void) (def-function ("add_completion" c-add-completion) ((str :cstring)) :module "cl-readline" :returning :int) (def-function ("clear_completions" c-clear-completions) () :module "cl-readline" :returning :void) (def-function "use_custom_complete" () :module "cl-readline" :returning :void) (def-function "use_filename_complete" () :module "cl-readline" :returning :void) (let (pkg) (defun add-completion (string) "Add STRING as a custom-completion." (setq pkg nil) (with-cstring (c-str string) (= 1 (c-add-completion c-str)))) (defun clear-completions () "Clear all custom-completions." (setq pkg nil) (c-clear-completions)) (defun use-package-complete (package) "Load symbols in package CL-USER as custom-completions." (unless (eql pkg package) (setq pkg package) (clear-completions) (do-symbols (sym (find-package package)) (add-completion (string-downcase (string sym))))) (use-custom-complete) nil)) ;;; Everything that affects the custom-completion collection goes ;;; above. (defun add-history (string) "Add STRING to history." (with-cstring (c-string string) (c-add-history c-string)) string) (defun readline (&key (prompt "") (history t)) "Read a line from current TTY with line-editing." (with-cstring (c-prompt prompt) (let* ((str (convert-and-free-foreign-string (c-readline c-prompt))) (str2 (string-trim *whitespace* str))) (when (and history (not (string= "" str2))) (add-history str2)) str))) (defun readexpr (&key (primary-prompt "=> ") (secondary-prompt "| ") (history t)) "Read an expression from current TTY with line-editing." (let (expr) (do* ((str (readline :prompt primary-prompt :history history) (readline :prompt secondary-prompt :history history)) (input str (concatenate 'string input " " str))) ((ignore-end-of-file (setq expr (with-input-from-string (in input) (read in nil nil)))) expr)))) ;; ;; Termios ;; (def-function "no_echo" () :module "cl-termios" :returning :void) (def-function "restore_term" () :module "cl-termios" :returning :void) (defmacro without-echo (&body forms) `(unwind-protect (progn (no-echo) ,@forms) (restore-term)))