From fd17672a7aa2216c4548c07870bd99355ccfd962 Mon Sep 17 00:00:00 2001 From: Daniel Nouri Date: Wed, 6 May 2026 11:41:25 +0200 Subject: [PATCH] Format tables shown on other frames A chat buffer can be visible on a different frame from the selected one. In that case table output should be formatted as soon as it arrives, rather than remaining raw until a later resize refreshes the chat. Prefer the selected-frame chat window for wrapping width, and otherwise use a visible chat window on another frame. --- pi-coding-agent-table.el | 11 ++++- test/pi-coding-agent-table-test.el | 64 ++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/pi-coding-agent-table.el b/pi-coding-agent-table.el index 483e72b..7488a7e 100644 --- a/pi-coding-agent-table.el +++ b/pi-coding-agent-table.el @@ -72,17 +72,24 @@ fontification when the same cell content reappears at different widths.") ;;;; Visibility and Width +(defun pi-coding-agent--chat-display-window () + "Return a visible window showing the current chat buffer. +Prefer a window on the selected frame, then fall back to any +visible frame." + (or (get-buffer-window (current-buffer) nil) + (get-buffer-window (current-buffer) 'visible))) + (defun pi-coding-agent--chat-buffer-hidden-p () "Return non-nil when the current chat buffer has no visible window. Returns nil in batch mode so unit tests that use windowless temp buffers are not affected by the visibility guard." (and (not noninteractive) - (null (get-buffer-window (current-buffer))))) + (null (pi-coding-agent--chat-display-window)))) (defun pi-coding-agent--chat-window-width () "Return usable character columns for the chat window, or nil if hidden. Excludes columns reserved by fringes such as line-number display." - (when-let* ((window (get-buffer-window (current-buffer) nil))) + (when-let* ((window (pi-coding-agent--chat-display-window))) (window-max-chars-per-line window))) (defun pi-coding-agent--chat-display-width () diff --git a/test/pi-coding-agent-table-test.el b/test/pi-coding-agent-table-test.el index 174378a..008ac40 100644 --- a/test/pi-coding-agent-table-test.el +++ b/test/pi-coding-agent-table-test.el @@ -838,6 +838,30 @@ what the parser recognizes as a `pipe_table'." (pi-coding-agent--display-message-delta "| Auth | Done |\n") (should (>= (pi-coding-agent-test--table-overlay-count) 1)))) +(ert-deftest pi-coding-agent-test-chat-buffer-hidden-p-sees-visible-window-on-other-frame () + "A chat buffer visible on another frame is not hidden." + (with-temp-buffer + (let ((noninteractive nil) + (calls nil)) + (cl-letf (((symbol-function 'get-buffer-window) + (lambda (buffer &optional all-frames) + (should (eq buffer (current-buffer))) + (push all-frames calls) + (cond + ((null all-frames) nil) + ((eq all-frames 'visible) 'other-frame-window) + (t (error "Unexpected all-frames value: %S" all-frames)))))) + (should-not (pi-coding-agent--chat-buffer-hidden-p)) + (should (equal (nreverse calls) '(nil visible))))))) + +(ert-deftest pi-coding-agent-test-chat-buffer-hidden-p-returns-nil-in-batch-without-window () + "Batch tests using windowless temp buffers are not treated as hidden." + (with-temp-buffer + (let ((noninteractive t)) + (cl-letf (((symbol-function 'get-buffer-window) + (lambda (&rest _args) nil))) + (should-not (pi-coding-agent--chat-buffer-hidden-p)))))) + (ert-deftest pi-coding-agent-test-chat-window-width-excludes-fringe-columns () "Chat window width reports usable character columns, not raw window width. When fringes like `display-line-numbers-mode' consume columns, @@ -850,5 +874,45 @@ When fringes like `display-line-numbers-mode' consume columns, (lambda (&optional _window _face) 76))) (should (= (pi-coding-agent--chat-window-width) 76)))))) +(ert-deftest pi-coding-agent-test-chat-window-width-falls-back-to-visible-window-on-other-frame () + "Chat window width uses another visible frame when selected frame lacks chat." + (with-temp-buffer + (let ((calls nil)) + (cl-letf (((symbol-function 'get-buffer-window) + (lambda (buffer &optional all-frames) + (should (eq buffer (current-buffer))) + (push all-frames calls) + (cond + ((null all-frames) nil) + ((eq all-frames 'visible) 'other-frame-window) + (t (error "Unexpected all-frames value: %S" all-frames))))) + ((symbol-function 'window-max-chars-per-line) + (lambda (window &optional _face) + (should (eq window 'other-frame-window)) + 64))) + (should (= (pi-coding-agent--chat-window-width) 64)) + (should (equal (nreverse calls) '(nil visible))))))) + +(ert-deftest pi-coding-agent-test-chat-window-width-prefers-selected-frame-window () + "Chat window width keeps selected-frame preference when chat is visible there." + (with-temp-buffer + (let ((calls nil)) + (cl-letf (((symbol-function 'get-buffer-window) + (lambda (buffer &optional all-frames) + (should (eq buffer (current-buffer))) + (push all-frames calls) + (cond + ((null all-frames) 'selected-frame-window) + ((eq all-frames 'visible) 'other-frame-window) + (t (error "Unexpected all-frames value: %S" all-frames))))) + ((symbol-function 'window-max-chars-per-line) + (lambda (window &optional _face) + (pcase window + ('selected-frame-window 90) + ('other-frame-window 50) + (_ (error "Unexpected window: %S" window)))))) + (should (= (pi-coding-agent--chat-window-width) 90)) + (should (equal (nreverse calls) '(nil))))))) + (provide 'pi-coding-agent-table-test) ;;; pi-coding-agent-table-test.el ends here