Add QTerminalWidget with libvterm backend replacing QScintilla terminal
ober
883e6b0b5351b6b90976af59566fa7f41937c0f5
--- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ libqt_shim.so: vendor/qt_shim.cpp -I$(QT_SHIM_H) -I$(QT_INC) -I$(QT_INC)/QtCore -I$(QT_INC)/QtGui -I$(QT_INC)/QtWidgets -I$(QT_INC)/Qsci \ vendor/qt_shim.cpp \ -o libqt_shim.so \ - -lQt6Core -lQt6Gui -lQt6Widgets -lqscintilla2_qt6 + -lQt6Core -lQt6Gui -lQt6Widgets -lqscintilla2_qt6 -lvterm -lutil qt_chez_shim.so: vendor/qt_chez_shim.c vendor/qt_shim.h gcc -shared -fPIC -O2 -o qt_chez_shim.so vendor/qt_chez_shim.c -Ivendor -Wall --- a/lib/jerboa-emacs/async.sls +++ b/lib/jerboa-emacs/async.sls @@ -552,8 +552,8 @@ (let ([v (hashtable-ref cache key - '#{miss gxqbd0sajiqb4war1wkachpqo-1})]) - (if (eq? v '#{miss gxqbd0sajiqb4war1wkachpqo-2}) + '#{miss l89txjuduef6khmnseoln0n2k-1})]) + (if (eq? v '#{miss l89txjuduef6khmnseoln0n2k-2}) (if (null? default) #f (car default)) v))) (def (weak-cache-set! cache key value) --- a/lib/jerboa-emacs/qt/app.sls +++ b/lib/jerboa-emacs/qt/app.sls @@ -763,24 +763,32 @@ (with-output-to-string (lambda () (display-exception e))))) (lambda () - (if (image-buffer? buf) - (begin - (qt-show-image-buffer! editor buf) - (let ([win (hash-get *editor-window-map* editor)]) - (when (and win - (qt-edit-window-image-scroll win)) - (let ([scroll (qt-edit-window-image-scroll - win)]) - (unless (hash-get - image-key-installed - scroll) - ((app-state-key-handler app) scroll) - (hash-put! image-key-installed scroll #t)) - (qt-widget-set-focus! scroll))))) - (begin - (qt-hide-image-buffer! editor) - (qt-reapply-highlighting! editor buf) - (qt-widget-set-focus! editor)))))))) + (cond + [(hash-get *terminal-widget-map* buf) => + (lambda (term) + (let ([win (hash-get *editor-window-map* editor)]) + (when win + (let* ([container (qt-edit-window-container + win)] + [count (qt-stacked-widget-count + container)]) + (qt-stacked-widget-set-current-index! + container + (- count 1)) + (qt-terminal-focus! term)))))] + [(image-buffer? buf) + (qt-show-image-buffer! editor buf) + (let ([win (hash-get *editor-window-map* editor)]) + (when (and win (qt-edit-window-image-scroll win)) + (let ([scroll (qt-edit-window-image-scroll win)]) + (unless (hash-get image-key-installed scroll) + ((app-state-key-handler app) scroll) + (hash-put! image-key-installed scroll #t)) + (qt-widget-set-focus! scroll))))] + [else + (qt-hide-image-buffer! editor) + (qt-reapply-highlighting! editor buf) + (qt-widget-set-focus! editor)])))))) (recent-files-load!) (bookmarks-load! app) (custom-keys-load!) @@ -803,7 +811,7 @@ ";; C-x 2 Split window C-x o Other window\n" ";; C-h f Describe command C-h k Describe key\n" ";;\n" - ";; This buffer is for Gerbil Scheme evaluation.\n" + ";; This buffer is for Jerboa Scheme evaluation.\n" ";; Type expressions and use M-x eval-buffer to evaluate.\n\n"))]) (qt-plain-text-edit-set-text! ed text) (qt-text-document-set-modified! @@ -1531,203 +1539,259 @@ (app-state-echo app) echo-label)))))))]) - (let ([is-printable (and (= (string-length - text) - 1) - (> (char->integer - (string-ref - text - 0)) - 31))] - [no-ctrl (zero? - (bitwise-and - mods - QT_MOD_CTRL))] - [no-alt (zero? - (bitwise-and + (let* ([qt-buf (qt-current-buffer + (app-state-frame + app))] + [qt-term (and qt-buf + (hash-get + *terminal-widget-map* + qt-buf))]) + (if (and qt-term + (null? + (key-state-prefix-keys + (app-state-key-state + app))) + (not (and (not (zero? + (bitwise-and + mods + QT_MOD_CTRL))) + (zero? + (bitwise-and + mods + QT_MOD_ALT)) + (= code + (+ QT_KEY_A + 23)))) + (not (and (not (zero? + (bitwise-and + mods + QT_MOD_ALT))) + (zero? + (bitwise-and + mods + QT_MOD_CTRL)) + (= code + (+ QT_KEY_A + 23))))) + (qt-terminal-send-key-event! + qt-term + code + mods + (or text "")) + (let ([is-printable (and (= (string-length + text) + 1) + (> (char->integer + (string-ref + text + 0)) + 31))] + [no-ctrl (zero? + (bitwise-and + mods + QT_MOD_CTRL))] + [no-alt (zero? + (bitwise-and + mods + QT_MOD_ALT))]) + (verbose-log! "CHORD-CHECK pending=" + (if *chord-pending-char* + (string + *chord-pending-char*) + "#f") + " key=" + (if (and is-printable + no-ctrl + no-alt) + text + "non-printable") + " chord-start?=" + (if (and is-printable + no-ctrl + no-alt) + (if (chord-start-char? + (string-ref + text + 0)) + "Y" + "N") + "N/A") + " autorepeat=" + (if autorepeat? "Y" "N") + " prefix=" + (if (null? + (key-state-prefix-keys + (app-state-key-state + app))) + "none" + "active")) + (cond + [(and *chord-pending-char* + (not *chord-timer-fired*)) + (let* ([ch1 *chord-pending-char*] + [saved-code *chord-pending-code*] + [saved-mods *chord-pending-mods*] + [saved-text *chord-pending-text*] + [ch2 (and (= (string-length + text) + 1) + (> (char->integer + (string-ref + text + 0)) + 31) + (zero? + (bitwise-and + mods + QT_MOD_CTRL)) + (zero? + (bitwise-and + mods + QT_MOD_ALT)) + (string-ref + text + 0))]) + (cond + [autorepeat? + (verbose-log! + "CHORD-AUTOREPEAT ignored ch=" + (string ch1)) + (void)] + [(and (not ch2) + (or (and (>= code + 16777248) + (<= code + 16777253)) + (= code + 16777299) + (= code + 16777300) + (= code + 16781571))) + (verbose-log! + "CHORD-IGNORE-MODIFIER pending=" + (string ch1) + " code=" + (number->string + code)) + (void)] + [(not ch2) + (verbose-log! + "CHORD-CANCEL-NONCHORD pending=" + (string ch1) + " code=" + (number->string + code)) + (qt-timer-stop! + *chord-timer*) + (set! *chord-pending-char* + #f) + (do-normal-key! + saved-code + saved-mods + saved-text) + (do-normal-key! + code mods - QT_MOD_ALT))]) - (verbose-log! "CHORD-CHECK pending=" - (if *chord-pending-char* - (string - *chord-pending-char*) - "#f") - " key=" - (if (and is-printable - no-ctrl - no-alt) - text - "non-printable") - " chord-start?=" - (if (and is-printable - no-ctrl - no-alt) - (if (chord-start-char? - (string-ref text 0)) - "Y" - "N") - "N/A") - " autorepeat=" - (if autorepeat? "Y" "N") - " prefix=" - (if (null? - (key-state-prefix-keys - (app-state-key-state - app))) - "none" - "active")) - (cond - [(and *chord-pending-char* - (not *chord-timer-fired*)) - (let* ([ch1 *chord-pending-char*] - [saved-code *chord-pending-code*] - [saved-mods *chord-pending-mods*] - [saved-text *chord-pending-text*] - [ch2 (and (= (string-length - text) - 1) - (> (char->integer - (string-ref - text - 0)) - 31) - (zero? - (bitwise-and + text)] + [else + (let ([chord-cmd (chord-lookup + ch1 + ch2)]) + (verbose-log! + "CHORD-RESOLVE ch1=" + (string ch1) + " ch2=" + (string ch2) + " cmd=" + (if chord-cmd + (symbol->string + chord-cmd) + "#f")) + (qt-timer-stop! + *chord-timer*) + (set! *chord-pending-char* + #f) + (if chord-cmd + (begin + (execute-command! + app + chord-cmd) + (qt-update-visual-decorations! + (qt-current-editor + (app-state-frame + app))) + (qt-update-mark-selection! + app) + (qt-modeline-update! + app) + (qt-tabbar-update! + app) + (qt-update-frame-title! + app) + (qt-echo-draw! + (app-state-echo + app) + echo-label)) + (begin + (do-normal-key! + saved-code + saved-mods + saved-text) + (do-normal-key! + code mods - QT_MOD_CTRL)) - (zero? - (bitwise-and - mods - QT_MOD_ALT)) - (string-ref - text - 0))]) - (cond - [autorepeat? - (verbose-log! - "CHORD-AUTOREPEAT ignored ch=" - (string ch1)) - (void)] - [(and (not ch2) - (or (and (>= code - 16777248) - (<= code - 16777253)) - (= code 16777299) - (= code 16777300) - (= code - 16781571))) - (verbose-log! - "CHORD-IGNORE-MODIFIER pending=" - (string ch1) - " code=" - (number->string code)) - (void)] - [(not ch2) - (verbose-log! - "CHORD-CANCEL-NONCHORD pending=" - (string ch1) - " code=" - (number->string code)) - (qt-timer-stop! - *chord-timer*) - (set! *chord-pending-char* - #f) - (do-normal-key! - saved-code - saved-mods - saved-text) - (do-normal-key! - code - mods - text)] - [else - (let ([chord-cmd (chord-lookup - ch1 - ch2)]) - (verbose-log! "CHORD-RESOLVE ch1=" - (string ch1) " ch2=" - (string ch2) " cmd=" - (if chord-cmd - (symbol->string - chord-cmd) - "#f")) - (qt-timer-stop! - *chord-timer*) - (set! *chord-pending-char* - #f) - (if chord-cmd - (begin - (execute-command! - app - chord-cmd) - (qt-update-visual-decorations! - (qt-current-editor - (app-state-frame - app))) - (qt-update-mark-selection! - app) - (qt-modeline-update! - app) - (qt-tabbar-update! - app) - (qt-update-frame-title! - app) - (qt-echo-draw! - (app-state-echo - app) - echo-label)) - (begin - (do-normal-key! - saved-code - saved-mods - saved-text) - (do-normal-key! - code + text))))]))] + [(and (not autorepeat?) + (= (string-length + text) + 1) + (> (char->integer + (string-ref + text + 0)) + 31) + (zero? + (bitwise-and mods - text))))]))] - [(and (not autorepeat?) - (= (string-length text) 1) - (> (char->integer + QT_MOD_CTRL)) + (zero? + (bitwise-and + mods + QT_MOD_ALT)) + (null? + (key-state-prefix-keys + (app-state-key-state + app))) + (chord-start-char? + (string-ref + text + 0))) + (verbose-log! "CHORD-PENDING ch=" + (string (string-ref text 0)) - 31) - (zero? - (bitwise-and - mods - QT_MOD_CTRL)) - (zero? - (bitwise-and - mods - QT_MOD_ALT)) - (null? - (key-state-prefix-keys - (app-state-key-state - app))) - (chord-start-char? - (string-ref text 0))) - (verbose-log! "CHORD-PENDING ch=" - (string (string-ref text 0)) - " timeout=" - (number->string - *chord-timeout*) - "ms") - (set! *chord-pending-char* - (string-ref text 0)) - (set! *chord-pending-code* - code) - (set! *chord-pending-mods* - mods) - (set! *chord-pending-text* - text) - (set! *chord-timer-fired* #f) - (qt-timer-start! - *chord-timer* - *chord-timeout*)] - [else - (do-normal-key! - code - mods - text)])))]))))]) + " timeout=" + (number->string + *chord-timeout*) + "ms") + (set! *chord-pending-char* + (string-ref text 0)) + (set! *chord-pending-code* + code) + (set! *chord-pending-mods* + mods) + (set! *chord-pending-text* + text) + (set! *chord-timer-fired* + #f) + (qt-timer-start! + *chord-timer* + *chord-timeout*)] + [else + (do-normal-key! + code + mods + text)])))))]))))]) (qt-on-key-press-consuming! (qt-current-editor fr) key-handler) --- a/lib/jerboa-emacs/qt/commands-config.sls +++ b/lib/jerboa-emacs/qt/commands-config.sls @@ -18,10 +18,11 @@ *qt-profiler-running* *qt-profiler-start-stats* *profiler-data* cmd-profiler-start cmd-profiler-stop cmd-show-tab-count cmd-show-trailing-whitespace-count - terminal-buffer-counter cmd-term cmd-terminal-send - cmd-term-interrupt cmd-term-send-eof cmd-term-send-tab - cmd-multi-vterm *terminal-copy-mode* cmd-vterm-copy-mode - cmd-vterm-copy-done get-terminal-buffers + *SCI_SETCODEPAGE* *SC_CP_UTF8* qt-insert-prompt! + terminal-buffer-counter *terminal-widget-map* cmd-term + cmd-terminal-send cmd-term-interrupt cmd-term-send-eof + cmd-term-send-tab cmd-multi-vterm *terminal-copy-mode* + cmd-vterm-copy-mode cmd-vterm-copy-done get-terminal-buffers qt-switch-to-terminal! cmd-term-list cmd-term-next cmd-term-prev cmd-ediff-files cmd-comment-dwim) (import @@ -854,10 +855,49 @@ (string-append (number->string count) " lines with trailing whitespace")))) + (define *SCI_SETCODEPAGE*--cell (vector 2037)) + (define *SC_CP_UTF8*--cell (vector 65001)) + (def (qt-insert-prompt! ed ts) + "Insert PS1 prompt with ANSI colors using Qt Scintilla APIs.\n Uses sci-send/SCI_APPENDTEXT (not TUI editor-append-text).\n Returns character count of document after insertion (for prompt-pos tracking).\n NOTE: must return CHARACTERS (not bytes) — prompt-pos is compared against\n string-length which is char-based. UTF-8 multi-byte chars (like PS1 arrows)\n make byte-offset != char-count." + (let* ([raw (terminal-prompt-raw ts)] + [clean (list->string + (filter + (lambda (c) + (not (or (char=? c (integer->char 1)) + (char=? c (integer->char 2))))) + (string->list raw)))] + [segments (parse-ansi-segments clean)]) + (let loop ([segs segments] + [pos (sci-send ed SCI_GETLENGTH)]) + (if (null? segs) + (string-length (qt-plain-text-edit-text ed)) + (let* ([seg (car segs)] + [text (text-segment-text seg)] + [fg (text-segment-fg-color seg)] + [bold? (text-segment-bold? seg)] + [style (color-to-style fg bold?)] + [utf8-bv (string->utf8 text)] + [text-len (bytevector-length utf8-bv)] + [utf8-str (let loop2 ([i (- text-len 1)] [acc '()]) + (if (< i 0) + (list->string acc) + (loop2 + (- i 1) + (cons + (integer->char + (bytevector-u8-ref utf8-bv i)) + acc))))]) + (sci-send/string ed SCI_APPENDTEXT utf8-str text-len) + (when (> style 0) + (sci-send ed SCI_STARTSTYLING pos 0) + (sci-send ed SCI_SETSTYLING text-len style)) + (loop (cdr segs) (+ pos text-len))))))) (define terminal-buffer-counter--cell (vector 0)) + (define *terminal-widget-map*--cell + (vector (make-hash-table-eq))) (def (cmd-term app) - "Open a new gsh-backed terminal buffer." - (verbose-log! "cmd-term: begin") + "Open a QTerminalWidget-backed terminal buffer.\n Uses libvterm for proper VT100 terminal emulation with full color support." + (verbose-log! "cmd-term: begin (QTerminalWidget)") (let* ([fr (app-state-frame app)] [ed (current-qt-editor app)] [name (begin @@ -871,38 +911,34 @@ "*")))] [buf (qt-buffer-create! name ed #f)]) (buffer-lexer-lang-set! buf 'terminal) - (qt-plain-text-edit-set-line-wrap! ed #f) - (verbose-log! "cmd-term: qt-buffer-attach! begin") (qt-buffer-attach! ed buf) - (verbose-log! "cmd-term: qt-buffer-attach! done") (qt-edit-window-buffer-set! (qt-current-window fr) buf) (with-catch (lambda (e) (let ([msg (with-output-to-string (lambda () (display-exception e)))]) - (jemacs-log! "cmd-term: gsh init failed: " msg) - (verbose-log! "cmd-term: gsh init FAILED: " msg) + (jemacs-log! "cmd-term: QTerminalWidget failed: " msg) + (verbose-log! "cmd-term: QTerminalWidget FAILED: " msg) (echo-error! (app-state-echo app) (string-append "Terminal failed: " msg)))) (lambda () - (verbose-log! "cmd-term: terminal-start! begin") - (let ([ts (terminal-start!)]) - (verbose-log! "cmd-term: terminal-start! done") - (hash-put! *terminal-state* buf ts) - (let ([prompt (terminal-prompt ts)]) - (verbose-log! - "cmd-term: qt-plain-text-edit-set-text! begin prompt-len=" - (number->string (string-length prompt))) - (qt-plain-text-edit-set-text! ed prompt) - (verbose-log! - "cmd-term: qt-plain-text-edit-set-text! done") - (terminal-state-prompt-pos-set! ts (string-length prompt)) - (qt-plain-text-edit-move-cursor! ed QT_CURSOR_END))) - (verbose-log! "cmd-term: done, terminal started") - (echo-message! - (app-state-echo app) - (string-append name " started")))))) + (let* ([win (qt-current-window fr)] + [container (qt-edit-window-container win)] + [term (qt-terminal-create container)]) + (qt-terminal-set-font! term "DejaVu Sans Mono" 11) + (qt-terminal-set-colors! term 12305103 2632756) + (let ([idx (qt-stacked-widget-add-widget! + container + (qt-terminal-widget term))]) + (qt-stacked-widget-set-current-index! container idx)) + (hash-put! *terminal-widget-map* buf term) + (qt-terminal-spawn! term "") + (qt-terminal-focus! term) + (verbose-log! "cmd-term: QTerminalWidget spawned") + (echo-message! + (app-state-echo app) + (string-append name " started"))))))) (def (cmd-terminal-send app) "Execute the current input line in the terminal via gsh.\n Builtins run synchronously, external commands run async via PTY.\n When PTY is busy (e.g. sudo password prompt), sends newline to PTY." (let* ([buf (current-qt-buffer app)] @@ -978,15 +1014,11 @@ #\newline) (qt-plain-text-edit-insert-text! ed "\n"))) (when (hash-get *terminal-state* buf) - (let ([prompt (terminal-prompt ts)]) - (qt-plain-text-edit-move-cursor! - ed - QT_CURSOR_END) - (qt-plain-text-edit-insert-text! ed prompt) - (terminal-state-prompt-pos-set! - ts - (string-length (qt-plain-text-edit-text ed))) - (qt-plain-text-edit-ensure-cursor-visible! ed)))] + (qt-plain-text-edit-move-cursor! ed QT_CURSOR_END) + (terminal-state-prompt-pos-set! + ts + (qt-insert-prompt! ed ts)) + (qt-plain-text-edit-ensure-cursor-visible! ed))] [(async) (qt-plain-text-edit-move-cursor! ed QT_CURSOR_END) (qt-plain-text-edit-ensure-cursor-visible! ed)] @@ -994,12 +1026,10 @@ (cond [(eq? output 'clear) (qt-plain-text-edit-set-text! ed "") - (let ([prompt (terminal-prompt ts)]) - (qt-plain-text-edit-insert-text! ed prompt) - (terminal-state-prompt-pos-set! - ts - (string-length (qt-plain-text-edit-text ed))) - (qt-plain-text-edit-ensure-cursor-visible! ed))] + (terminal-state-prompt-pos-set! + ts + (qt-insert-prompt! ed ts)) + (qt-plain-text-edit-ensure-cursor-visible! ed)] [(eq? output 'exit) (terminal-stop! ts) (let* ([fr (app-state-frame app)] @@ -1048,14 +1078,12 @@ (qt-plain-text-edit-insert-text! ed "^C\n") (qt-plain-text-edit-ensure-cursor-visible! ed))] [else - (let* ([ed (current-qt-editor app)] - [prompt (terminal-prompt ts)]) + (let ([ed (current-qt-editor app)]) (qt-plain-text-edit-move-cursor! ed QT_CURSOR_END) (qt-plain-text-edit-insert-text! ed "^C\n") - (qt-plain-text-edit-insert-text! ed prompt) (terminal-state-prompt-pos-set! ts - (string-length (qt-plain-text-edit-text ed))) + (qt-insert-prompt! ed ts)) (qt-plain-text-edit-ensure-cursor-visible! ed))]))) (def (cmd-term-send-eof app) "Close the terminal/shell/eshell buffer (Ctrl-D).\n Only exits if the current input line is empty (standard shell behavior)." @@ -1364,6 +1392,17 @@ (identifier-syntax [id (vector-ref *profiler-data*--cell 0)] [(set! id val) (vector-set! *profiler-data*--cell 0 val)])) + (define-syntax *SCI_SETCODEPAGE* + (identifier-syntax + [id (vector-ref *SCI_SETCODEPAGE*--cell 0)] + [(set! id val) (vector-set! + *SCI_SETCODEPAGE*--cell + 0 + val)])) + (define-syntax *SC_CP_UTF8* + (identifier-syntax + [id (vector-ref *SC_CP_UTF8*--cell 0)] + [(set! id val) (vector-set! *SC_CP_UTF8*--cell 0 val)])) (define-syntax terminal-buffer-counter (identifier-syntax [id (vector-ref terminal-buffer-counter--cell 0)] @@ -1371,6 +1410,13 @@ terminal-buffer-counter--cell 0 val)])) + (define-syntax *terminal-widget-map* + (identifier-syntax + [id (vector-ref *terminal-widget-map*--cell 0)] + [(set! id val) (vector-set! + *terminal-widget-map*--cell + 0 + val)])) (define-syntax *terminal-copy-mode* (identifier-syntax [id (vector-ref *terminal-copy-mode*--cell 0)] --- a/lib/jerboa-emacs/qt/commands-edit.sls +++ b/lib/jerboa-emacs/qt/commands-edit.sls @@ -741,7 +741,7 @@ (qt-edit-window-buffer-set! (qt-current-window fr) buf) (gsh-eshell-init-buffer! buf) (let ([welcome (string-append - "gsh — Gerbil Shell\n" + "gsh — Jerboa Shell\n" "Type commands or 'exit' to close.\n\n" (gsh-eshell-get-prompt buf))]) (qt-plain-text-edit-set-text! ed welcome) --- a/lib/jerboa-emacs/qt/commands-parity.sls +++ b/lib/jerboa-emacs/qt/commands-parity.sls @@ -1087,7 +1087,7 @@ (def (cmd-help-with-tutorial app) "Show the jemacs tutorial (C-h t)." (let* ([text (string-append "=== Jemacs Tutorial ===\n\n" - "Welcome to Jemacs, a Gerbil Scheme Emacs replacement.\n\n" + "Welcome to Jemacs, a Jerboa Scheme Emacs replacement.\n\n" "== Basic Movement ==\n" " C-f / C-b Forward / backward character\n" " M-f / M-b Forward / backward word\n" @@ -1131,7 +1131,7 @@ " M-x magit-status Git integration\n" " M-x treemacs File tree\n" " M-x shell Shell\n" - " M-x eshell Gerbil shell\n" + " M-x eshell Jerboa shell\n" " M-x term Terminal\n")] [fr (app-state-frame app)] [ed (current-qt-editor app)] --- a/lib/jerboa-emacs/qt/commands-parity2.sls +++ b/lib/jerboa-emacs/qt/commands-parity2.sls @@ -168,7 +168,7 @@ "Switch to CSS mode with syntax highlighting." (qt-set-major-mode! app 'css "CSS mode")) (def (cmd-scheme-mode app) - "Switch to Scheme/Gerbil mode with syntax highlighting." + "Switch to Scheme/Jerboa mode with syntax highlighting." (qt-set-major-mode! app 'scheme "Scheme mode")) (def (cmd-check-parens app) "Check for unbalanced parentheses in the current buffer." --- a/lib/jerboa-emacs/qt/commands-parity5.sls +++ b/lib/jerboa-emacs/qt/commands-parity5.sls @@ -1181,7 +1181,7 @@ (sci-send ed SCI_SETREADONLY 1) (qt-plain-text-edit-set-cursor-position! ed 0)))))))) (def (cmd-package-list-packages app) - "List installed Gerbil packages." + "List installed Jerboa packages." (let* ([output (qt-run-gerbil-pkg '("list"))] [fr (app-state-frame app)] [win (qt-current-window fr)] @@ -1191,11 +1191,11 @@ (qt-edit-window-buffer-set! win buf) (qt-plain-text-edit-set-text! ed - (string-append "Installed Gerbil Packages\n\n" output "\n")) + (string-append "Installed Jerboa Packages\n\n" output "\n")) (sci-send ed SCI_SETREADONLY 1) (qt-plain-text-edit-set-cursor-position! ed 0))) (def (cmd-package-install app) - "Install a Gerbil package by name." + "Install a Jerboa package by name." (let ([pkg (qt-echo-read-string app "Package to install: ")]) @@ -1208,7 +1208,7 @@ (app-state-echo app) (string-append "Install: " result)))))) (def (cmd-package-delete app) - "Uninstall a Gerbil package." + "Uninstall a Jerboa package." (let ([pkg (qt-echo-read-string app "Package to remove: ")]) (when (and pkg (> (string-length pkg) 0)) (let ([result (qt-run-gerbil-pkg (list "uninstall" pkg))]) @@ -1216,7 +1216,7 @@ (app-state-echo app) (string-append "Uninstall: " result)))))) (def (cmd-package-refresh-contents app) - "Refresh Gerbil package list." + "Refresh Jerboa package list." (echo-message! (app-state-echo app) "Updating packages...") (let ([result (qt-run-gerbil-pkg '("update"))]) (echo-message! @@ -1229,7 +1229,7 @@ [ed (qt-edit-window-editor win)] [buf (qt-buffer-create! "*Package Archives*" ed #f)] [text (string-append "Package Archives\n" (make-string 40 #\=) "\n\n" - "Gerbil packages are managed via gerbil pkg.\n\n" + "Jerboa packages are managed via gerbil pkg.\n\n" "Commands:\n" " M-x package-install Install a package\n" " M-x package-delete Remove a package\n" --- a/lib/jerboa-emacs/qt/commands-search.sls +++ b/lib/jerboa-emacs/qt/commands-search.sls @@ -429,7 +429,7 @@ (compilation-run-command! app cmd)))) (define *compile-on-save*--cell (vector #f)) (def (compile-on-save-check! app path) - "If compile-on-save is enabled and PATH is a .ss file in a Gerbil project,\n run gerbil build in the background." + "If compile-on-save is enabled and PATH is a .ss file in a Jerboa project,\n run gerbil build in the background." (when (and *compile-on-save* path (string-suffix? ".ss" path)) @@ -642,7 +642,7 @@ (reverse errors))] [else (flycheck-parse-gcc-format output file)])) (def (flycheck-check! app path) - "Run linter async on a source file, parse errors. Updates *flycheck-errors*.\nSupports Gerbil (.ss), Python, JS/TS, Go, Shell, C/C++, Ruby." + "Run linter async on a source file, parse errors. Updates *flycheck-errors*.\nSupports Jerboa (.ss), Python, JS/TS, Go, Shell, C/C++, Ruby." (when (and *flycheck-mode* path) (cond [(string-suffix? ".ss" path) @@ -748,7 +748,7 @@ lines) (reverse errors))) (def (cmd-flycheck-mode app) - "Toggle flycheck (live syntax checking on save) for Gerbil files." + "Toggle flycheck (live syntax checking on save) for Jerboa files." (set! *flycheck-mode* (not *flycheck-mode*)) (when (not *flycheck-mode*) (let ([ed (current-qt-editor app)]) @@ -823,7 +823,7 @@ (qt-text-document-set-modified! (buffer-doc-pointer buf) #f) (qt-plain-text-edit-set-cursor-position! ed 0)))) (def (cmd-toggle-compile-on-save app) - "Toggle automatic compilation when saving Gerbil files." + "Toggle automatic compilation when saving Jerboa files." (set! *compile-on-save* (not *compile-on-save*)) (echo-message! (app-state-echo app) @@ -1042,7 +1042,7 @@ (current-qt-editor app) date-str))) (def (cmd-eval-buffer app) - "Evaluate all top-level forms in the current buffer.\n Full Gerbil syntax supported (def, defstruct, hash, match, etc.)." + "Evaluate all top-level forms in the current buffer.\n Full Jerboa syntax supported (def, defstruct, hash, match, etc.)." (let* ([echo (app-state-echo app)] [ed (current-qt-editor app)] [buf (current-qt-buffer app)] --- a/lib/jerboa-emacs/qt/commands-shell.sls +++ b/lib/jerboa-emacs/qt/commands-shell.sls @@ -1440,7 +1440,7 @@ (app-state-echo app) (string-join shown " ")))])))))))) (def (cmd-completion-at-point app) - "Smart completion at point. For Gerbil buffers, combines buffer words\n with known Gerbil standard library symbols." + "Smart completion at point. For Jerboa buffers, combines buffer words\n with known Jerboa standard library symbols." (let* ([ed (current-qt-editor app)] [buf (current-qt-buffer app)] [lang (buffer-lexer-lang buf)] @@ -1570,10 +1570,10 @@ "Show Emacs manual via Info." (info-read-topic! app "emacs")) (def (cmd-info-elisp-manual app) - "Show Gerbil documentation." + "Show Jerboa documentation." (echo-message! (app-state-echo app) - "Gerbil Scheme documentation at https://cons.io")) + "Jerboa Scheme documentation at https://jerboa-lang.org")) (def (cmd-report-bug app) "Report a bug." (echo-message! --- a/lib/jerboa-emacs/qt/commands-shell2.sls +++ b/lib/jerboa-emacs/qt/commands-shell2.sls @@ -533,7 +533,7 @@ (qt-plain-text-edit-ensure-cursor-visible! ed))) (echo-message! (app-state-echo app) "Xref: forward")))) (def (cmd-eldoc-mode app) - "Toggle eldoc mode — shows function signatures in echo area on idle.\nWhen enabled, displays the signature of the enclosing function for\nScheme/Gerbil/Lisp buffers. Also used by LSP for hover information." + "Toggle eldoc mode — shows function signatures in echo area on idle.\nWhen enabled, displays the signature of the enclosing function for\nScheme/Jerboa/Lisp buffers. Also used by LSP for hover information." (set! *eldoc-mode* (not *eldoc-mode*)) (echo-message! (app-state-echo app) --- a/lib/jerboa-emacs/qt/commands-vcs.sls +++ b/lib/jerboa-emacs/qt/commands-vcs.sls @@ -1376,7 +1376,7 @@ (define *gerbil-signatures*--cell (vector (make-hash-table))) (def (eldoc-init-signatures!) - "Populate the signature database with common Gerbil functions." + "Populate the signature database with common Jerboa functions." (hash-put! *gerbil-signatures* "hash-get" --- a/lib/jerboa-emacs/qt/commands.sls +++ b/lib/jerboa-emacs/qt/commands.sls @@ -4,34 +4,34 @@ (library (jerboa-emacs qt commands) (export qt-register-all-commands! dired-open-directory! - qt-open-image-inline! *qt-app-ptr* qt-kill-ring-push! - *isearch-active* isearch-handle-key! *qreplace-active* - qreplace-handle-key! recent-files-add! recent-files-load! - bookmarks-load! session-save! session-restore-files - *tab-bar-visible* *auto-revert-tail-buffers* *file-mtimes* - file-mtime-record! file-mtime-changed? *eldoc-mode* - eldoc-display! *current-theme* *themes* theme-stylesheet - load-theme! apply-theme! load-theme define-theme! - buffer-touch! custom-keys-load! abbrevs-load! - load-init-file! scratch-save! scratch-restore! - scratch-update-text! undo-history-record! winner-save! - *follow-mode* *view-mode-buffers* *so-long-buffers* - check-so-long! savehist-save! savehist-load! - gsh-history-save! gsh-history-load! save-place-load! - save-place-save! auto-fill-check! - *auto-save-disabled-buffers* *require-final-newline* - *save-place-enabled* *centered-cursor-mode* - uniquify-buffer-name! shell-command-to-string - shell-command-to-buffer! register-shell-command! - *user-shell-commands* workspace-init! *workspaces* - *current-workspace* workspace-add-buffer! - workspace-remove-buffer! qt-pulse-line! qt-pulse-tick! - qt-pulse-check-jump! qt-idle-highlight-symbol! - *diff-hl-active* *qt-describe-key-pending* - qt-describe-key-result! *qt-quoted-insert-pending* - qt-quoted-insert-handle! qt-record-edit-position! - *qt-desktop-save-mode* qt-aggressive-indent-line! - *snake-active* snake-handle-key!) + qt-open-image-inline! *qt-app-ptr* *terminal-widget-map* + qt-kill-ring-push! *isearch-active* isearch-handle-key! + *qreplace-active* qreplace-handle-key! recent-files-add! + recent-files-load! bookmarks-load! session-save! + session-restore-files *tab-bar-visible* + *auto-revert-tail-buffers* *file-mtimes* file-mtime-record! + file-mtime-changed? *eldoc-mode* eldoc-display! + *current-theme* *themes* theme-stylesheet load-theme! + apply-theme! load-theme define-theme! buffer-touch! + custom-keys-load! abbrevs-load! load-init-file! + scratch-save! scratch-restore! scratch-update-text! + undo-history-record! winner-save! *follow-mode* + *view-mode-buffers* *so-long-buffers* check-so-long! + savehist-save! savehist-load! gsh-history-save! + gsh-history-load! save-place-load! save-place-save! + auto-fill-check! *auto-save-disabled-buffers* + *require-final-newline* *save-place-enabled* + *centered-cursor-mode* uniquify-buffer-name! + shell-command-to-string shell-command-to-buffer! + register-shell-command! *user-shell-commands* + workspace-init! *workspaces* *current-workspace* + workspace-add-buffer! workspace-remove-buffer! + qt-pulse-line! qt-pulse-tick! qt-pulse-check-jump! + qt-idle-highlight-symbol! *diff-hl-active* + *qt-describe-key-pending* qt-describe-key-result! + *qt-quoted-insert-pending* qt-quoted-insert-handle! + qt-record-edit-position! *qt-desktop-save-mode* + qt-aggressive-indent-line! *snake-active* snake-handle-key!) (import (except (chezscheme) make-hash-table hash-table? iota \x31;+ \x31;- getenv path-extension path-absolute? thread? make-mutex @@ -678,6 +678,47 @@ (echo-error! echo (string-append "No buffer: " target-name))))))) + (def (cmd-kill-buffer-force app) + "Kill current buffer immediately, no prompts. Switches to another buffer first.\n Used by stress tests and automation where echo-area interaction is not possible." + (let* ([echo (app-state-echo app)]