bug: header line backgrounds don't cover quote prefix on email-quoted diffs #142

Closed
opened 2026-03-04 05:59:37 +00:00 by barrettruth · 3 comments
barrettruth commented 2026-03-04 05:59:37 +00:00

Problem

When parsing email-quoted diffs (> diff --git ...), the diff treesitter grammar applies @diff.plus.diff and @diff.minus.diff captures to +++/--- header lines. These captures start at col = quote_width (e.g. col 2 for > prefix), leaving the quote prefix area (col 0–1) with no background highlight.

The non-quoted version covers the full line (col 0 to EOL), so the visual difference is jarring — the quoted header lines have a colored background on only part of the line.

Affected lines: > --- a/..., > +++ b/....

Proposed fix

When quote_width > 0, detect ---/+++ header lines and add a full-line background extmark (hl_eol = true, col 0) matching the @diff.plus/@diff.minus highlight, just like hunk body lines already get DiffsAdd/DiffsDelete line backgrounds. The > prefix stays visible in the buffer — buffers should show their actual content — but the background covers the full line.

Conceal is the wrong approach. Hiding the quote prefix, if desired, should be opt-in via hide_prefix, not forced.

Context

Introduced by the email-quoted diff parsing feature (#141). The core parsing and highlight offset logic works correctly — this is a visual polish issue specific to header lines.

## Problem When parsing email-quoted diffs (`> diff --git ...`), the diff treesitter grammar applies `@diff.plus.diff` and `@diff.minus.diff` captures to `+++`/`---` header lines. These captures start at `col = quote_width` (e.g. col 2 for `> ` prefix), leaving the quote prefix area (col 0–1) with no background highlight. The non-quoted version covers the full line (col 0 to EOL), so the visual difference is jarring — the quoted header lines have a colored background on only part of the line. Affected lines: `> --- a/...`, `> +++ b/...`. ## Proposed fix When `quote_width > 0`, detect `---`/`+++` header lines and add a full-line background extmark (`hl_eol = true`, col 0) matching the `@diff.plus`/`@diff.minus` highlight, just like hunk body lines already get `DiffsAdd`/`DiffsDelete` line backgrounds. The `> ` prefix stays visible in the buffer — buffers should show their actual content — but the background covers the full line. Conceal is the wrong approach. Hiding the quote prefix, if desired, should be opt-in via `hide_prefix`, not forced. ## Context Introduced by the email-quoted diff parsing feature (#141). The core parsing and highlight offset logic works correctly — this is a visual polish issue specific to header lines.
barrettruth commented 2026-03-04 07:19:32 +00:00

Progress

Investigated and partially fixed. The issue was deeper than just header line backgrounds.

Root cause

DiffsClear only defined fg (Normal foreground). In Neovim's extmark priority model, each highlight attribute (fg, bg, bold, etc.) is resolved independently across the priority stack. A higher-priority extmark that only defines fg does not suppress a lower-priority extmark's bg. This meant native treesitter's wrong backgrounds (from misinterpreting > -prefixed lines) bled through everywhere DiffsClear was applied.

Fixes applied

  1. DiffsClear now defines both fg and bg (init.lua) — suppresses native treesitter backgrounds
  2. Header lines get DiffsClear at col 0 when qw > 0 — clears native TS before re-applying diff grammar treesitter at elevated priority (199 vs default 100)
  3. @@ line gets explicit highlighting when qw > 0 — was previously unhandled (not in header_lines, not a body line), now gets DiffsClear + diff grammar treesitter
  4. Body line > prefix gets DiffsClear (col 0→qw) — suppresses native TS on the quote prefix

Remaining issues

  1. 1-col gap at col qw on context lines: Between prefix DiffsClear (0→qw) and content DiffsClear (pw+qw→EOL), context body lines have a 1-column gap where native TS bg can bleed through. Masked on +/- lines by DiffsAdd/DiffsDelete at p200.
  2. Bare > context lines: May not get full DiffsClear coverage (line_len ≤ pw so content DiffsClear never fires).
  3. Diff prefix marker color: +/- at col qw lacks diff-grammar fg in quoted mode (native TS can't parse > +...).

Config option idea

Should there be a config option to hide the > quote prefix (via hide_prefix or a new hide_quote_prefix)? The buffer content stays unchanged, but the prefix would be visually concealed. This is separate from the background fix.

## Progress Investigated and partially fixed. The issue was deeper than just header line backgrounds. ### Root cause `DiffsClear` only defined `fg` (Normal foreground). In Neovim's extmark priority model, each highlight attribute (fg, bg, bold, etc.) is resolved independently across the priority stack. A higher-priority extmark that only defines `fg` does **not** suppress a lower-priority extmark's `bg`. This meant native treesitter's wrong backgrounds (from misinterpreting `> `-prefixed lines) bled through everywhere `DiffsClear` was applied. ### Fixes applied 1. **`DiffsClear` now defines both `fg` and `bg`** (init.lua) — suppresses native treesitter backgrounds 2. **Header lines get `DiffsClear` at col 0** when `qw > 0` — clears native TS before re-applying diff grammar treesitter at elevated priority (199 vs default 100) 3. **`@@` line gets explicit highlighting** when `qw > 0` — was previously unhandled (not in `header_lines`, not a body line), now gets `DiffsClear` + diff grammar treesitter 4. **Body line `> ` prefix gets `DiffsClear`** (col 0→qw) — suppresses native TS on the quote prefix ### Remaining issues 1. **1-col gap at col `qw` on context lines**: Between prefix DiffsClear (0→qw) and content DiffsClear (pw+qw→EOL), context body lines have a 1-column gap where native TS bg can bleed through. Masked on +/- lines by DiffsAdd/DiffsDelete at p200. 2. **Bare `>` context lines**: May not get full DiffsClear coverage (line_len ≤ pw so content DiffsClear never fires). 3. **Diff prefix marker color**: `+`/`-` at col `qw` lacks diff-grammar fg in quoted mode (native TS can't parse `> +...`). ### Config option idea Should there be a config option to hide the `> ` quote prefix (via `hide_prefix` or a new `hide_quote_prefix`)? The buffer content stays unchanged, but the prefix would be visually concealed. This is separate from the background fix.
barrettruth commented 2026-03-04 07:21:17 +00:00

NOTE: we see a green bg flash on the second code portion of

This is a normal diff (parses fine):

diff --git a/foo.py b/foo.py
index 3c507e6..a41a179 100644
--- a/foo.py
+++ b/foo.py
@@ -1,4 +1,5 @@
 from typing import Annotated

 class Foo:
-    p
+    def bar(self) -> None:
+        pass

---

This is the same diff in an email reply (currently produces 0 hunks):

Looks good, one nit:

> diff --git a/foo.py b/foo.py
> index 3c507e6..a41a179 100644
> --- a/foo.py
> +++ b/foo.py
> @@ -1,4 +1,5 @@
>  from typing import Annotated
>
>  class Foo:
> -    p
> +    def bar(self) -> None:
> +        pass

Maybe rename `p` to something descriptive?

in the current impl, indicating inconsistent hl (this not seen in section 1) and possibly related to #143

NOTE: we see a green bg flash on the second code portion of ```diff This is a normal diff (parses fine): diff --git a/foo.py b/foo.py index 3c507e6..a41a179 100644 --- a/foo.py +++ b/foo.py @@ -1,4 +1,5 @@ from typing import Annotated class Foo: - p + def bar(self) -> None: + pass --- This is the same diff in an email reply (currently produces 0 hunks): Looks good, one nit: > diff --git a/foo.py b/foo.py > index 3c507e6..a41a179 100644 > --- a/foo.py > +++ b/foo.py > @@ -1,4 +1,5 @@ > from typing import Annotated > > class Foo: > - p > + def bar(self) -> None: > + pass Maybe rename `p` to something descriptive? ``` in the current impl, indicating inconsistent hl (this not seen in section 1) and possibly related to #143
barrettruth commented 2026-03-05 15:31:37 +00:00

closed in #149

closed in #149
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
barrettruth/diffs.nvim#142
No description provided.