Fix make static-qt: resolve Scheme import conflicts and link jsh coreutils
ober
47a3b9d91ac3c89316b28319050ba367c482b3a1
--- a/Makefile +++ b/Makefile @@ -254,6 +254,7 @@ SCI_SRC ?= $(HOME)/mine/chez-scintilla QT_SRC ?= $(HOME)/mine/chez-qt QTSHIM_SRC ?= $(HOME)/mine/gerbil-qt COREUTILS_SRC ?= $(HOME)/mine/jerboa-coreutils +JSH_COREUTILS_LIB ?= $(JSH_SRC)/rust-coreutils/target/x86_64-unknown-linux-musl/release/libjsh_coreutils.a DEPS_IMAGE := jemacs-deps:$(ARCH) @@ -297,6 +298,7 @@ build-jemacs-qt-static: check-root cp /src/vendor/jerboa-shell/embed-crypto.c /deps/jsh/ 2>/dev/null; \ cp /src/vendor/jerboa-shell/embed-crypto.h /deps/jsh/ 2>/dev/null; \ cp /src/vendor/jerboa-shell/ffi-shim.c /deps/jsh/ 2>/dev/null; \ + cp /src/vendor/jerboa-shell/libcoreutils.c /deps/jsh/ 2>/dev/null; \ if [ -f /src/vendor/jerboa-shell/crypto_stub.c ]; then \ gcc -c -O2 /src/vendor/jerboa-shell/crypto_stub.c -o /tmp/jemacs-build/crypto_stub.o; \ fi; \ @@ -370,6 +372,7 @@ build-jemacs-qt-static: check-root CHEZ_QT_DIR=/deps/chez-qt \ CHEZ_QT_SHIM_DIR=/deps/gerbil-qt/vendor \ COREUTILS_DIR=/deps/coreutils \ + JSH_COREUTILS_LIB=/deps/jsh/libjsh_coreutils.a \ TREE_SITTER_INCLUDE=/opt/tree-sitter-include \ TREE_SITTER_LIB=/opt/tree-sitter-lib \ TREE_SITTER_GRAMMARS=/opt/tree-sitter-grammars \ @@ -389,8 +392,10 @@ linux-static-qt-docker: -v $(JERBOA)/lib/std:/host-jerboa-std:ro \ -v $(COREUTILS_SRC)/lib:/host-coreutils:ro \ -v $(JSH_SRC)/src:/host-jsh-src:ro \ + -v $(JSH_COREUTILS_LIB):/host-jsh-coreutils.a:ro \ $(DEPS_IMAGE) \ sh -c "apk add --no-cache libvterm-dev libvterm-static >/dev/null 2>&1; \ + cp /host-jsh-coreutils.a /deps/jsh/libjsh_coreutils.a; \ cp -a /host-jsh-src/. /deps/jsh/src/; \ cp -a /host-coreutils/. /deps/coreutils/; \ find /deps/coreutils -name '*.sls' -exec sed -i 's/(load-shared-object #f)/(void)/g' {} +; \ --- a/build-binary-qt.ss +++ b/build-binary-qt.ss @@ -456,6 +456,15 @@ echo OK" (display "Error: jsh ffi-shim.c compilation failed\n") (exit 1)))) +;; jsh libcoreutils (terminal width/height/raw-mode for ls, top patches) +(when jemacs-static? + (let* ((jsh-root (path-parent jsh-dir)) + (cmd (format "gcc -c -O2 -o jemacs-qt-jsh-coreutils.o ~a/libcoreutils.c -Wall 2>&1" + jsh-root))) + (unless (= 0 (system cmd)) + (display "Error: libcoreutils.c compilation failed\n") + (exit 1)))) + ;; jsh embed-crypto (pure C crypto for embed encryption — no external deps) (when jemacs-static? (let* ((jsh-root (path-parent jsh-dir)) @@ -554,16 +563,18 @@ echo OK" ts-shim-obj ts-queries-obj ts-lib-dir ts-gram-dir)) (crypto-stub (if (file-exists? "/tmp/jemacs-build/crypto_stub.o") "/tmp/jemacs-build/crypto_stub.o" "")) + ;; jsh Rust coreutils static library (musl build, pre-compiled on host) + (jsh-coreutils-lib (or (getenv "JSH_COREUTILS_LIB") "")) (cmd (format "g++ -static -Wl,--export-dynamic -o jemacs-qt \ -jemacs-qt-main.o jemacs-qt-chez-shim.o jemacs-qt-pcre2-shim.o jemacs-qt-jsh-ffi.o \ +jemacs-qt-main.o jemacs-qt-chez-shim.o jemacs-qt-pcre2-shim.o jemacs-qt-jsh-ffi.o jemacs-qt-jsh-coreutils.o \ jemacs-qt-embed-crypto.o jemacs-qt-ssh-agent-stub.o ~a \ jemacs-qt-pty-shim.o jemacs-qt-vterm-shim.o jemacs-qt-repl-shim.o jemacs-qt-jerboa-landlock.o jemacs-qt-sci-stubs.o \ qt_static_symbols.o \ -~a ~a ~a ~a ~a \ +~a ~a ~a ~a ~a ~a \ -L~a -lkernel -llz4 -lz \ -lvterm -lm -ldl -lpthread -luuid -lncurses -lstdc++ 2>&1" crypto-stub - libqt-shim qt-plugins ts-link qt-libs pcre2-libs + libqt-shim qt-plugins ts-link qt-libs pcre2-libs jsh-coreutils-lib chez-dir))) (printf " ~a~n" cmd) (unless (= 0 (system cmd)) @@ -591,7 +602,7 @@ qt_static_symbols.o \ "jemacs_qt_scheme_boot.h" "jemacs_qt_jemacs_qt_boot.h" "jemacs-qt-all.so" "qt-main.so" "qt-main.wpo" "jemacs-qt.boot") (if jemacs-static? - '("jemacs-qt-jsh-ffi.o" "jemacs-qt-embed-crypto.o" + '("jemacs-qt-jsh-ffi.o" "jemacs-qt-jsh-coreutils.o" "jemacs-qt-embed-crypto.o" "jemacs-qt-ssh-agent-stub.o" "jemacs-qt-ssh-agent-stub.c" "jemacs-qt-pty-shim.o" "jemacs-qt-vterm-shim.o" "jemacs-qt-jerboa-landlock.o" --- a/lib/jerboa-emacs/async.sls +++ b/lib/jerboa-emacs/async.sls @@ -552,8 +552,8 @@ (let ([v (hashtable-ref cache key - '#{miss m9ldnpzbli8vj712n2xb0ixmh-1})]) - (if (eq? v '#{miss m9ldnpzbli8vj712n2xb0ixmh-2}) + '#{miss ggxha04xz6hyzrhna9yglgxud-0})]) + (if (eq? v '#{miss ggxha04xz6hyzrhna9yglgxud-1}) (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 @@ -92,6 +92,7 @@ (def *vterm-render-interval-ms* 33) (def *pty-batch-budget* 65536) (def *vterm-scrollback-limit* 100000) + (def *pty-poll-in-progress?* #f) (def *vterm-last-render-time* (make-hash-table-eq)) (def *vterm-last-rendered* (make-hash-table-eq)) (def *vterm-initialized* (make-hash-table-eq)) @@ -1761,143 +1762,169 @@ ed)) (loop (cdr wins))))))))))) (buffer-list)) - (for-each - (lambda (buf) - (when (shell-buffer? buf) - (let ([ss (hash-get *shell-state* buf)]) - (when (and ss (shell-pty-busy? ss)) - (let drain () - (let ([msg (shell-poll-output ss)]) - (when msg - (qt-poll-shell-pty-msg! fr buf ss msg) - (when (eq? (car msg) 'data) (drain)))))))) - (when (terminal-buffer? buf) - (let ([ts (hash-get *terminal-state* buf)]) - (when (and ts (terminal-pty-busy? ts)) - (let ([vt (terminal-state-vtscreen ts)]) - (when vt - (let ed-loop ([wins (qt-frame-windows fr)]) - (when (pair? wins) - (if (eq? (qt-edit-window-buffer (car wins)) - buf) - (let* ([ed (qt-edit-window-editor - (car wins))] - [new-rows (max 2 - (sci-send - ed - 2370 - 0))] - [widget-w (qt-widget-width ed)] - [char-w (max 1 - (sci-send/string - ed - 2275 - "0" - 0))] - [new-cols (max 20 - (quotient - widget-w - char-w))] - [old-rows (vtscreen-rows vt)] - [old-cols (vtscreen-cols vt)]) - (when (or (not (= new-rows old-rows)) - (not (= new-cols old-cols))) - (verbose-log! "PTY-RESIZE: " - (number->string old-rows) "x" - (number->string old-cols) " -> " - (number->string new-rows) "x" - (number->string new-cols)) - (vtscreen-resize! - vt - new-rows - new-cols) - (terminal-resize! - ts - new-rows - new-cols) - (hash-remove! *vterm-row-cache* ts) - (hash-put! - *vterm-initialized* - ts - #f))) - (ed-loop (cdr wins)))))))) - (when (and ts (terminal-pty-busy? ts)) - (let drain ([chunks (list)] [bytes 0] [done-msg #f]) - (if (and (> bytes 0) - (>= bytes *pty-batch-budget*)) - (let ([combined (apply - string-append - (reverse chunks))]) - (verbose-log! - "PTY-BATCH-CAP: " - (number->string (string-length combined)) - " bytes (capped)") - (qt-poll-terminal-pty-batch! - fr - buf - ts - combined)) - (let ([msg (terminal-poll-output ts)]) - (cond - [(not msg) - (if (pair? chunks) - (let ([combined (apply - string-append - (reverse chunks))]) - (verbose-log! - "PTY-BATCH: " - (number->string - (string-length combined)) - " bytes") - (qt-poll-terminal-pty-batch! - fr - buf - ts - combined)) - (when (and (terminal-state-vtscreen - ts) - (hash-ref - *vterm-initialized* - ts - #f) - (vterm-render-due? ts)) - (qt-poll-terminal-pty-batch! + (unless *pty-poll-in-progress?* + (dynamic-wind + (lambda () (set! *pty-poll-in-progress?* #t)) + (lambda () + (for-each + (lambda (buf) + (when (shell-buffer? buf) + (let ([ss (hash-get *shell-state* buf)]) + (when (and ss (shell-pty-busy? ss)) + (let drain () + (let ([msg (shell-poll-output ss)]) + (when msg + (qt-poll-shell-pty-msg! fr buf ss msg) + (when (eq? (car msg) 'data) + (drain)))))))) + (when (terminal-buffer? buf) + (let ([ts (hash-get *terminal-state* buf)]) + (when ts + (let ([vt (terminal-state-vtscreen ts)]) + (when vt + (let ed-loop ([wins (qt-frame-windows + fr)]) + (when (pair? wins) + (if (eq? (qt-edit-window-buffer + (car wins)) + buf) + (let* ([ed (qt-edit-window-editor + (car wins))] + [new-rows (max 2 + (sci-send + ed + 2370 + 0))] + [widget-w (qt-widget-width + ed)] + [char-w (max 1 + (sci-send/string + ed + 2275 + "0" + 0))] + [new-cols (max 20 + (quotient + widget-w + char-w))] + [old-rows (vtscreen-rows + vt)] + [old-cols (vtscreen-cols + vt)]) + (when (or (not (= new-rows + old-rows)) + (not (= new-cols + old-cols))) + (verbose-log! "PTY-RESIZE: " + (number->string old-rows) + "x" + (number->string old-cols) + " -> " + (number->string new-rows) + "x" + (number->string new-cols)) + (vtscreen-resize! + vt + new-rows + new-cols) + (when (terminal-pty-busy? ts) + (terminal-resize! + ts + new-rows + new-cols)) + (hash-remove! + *vterm-row-cache* + ts) + (hash-put! + *vterm-initialized* + ts + #f))) + (ed-loop (cdr wins)))))))) + (when (and ts (terminal-pty-busy? ts)) + (let drain ([chunks (list)] + [bytes 0] + [done-msg #f]) + (if (and (> bytes 0) + (>= bytes *pty-batch-budget*)) + (let ([combined (apply + string-append + (reverse chunks))]) + (verbose-log! + "PTY-BATCH-CAP: " + (number->string + (string-length combined)) + " bytes (capped)") + (qt-poll-terminal-pty-batch! + fr + buf + ts + combined)) + (let ([msg (terminal-poll-output ts)]) + (cond + [(not msg) + (if (pair? chunks) + (let ([combined (apply + string-append + (reverse + chunks))]) + (verbose-log! + "PTY-BATCH: " + (number->string + (string-length combined)) + " bytes") + (qt-poll-terminal-pty-batch! + fr + buf + ts + combined)) + (when (and (terminal-state-vtscreen + ts) + (hash-ref + *vterm-initialized* + ts + #f) + (vterm-render-due? + ts)) + (qt-poll-terminal-pty-batch! + fr + buf + ts + ""))) + (when done-msg + (qt-poll-terminal-pty-msg! + fr + buf + ts + done-msg))] + [(eq? (car msg) 'data) + (drain + (cons (cdr msg) chunks) + (+ bytes + (string-length (cdr msg))) + done-msg)] + [else + (when (pair? chunks) + (let ([combined (apply + string-append + (reverse + chunks))]) + (verbose-log! + "PTY-BATCH+DONE: " + (number->string + (string-length combined)) + " bytes") + (qt-poll-terminal-pty-batch! + fr + buf + ts + combined))) + (qt-poll-terminal-pty-msg! fr buf ts - ""))) - (when done-msg - (qt-poll-terminal-pty-msg! - fr - buf - ts - done-msg))] - [(eq? (car msg) 'data) - (drain - (cons (cdr msg) chunks) - (+ bytes (string-length (cdr msg))) - done-msg)] - [else - (when (pair? chunks) - (let ([combined (apply - string-append - (reverse chunks))]) - (verbose-log! - "PTY-BATCH+DONE: " - (number->string - (string-length combined)) - " bytes") - (qt-poll-terminal-pty-batch! - fr - buf - ts - combined))) - (qt-poll-terminal-pty-msg! - fr - buf - ts - msg)])))))))) - (buffer-list)) + msg)])))))))) + (buffer-list))) + (lambda () (set! *pty-poll-in-progress?* #f)))) (for-each (lambda (buf) (when (chat-buffer? buf) --- a/src/jerboa-emacs/editor-core.ss +++ b/src/jerboa-emacs/editor-core.ss @@ -31,12 +31,90 @@ :jerboa-emacs/persist) ;;;============================================================================ +;;; Missing Scintilla constants (used by scaffold commands) +;;;============================================================================ + +(def SCI_GETTEXTRANGE 2162) +(def SCI_DELETEBACK 2326) +(def SCI_GETMARGINLEFT 2155) +(def SCI_SETMARGINLEFT 2155) +(def SCI_SETMARGINRIGHT 2157) +;; SCI_INDICSETALPHA already defined below (line ~1599) +(def SCI_MOVESELECTEDLINESUP 2620) +(def SCI_MOVESELECTEDLINESDOWN 2621) +(def SCI_SETELEMENTCOLOUR 2753) +;; SCI_SETSTYLING and SCI_STARTSTYLING already come from terminal.ss + +;;;============================================================================ +;;; Utility: string->alien/nul (identity — Scintilla TUI accepts strings directly) +;;;============================================================================ + +(def (string->alien/nul s) s) +(def (string->alien s) s) +(def (alien/nul->string s) s) +(def (bytevector->alien bv) bv) +(def (cons->alien . args) 0) + +(def (tui-rows) 24) +(def (tui-cols) 80) + +;;; Aliases for scaffold commands that use non-existent names +(def (editor-cursor-position ed) (editor-get-current-pos ed)) +(def (editor-line-start ed line) (editor-position-from-line ed line)) +(def (editor-line-end ed line) (editor-get-line-end-position ed line)) +(def (editor-replace-range ed start end text) + (editor-delete-range ed start (- end start)) + (editor-insert-text ed start text)) + +;;; Global mode-state table (phantom field app-state-modes doesn't exist) +(def *jemacs-mode-state* (make-hash-table)) +(def (app-state-modes app) *jemacs-mode-state*) + +;;; Indicator helpers (phantom functions in scaffold code) +(def (editor-indicator-fill ed indicator-id start end) + (send-message ed SCI_SETINDICATORCURRENT indicator-id 0) + (send-message ed SCI_INDICATORFILLRANGE start (- end start))) +(def (editor-indicator-clear ed indicator-id start len) + (send-message ed SCI_SETINDICATORCURRENT indicator-id 0) + (send-message ed SCI_INDICATORCLEARRANGE start len)) + +;;;============================================================================ ;;; Shared state (used across editor sub-modules) ;;;============================================================================ (def *auto-pair-mode* #t) (def *auto-revert-mode* #f) (def *aggressive-indent-mode* #f) (def *delete-selection-mode* #t) ;; default on, like Emacs +(def *electric-quote-mode* #f) + +(def (electric-quote-char ch ed) + "Return a curly-quote replacement string for CH at the current position in ED, + or #f if no replacement should be made. Uses the character before point to + decide opening vs closing: after whitespace/BOL → opening, otherwise → closing." + (let* ((pos (editor-get-current-pos ed)) + (prev-ch (if (> pos 0) + (send-message ed SCI_GETCHARAT (- pos 1) 0) + 0)) + (at-word-boundary? (or (= pos 0) + (= prev-ch 32) ; space + (= prev-ch 10) ; newline + (= prev-ch 13) ; CR + (= prev-ch 9) ; tab + (= prev-ch 40) ; ( + (= prev-ch 91) ; [ + (= prev-ch 123)))) ; { + (cond + ;; Double quote → curly double quotes + ((= ch 34) ; " + (if at-word-boundary? + "\x201C;" ; left double quotation mark + "\x201D;")) ; right double quotation mark + ;; Single quote / apostrophe → curly single quotes + ((= ch 39) ; ' + (if at-word-boundary? + "\x2018;" ; left single quotation mark + "\x2019;")) ; right single quotation mark + (else #f)))) ;;;============================================================================ ;;; Pulse/flash highlight on jump (beacon-like) @@ -84,6 +162,7 @@ ;;;============================================================================ ;;; Volatile highlights — flash changed regions (yank, undo) ;;;============================================================================ +(def *volatile-highlights* #f) (def *volatile-highlight-indicator* 2) (def *volatile-highlight-countdown* 0) (def *volatile-highlight-editor* #f) @@ -580,7 +659,7 @@ (let ((new-line (string-append target-indent trimmed))) (send-message ed SCI_SETTARGETSTART line-start 0) (send-message ed SCI_SETTARGETEND line-end 0) - (editor-replace-target ed new-line) + (send-message/string ed SCI_REPLACETARGET new-line) (let ((new-pos (+ line-start (string-length target-indent) (max 0 (- pos line-start (string-length current-indent)))))) --- a/src/jerboa-emacs/editor-extra-editing2.ss +++ b/src/jerboa-emacs/editor-extra-editing2.ss @@ -20,6 +20,8 @@ :jerboa-emacs/echo :jerboa-emacs/editor-extra-helpers :jerboa-emacs/editor-extra-editing + (only-in :jerboa-emacs/editor-core SCI_DELETEBACK) + (only-in :jerboa-emacs/terminal SCI_SETSTYLING SCI_STARTSTYLING) (only-in :jerboa-emacs/persist *enriched-mode* *picture-mode*)) --- a/src/jerboa-emacs/editor-extra-final.ss +++ b/src/jerboa-emacs/editor-extra-final.ss @@ -22,14 +22,22 @@ :jerboa-emacs/modeline :jerboa-emacs/echo (only-in :jerboa-emacs/editor-core - search-forward-regexp-impl!) + search-forward-regexp-impl! + string->alien/nul string->alien alien/nul->string + bytevector->alien cons->alien tui-rows tui-cols + SCI_GETTEXTRANGE SCI_SETMARGINLEFT SCI_SETMARGINRIGHT + SCI_INDICSETALPHA + editor-cursor-position editor-line-start editor-line-end + editor-replace-range app-state-modes + editor-indicator-fill editor-indicator-clear) + (only-in :jerboa-emacs/org-table editor-current-line) (only-in :jerboa-emacs/editor-ui position-cursor-for-replace!) - :jerboa-emacs/editor-extra-helpers - :jerboa-emacs/editor-extra-web - :jerboa-emacs/editor-extra-media - :jerboa-emacs/editor-extra-media2 - :jerboa-emacs/editor-extra-modes) + (except-in :jerboa-emacs/editor-extra-helpers + cmd-fido-mode cmd-icomplete-mode) + (only-in :jerboa-emacs/editor-extra-web url-encode) + (only-in :jerboa-emacs/editor-extra-modes cmd-completion-at-point switch-to-buffer create-buffer cmd-indent-guide-mode *spray-wpm* editor-get-text-range shell-quote cmd-color-theme-select) + (only-in :jerboa-emacs/editor-text find-buffer-by-file-path)) ;;;============================================================================ ;;; Task #51: Additional unique commands to cross 1000 registrations @@ -1554,7 +1562,6 @@ ;;; Batch 33: insert-char-by-code, subword, bidi, fill-column indicator, etc. ;;; ========================================================================= -(def *subword-mode* #f) (def *auto-composition-mode* #t) (def *bidi-display-reordering* #t) (def *fill-column-indicator* #f) @@ -1853,7 +1860,7 @@ *buffer-list*)) (tabs (map (lambda (b) (let* ((name (buffer-name b)) - (mod? (and (buffer-doc b) + (mod? (and (buffer-doc-pointer b) (let ((ed (create-scintilla-editor 1 1))) ;; Quick check - can't easily check mod #f))) @@ -2233,7 +2240,6 @@ (def *kmacro-recording* #f) (def *kmacro-events* '()) (def *kmacro-ring* '()) -(def *kmacro-counter* 0) (def (kmacro-recording?) *kmacro-recording*) @@ -2291,7 +2297,7 @@ (for-each (lambda (ev) (when (and (pair? ev) (symbol? (car ev))) - (let ((cmd-fn (command-lookup (car ev)))) + (let ((cmd-fn (find-command (car ev)))) (when cmd-fn (cmd-fn app))))) macro) (echo-message! echo "Macro replayed"))))) @@ -3672,7 +3678,7 @@ (frame (app-state-frame app)) (win (current-window frame)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") (let* ((dir (path-directory file)) @@ -3813,7 +3819,7 @@ (let ((nbuf (make-buffer filepath))) (buffer-attach! ed nbuf) (set! (edit-window-buffer win) nbuf) - (buffer-file-set! nbuf filepath) + (buffer-file-path-set! nbuf filepath) (editor-set-text ed content) (editor-goto-pos ed (string-length content)) (echo-message! echo (str "Created note: " filename))))))) @@ -3850,7 +3856,7 @@ (nbuf (make-buffer filepath))) (buffer-attach! ed nbuf) (set! (edit-window-buffer win) nbuf) - (buffer-file-set! nbuf filepath) + (buffer-file-path-set! nbuf filepath) (editor-set-text ed content) (editor-goto-pos ed 0) (echo-message! echo (str "Opened: " choice)))))) @@ -3869,17 +3875,17 @@ (with-catch (lambda (e) (echo-message! echo (str "Detach error: " e))) (lambda () - (let-values (((p-stdin p-stdout p-stderr pid) - (open-process-ports - (str "nohup " cmd " > /tmp/detached-" (number->string pid) - ".log 2>&1 &") - 'block (native-transcoder)))) - (close-port p-stdin) (close-port p-stdout) (close-port p-stderr) - (set! *detached-sessions* - (cons (list (cons 'cmd cmd) (cons 'pid pid) - (cons 'time (time-second (current-time)))) - *detached-sessions*)) - (echo-message! echo (str "Detached: " cmd " (pid " pid ")")))))))) + (let* ((log-file (str "/tmp/detached-" (number->string (time-second (current-time))) ".log"))) + (let-values (((p-stdin p-stdout p-stderr pid) + (open-process-ports + (str "nohup " cmd " > " log-file " 2>&1 &") + 'block (native-transcoder)))) + (close-port p-stdin) (close-port p-stdout) (close-port p-stderr) + (set! *detached-sessions* + (cons (list (cons 'cmd cmd) (cons 'pid pid) + (cons 'time (time-second (current-time)))) + *detached-sessions*)) + (echo-message! echo (str "Detached: " cmd " (pid " pid ")"))))))))) (def (cmd-detached-list app) "List all detached sessions." @@ -4130,7 +4136,7 @@ (frame (app-state-frame app)) (win (current-window frame)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") (with-catch @@ -4242,7 +4248,7 @@ (win (current-window frame)) (ed (edit-window-editor win)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") (let* ((line-num (+ 1 (send-message ed SCI_LINEFROMPOSITION @@ -4880,7 +4886,7 @@ (frame (app-state-frame app)) (win (current-window frame)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") (with-catch @@ -5106,7 +5112,7 @@ (frame (app-state-frame app)) (win (current-window frame)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") (let ((ed (edit-window-editor win))) @@ -5419,7 +5425,7 @@ (win (current-window frame)) (ed (edit-window-editor win)) (buf (edit-window-buffer win)) - (file (buffer-file buf)) + (file (buffer-file-path buf)) (name (if file (let loop ((i (- (string-length file) 1))) (cond ((< i 0) file) @@ -5506,7 +5512,7 @@ (frame (app-state-frame app)) (win (current-window frame)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") (with-catch @@ -5541,7 +5547,7 @@ (frame (app-state-frame app)) (win (current-window frame)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") (let* ((row (tui-rows)) (width (tui-cols)) @@ -5552,7 +5558,7 @@ (lambda (e) (echo-message! echo (str "Rename error: " e))) (lambda () (rename-file file new-path) - (buffer-file-set! buf new-path) + (buffer-file-path-set! buf new-path) (echo-message! echo (str "Renamed to " new-path)))))))))) ;; --- Feature 20: Sudo Edit --- @@ -5564,7 +5570,7 @@ (win (current-window frame)) (ed (edit-window-editor win)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") (with-catch @@ -5788,7 +5794,7 @@ (win (current-window frame)) (ed (edit-window-editor win)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") (with-catch @@ -5848,7 +5854,7 @@ (frame (app-state-frame app)) (win (current-window frame)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") (with-catch @@ -5947,7 +5953,7 @@ (echo-message! echo "No selection to copy") (let* ((text (editor-get-text-range ed start end)) (buf (edit-window-buffer win)) - (file (buffer-file buf)) + (file (buffer-file-path buf)) (ext (if file (path-extension file) "txt")) (row (tui-rows)) (width (tui-cols)) (fmt (echo-read-string echo "Format [markdown/org/html/slack/jira]: " row width))) @@ -6055,7 +6061,7 @@ (frame (app-state-frame app)) (win (current-window frame)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") (let ((auto-save (str file "~"))) @@ -6352,7 +6358,7 @@ (file (car parts)) (line-num (string->number (cadr parts)))) (if (and file line-num (file-exists? file)) - (let ((buf (find-or-create-file-buffer file))) + (let ((buf (or (find-buffer-by-file-path file) (create-buffer file)))) (switch-to-buffer frame buf) (let ((new-ed (edit-window-editor (current-window frame)))) (let ((target-pos (send-message new-ed SCI_POSITIONFROMLINE (- line-num 1) 0))) @@ -6484,7 +6490,7 @@ (win (current-window frame)) (ed (edit-window-editor win)) (buf (edit-window-buffer win)) - (file (buffer-file buf)) + (file (buffer-file-path buf)) (text (editor-get-text ed))) (if (not file) (echo-message! echo "No file — prettier needs a filename for language detection") @@ -6551,7 +6557,7 @@ (win (current-window frame)) (ed (edit-window-editor win)) (buf (edit-window-buffer win)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "No file associated with buffer") ;; Use formatter based on file extension @@ -6952,13 +6958,13 @@ "Display an enhanced buffer menu with sizes and modification status." (let* ((echo (app-state-echo app)) (frame (app-state-frame app)) - (bufs (frame-buffers frame)) + (bufs (buffer-list)) (new-buf (create-buffer "*buffer-menu*")) (header " MR Buffer Size File\n -- ------ ---- ----\n") (lines (map (lambda (buf) (let* ((name (buffer-name buf)) - (file (or (buffer-file buf) "")) - (modified (buffer-modified? buf)) + (file (or (buffer-file-path buf) "")) + (modified (buffer-modified buf)) (flag-m (if modified "*" " ")) (pad-name (if (< (string-length name) 30) (str name (make-string (- 30 (string-length name)) #\space)) @@ -7341,9 +7347,9 @@ (empty-row "| | | | | | | |\n") (board-text (str "=== Connect Four ===\n\n" header separator - (apply str (let build ((i 0) (acc '())) - (if (>= i rows) (reverse acc) - (build (+ i 1) (cons (str empty-row separator) acc))))) + (apply string-append (let build ((i 0) (acc '())) + (if (>= i rows) (reverse acc) + (build (+ i 1) (cons (str empty-row separator) acc))))) "\nUse M-x c4-drop to drop a piece (column 1-7).\n"))) (editor-set-text ed board-text) (echo-message! echo "Connect Four! Use M-x c4-drop")))) @@ -7402,8 +7408,8 @@ ;; cmd-paredit-mode: Show paredit-style structural editing cheat sheet (def (cmd-paredit-mode app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) (text (str "=== Paredit Mode Reference ===\n\n" "Paredit provides structural editing for S-expressions.\n\n" @@ -7429,8 +7435,8 @@ ;; cmd-hi-lock-mode: Highlight all occurrences of a pattern in current buffer (def (cmd-hi-lock-mode app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) (pattern (echo-read-string echo "Hi-lock pattern: "))) (if (or (not pattern) (string=? pattern "")) @@ -7450,11 +7456,11 @@ ;; cmd-syntax-highlight-region: Show syntax info for the selected region (def (cmd-syntax-highlight-region app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) - (sel-start (editor-selection-start ed)) - (sel-end (editor-selection-end ed))) + (sel-start (editor-get-selection-start ed)) + (sel-end (editor-get-selection-end ed))) (if (= sel-start sel-end) (echo-message! echo "No region selected") (let* ((region-text (editor-get-text-range ed sel-start sel-end)) @@ -7484,8 +7490,8 @@ ;; cmd-stack-overflow-search: Search Stack Overflow via DuckDuckGo (def (cmd-stack-overflow-search app) (let* ((echo (app-state-echo app)) - (buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (buf (current-buffer-from-app app)) + (ed (current-editor app)) (query (echo-read-string echo "Stack Overflow search: "))) (if (or (not query) (string=? query "")) (echo-message! echo "No query specified") @@ -7509,8 +7515,8 @@ ;; cmd-cheat-sheet: Display a cheat sheet for common editor commands (def (cmd-cheat-sheet app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) (text (str "=== jemacs Cheat Sheet ===\n\n" "--- Movement ---\n" @@ -7556,12 +7562,12 @@ ;; cmd-apropos-documentation: Search commands by keyword (def (cmd-apropos-documentation app) (let* ((echo (app-state-echo app)) - (buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (buf (current-buffer-from-app app)) + (ed (current-editor app)) (query (echo-read-string echo "Apropos: "))) (if (or (not query) (string=? query "")) (echo-message! echo "No query specified") - (let* ((all-cmds (hash-keys (app-state-commands app))) + (let* ((all-cmds (hash-keys *all-commands*)) (matches (filter (lambda (sym) (string-contains (symbol->string sym) query)) all-cmds)) @@ -7580,8 +7586,8 @@ ;; cmd-scratch-message: Insert the default *scratch* buffer message (def (cmd-scratch-message app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) (text (str ";; This buffer is for text that is not saved, and for Scheme evaluation.\n" ";; To create a file, visit it with C-x C-f and enter text in its buffer.\n" @@ -7602,8 +7608,8 @@ ;; cmd-geiser-mode: Show Geiser REPL reference for Scheme interaction (def (cmd-geiser-mode app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) (text (str "=== Geiser Mode Reference ===\n\n" "Geiser provides Scheme interaction in Emacs.\n\n" @@ -7629,8 +7635,8 @@ ;; cmd-sly-mode: Show SLY (Sylvester the Cat's Common Lisp IDE) reference (def (cmd-sly-mode app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) (text (str "=== SLY Mode Reference ===\n\n" "SLY is a Common Lisp IDE for Emacs (fork of SLIME).\n\n" @@ -7657,8 +7663,8 @@ ;; cmd-slime-mode: Show SLIME (Superior Lisp Interaction Mode) reference (def (cmd-slime-mode app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) (text (str "=== SLIME Mode Reference ===\n\n" "SLIME is the Superior Lisp Interaction Mode for Emacs.\n\n" @@ -7690,11 +7696,11 @@ ;; cmd-fill-region: Wrap all paragraphs in region to fill column (def (cmd-fill-region app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) - (sel-start (editor-selection-start ed)) - (sel-end (editor-selection-end ed))) + (sel-start (editor-get-selection-start ed)) + (sel-end (editor-get-selection-end ed))) (if (= sel-start sel-end) (echo-message! echo "No region selected") (let* ((fill-col 80) @@ -7736,12 +7742,12 @@ ;; cmd-justify-paragraph: Right-justify current paragraph (def (cmd-justify-paragraph app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) (fill-col 80) (cur-line (editor-current-line ed)) - (total-lines (editor-line-count ed)) + (total-lines (editor-get-line-count ed)) (para-start (let loop ((ln cur-line)) (if (<= ln 0) 0 (let ((text (editor-get-line ed ln))) @@ -7767,8 +7773,8 @@ ;; cmd-center-line: Center the current line within fill column (def (cmd-center-line app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) (fill-col 80) (cur-line (editor-current-line ed)) @@ -7802,10 +7808,10 @@ ;; cmd-revert-buffer-quick: Reload buffer from disk without confirmation (def (cmd-revert-buffer-quick app) - (let* ((buf (app-state-current-buffer app)) - (ed (buffer-editor buf)) + (let* ((buf (current-buffer-from-app app)) + (ed (current-editor app)) (echo (app-state-echo app)) - (file (buffer-file buf))) + (file (buffer-file-path buf))) (if (not file) (echo-message! echo "Buffer has no file") (if (not (file-exists? file))