All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jason Gunthorpe <jgg@nvidia.com>
To: tools@kernel.org
Subject: [PATCH b4 v2 1/4] review: trim trailing quoted when adding a tag
Date: Mon,  7 Sep 2026 16:22:51 -0300	[thread overview]
Message-ID: <1-v2-de162fd5fc4a+2b7-trimming_jgg@nvidia.com> (raw)
In-Reply-To: <0-v2-de162fd5fc4a+2b7-trimming_jgg@nvidia.com>

If some comments are added and then a review tag is placed the trailing
quote that is normally trimmed is instead retained with the trailer
landing at the end of the message. Instead place it right after the last
user comment. Skip both > and | quoted sections.

Assisted-by: LLM
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 src/b4/review/_review.py | 18 +++++++++++++++---
 src/tests/test_review.py | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/src/b4/review/_review.py b/src/b4/review/_review.py
index a37533230f484a..96f3e5bbd54130 100644
--- a/src/b4/review/_review.py
+++ b/src/b4/review/_review.py
@@ -3297,13 +3297,25 @@ def _insert_trailer_in_reply(reply_text: str, trailer: str) -> str:
     """Append *trailer* as its own bare line in the reply buffer.
 
     The line is added at the end of the maintainer's content, before any
-    trailing ``-- `` signature, grouped with any trailers already there.  The
-    maintainer can move it afterwards — placement is just a sensible default.
+    trailing quoted context or ``-- `` signature, grouped with any trailers
+    already there.  Keeping a trailing quote below the trailer lets the
+    ordinary send-time trimming discard it.  The maintainer can move the
+    trailer afterwards — placement is just a sensible default.
     """
     lines = _normalize_line_endings(reply_text).split('\n')
     sig_idx = next((i for i, ln in enumerate(lines) if ln == '-- '), len(lines))
     head = lines[:sig_idx]
     tail = lines[sig_idx:]
+    quoted_tail: List[str] = []
+    quote_start = len(head)
+    while quote_start and (
+        head[quote_start - 1].startswith(('>', '|'))
+        or not head[quote_start - 1].strip()
+    ):
+        quote_start -= 1
+    if any(line.startswith('>') for line in head[quote_start:]):
+        quoted_tail = head[quote_start:]
+        head = head[:quote_start]
     while head and not head[-1].strip():
         head.pop()
     # Separate from non-trailer content with a blank line so the trailers
@@ -3311,7 +3323,7 @@ def _insert_trailer_in_reply(reply_text: str, trailer: str) -> str:
     if head and not _BARE_TRAILER_RE.match(head[-1]):
         head.append('')
     head.append(trailer)
-    return '\n'.join(head + tail)
+    return '\n'.join(head + quoted_tail + tail)
 
 
 def _remove_trailer_from_reply(reply_text: str, name: str) -> str:
diff --git a/src/tests/test_review.py b/src/tests/test_review.py
index 460cfb9b65196d..eb7e36c52eeebb 100644
--- a/src/tests/test_review.py
+++ b/src/tests/test_review.py
@@ -909,6 +909,40 @@ class TestReplyTrailerEditing:
         # No blank line inserted between the two trailers.
         assert 'Reviewed-by: Me <me@x.com>\nTested-by: Me <me@x.com>' in out
 
+    def test_insert_before_trailing_quote(self) -> None:
+        buf = 'Please fix this.\n\n> context left below my message\n> +old code\n'
+        trailer = 'Reviewed-by: Me <me@x.com>'
+        out = review._insert_trailer_in_reply(buf, trailer)
+        assert out == (
+            'Please fix this.\n\n'
+            'Reviewed-by: Me <me@x.com>\n'
+            '\n'
+            '> context left below my message\n'
+            '> +old code\n'
+        )
+        assert review._trim_quoted_reply(out) == 'Please fix this.\n\n' + trailer
+
+    def test_insert_before_trailing_quote_with_external_review(self) -> None:
+        buf = (
+            'Please fix this.\n'
+            '\n'
+            '> context before external feedback\n'
+            '\n'
+            '| Bot <bot@example.com>:\n'
+            '|\n'
+            '| An external finding.\n'
+            '\n'
+            '> context after external feedback\n'
+        )
+        trailer = 'Reviewed-by: Me <me@x.com>'
+
+        out = review._insert_trailer_in_reply(buf, trailer)
+
+        # The external-review block is scaffolding inside one trailing quoted
+        # run.  Adding a trailer must not split that run and make the quoted
+        # context before the external finding survive send-time trimming.
+        assert review._trim_quoted_reply(out) == 'Please fix this.\n\n' + trailer
+
     def test_remove_drops_matching_bare_line(self) -> None:
         buf = 'Thanks!\n\nReviewed-by: Me <me@x.com>\nAcked-by: Me <me@x.com>'
         out = review._remove_trailer_from_reply(buf, 'reviewed-by')
-- 
2.43.0


  reply	other threads:[~2026-09-07 19:23 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-07 19:22 [PATCH b4 v2 0/4] Improve email quote trimming Jason Gunthorpe
2026-09-07 19:22 ` Jason Gunthorpe [this message]
2026-09-07 19:22 ` [PATCH b4 v2 2/4] review: discard blank lines between | and > quotes when trimming Jason Gunthorpe
2026-09-07 19:22 ` [PATCH b4 v2 3/4] review: add >--cut-- inline marker to snip quoted reply context Jason Gunthorpe
2026-09-07 19:22 ` [PATCH b4 v2 4/4] review: emacs: highlighting and keystroke for >--cut-- Jason Gunthorpe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1-v2-de162fd5fc4a+2b7-trimming_jgg@nvidia.com \
    --to=jgg@nvidia.com \
    --cc=tools@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.