# HG changeset patch # User Richard Westhaver # Date 1726885128 14400 # Node ID da507f0274b33608147ef1b1e55159996eb718d0 # Parent cad61259ba57786a04336d60fe13e51b36c2043f readline FFI diff -r cad61259ba57 -r da507f0274b3 lisp/ffi/readline/constants.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/ffi/readline/constants.lisp Fri Sep 20 22:18:48 2024 -0400 @@ -0,0 +1,36 @@ +("readline/readline.h") +((:integer +rl-readline-version+ "RL_READLINE_VERSION") + (:integer +rl-version-major+ "RL_VERSION_MAJOR") + (:integer +rl-version-minor+ "RL_VERSION_MINOR") + (:integer +no-match+ "NO_MATCH") + (:integer +single-match+ "SINGLE_MATCH") + (:integer +mult-match+ "MULT_MATCH") + (:integer +rl-state-none+ "RL_STATE_NONE") + (:integer +rl-state-initializing+ "RL_STATE_INITIALIZING") + (:integer +rl-state-initialized+ "RL_STATE_INITIALIZED") + (:integer +rl-state-termprepped+ "RL_STATE_TERMPREPPED") + (:integer +rl-state-readcmd+ "RL_STATE_READCMD") + (:integer +rl-state-metanext+ "RL_STATE_METANEXT") + (:integer +rl-state-dispatching+ "RL_STATE_DISPATCHING") + (:integer +rl-state-moreinput+ "RL_STATE_MOREINPUT") + (:integer +rl-state-isearch+ "RL_STATE_ISEARCH") + (:integer +rl-state-nsearch+ "RL_STATE_NSEARCH") + (:integer +rl-state-search+ "RL_STATE_SEARCH") + (:integer +rl-state-numericarg+ "RL_STATE_NUMERICARG") + (:integer +rl-state-macroinput+ "RL_STATE_MACROINPUT") + (:integer +rl-state-macrodef+ "RL_STATE_MACRODEF") + (:integer +rl-state-overwrite+ "RL_STATE_OVERWRITE") + (:integer +rl-state-completing+ "RL_STATE_COMPLETING") + (:integer +rl-state-sighandler+ "RL_STATE_SIGHANDLER") + (:integer +rl-state-undoing+ "RL_STATE_UNDOING") + (:integer +rl-state-inputpending+ "RL_STATE_INPUTPENDING") + (:integer +rl-state-ttycsaved+ "RL_STATE_TTYCSAVED") + (:integer +rl-state-callback+ "RL_STATE_CALLBACK") + (:integer +rl-state-vimotion+ "RL_STATE_VIMOTION") + (:integer +rl-state-multikey+ "RL_STATE_MULTIKEY") + (:integer +rl-state-vicmdonce+ "RL_STATE_VICMDONCE") + (:integer +rl-state-charsearch+ "RL_STATE_CHARSEARCH") + (:integer +rl-state-redisplaying+ "RL_STATE_REDISPLAYING") + (:integer +rl-state-done+ "RL_STATE_DONE") + (:integer +rl-state-timeout+ "RL_STATE_TIMEOUT") + (:integer +rl-state-eof+ "RL_STATE_EOF")) diff -r cad61259ba57 -r da507f0274b3 lisp/ffi/readline/readline.asd --- a/lisp/ffi/readline/readline.asd Fri Sep 20 19:59:36 2024 -0400 +++ b/lisp/ffi/readline/readline.asd Fri Sep 20 22:18:48 2024 -0400 @@ -10,9 +10,19 @@ ;; designed to handle many of the tricky OS-specific bits for us. ;;; Code: +(eval-when (:compile-toplevel :load-toplevel :execute) + (require :sb-grovel)) + +(defpackage :readline.sys + (:use :cl :asdf :sb-grovel :sb-alien)) + +(in-package :readline.sys) + (defsystem :readline - :depends-on (:std) - :components ((:file "pkg")) + :depends-on (:std :sb-grovel) + :components ((:file "pkg") + (grovel-constants-file "constants" + :package :readline)) :in-order-to ((test-op (test-op "readline/tests")))) (defsystem :readline/tests diff -r cad61259ba57 -r da507f0274b3 lisp/ffi/readline/readline.lisp --- a/lisp/ffi/readline/readline.lisp Fri Sep 20 19:59:36 2024 -0400 +++ b/lisp/ffi/readline/readline.lisp Fri Sep 20 22:18:48 2024 -0400 @@ -12,10 +12,80 @@ :list-all 63 :not-list-cmn-prefix 64) -(define-alien-type rl-history-entry (struct rl-history-entry +(define-alien-type rl-hist-entry (struct rl-hist-entry (line (* t)) (time (* t)) (data (* t)))) + +;; HS_STIFLED +(define-alien-type rl-history-state + (struct rl-history-state + (hist-entries (array (* rl-hist-entry))) + (offset int) + (length int) + (size int) + (flags int))) + +(define-alien-enum (rl-undo-code int :test eq) + :delete 0 + :insert 1 + :begin 2 + :end 3) + +(define-alien-type rl-undo-list + (struct rl-undo-list + (next (* (struct rl-undo-list))) + (start int) + (end int) + (text c-string) + (what rl-undo-code))) + +(define-alien-type rl-command-func + (function int int int)) + +(define-alien-type rl-funmap + (struct rl-funmap + (name c-string) + (function (* rl-command-func)))) + +(define-alien-type rl-keymap-entry + (struct rl-keymap-entry + (type char) + (function (* rl-command-func)))) + +(define-alien-type rl-keymap (array rl-keymap-entry)) + +(define-alien-type readline-state + (struct readline-state + (point int) + (end int) + (mark int) + (buflen int) + (buffer c-string) + (ul (* rl-undo-list)) + (prompt c-string) + (rlstate int) + (done int) + (kmap rl-keymap) + (lastfunc (* rl-command-func)) + (insmode int) + (edmode int) + (kseq c-string) + (kseqlen int) + (pendingin int) + (inf (* t)) + (outf (* t)) + (macro c-string) + (catchsigs int) + (catchsigwinch int) + (entryfunc (* rl-command-func)) + (menuentryfunc (* rl-command-func)) + (ignorefunc (* rl-command-func)) + (attemptfunc (* rl-command-func)) + (wordbreakchars c-string) + (reserved (array char 64)))) + +;;; Well Known Vars (macrolet ((def-rl-var (name var type) `(define-alien-variable (,name ,var) ,type))) (def-rl-var "rl_line_buffer" *line-buffer* c-string) @@ -74,33 +144,196 @@ (def-rl-var "history_base" *history-base* int) (def-rl-var "history_length" *history-length* int)) -(defvar *states* - '(:initializing ; 0x0000001 initializing - :initialized ; 0x0000002 initialization done - :termprepped ; 0x0000004 terminal is prepped - :readcmd ; 0x0000008 reading a command key - :metanext ; 0x0000010 reading input after ESC - :dispatching ; 0x0000020 dispatching to a command - :moreinput ; 0x0000040 reading more input in a command function - :isearch ; 0x0000080 doing incremental search - :nsearch ; 0x0000100 doing non-incremental search - :search ; 0x0000200 doing a history search - :numericarg ; 0x0000400 reading numeric argument - :macroinput ; 0x0000800 getting input from a macro - :macrodef ; 0x0001000 defining keyboard macro - :overwrite ; 0x0002000 overwrite mode - :completing ; 0x0004000 doing completion - :sighandler ; 0x0008000 in readline sighandler - :undoing ; 0x0010000 doing an undo - :inputpending ; 0x0020000 rl_execute_next called - :ttycsaved ; 0x0040000 tty special chars saved - :callback ; 0x0080000 using the callback interface - :vimotion ; 0x0100000 reading vi motion arg - :multikey ; 0x0200000 reading multiple-key command - :vicmdonce ; 0x0400000 entered vi command mode at least once - :redisplaying ; 0x0800000 updating terminal display - :done) ; 0x1000000 done; accepted line - "Possible state values for `+readline-state+'.") +;; low-level +(macrolet ((def-rl-int2 (&rest names) + `(progn + ,@(loop for i in names + collect + (std:with-gensyms (i1 i2) + `(define-alien-routine ,i int (,i1 int) (,i2 int))))))) + (def-rl-int2 "rl_digit_argument" "rl_universal_argument" "rl_forward_byte" + "rl_forward_char" "rl_forward" "rl_backward_byte" "rl_backward_char" "rl_backward" + "rl_beg_of_line" "rl_end_of_line" "rl_forward_word" "rl_backward_word" "rl_refresh_line" + "rl_clear_screen" "rl_clear_display" "rl_skip_csi_sequence" "rl_arrow_keys" + "rl_previous_screen_line" "rl_next_screen_line" + "rl_insert" "rl_quoted_insert" "rl_tab_insert" "rl_newline" "rl_do_lowercase_version" + "rl_rubout" "rl_delete" "rl_rubout_or_delete" "rl_delete_horizontal_space" "rl_delete_or_show_completions" + "rl_insert_comment" "rl_upcase_word" "rl_downcase_word" "rl_capitalize_word" "rl_transpose_words" + "rl_transpose_chars" "rl_char_search" "rl_backward_char_search" "rl_beginning_of_history" + "rl_end_of_history" "rl_get_next_history" "rl_get_previous_history" "rl_operate_and_get_next" + "rl_fetch_history" "rl_set_mark" "rl_exchange_point_and_mark" "rl_vi_editing_mode" + "rl_emacs_editing_mode" "rl_overwrite_mode" "rl_re_read_init_file" "rl_dump_functions" "rl_dump_macros" + "rl_dump_variables" "rl_complete" "rl_possible_completions" "rl_insert_completions" "rl_old_menu_complete" + "rl_backward_menu_complete" "rl_kill_word" "rl_backward_kill_word" "rl_kill_line" "rl_backward_kill_line" + "rl_kill_full_line" "rl_unix_word_rubout" "rl_unix_line_discard" "rl_copy_region_to_kill" "rl_kill_region" + "rl_copy_forward_word" "rl_copy_backward_word" "rl_yank" "rl_yank_pop" "rl_yank_nth_arg" "rl_yank_last_arg" + "rl_bracketed_paste_begin" + #+win32 "rl_paste_from_clipboard" + "rl_reverse_search_history" "rl_forward_search_history" "rl_start_kbd_macro" "rl_end_kbd_macro" + "rl_call_last_kbd_macro" "rl_print_last_kbd_macro" "rl_revert_line" "rl_undo_command" "rl_tilde_expand" + "rl_restart_output" "rl_stop_output" "rl_abort" "rl_tty_status" + "rl_history_search_forward" "rl_history_search_backward" "rl_history_substr_search_forward" + "rl_history_substr_search_backward" "rl_noninc_forward_search" "rl_noninc_reverse_search" + "rl_noninc_forward_search_again" "rl_noninc_reverse_search_again" + "rl_insert_close" "rl_vi_redo" "rl_vi_undo" "rl_vi_yank_arg" "rl_vi_fetch_history" "rl_vi_search_again" + "rl_vi_search" "rl_vi_complete" "rl_vi_tilde_expand" "rl_vi_prev_word" "rl_vi_next_word" "rl_vi_end_word" + "rl_vi_insert_beg" "rl_vi_append_mode" "rl_vi_append_eol" "rl_vi_eof_maybe" "rl_vi_insertion_mode" + "rl_vi_insert_mode" "rl_vi_movement_mode" "rl_vi_arg_digit" "rl_vi_change_case" "rl_vi_put" "rl_vi_column" + "rl_vi_delete_to" "rl_vi_change_to" "rl_vi_yank_to" "rl_vi_yank_pop" "rl_vi_rubout" "rl_vi_delete" + "rl_vi_back_to_indent" "rl_vi_unix_word_rubout" "rl_vi_first_print" "rl_vi_char_search" "rl_vi_match" + "rl_vi_change_char" "rl_vi_subst" "rl_vi_overstrike" "rl_vi_overstrike_delete" "rl_vi_replace" + "rl_vi_set_mark" "rl_vi_goto_mark" + ;; NOTE 2024-09-20: there are uppercase versions - fWord eWord + "rl_vi_fword" "rl_vi_bword" "rl_vi_eword")) + +;;; Well Published Functions +(define-alien-routine "readline" c-string (prompt c-string)) +(define-alien-routine "rl_set_prompt" int (prompt c-string)) +(define-alien-routine "rl_expand_prompt" int (prompt c-string)) +(define-alien-routine "rl_initialize" int) +;; undocument; unused by readline +;; (define-alien-routine "rl_discard_argument" int) + +;; [[file:/usr/include/readline/readline.h::/* Utility functions to bind keys to readline commands. */][last]] +(define-alien-routine "rl_add_defun" int (name c-string) (func (* rl-command-func))) +(define-alien-routine "rl_bind_key" int (key int) (function (* rl-command-func))) +(define-alien-routine "rl_bind_key_in_map" int (key int) (func (* rl-command-func)) (map rl-keymap)) +(define-alien-routine "rl_unbind_key" int (key int)) +(define-alien-routine "rl_unbind_key_in_map" int (key int) (map rl-keymap)) +(define-alien-routine "rl_bind_key_if_unbound" int (key int) (function (* rl-command-func))) +(define-alien-routine "rl_bind_key_if_unbound_in_map" int (key int) (function (* rl-command-func)) (map rl-keymap)) +(define-alien-routine "rl_generic_bind" int (key int) (str c-string) (name c-string) (map rl-keymap)) +(define-alien-routine "rl_variable_value" c-string (name c-string)) +(define-alien-routine "rl_variable_bind" int (name c-string) (val c-string)) + +(define-alien-routine "rl_read_init_file" int (file c-string)) +(define-alien-routine "rl_parse_and_bind" int (binding c-string)) + +;; keymaps +(define-alien-routine "rl_make_bare_keymap" rl-keymap) +(define-alien-routine "rl_empty_keymap" int (map rl-keymap)) +(define-alien-routine "rl_copy_keymap" rl-keymap (map rl-keymap)) +(define-alien-routine "rl_make_keymap" rl-keymap) +(define-alien-routine "rl_discard_keymap" void (map rl-keymap)) +(define-alien-routine "rl_free_keymap" void (map rl-keymap)) +(define-alien-routine "rl_set_keymap" void (map rl-keymap)) +(define-alien-routine "rl_get_keymap" rl-keymap) +(define-alien-routine "rl_set_keymap_name" int (name c-string) (map rl-keymap)) + +;; funmaps +(define-alien-routine "rl_add_funmap_entry" int (name c-string) (function (* rl-command-func))) +(define-alien-routine "rl_funmap_names" (array c-string)) + +;; kbd macros +(define-alien-routine "rl_push_macro_input" void (input c-string)) + +;; undo +(define-alien-routine "rl_add_undo" void (code rl-undo-code) (i1 int) (i2 int) (input c-string)) +(define-alien-routine "rl_free_undo_list" void) +(define-alien-routine "rl_do_undo" int) +(define-alien-routine "rl_begin_undo_group" int) +(define-alien-routine "rl_end_undo_group" int) +(define-alien-routine "rl_modifying" int (i1 int) (i2 int)) + +;; redisplay +(define-alien-routine "rl_redisplay" void) +(define-alien-routine "rl_on_new_line" int) +(define-alien-routine "rl_on_new_line_with_prompt" int) +(define-alien-routine "rl_forced_update_display" int) +(define-alien-routine "rl_clear_visible_line" int) +(define-alien-routine "rl_clear_message" int) +(define-alien-routine "rl_reset_line_state" int) +(define-alien-routine "rl_crlf" int) + +;; mark and region +(define-alien-routine "rl_keep_mark_active" void) +(define-alien-routine "rl_activate_mark" void) +(define-alien-routine "rl_deactivate_mark" void) +(define-alien-routine "rl_mark_active_p" int) +(define-alien-routine "rl_message" int) +(define-alien-routine "rl_show_char" int (char int)) +;; undocumented +(define-alien-routine "rl_character_len" int (i1 int) (i2 int)) +(define-alien-routine "rl_redraw_prompt_last_line" void) + +(define-alien-routine "rl_save_prompt" void) +(define-alien-routine "rl_restore_prompt" void) + +;; text editing +(define-alien-routine "rl_replace_line" void (line c-string) (idx int)) +(define-alien-routine "rl_insert_text" int (text c-string)) +(define-alien-routine "rl_delete_text" int (i1 int) (i2 int)) +(define-alien-routine "rl_kill_text" int (i1 int) (i2 int)) +(define-alien-routine "rl_copy_text" c-string (i1 int) (i2 int)) + +;; tty +(define-alien-routine "rl_prep_terminal" void (i int)) +(define-alien-routine "rl_deprep_terminal" void) +(define-alien-routine "rl_tty_set_default_bindings" void (map rl-keymap)) +(define-alien-routine "rl_tty_unset_default_bindings" void (map rl-keymap)) +(define-alien-routine "rl_tty_set_echoing" int (val int)) +(define-alien-routine "rl_reset_terminal" int (val c-string)) +(define-alien-routine "rl_resize_terminal" void) +(define-alien-routine "rl_set_screen_size" void (x int) (y int)) +(define-alien-routine "rl_get_screen_size" void (i1 (* int)) (i2 (* int))) +(define-alien-routine "rl_reset_screen_size" void) + +(define-alien-routine "rl_get_termcap" c-string (key c-string)) + +;; character input +(define-alien-routine "rl_stuff_char" int (c int)) +(define-alien-routine "rl_execute_next" int (i int)) +(define-alien-routine "rl_clear_pending_input" int) +(define-alien-routine "rl_read_key" int) +(define-alien-routine "rl_getc" int (c (* t))) ;; NOTE: (* FILE) +(define-alien-routine "rl_set_keyboard_input_timeout" int (val int)) + +;;timeouts +(define-alien-routine "rl_set_timeout" int (n1 unsigned-int) (n2 unsigned-int)) +(define-alien-routine "rl_timeout_remaining" int (n1 (* unsigned-int)) (n2 (* unsigned-int))) + +;; public utils +(define-alien-routine "rl_extend_lind_buffer" void (i int)) +(define-alien-routine "rl_ding" int) +(define-alien-routine "rl_alphabetic" int (i int)) +(define-alien-routine "rl_free" void (o (* t))) + +;; signals +(define-alien-routine "rl_set_signals" int) +(define-alien-routine "rl_clear_signals" int) +(define-alien-routine "rl_cleanup_after_signal" void) +(define-alien-routine "rl_reset_after_signal" void) +(define-alien-routine "rl_free_line_state" void) +(define-alien-routine "rl_pending_signal" int) +(define-alien-routine "rl_check_signals" void) +(define-alien-routine "rl_echo_signal_char" void (c int)) +(define-alien-routine "rl_set_paren_blink_timeout" int (val int)) + +;; history +(define-alien-routine "rl_clear_history" void) +(define-alien-routine "rl_maybe_save_line" int) +(define-alien-routine "rl_maybe_unsave_line" int) +(define-alien-routine "rl_maybe_replace_line" int) + +;; completion +(define-alien-routine "rl_complete_internal" int (i int)) +(define-alien-routine "rl_display_match_list" void (list (array c-string)) (i1 int) (i2 int)) +;; (define-alien-routine "rl_completion_matches" (array c-string) (input c-string) (function (* rl-compentry-func))) +(define-alien-routine "rl_username_completion_function" c-string (name c-string) (i int)) +(define-alien-routine "rl_filename_completion_function" c-string (name c-string) (i int)) +(define-alien-routine "rl_completion_mode" int (function (* rl-command-func))) + +;; history.h +(define-alien-routine "using_history" void) +(define-alien-routine "add_history" void (line c-string)) +(define-alien-routine "clear_history" void) +(define-alien-routine "stifle_history" void (i int)) +(define-alien-routine "unstifle_history" int) +(define-alien-routine "history_is_stifled" int) +(define-alien-routine "history_list" (array (* rl-hist-entry))) + +(define-alien-routine "rl_save_state" int (state (* readline-state))) +(define-alien-routine "rl_restore_state" int (state (* readline-state))) (defvar +c-buffer-size+ 256 "How many bytes to allocate per Lisp string when converting list of @@ -112,9 +345,6 @@ (values (ldb (byte 8 8) version) (ldb (byte 8 0) version))) -;; (defun decode-state (state) -;; "Transform Readline state STATE into list of keywords. See `+states+' for -;; list of components that can appear in result list." ;; (mapcan (lambda (index keyword) ;; (when (logbitp index state) ;; (list keyword))) @@ -154,7 +384,7 @@ PREDICATE. Return T if there is no history saved." (if (zerop *history-length*) t - (with-alien ((s rl-history-entry)) + (with-alien ((s rl-hist-entry)) (funcall predicate ;; TODO 2024-09-19: does SBCL know how to conver this to a lisp string automatically? (with-alien-slots @@ -166,9 +396,6 @@ s line))))) -(define-alien-routine "readline" (* t) (prompt c-string)) -(define-alien-routine "add_history" void (line c-string)) - (defun rl (&key prompt already-prompted @@ -208,12 +435,6 @@ str) (free-alien ptr))))) -;; (defun ensure-initialization () -;; "Make sure that Readline is initialized. If it's not initialized yet, -;; initialize it." -;; (unless (find :initialized *readline-state*) -;; (initialize))) - ;; (defmacro with-possible-redirection (filename append &body body) ;; "If FILENAME is not NIL, try to create C file named FILENAME, ;; temporarily reassign `*outstream*' to pointer to this file, perform BODY,