Skip to content

Commit 0f6dff9

Browse files
committed
Avoid unnecessary streaming table scans
1 parent 6141936 commit 0f6dff9

2 files changed

Lines changed: 54 additions & 3 deletions

File tree

pi-coding-agent-render.el

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ When set, per-message fontification and table decoration are skipped;
5656
`pi-coding-agent--postprocess-history-buffer' runs one consolidated pass after
5757
all history has been inserted.")
5858

59+
(defvar-local pi-coding-agent--streaming-table-candidate nil
60+
"Non-nil when recent streaming text may contain a markdown pipe table.
61+
Streaming table decoration is comparatively expensive because it queries the
62+
current message with tree-sitter. Most assistant text is not table content, so
63+
we track whether a pipe has appeared since the last decoration attempt and skip
64+
the query when no table can be present.")
5965

6066
(defun pi-coding-agent--history-postprocessing-deferred-p ()
6167
"Return non-nil when history display post-processing is currently deferred."
@@ -95,6 +101,7 @@ Note: status is set to `streaming' by the event handler."
95101
(setq pi-coding-agent--line-parse-state 'line-start)
96102
(setq pi-coding-agent--in-code-block nil)
97103
(setq pi-coding-agent--in-thinking-block nil)
104+
(setq pi-coding-agent--streaming-table-candidate nil)
98105
(pi-coding-agent--set-activity-phase "thinking"))
99106

100107
(defun pi-coding-agent--process-streaming-char (char state in-block)
@@ -194,8 +201,14 @@ fontification; tree-sitter re-parses at the C level on each insert."
194201
(goto-char (marker-position pi-coding-agent--streaming-marker))
195202
(insert transformed)
196203
(set-marker pi-coding-agent--streaming-marker (point))))
197-
;; After inserting text with completed lines, check for active table
198-
(when (string-match-p "\n" delta)
204+
;; After inserting text with completed lines, check for active tables only
205+
;; if recent streaming text contained a pipe. This avoids a tree-sitter
206+
;; table query on every non-table newline in long assistant messages.
207+
(when (string-match-p "|" delta)
208+
(setq pi-coding-agent--streaming-table-candidate t))
209+
(when (and pi-coding-agent--streaming-table-candidate
210+
(string-match-p "\n" delta))
211+
(setq pi-coding-agent--streaming-table-candidate nil)
199212
(pi-coding-agent--maybe-decorate-streaming-table)))))
200213

201214
(defun pi-coding-agent--thinking-insert-position ()
@@ -1144,7 +1157,8 @@ Updates buffer-local state and renders display updates."
11441157
("text_end"
11451158
;; Text block ended — finalize any active table that may have
11461159
;; a trailing row without newline (backstop for streaming).
1147-
(pi-coding-agent--maybe-decorate-streaming-table))
1160+
(pi-coding-agent--maybe-decorate-streaming-table)
1161+
(setq pi-coding-agent--streaming-table-candidate nil))
11481162
("thinking_start"
11491163
(pi-coding-agent--display-thinking-start))
11501164
("thinking_delta"

test/pi-coding-agent-render-test.el

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,43 @@
5050
(pi-coding-agent--display-message-delta "world!")
5151
(should (string-match-p "Hello, world!" (buffer-string)))))
5252

53+
(ert-deftest pi-coding-agent-test-display-message-delta-skips-table-scan-without-pipe ()
54+
"Streaming text without pipes should not query for markdown tables."
55+
(with-temp-buffer
56+
(pi-coding-agent-chat-mode)
57+
(pi-coding-agent--display-agent-start)
58+
(let ((table-scan-count 0))
59+
(cl-letf (((symbol-function 'pi-coding-agent--maybe-decorate-streaming-table)
60+
(lambda () (setq table-scan-count (1+ table-scan-count)))))
61+
(pi-coding-agent--display-message-delta "ordinary prose\nmore prose\n"))
62+
(should (= table-scan-count 0)))))
63+
64+
(ert-deftest pi-coding-agent-test-display-message-delta-scans-table-after-pipe-newline ()
65+
"Streaming text with a pipe and newline should check for markdown tables."
66+
(with-temp-buffer
67+
(pi-coding-agent-chat-mode)
68+
(pi-coding-agent--display-agent-start)
69+
(let ((table-scan-count 0))
70+
(cl-letf (((symbol-function 'pi-coding-agent--maybe-decorate-streaming-table)
71+
(lambda () (setq table-scan-count (1+ table-scan-count)))))
72+
(pi-coding-agent--display-message-delta "| a | b |")
73+
(should (= table-scan-count 0))
74+
(pi-coding-agent--display-message-delta "\n|---|---|\n"))
75+
(should (= table-scan-count 1)))))
76+
77+
(ert-deftest pi-coding-agent-test-text-end-clears-streaming-table-candidate ()
78+
"The text_end table backstop clears any pending streaming table candidate."
79+
(with-temp-buffer
80+
(pi-coding-agent-chat-mode)
81+
(setq pi-coding-agent--streaming-table-candidate t)
82+
(let ((table-scan-count 0))
83+
(cl-letf (((symbol-function 'pi-coding-agent--maybe-decorate-streaming-table)
84+
(lambda () (setq table-scan-count (1+ table-scan-count)))))
85+
(pi-coding-agent--handle-display-event
86+
'(:type "message_update"
87+
:assistantMessageEvent (:type "text_end"))))
88+
(should (= table-scan-count 1))
89+
(should-not pi-coding-agent--streaming-table-candidate))))
5390

5491
(ert-deftest pi-coding-agent-test-delta-transforms-atx-headings ()
5592
"ATX headings in assistant content are leveled down.

0 commit comments

Comments
 (0)