Commit graph

35 commits

Author SHA1 Message Date
2e1ebdee03 feat(highlight): add treesitter context padding from disk
Problem: treesitter parses each diff hunk in isolation, so incomplete
syntax constructs at hunk boundaries (e.g., a function definition with
no body) produce ERROR nodes and drop captures.

Solution: read N lines from the on-disk file before/after each hunk and
prepend/append them as unmapped padding lines. The line_map guard in
highlight_treesitter skips extmarks for unmapped lines, so padding
provides syntax context without visual output. Controlled by
highlights.context (default 25, 0 to disable). Also applies to the vim
syntax fallback path via a leading_offset filter.
2026-02-07 13:05:53 -05:00
bbb87b660e fix(highlight): split old/new treesitter parsing
Problem: highlight_treesitter concatenated all hunk lines (context, -,
+) into a single string. Mixed old/new code produced invalid syntax
(e.g. two return statements), causing treesitter error recovery to drop
captures on lines after the syntax error.

Solution: split hunk lines into two versions — new (context + added)
and old (context + deleted) — each parsed independently. Use a line_map
to resolve treesitter row indices to buffer lines, with the old version
only mapping deleted lines to avoid duplicate extmarks on context.

Also fixes three related issues exposed by the improved TS coverage:

- Replace Normal extmark with DiffsClear (explicit fg from Normal.fg).
  Normal in extmarks doesn't reliably override vim :syntax foreground.

- Reorder priority stack to DiffsClear(198) < syntax(199) < line
  bg(200) < char bg(201). TS capture groups can carry colorscheme
  backgrounds that would override diff line backgrounds at higher
  priority.

- Gate DiffsClear on per-line coverage tracking. Only clear fugitive
  syntax fg on lines where TS/vim actually produced captures, preventing
  force-clearing on lines where error recovery drops captures.
2026-02-07 00:50:21 -05:00
f948982848 fix(commands): handle :e on diffs:// buffers via BufReadCmd
Problem: running :e on a :Gdiff buffer cleared all content because
diffs:// buffers had no BufReadCmd handler. Neovim tried to read the
buffer name as a file path, found nothing on disk, and emptied the
buffer. This affected all three buffer creation paths (gdiff,
gdiff_file, gdiff_section).

Solution: register a BufReadCmd autocmd for diffs://* that parses the
URL and regenerates diff content from git. Change buffer options from
nofile/wipe to nowrite/delete (matching fugitive's approach) so
buffer-local autocmds and variables survive across unload/reload
cycles. Store old filepath as buffer variable for rename support.
2026-02-06 22:21:33 -05:00
10af59a70d feat(config): replace algorithm 'auto'/'native' with 'default'/'vscode'
'default' inherits algorithm and linematch from diffopt, 'vscode' uses
the FFI library. Removes the need for diffs.nvim to duplicate settings
that users already control globally.
2026-02-06 21:23:40 -05:00
cc947167c3 fix(highlight): use hl_group instead of line_hl_group for diff backgrounds
line_hl_group bg occupies a separate rendering channel from hl_group in
Neovim's extmark system, causing character-level bg-only highlights to be
invisible regardless of priority. Switching to hl_group + hl_eol ensures
all backgrounds compete in the same channel.

Also reorders priorities (Normal 198 < line bg 199 < syntax 200 < char
bg 201), bumps char-level blend alpha from 0.4 to 0.7 for visibility,
and adds debug logging throughout the intra pipeline.
2026-02-06 18:31:10 -05:00
997bc49f8b feat(highlight): add character-level intra-line diff highlighting
Line-level backgrounds (DiffsAdd/DiffsDelete) now get a second tier:
changed characters within modified lines receive an intense background
overlay (DiffsAddText/DiffsDeleteText at 70% alpha vs 40% for lines).
Treesitter foreground colors show through since the extmarks only set bg.

diff.lua extracts contiguous -/+ change groups from hunk lines and diffs
each group byte-by-byte using vim.diff(). An optional libvscodediff FFI
backend (lib.lua) auto-downloads the .so from codediff.nvim releases and
falls back to native if unavailable.

New config: highlights.intra.{enabled, algorithm, max_lines}. Gated by
max_lines (default 200) to avoid stalling on huge hunks. Priority 201
sits above treesitter (200) so the character bg always wins.

Closes #60
2026-02-06 13:53:58 -05:00
33c58c7498 fix(parser): detect filetype from file content (shebang/modeline)
When a file has no extension but contains a shebang (e.g., `#!/bin/bash`),
filetype detection now reads the first 10 lines from disk and uses
`vim.filetype.match({ filename, contents })` for content-based detection.

This enables syntax highlighting for files like `build` scripts that rely
on shebang detection, even when the file isn't open in a buffer.

Detection order:
1. Existing buffer's filetype (already implemented in #69)
2. File content (shebang/modeline) - NEW
3. Filename extension only

Also adds `filetype on` to test helpers to ensure `vim.g.ft_ignore_pat`
is set, which is required for shell detection.
2026-02-05 01:08:43 -05:00
9e857d4b29 feat(fugitive): line position tracking for keymaps
When pressing `du`/`dU` from a hunk line in the fugitive status buffer
(after expanding with `=`), the unified diff now opens at the
corresponding line instead of line 1.

Implementation:
- `fugitive.get_hunk_position()` returns @@ header and offset when on a hunk line
- `commands.find_hunk_line()` finds matching @@ header in diff buffer
- `commands.gdiff_file()` accepts optional `hunk_position` and jumps after opening

Also updates @phanen's README credit for the previous two fixes.

Closes #65
2026-02-05 00:27:35 -05:00
c51d625dc6 fix(parser): detect filetype from existing buffer
Files detected via shebang or modeline (e.g., `build` with `#!/bin/bash`)
weren't getting syntax highlighting because `vim.filetype.match()` only
does filename-based detection.

Now `get_ft_from_filename()` first checks if a buffer already exists for
the file and uses its detected filetype. This requires knowing the repo
root to construct the full path, so:

- `parse_buffer()` reads `b:diffs_repo_root` or `b:git_dir` (fugitive)
- `commands.lua` sets `b:diffs_repo_root` on diff buffers it creates

Co-authored-by: phanen <phanen@qq.com>
2026-02-05 00:13:32 -05:00
980bedc8a6 fix(parser): emit hunks for files with unknown filetypes
Previously, hunks were discarded entirely if vim.filetype.match()
returned nil. This meant files with unrecognized extensions got no
highlighting at all - not even the basic green/red backgrounds for
added/deleted lines.

Remove the (current_lang or current_ft) condition from flush_hunk()
so all hunks are collected. highlight_hunk() already handles the
case where ft/lang are nil by skipping syntax highlighting but still
applying background colors.

Co-authored-by: phanen <phanen@qq.com>
2026-02-04 23:51:15 -05:00
08e22af113 fix(tests): suppress unused variable warnings for selene 2026-02-04 23:25:39 -05:00
9ed0639005 fix(fugitive): handle renamed files correctly
Parse both old and new filenames from rename lines (R old -> new).
When diffing staged renames, use old filename as base to correctly
show content changes rather than treating the file as entirely new.

Also adds comprehensive tests for filename edge cases:
- Double extensions, hyphens, underscores, dotfiles
- Deep nested paths, complex renames
- Documents known limitation with filenames containing ' -> '
2026-02-04 23:12:30 -05:00
6072dd0156 feat(fugitive): add section header and untracked file support
Section headers (Staged/Unstaged) now show all diffs in that section,
matching fugitive's behavior. Untracked files show as all-added diffs.
Deleted files show as all-removed diffs.

Also handles edge cases:
- Empty new/old content for deleted/new files
- Section header detection returns is_header flag
2026-02-04 22:39:07 -05:00
ce8fe3b89b test(fugitive): add unit tests for line parsing
Tests for get_section_at_line() and get_file_at_line() covering:
- Section detection (staged, unstaged, untracked)
- File parsing (modified, added, deleted, renamed, untracked)
- Hunk line walk-back to parent file
- Files appearing in multiple sections
2026-02-04 22:23:25 -05:00
045a9044b5 feat: add :Gdiff, :Gvdiff, :Ghdiff commands for unified diff view
Compares current buffer against any git revision (default HEAD), opens result
with full diffs.nvim syntax highlighting. Follows fugitive convention:
:Gdiff/:Gvdiff open vertical split, :Ghdiff opens horizontal split.
2026-02-04 19:52:17 -05:00
a25f1e9d84 feat: treesitter highlighting for diff headers
Apply treesitter highlighting to diff metadata lines (diff --git, index,
---, +++) using the diff language parser. Header info is attached only
to the first hunk of each file to avoid duplicate highlighting.

Based on PR #52 by @phanen with fixes:
- header_lines now only contains diff metadata, not hunk content
- header info attached only to first hunk per file
- removed arbitrary hunk count restriction
2026-02-04 15:11:35 -05:00
2b38874699 feat(config): use vim.g over .setup() 2026-02-03 16:18:55 -05:00
fd270b8215 fix(test): remove other uesless test 2026-02-03 02:53:25 -05:00
92cddd75c3 fix(test): remove old test 2026-02-03 02:51:48 -05:00
c16699004a feat(test): misc tests for more robustness 2026-02-03 01:02:38 -05:00
0ae692bce7 fix(test): rename 2026-02-02 22:09:27 -05:00
67116f38bc feat: rename everything 2026-02-02 22:09:13 -05:00
1dd62373b6 feat: cleanup ci tests 2026-02-02 21:05:25 -05:00
a082b9c4b3 feat: update 2026-02-02 15:34:37 -05:00
2c330732bb feat(highlight): vim highlight fallback 2026-02-02 15:28:58 -05:00
69943a09c4 feat: cleanup config options 2026-02-02 15:18:25 -05:00
dabf2e2cc9 feat: highlight improvemnets 2026-02-02 13:53:43 -05:00
3aa7d1d6f8 feat: use conceal overlay 2026-02-02 13:22:22 -05:00
ea8a2cbaa9 feat: rename param 2026-02-02 01:07:59 -05:00
d7537e93d0 feat: fix highlighting 2026-02-02 00:57:41 -05:00
b3e687c954 fix: proper background higlights 2026-02-02 00:35:08 -05:00
935eb8f7ed feat: highlights, debug fixes, and config validation 2026-02-02 00:22:44 -05:00
00bf84cb05 feat: highlights 2026-02-01 23:17:20 -06:00
8f5e8e3b17 fix(test): hopefully they work 2026-02-01 23:41:59 -05:00
ae1df3e7a8 feat(test): testing infrastructure 2026-02-01 23:09:05 -05:00