diff --git a/agent-shell-markdown.el b/agent-shell-markdown.el index 6db90d33..399b81fd 100644 --- a/agent-shell-markdown.el +++ b/agent-shell-markdown.el @@ -466,14 +466,6 @@ body un-fontified." ;; chunk and would otherwise clear our `face' properties. (agent-shell-markdown--mirror-face-to-font-lock-face (point-min) (point-max)) - ;; Tag rendered chars so a yank into another buffer drops the - ;; styling, display overrides, internal markers, and keymaps - ;; we layered on — paste should give plain chars, not our - ;; implementation cruft. - (put-text-property (point-min) (point-max) - 'yank-handler - (list (lambda (s) - (insert (substring-no-properties s))))) ;; Mark rendered chars `fontified' so jit-lock never re-runs over ;; them during a mouse drag. We style via `face'/`font-lock-face' ;; text properties, not font-lock keywords (`font-lock-defaults' diff --git a/agent-shell.el b/agent-shell.el index a8138cc8..6f867e79 100644 --- a/agent-shell.el +++ b/agent-shell.el @@ -2097,6 +2097,10 @@ See also `agent-shell-confirm-interrupt'." "Return visible text between START and END, stripping hidden markup. If DELETE is non-nil, delete the text between START and END. +The result carries no text properties, and \"> \" prefixes added +by `agent-shell--block-quote' are dropped, so pasting a copy gives +plain text matching what was on screen. + START and END may be given in either order: like the stock `buffer-substring', a reversed range (START > END, e.g. a right-to-left mouse selection or a kill where mark > point) is @@ -2119,10 +2123,13 @@ copy depending on selection direction." (setq pos (max next (1+ pos))))) (when delete (delete-region beg fin)) - (remove-text-properties 0 (length text) - '(line-prefix nil wrap-prefix nil) - text) - text)) + ;; One "> " per line, matching what the block quote inserted. + (substring-no-properties + (replace-regexp-in-string + (rx line-start "> ") + (lambda (match) + (if (get-text-property 0 'agent-shell-block-quote match) "" match)) + text nil t)))) (defvar-keymap agent-shell-mode-map :parent shell-maker-mode-map @@ -9680,8 +9687,9 @@ When DEACTIVATE is non-nil, deactivate region/selection." "Return TEXT with each line prefixed by \"> \", displayed as a bar. Underlying text keeps the \"> \" so it remains valid markdown; -the bar is a display-only override. Yanks strip both the bar -styling and the leading \"> \" so paste gives plain text." +the bar is a display-only override. The `agent-shell-block-quote' +property tells `agent-shell--filter-buffer-substring' to drop the +\"> \" from copies so paste gives plain text." (let* ((bar (propertize "▌" 'face 'agent-shell-markdown-blockquote)) (wrap (propertize "▌ " 'face 'agent-shell-markdown-blockquote)) (quoted (concat "> " (replace-regexp-in-string @@ -9692,12 +9700,7 @@ styling and the leading \"> \" so paste gives plain text." 0 (length rendered) (list 'wrap-prefix wrap 'face 'agent-shell-markdown-blockquote - 'yank-handler - (list (lambda (s) - (insert - (replace-regexp-in-string - (rx line-start "> ") "" - (substring-no-properties s)))))) + 'agent-shell-block-quote t) rendered) (while (string-match (rx line-start ">") rendered pos) (put-text-property (match-beginning 0) (match-end 0) diff --git a/tests/agent-shell-markdown-tests.el b/tests/agent-shell-markdown-tests.el index 04ed41c4..ef59f369 100644 --- a/tests/agent-shell-markdown-tests.el +++ b/tests/agent-shell-markdown-tests.el @@ -3594,22 +3594,6 @@ A " nil) (should (string-match-p "^hello\nworld\n$" (substring-no-properties (buffer-string)))))) -(ert-deftest agent-shell-markdown-yank-strips-properties () - ;; Rendered chars carry a `yank-handler' that strips every text - ;; property on paste — display overrides, internal markers, faces, - ;; keymaps — so a copy/paste into another buffer gives plain chars, - ;; not our implementation cruft. - (with-temp-buffer - (insert "**bold** and `code`\n") - (agent-shell-markdown-replace-markup) - (kill-new (buffer-substring (point-min) (point-max)))) - (with-temp-buffer - (yank) - (let ((pos (point-min))) - (while (< pos (point-max)) - (should-not (text-properties-at pos)) - (setq pos (1+ pos)))))) - (ert-deftest agent-shell-markdown-convert-blockquote-single-level () ;; `> text\n' keeps the `>' in the buffer (source round-trips) but ;; shows `▌' as a display override. The line content carries the diff --git a/tests/agent-shell-tests.el b/tests/agent-shell-tests.el index 1267e8b9..079dd773 100644 --- a/tests/agent-shell-tests.el +++ b/tests/agent-shell-tests.el @@ -4225,6 +4225,42 @@ direction." (should (equal forward "hello world")) (should (equal reversed forward))))) +(ert-deftest agent-shell-filter-buffer-substring-strips-text-properties () + "Copied rendered output carries no text properties. +Faces, display overrides, and internal markers stay in the buffer; +a copy/paste into another buffer gives plain chars." + (with-temp-buffer + (insert "**bold** and `code`\n") + (agent-shell-markdown-replace-markup) + (let ((result (agent-shell--filter-buffer-substring (point-min) (point-max))) + (pos 0)) + (should (equal result "bold and code\n")) + (while (< pos (length result)) + (should-not (text-properties-at pos result)) + (setq pos (1+ pos)))))) + +(ert-deftest agent-shell-filter-buffer-substring-strips-block-quote-prefix () + "Copying quoted text drops the \"> \" `agent-shell--block-quote' added." + (with-temp-buffer + (insert (agent-shell--block-quote "hello\nworld")) + (should (equal (agent-shell--filter-buffer-substring (point-min) (point-max)) + "hello\nworld")))) + +(ert-deftest agent-shell-filter-buffer-substring-strips-one-quote-level () + "Quoting already-quoted text keeps the inner \"> \" on copy." + (with-temp-buffer + (insert (agent-shell--block-quote "> hello")) + (should (equal (agent-shell--filter-buffer-substring (point-min) (point-max)) + "> hello")))) + +(ert-deftest agent-shell-filter-buffer-substring-keeps-rendered-block-quote () + "Markdown blockquotes copy with their \"> \" so the source round-trips." + (with-temp-buffer + (insert "> hello\n") + (agent-shell-markdown-replace-markup) + (should (equal (agent-shell--filter-buffer-substring (point-min) (point-max)) + "> hello\n")))) + (ert-deftest agent-shell-trim-strips-untagged-whitespace () ;; Plain `string-trim'-style behavior when nothing is tagged: outer ;; whitespace is removed.