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
This commit is contained in:
parent
a6d4dcff1f
commit
9e857d4b29
5 changed files with 247 additions and 8 deletions
|
|
@ -1,13 +1,15 @@
|
|||
require('spec.helpers')
|
||||
|
||||
local commands = require('diffs.commands')
|
||||
|
||||
describe('commands', function()
|
||||
describe('setup', function()
|
||||
it('registers Gdiff, Gvdiff, and Ghdiff commands', function()
|
||||
require('diffs.commands').setup()
|
||||
local commands = vim.api.nvim_get_commands({})
|
||||
assert.is_not_nil(commands.Gdiff)
|
||||
assert.is_not_nil(commands.Gvdiff)
|
||||
assert.is_not_nil(commands.Ghdiff)
|
||||
commands.setup()
|
||||
local cmds = vim.api.nvim_get_commands({})
|
||||
assert.is_not_nil(cmds.Gdiff)
|
||||
assert.is_not_nil(cmds.Gvdiff)
|
||||
assert.is_not_nil(cmds.Ghdiff)
|
||||
end)
|
||||
end)
|
||||
|
||||
|
|
@ -37,4 +39,60 @@ describe('commands', function()
|
|||
assert.are.equal('', diff_output)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('find_hunk_line', function()
|
||||
it('finds matching @@ header and returns target line', function()
|
||||
local diff_lines = {
|
||||
'diff --git a/file.lua b/file.lua',
|
||||
'--- a/file.lua',
|
||||
'+++ b/file.lua',
|
||||
'@@ -1,3 +1,4 @@',
|
||||
' local M = {}',
|
||||
'+local new = true',
|
||||
' return M',
|
||||
}
|
||||
local hunk_position = {
|
||||
hunk_header = '@@ -1,3 +1,4 @@',
|
||||
offset = 2,
|
||||
}
|
||||
local target_line = commands.find_hunk_line(diff_lines, hunk_position)
|
||||
assert.equals(6, target_line)
|
||||
end)
|
||||
|
||||
it('returns nil when hunk header not found', function()
|
||||
local diff_lines = {
|
||||
'diff --git a/file.lua b/file.lua',
|
||||
'@@ -1,3 +1,4 @@',
|
||||
' local M = {}',
|
||||
}
|
||||
local hunk_position = {
|
||||
hunk_header = '@@ -99,3 +99,4 @@',
|
||||
offset = 1,
|
||||
}
|
||||
local target_line = commands.find_hunk_line(diff_lines, hunk_position)
|
||||
assert.is_nil(target_line)
|
||||
end)
|
||||
|
||||
it('handles multiple hunks and finds correct one', function()
|
||||
local diff_lines = {
|
||||
'diff --git a/file.lua b/file.lua',
|
||||
'--- a/file.lua',
|
||||
'+++ b/file.lua',
|
||||
'@@ -1,3 +1,4 @@',
|
||||
' local M = {}',
|
||||
'+local x = 1',
|
||||
' ',
|
||||
'@@ -10,3 +11,4 @@',
|
||||
' function M.foo()',
|
||||
'+ print("hello")',
|
||||
' end',
|
||||
}
|
||||
local hunk_position = {
|
||||
hunk_header = '@@ -10,3 +11,4 @@',
|
||||
offset = 2,
|
||||
}
|
||||
local target_line = commands.find_hunk_line(diff_lines, hunk_position)
|
||||
assert.equals(10, target_line)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -357,4 +357,124 @@ describe('fugitive', function()
|
|||
vim.api.nvim_buf_delete(buf, { force = true })
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('get_hunk_position', function()
|
||||
local function create_status_buffer(lines)
|
||||
local buf = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
|
||||
return buf
|
||||
end
|
||||
|
||||
it('returns nil when on file header line', function()
|
||||
local buf = create_status_buffer({
|
||||
'Unstaged (1)',
|
||||
'M file.lua',
|
||||
'@@ -1,3 +1,4 @@',
|
||||
' local M = {}',
|
||||
'+local new = true',
|
||||
})
|
||||
local pos = fugitive.get_hunk_position(buf, 2)
|
||||
assert.is_nil(pos)
|
||||
vim.api.nvim_buf_delete(buf, { force = true })
|
||||
end)
|
||||
|
||||
it('returns nil when on @@ header line', function()
|
||||
local buf = create_status_buffer({
|
||||
'Unstaged (1)',
|
||||
'M file.lua',
|
||||
'@@ -1,3 +1,4 @@',
|
||||
' local M = {}',
|
||||
})
|
||||
local pos = fugitive.get_hunk_position(buf, 3)
|
||||
assert.is_nil(pos)
|
||||
vim.api.nvim_buf_delete(buf, { force = true })
|
||||
end)
|
||||
|
||||
it('returns hunk header and offset for + line', function()
|
||||
local buf = create_status_buffer({
|
||||
'Unstaged (1)',
|
||||
'M file.lua',
|
||||
'@@ -1,3 +1,4 @@',
|
||||
' local M = {}',
|
||||
'+local new = true',
|
||||
' return M',
|
||||
})
|
||||
local pos = fugitive.get_hunk_position(buf, 5)
|
||||
assert.is_not_nil(pos)
|
||||
assert.equals('@@ -1,3 +1,4 @@', pos.hunk_header)
|
||||
assert.equals(2, pos.offset)
|
||||
vim.api.nvim_buf_delete(buf, { force = true })
|
||||
end)
|
||||
|
||||
it('returns hunk header and offset for - line', function()
|
||||
local buf = create_status_buffer({
|
||||
'Unstaged (1)',
|
||||
'M file.lua',
|
||||
'@@ -1,3 +1,3 @@',
|
||||
' local M = {}',
|
||||
'-local old = false',
|
||||
' return M',
|
||||
})
|
||||
local pos = fugitive.get_hunk_position(buf, 5)
|
||||
assert.is_not_nil(pos)
|
||||
assert.equals('@@ -1,3 +1,3 @@', pos.hunk_header)
|
||||
assert.equals(2, pos.offset)
|
||||
vim.api.nvim_buf_delete(buf, { force = true })
|
||||
end)
|
||||
|
||||
it('returns hunk header and offset for context line', function()
|
||||
local buf = create_status_buffer({
|
||||
'Unstaged (1)',
|
||||
'M file.lua',
|
||||
'@@ -1,3 +1,4 @@',
|
||||
' local M = {}',
|
||||
'+local new = true',
|
||||
' return M',
|
||||
})
|
||||
local pos = fugitive.get_hunk_position(buf, 6)
|
||||
assert.is_not_nil(pos)
|
||||
assert.equals('@@ -1,3 +1,4 @@', pos.hunk_header)
|
||||
assert.equals(3, pos.offset)
|
||||
vim.api.nvim_buf_delete(buf, { force = true })
|
||||
end)
|
||||
|
||||
it('returns correct offset for first line after @@', function()
|
||||
local buf = create_status_buffer({
|
||||
'Unstaged (1)',
|
||||
'M file.lua',
|
||||
'@@ -1,3 +1,4 @@',
|
||||
' local M = {}',
|
||||
})
|
||||
local pos = fugitive.get_hunk_position(buf, 4)
|
||||
assert.is_not_nil(pos)
|
||||
assert.equals(1, pos.offset)
|
||||
vim.api.nvim_buf_delete(buf, { force = true })
|
||||
end)
|
||||
|
||||
it('handles @@ header with context text', function()
|
||||
local buf = create_status_buffer({
|
||||
'Unstaged (1)',
|
||||
'M file.lua',
|
||||
'@@ -10,3 +10,4 @@ function M.hello()',
|
||||
' print("hi")',
|
||||
'+ print("world")',
|
||||
})
|
||||
local pos = fugitive.get_hunk_position(buf, 5)
|
||||
assert.is_not_nil(pos)
|
||||
assert.equals('@@ -10,3 +10,4 @@ function M.hello()', pos.hunk_header)
|
||||
assert.equals(2, pos.offset)
|
||||
vim.api.nvim_buf_delete(buf, { force = true })
|
||||
end)
|
||||
|
||||
it('returns nil when section header interrupts search', function()
|
||||
local buf = create_status_buffer({
|
||||
'Unstaged (1)',
|
||||
'M file.lua',
|
||||
' some orphan line',
|
||||
})
|
||||
local pos = fugitive.get_hunk_position(buf, 3)
|
||||
assert.is_nil(pos)
|
||||
vim.api.nvim_buf_delete(buf, { force = true })
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue