Implement Qt recentf mode
ober
92bcd63a14fa5ddbf6f974a73e47b7794b451b38
--- a/src/jerboa-emacs/persist.ss +++ b/src/jerboa-emacs/persist.ss @@ -8,6 +8,7 @@ ;; Recent files *recent-files* *recent-files-max* + *recentf-mode* recent-files recent-files-max recent-files-add! @@ -160,12 +161,13 @@ (def *recent-files* '()) (def *recent-files-max* 50) +(def *recentf-mode* #t) (def (recent-files) *recent-files*) (def (recent-files-max) *recent-files-max*) (def (recent-files-add! path) "Add a file path to the recent files list. Deduplicates and limits size." - (when (and (string? path) (> (string-length path) 0)) + (when (and *recentf-mode* (string? path) (> (string-length path) 0)) ;; Normalize: expand to absolute path (let ((abs-path (path-expand path))) ;; Remove existing entry (move to front) --- a/src/jerboa-emacs/qt/commands-parity5.ss +++ b/src/jerboa-emacs/qt/commands-parity5.ss @@ -49,6 +49,7 @@ :jerboa-emacs/qt/commands-parity3b :jerboa-emacs/qt/commands-parity4 (only-in :jerboa-emacs/persist + *recentf-mode* recent-files-load! recent-files-save! *which-key-mode* *which-key-delay* *copilot-mode* *copilot-api-key* *copilot-model* *copilot-api-url* *copilot-suggestion* *copilot-suggestion-pos* @@ -1357,6 +1358,18 @@ (if *winner-mode* "Winner mode ON" "Winner mode OFF"))) +(def (cmd-recentf-mode app) + "Toggle Qt recentf-mode file tracking." + (set! *recentf-mode* (not *recentf-mode*)) + (if *recentf-mode* + (recent-files-load!) + (recent-files-save!)) + (hash-put! *qt-toggle-states* 'recentf-mode *recentf-mode*) + (hash-put! *qt-toggle-states* 'toggle-recentf-mode *recentf-mode*) + (echo-message! (app-state-echo app) + (if *recentf-mode* + "Recentf mode ON" + "Recentf mode OFF"))) (def *qt-run-with-timer-counter* 0) (def (next-run-with-timer-name!) @@ -1466,6 +1479,8 @@ (cons 'toggle-global-display-line-numbers cmd-global-display-line-numbers-mode) (cons 'winner-mode cmd-winner-mode) (cons 'toggle-winner-mode cmd-winner-mode) + (cons 'recentf-mode cmd-recentf-mode) + (cons 'toggle-recentf-mode cmd-recentf-mode) (cons 'run-with-timer cmd-run-with-timer) (cons 'ibuffer-mark cmd-ibuffer-mark) (cons 'ibuffer-delete cmd-ibuffer-delete) --- a/src/jerboa-emacs/qt/commands-shell.ss +++ b/src/jerboa-emacs/qt/commands-shell.ss @@ -16,6 +16,7 @@ (only-in :jsh/registry builtin-lookup builtin-register!) (only-in :jerboa-emacs/persist theme-settings-save! theme-settings-load! mx-history-save! mx-history-load! + *recent-files* *auto-fill-mode* *fill-column* *abbrev-table* *abbrev-mode-enabled* *delete-trailing-whitespace-on-save*) --- a/src/jerboa-emacs/qt/commands-vcs.ss +++ b/src/jerboa-emacs/qt/commands-vcs.ss @@ -21,6 +21,8 @@ :jerboa-emacs/qt/echo :jerboa-emacs/qt/highlight :jerboa-emacs/qt/modeline + (only-in :jerboa-emacs/persist + *recent-files* recent-files-save! recent-files-load! recent-files-cleanup!) :jerboa-emacs/qt/commands-core :jerboa-emacs/qt/commands-core2 :jerboa-emacs/qt/commands-edit @@ -669,59 +671,7 @@ (echo-message! (app-state-echo app) (string-append "Would kill " (number->string killed) " matching buffers")))))) -(def *recent-files* []) -(def *recent-files-max* 50) -(def *recent-files-path* - (path-expand ".jemacs-recent-files" (user-info-home (user-info (user-name))))) - -(def (recent-files-add! path) - "Add a file path to the recent files list (most recent first, no duplicates)." - (when (and path (string? path) (> (string-length path) 0)) - (let ((abs-path (path-expand path))) - ;; Remove existing entry if present, then prepend - (set! *recent-files* - (cons abs-path - (let loop ((files *recent-files*) (acc [])) - (cond - ((null? files) (reverse acc)) - ((string=? (car files) abs-path) (loop (cdr files) acc)) - (else (loop (cdr files) (cons (car files) acc))))))) - ;; Trim to max size - (when (> (length *recent-files*) *recent-files-max*) - (set! *recent-files* - (let loop ((files *recent-files*) (n 0) (acc [])) - (if (or (null? files) (>= n *recent-files-max*)) - (reverse acc) - (loop (cdr files) (+ n 1) (cons (car files) acc)))))) - ;; Save to disk - (recent-files-save!)))) - -(def (recent-files-save!) - "Persist recent files list to disk." - (with-catch - (lambda (e) #f) - (lambda () - (call-with-output-file *recent-files-path* - (lambda (port) - (for-each (lambda (f) (display f port) (newline port)) - *recent-files*)))))) - -(def (recent-files-load!) - "Load recent files list from disk." - (with-catch - (lambda (e) #f) - (lambda () - (when (file-exists? *recent-files-path*) - (set! *recent-files* - (call-with-input-file *recent-files-path* - (lambda (port) - (let loop ((acc [])) - (let ((line (read-line port))) - (if (eof-object? line) - (reverse acc) - (if (> (string-length line) 0) - (loop (cons line acc)) - (loop acc)))))))))))) +;;; Recent files are persisted by :jerboa-emacs/persist. (def (cmd-list-recent-files app) "Show list of recently opened files." @@ -737,7 +687,7 @@ (def (cmd-clear-recent-files app) "Clear the recent files list." - (set! *recent-files* []) + (set! *recent-files* '()) (recent-files-save!) (echo-message! (app-state-echo app) "Recent files cleared")) @@ -770,11 +720,7 @@ (def (cmd-recentf-cleanup app) "Remove non-existent files from the recent files list." - (let* ((before (length *recent-files*)) - (cleaned (filter file-exists? *recent-files*)) - (removed (- before (length cleaned)))) - (set! *recent-files* cleaned) - (recent-files-save!) + (let ((removed (recent-files-cleanup!))) (echo-message! (app-state-echo app) (string-append "Removed " (number->string removed) " non-existent files")))) --- a/src/jerboa-emacs/qt/commands-vcs2.ss +++ b/src/jerboa-emacs/qt/commands-vcs2.ss @@ -20,6 +20,7 @@ :jerboa-emacs/qt/echo :jerboa-emacs/qt/highlight :jerboa-emacs/qt/modeline + (only-in :jerboa-emacs/persist recent-files-add!) :jerboa-emacs/qt/commands-core :jerboa-emacs/qt/commands-core2 :jerboa-emacs/qt/commands-edit --- a/src/jerboa-emacs/qt/commands.ss +++ b/src/jerboa-emacs/qt/commands.ss @@ -118,6 +118,7 @@ (only-in :jerboa-emacs/persist buffer-local-set! buffer-local-get save-place-save! save-place-load! + recent-files-add! recent-files-load! save-place-remember! save-place-restore *save-place-enabled* *require-final-newline* *centered-cursor-mode* --- a/tests/test-qt-part2.ss +++ b/tests/test-qt-part2.ss @@ -27,6 +27,8 @@ (only (jerboa-emacs qt commands-edit) *line-numbers-visible*) (only (jerboa-emacs qt commands-core) *so-long-threshold* *winner-mode* *winner-history* *winner-future*) + (only (jerboa-emacs persist) + *recentf-mode* *recent-files* recent-files-add!) (only (jerboa-emacs qt commands-parity5) schedule-user-timer!) (only (jerboa-emacs async) master-timer-tick!) (jerboa-emacs qt keymap) @@ -108,7 +110,7 @@ (loop (+ i 1) (cons (string-append "line " (number->string i) "\n") acc))))) -(display "\n=== Qt Part2 Groups 44-62 ===\n") +(display "\n=== Qt Part2 Groups 44-63 ===\n") (test-case "group44 qt key/mouse fidelity" (check (qt-key-event->string QT_KEY_RETURN 0 "") => "C-m") @@ -336,9 +338,43 @@ (set! *winner-mode* old-mode) (set! *winner-history* old-history) (set! *winner-future* old-future)))))) +(test-case "group63 recentf-mode controls shared recent files" + (let-values (((ed w app) (make-qt-test-app "part2-63"))) + (let ((old-mode *recentf-mode*) + (old-files *recent-files*) + (old-home (getenv "HOME" #f)) + (dir "/tmp/jemacs-recentf-mode-test") + (path "/tmp/jemacs-recentf-mode-test/file.txt")) + (dynamic-wind + (lambda () + (with-catch (lambda (e) #f) + (lambda () (create-directory dir))) + (call-with-output-file path + (lambda (port) (display "recentf" port)) + 'replace) + (setenv "HOME" dir) + (set! *recentf-mode* #t) + (set! *recent-files* '())) + (lambda () + (execute-command! app 'recentf-mode) + (check *recentf-mode* => #f) + (check (echo-state-message (app-state-echo app)) => "Recentf mode OFF") + (recent-files-add! path) + (check *recent-files* => '()) + (execute-command! app 'toggle-recentf-mode) + (check *recentf-mode* => #t) + (check (echo-state-message (app-state-echo app)) => "Recentf mode ON") + (recent-files-add! path) + (check *recent-files* => (list path))) + (lambda () + (set! *recentf-mode* old-mode) + (set! *recent-files* old-files) + (setenv "HOME" (or old-home "/tmp")) + (with-catch (lambda (e) #f) + (lambda () (delete-file path)))))))) (newline) (let ([total (+ *pass* *fail*)]) - (printf "Part2 results: ~a/~a tests passed (groups 44-62)~n" *pass* total) + (printf "Part2 results: ~a/~a tests passed (groups 44-63)~n" *pass* total) (when (> *fail* 0) (printf "FAILED: ~a test(s)~n" *fail*)) (when (= *fail* 0)