Skip to content

Commit ee00f4d

Browse files
authored
fix: Consistent single blank line between chat sections (#98)
Two fixes for extra blank lines in chat buffer: 1. display-agent-end: normalize to single trailing \n (was \n\n). Section headers prepend \n, so \n\n created triple newlines. 2. display-message-delta: strip leading newlines from first delta. Models send \n\n before first content, creating blank lines after the setext header. Detected by comparing markers: when message-start-marker equals streaming-marker, no content has been inserted yet.
1 parent e4766ed commit ee00f4d

File tree

2 files changed

+60
-7
lines changed

2 files changed

+60
-7
lines changed

pi-coding-agent.el

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,12 @@ on each delta - fontification happens at message end instead."
960960
(when (and delta pi-coding-agent--streaming-marker)
961961
(let* ((inhibit-read-only t)
962962
(inhibit-modification-hooks t)
963+
;; Strip leading newlines from first content after header
964+
(delta (if (and pi-coding-agent--message-start-marker
965+
(= (marker-position pi-coding-agent--message-start-marker)
966+
(marker-position pi-coding-agent--streaming-marker)))
967+
(string-trim-left delta "\n+")
968+
delta))
963969
(transformed (pi-coding-agent--transform-delta delta)))
964970
(pi-coding-agent--with-scroll-preservation
965971
(save-excursion
@@ -1008,7 +1014,7 @@ CONTENT is ignored - we use what was already streamed."
10081014
(set-marker pi-coding-agent--streaming-marker (point)))))))
10091015

10101016
(defun pi-coding-agent--display-agent-end ()
1011-
"Display end of agent turn and process follow-up queue.
1017+
"Finalize agent turn: normalize whitespace, handle abort, process queue.
10121018
Note: status is set to `idle' by the event handler."
10131019
;; Reset local message tracker.
10141020
;; Ensures clean state for next turn (e.g., if abort occurred before echo arrived).
@@ -1030,14 +1036,13 @@ Note: status is set to `idle' by the event handler."
10301036
(insert "\n\n" (propertize "[Aborted]" 'face 'error) "\n")))
10311037
(setq pi-coding-agent--aborted nil)
10321038
(setq pi-coding-agent--followup-queue nil))
1033-
;; Add spacing for next turn, avoiding excess blank lines
1034-
;; Use scroll preservation so following windows stay at end
1039+
;; Normalize trailing newlines - ensure content ends with single newline.
10351040
(pi-coding-agent--with-scroll-preservation
10361041
(save-excursion
10371042
(goto-char (point-max))
10381043
(skip-chars-backward "\n")
10391044
(delete-region (point) (point-max))
1040-
(insert "\n\n"))))
1045+
(insert "\n"))))
10411046
(pi-coding-agent--spinner-stop)
10421047
(pi-coding-agent--fontify-timer-stop)
10431048
(pi-coding-agent--refresh-header)

test/pi-coding-agent-test.el

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -773,13 +773,13 @@ as the top-level structure."
773773
(pi-coding-agent--display-thinking-delta " about this.")
774774
(should (string-match-p "Let me think... about this." (buffer-string)))))
775775

776-
(ert-deftest pi-coding-agent-test-display-agent-end-adds-newlines ()
777-
"agent_end event adds trailing newlines."
776+
(ert-deftest pi-coding-agent-test-display-agent-end-adds-newline ()
777+
"agent_end normalizes trailing whitespace to single newline."
778778
(with-temp-buffer
779779
(pi-coding-agent-chat-mode)
780780
(pi-coding-agent--append-to-chat "Some response")
781781
(pi-coding-agent--display-agent-end)
782-
(should (string-suffix-p "\n\n" (buffer-string)))))
782+
(should (string-suffix-p "response\n" (buffer-string)))))
783783

784784
(ert-deftest pi-coding-agent-test-spacing-no-blank-line-after-user-header ()
785785
"User header has no blank line after setext underline.
@@ -800,6 +800,26 @@ The hidden === provides visual spacing when `markdown-hide-markup' is t."
800800
;; Pattern: setext heading (Assistant + underline), NO blank line, content
801801
(should (string-match-p "Assistant\n=+\nHi" (buffer-string)))))
802802

803+
(ert-deftest pi-coding-agent-test-spacing-delta-leading-newlines-stripped ()
804+
"Leading newlines from first text delta are stripped.
805+
Models often send \\n\\n before first content, which would create
806+
extra blank lines after the setext header."
807+
(with-temp-buffer
808+
(pi-coding-agent-chat-mode)
809+
(pi-coding-agent--display-agent-start)
810+
(pi-coding-agent--display-message-delta "\n\nHi")
811+
(should (string-match-p "Assistant\n=+\nHi" (buffer-string)))))
812+
813+
(ert-deftest pi-coding-agent-test-spacing-thinking-leading-newlines-stripped ()
814+
"Leading newlines before thinking block are stripped.
815+
Models may send \\n\\n before thinking content too."
816+
(with-temp-buffer
817+
(pi-coding-agent-chat-mode)
818+
(pi-coding-agent--display-agent-start)
819+
(pi-coding-agent--display-thinking-start)
820+
;; Thinking start should appear directly after header, no blank line
821+
(should (string-match-p "Assistant\n=+\n>" (buffer-string)))))
822+
803823
(ert-deftest pi-coding-agent-test-spacing-blank-line-before-tool ()
804824
"Tool block is preceded by blank line when after text."
805825
(with-temp-buffer
@@ -823,6 +843,34 @@ The hidden === provides visual spacing when `markdown-hide-markup' is t."
823843
;; Should end with closing fence and blank line
824844
(should (string-match-p "```\n\n" (buffer-string)))))
825845

846+
(ert-deftest pi-coding-agent-test-spacing-single-blank-line-between-turns ()
847+
"Only one blank line between agent response and next section header.
848+
agent_end + next section's leading newline must not create triple newlines."
849+
(with-temp-buffer
850+
(pi-coding-agent-chat-mode)
851+
;; Turn 1: user + assistant
852+
(pi-coding-agent--display-user-message "Hi")
853+
(pi-coding-agent--display-agent-start)
854+
(pi-coding-agent--display-message-delta "Hello!")
855+
(pi-coding-agent--render-complete-message)
856+
(pi-coding-agent--display-agent-end)
857+
;; Turn 2: user message
858+
(setq pi-coding-agent--assistant-header-shown nil)
859+
(pi-coding-agent--display-user-message "Bye")
860+
;; Should never have triple newlines (which would be two blank lines)
861+
(should-not (string-match-p "\n\n\n" (buffer-string)))))
862+
863+
(ert-deftest pi-coding-agent-test-spacing-single-blank-line-before-compaction ()
864+
"Only one blank line between agent response and compaction header."
865+
(with-temp-buffer
866+
(pi-coding-agent-chat-mode)
867+
(pi-coding-agent--display-agent-start)
868+
(pi-coding-agent--display-message-delta "Some response.")
869+
(pi-coding-agent--render-complete-message)
870+
(pi-coding-agent--display-agent-end)
871+
(pi-coding-agent--display-compaction-result 50000 "Summary.")
872+
(should-not (string-match-p "\n\n\n" (buffer-string)))))
873+
826874
(ert-deftest pi-coding-agent-test-spacing-no-double-blank-between-tools ()
827875
"Consecutive tools have single blank line between them."
828876
(with-temp-buffer

0 commit comments

Comments
 (0)