Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions pi-coding-agent-render.el
Original file line number Diff line number Diff line change
Expand Up @@ -5251,8 +5251,10 @@ Uses the current buffer's completed-thinking display mode."
(defun pi-coding-agent--history-postprocess-start ()
"Return the first position that needs eager history post-processing.
Large resumed histories should render the visible tail promptly. Older content
can rely on normal jit-lock when visited, while display-only table decoration is
kept to the same hot-tail suffix used by resize refreshes."
relies on jit-lock when visited: tree-sitter fontification and the registered
`pi-coding-agent--jit-decorate-tables' pass both run as each region scrolls into
view, so eager decoration is limited to the same hot-tail suffix used by resize
refreshes."
(if (markerp pi-coding-agent--hot-tail-start)
(marker-position pi-coding-agent--hot-tail-start)
(point-min)))
Expand All @@ -5274,8 +5276,10 @@ contain `|' but cannot be pipe tables.")
"Run consolidated display post-processing after history replay.
History replay inserts many small user/assistant chunks. Running fontification
and table decoration after each chunk is expensive in large sessions, so replay
defers that work. Fontification is left to jit-lock on redisplay; the only
synchronous pass decorates candidate tables in the recent hot tail."
defers that work. Fontification and table decoration are both left to jit-lock
on redisplay (see `pi-coding-agent--jit-decorate-tables'); the only synchronous
pass here decorates candidate tables in the recent hot tail so the visible tail
is a grid immediately, without waiting for a redisplay."
(let ((start (pi-coding-agent--history-postprocess-start))
(end (point-max)))
(when (pi-coding-agent--history-table-candidate-p start end)
Expand Down
26 changes: 26 additions & 0 deletions pi-coding-agent-table.el
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
;; - `pi-coding-agent--decorate-tables-in-region' — stable path
;; - `pi-coding-agent--maybe-decorate-streaming-table' — streaming path
;; - `pi-coding-agent--maybe-refresh-hot-tail-tables' — resize path
;; - `pi-coding-agent--jit-decorate-tables' — lazy scroll-into-view path
;;
;; Depends on `pi-coding-agent-ui' for visible-text extraction and
;; scroll preservation, and on `markdown-table-wrap' for the wrapping engine.
Expand Down Expand Up @@ -630,6 +631,31 @@ Idempotent: existing table overlays in the region are removed first."
(when (pi-coding-agent--table-has-data-row-p (car region) (cdr region))
(pi-coding-agent--decorate-table (car region) (cdr region) width)))))

;;;; Lazy Scroll-Into-View Decoration (jit-lock)

;; History replay only decorates the hot tail eagerly (see
;; `pi-coding-agent--postprocess-history-buffer'); older tables are left as raw
;; markdown so large resumed sessions load promptly. Tree-sitter fontification
;; already renders lazily as jit-lock brings each region into view, but table
;; decoration is a display-overlay pass that jit-lock does not know about, so
;; older tables would stay raw until a resize or manual toggle. Registering a
;; jit-lock function closes that gap: as you scroll an older table into view,
;; it is decorated on the same redisplay pass that fontifies it -- no load-time
;; cost, because jit-lock only ever runs on regions about to be displayed.

(defun pi-coding-agent--jit-decorate-tables (beg end)
"Decorate pipe tables overlapping BEG..END, expanded to whole tables.
Registered with `jit-lock-register' so tables render when scrolled into
view. jit-lock hands out arbitrary chunk boundaries that may bisect a
table, so the region is grown to the full extent of every overlapping
table before decorating; this keeps the idempotent overlay-removal in
`pi-coding-agent--decorate-tables-in-region' aligned to whole tables and
never leaves a table decorated from a partial range."
(when-let* ((regions (pi-coding-agent--treesit-table-regions beg end)))
(let ((full-beg (apply #'min beg (mapcar #'car regions)))
(full-end (apply #'max end (mapcar #'cdr regions))))
(pi-coding-agent--decorate-tables-in-region full-beg full-end))))

;;;; Cleanup

(defun pi-coding-agent--cleanup-visible-string-buffer ()
Expand Down
7 changes: 7 additions & 0 deletions pi-coding-agent-ui.el
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
(declare-function pi-coding-agent--cleanup-on-kill "pi-coding-agent-render")
(declare-function pi-coding-agent--restore-tool-properties "pi-coding-agent-render")
(declare-function pi-coding-agent--maybe-refresh-hot-tail-tables "pi-coding-agent-table")
(declare-function pi-coding-agent--jit-decorate-tables "pi-coding-agent-table")

;; pi-coding-agent-input.el (input buffer commands)
(declare-function pi-coding-agent-quit "pi-coding-agent-input")
Expand Down Expand Up @@ -857,6 +858,12 @@ This is a read-only buffer showing the conversation history."
;; Run after font-lock to undo markdown damage in tool overlays.
(jit-lock-register #'pi-coding-agent--restore-tool-properties)

;; Decorate pipe tables lazily as they scroll into view. History replay
;; eagerly decorates only the hot tail; this jit-lock pass renders older
;; tables on the same redisplay that fontifies them, so resumed sessions
;; stay fast to load yet every table becomes a grid once seen.
(jit-lock-register #'pi-coding-agent--jit-decorate-tables)

;; Compute theme-derived faces used by chat overlays.
(pi-coding-agent--update-theme-derived-faces)

Expand Down
54 changes: 54 additions & 0 deletions test/pi-coding-agent-table-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,60 @@ 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-jit-decorate-tables-decorates-region ()
"jit-decorate-tables renders a table overlapping the requested region."
(with-temp-buffer
(pi-coding-agent-chat-mode)
(let ((inhibit-read-only t))
(insert pi-coding-agent-test--wide-table))
(font-lock-ensure)
(pi-coding-agent--jit-decorate-tables (point-min) (point-max))
(should (>= (pi-coding-agent-test--table-overlay-count) 1))))

(ert-deftest pi-coding-agent-test-jit-decorate-tables-expands-partial-region ()
"A jit-lock chunk that bisects a table still decorates the whole table.
jit-lock hands out arbitrary boundaries; the region is grown to the full
tree-sitter table extent so overlays cover every row, not a partial range."
(with-temp-buffer
(pi-coding-agent-chat-mode)
(let ((table-beg nil)
(inhibit-read-only t))
(insert "Some intro prose before the table.\n\n")
(setq table-beg (point))
(insert pi-coding-agent-test--wide-table)
(font-lock-ensure)
;; Request a range that begins in the middle of the table and ends
;; before its last row -- the worst case for a redisplay chunk.
(pi-coding-agent--jit-decorate-tables (+ table-beg 20) (- (point-max) 20))
;; The whole four-line table (header, separator, two data rows) gets
;; one overlay per raw line, so all rows are covered, not just those
;; inside the narrow request.
(should (= (pi-coding-agent-test--table-overlay-count) 4)))))

(ert-deftest pi-coding-agent-test-jit-decorate-tables-noop-without-table ()
"jit-decorate-tables creates no overlays when the region has no table."
(with-temp-buffer
(pi-coding-agent-chat-mode)
(let ((inhibit-read-only t))
(insert "Just prose here, no pipe table at all.\n\nMore prose.\n"))
(font-lock-ensure)
(pi-coding-agent--jit-decorate-tables (point-min) (point-max))
(should (= (pi-coding-agent-test--table-overlay-count) 0))))

(ert-deftest pi-coding-agent-test-jit-decorate-tables-respects-raw-toggle ()
"jit-decorate-tables leaves user-toggled raw tables undecorated.
The `pi-coding-agent--skip-raw-tables' advice guards every decoration
path, including this lazy one, so scrolling a raw table into view does
not clobber the user's choice."
(with-temp-buffer
(pi-coding-agent-chat-mode)
(let ((inhibit-read-only t))
(insert pi-coding-agent-test--wide-table))
(font-lock-ensure)
(pi-coding-agent--mark-table-raw (point-min) (point-max))
(pi-coding-agent--jit-decorate-tables (point-min) (point-max))
(should (= (pi-coding-agent-test--table-overlay-count) 0))))

(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
Expand Down
Loading