Skip to content

bug: git_diff picker uses preview's first line as pos instead of hunk start line #2752

@sQVe

Description

@sQVe

Summary

When using Snacks.picker.git_diff() with a base option, each picker entry's line number reflects the first line of the rendered diff preview block rather than the actual hunk start line in the file. This causes incorrect jump targets when opening a file from the picker and wrong lnum values when sending results to the quickfix list via <c-q>.

Environment

  • snacks.nvim: 9912042 (main, 2026-03-04)
  • Neovim: v0.12.0-dev-2435+g18c5f06c9f
  • OS: Linux

Steps to reproduce

-- Minimal config
Snacks.picker.git_diff({
  base = "origin/main", -- or any commit/branch
})
  1. Open the picker. Each entry shows a file with a line number.
  2. Select an entry and press <CR> — the cursor lands at the wrong line (often line 1).
  3. Alternatively, press <c-q> to send all entries to the quickfix list. Every lnum is incorrect.

Repro

vim.env.LAZY_STDPATH = ".repro"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()

require("lazy.minit").repro({
  spec = {
    { "folke/snacks.nvim", opts = {} },
  },
})

-- From a git repo on a branch that has commits ahead of main, run:
-- :lua Snacks.picker.git_diff({ base = "main" })

Expected behaviour

Each entry's pos (and the resulting quickfix lnum) should be the hunk start line on the right-hand side of the unified diff header — i.e. the +N value from @@ -a,b +N,M @@.

Actual behaviour

Entries use the first line of the rendered diff preview block as their pos, rather than the hunk start line from the @@ ... +N,M @@ header. Each entry's line number therefore reflects wherever the preview panel begins rendering, not the actual changed line in the file.

Investigation

The data flow for line numbers is:

  1. snacks/picker/source/git.lua:261 — runs git diff --no-color --no-ext-diff --diff-filter=u [--merge-base <base>]
  2. snacks/picker/source/diff.lua:112M.parse() iterates raw diff lines
  3. snacks/picker/source/diff.lua:262M.parse_hunk_header() extracts right.line from @@ -a,b +line,count @@
  4. snacks/picker/source/diff.lua:89add() sets pos = { line, 0 } on each item
  5. snacks/picker/actions.lua:540setqflist() reads item.pos[1] as quickfix lnum

The static parsing logic in parse_hunk_header appears correct for standard unified diff output. For example, with the following actual diff produced by the repo under test:

@@ -108,39 +108,8 @@
@@ -154,7 +123,6 @@
@@ -12,14 +12,12 @@ some context
@@ -34,5 +32,4 @@ some context

The expected pos values are 108, 123, 12, and 32 respectively. The bug appears to be a runtime issue — either in how opts.group is propagated to Diff.diff(), or in how pos is overwritten downstream — rather than a parsing failure.

Notes

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleThis issue or PR has been inactive for a whilewontfixThis issue will not be fixed or implemented

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions