Fix Qt tab bar staleness
ober
fc39fb15625ebad64bbd36288e87543898de841c
--- a/src/jerboa-emacs/qt/app.ss +++ b/src/jerboa-emacs/qt/app.ss @@ -521,10 +521,28 @@ ;; Tab bar state — populated during qt-main, used by qt-tabbar-update! (def *tab-bar-layout* #f) -(def *tab-bar-buttons* '()) ;; list of (buffer . button) pairs -(def *tab-bar-last-state* #f) ;; cache: (current-buf . buffer-count) to skip redundant updates +(def *tab-bar-buttons* '()) ;; list of (buffer . tab-widget) pairs +(def *tab-bar-last-state* #f) ;; cache of current tab plus tab labels/modified flags (def *tab-bar-widget* #f) ;; the tab bar widget itself (for show/hide) +(def (qt-tabbar-buffer-state buf) + "Return the tab cache state for BUF." + (let ((doc (buffer-doc-pointer buf))) + (list buf + (buffer-name buf) + (and doc (qt-text-document-modified? doc))))) +(def (qt-tabbar-switch-to-buffer! app buf) + "Display BUF in the current Qt window and refresh tab/UI state." + (let* ((fr (app-state-frame app)) + (ed (qt-current-editor fr))) + (when ed + (qt-buffer-attach! ed buf) + (set! (qt-edit-window-buffer (qt-current-window fr)) buf) + (qt-update-visual-decorations! ed) + (qt-modeline-update! app) + (set! *tab-bar-last-state* #f) + (qt-tabbar-update! app)))) + (def (qt-tabbar-update! app) "Rebuild the tab bar to reflect current buffer list." ;; Show/hide the tab bar widget @@ -536,24 +554,26 @@ (let* ((fr (app-state-frame app)) (current-buf (qt-edit-window-buffer (qt-current-window fr))) (bufs (buffer-list)) - (new-state (cons current-buf (length bufs)))) - ;; Skip update if nothing changed + (new-state (list current-buf (map qt-tabbar-buffer-state bufs)))) + ;; Skip update if nothing visible changed. (unless (and *tab-bar-last-state* - (eq? (car new-state) (car *tab-bar-last-state*)) - (= (cdr new-state) (cdr *tab-bar-last-state*))) + (equal? new-state *tab-bar-last-state*)) (set! *tab-bar-last-state* new-state) - ;; Destroy old buttons + ;; Destroy old tab widgets (for-each (lambda (pair) (qt-widget-destroy! (cdr pair))) *tab-bar-buttons*) (set! *tab-bar-buttons* '()) - ;; Create new buttons for each buffer + ;; Create new tab widgets for each buffer (for-each (lambda (buf) (let* ((name (buffer-name buf)) - (mod? (and (buffer-doc-pointer buf) - (qt-text-document-modified? (buffer-doc-pointer buf)))) + (doc (buffer-doc-pointer buf)) + (mod? (and doc (qt-text-document-modified? doc))) (label (if mod? (string-append name " *") name)) - (btn (qt-push-button-create label))) - ;; Style: current buffer gets highlighted + (tab-item (qt-widget-create *tab-bar-widget*)) + (tab-layout (qt-hbox-layout-create tab-item)) + (btn (qt-push-button-create label)) + (close-btn (qt-push-button-create "x"))) + ;; Style: current buffer gets highlighted; close uses a compact hit target. (let ((font-css (string-append " font-family: " *default-font-family* "; font-size: " (number->string (max 1 (- *default-font-size* 2))) "pt;"))) (if (eq? buf current-buf) @@ -561,20 +581,25 @@ (string-append "QPushButton { color: #ffffff; background: #404060; border: 1px solid #606080; border-radius: 3px; padding: 2px 8px;" font-css " }")) (qt-widget-set-style-sheet! btn (string-append "QPushButton { color: #a0a0a0; background: #252525; border: 1px solid #383838; border-radius: 3px; padding: 2px 8px;" font-css " }\n" - " QPushButton:hover { color: #d8d8d8; background: #353535; }")))) - ;; Click handler: switch to this buffer + " QPushButton:hover { color: #d8d8d8; background: #353535; }"))) + (qt-widget-set-style-sheet! close-btn + (string-append "QPushButton { color: #909090; background: #1c1c1c; border: 1px solid #303030; border-radius: 3px; padding: 2px 5px;" font-css " }\n" + "QPushButton:hover { color: #ffffff; background: #5a3030; border-color: #805050; }"))) + ;; Click handlers: switch or close this buffer. (qt-on-clicked! btn (lambda () - (let* ((ed (qt-current-editor fr))) - (qt-buffer-attach! ed buf) - (set! (qt-edit-window-buffer (qt-current-window fr)) buf) - (qt-update-visual-decorations! ed) - (qt-modeline-update! app) - (set! *tab-bar-last-state* #f) ;; force refresh - (qt-tabbar-update! app)))) + (qt-tabbar-switch-to-buffer! app buf))) + (qt-on-clicked! close-btn + (lambda () + (qt-tabbar-switch-to-buffer! app buf) + (execute-command! app 'kill-buffer-cmd) + (set! *tab-bar-last-state* #f) + (qt-tabbar-update! app))) ;; Add to layout - (qt-layout-add-widget! *tab-bar-layout* btn) - (set! *tab-bar-buttons* (cons (cons buf btn) *tab-bar-buttons*)))) + (qt-layout-add-widget! tab-layout btn) + (qt-layout-add-widget! tab-layout close-btn) + (qt-layout-add-widget! *tab-bar-layout* tab-item) + (set! *tab-bar-buttons* (cons (cons buf tab-item) *tab-bar-buttons*)))) bufs) ;; Add stretch at the end to push tabs left (qt-layout-add-stretch! *tab-bar-layout*))))) @@ -2345,7 +2370,7 @@ (qt-frame-current-idx (app-state-frame app)))))))) (qt-startup-trace "debug repl setup done") ;; Tree-sitter debounced re-highlight — re-parse when buffer content changes. - ;; Tracks last-known text length per buffer to detect modifications. + ;; Tracks a monotonic edit version so same-length edits still reparse. (qt-startup-trace "periodic treesitter begin") (schedule-periodic! 'treesitter-reparse 150 (lambda ()