Skip to content

Commit 243a02e

Browse files
feat(nvim): update neotree for git
- `<cr>` open the file (close other windows) - `gd` show diff against merge base (close other windows)
1 parent eb906ee commit 243a02e

3 files changed

Lines changed: 165 additions & 2 deletions

File tree

packages/nvim/lua/hjdivad/neotree.lua

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,30 @@ function M.open_file_for_diff(state)
218218
M.open_file_for_diff_by_path(node.path)
219219
end
220220

221+
---Open a file and close other windows
222+
---@param state neotree.StateWithTree Neo-tree state
223+
function M.open_file_close_others(state)
224+
local node = state.tree:get_node()
225+
if not node or node.type ~= "file" then
226+
return
227+
end
228+
229+
local neotree_win = get_neotree_window()
230+
if not neotree_win then
231+
return
232+
end
233+
234+
-- Move to the neotree window
235+
vim.api.nvim_set_current_win(neotree_win)
236+
237+
-- Split to the right and open the file (this preserves neotree sizing)
238+
vim.cmd("rightbelow vsplit")
239+
240+
local file_win = vim.api.nvim_get_current_win()
241+
vim.cmd("edit " .. vim.fn.fnameescape(node.path))
242+
close_other_windows(neotree_win, file_win)
243+
end
244+
221245
---Switch to or create the dedicated git changes tab
222246
function M.switch_to_git_changes_tab()
223247
-- Check if we have a tracked tab and it still exists with Neo-tree

packages/nvim/lua/plugins/editor.lua

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,22 @@ return {
9494
git_status = {
9595
window = {
9696
mappings = {
97-
["<cr>"] = function(state)
97+
["gd"] = function(state)
9898
local node = state.tree:get_node()
9999
if node and node.type == "file" then
100100
require('hjdivad.neotree').open_file_for_diff(state)
101101
else
102102
require("neo-tree/sources/common/commands").toggle_node(state)
103103
end
104-
end
104+
end,
105+
["<cr>"] = function(state)
106+
local node = state.tree:get_node()
107+
if node and node.type == "file" then
108+
require('hjdivad.neotree').open_file_close_others(state)
109+
else
110+
require("neo-tree/sources/common/commands").toggle_node(state)
111+
end
112+
end,
105113
},
106114
},
107115
},

packages/nvim/tests/hjdivad/neotree_spec.lua

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,137 @@ describe("neotree", function()
337337
end)
338338
end)
339339

340+
describe("open_file_close_others", function()
341+
local function make_node(id, type_, path_)
342+
return {
343+
id = id,
344+
type = type_,
345+
path = path_,
346+
}
347+
end
348+
349+
local function make_state(selected_node)
350+
return {
351+
tree = {
352+
get_node = function()
353+
return selected_node
354+
end,
355+
},
356+
}
357+
end
358+
359+
it("opens the file and closes other windows", function()
360+
local file = make_node("f1", "file", "/tmp/test.txt")
361+
local state = make_state(file)
362+
363+
-- Track vim commands and API calls
364+
local cmds = {}
365+
local original_cmd = vim.cmd
366+
vim.cmd = function(c)
367+
table.insert(cmds, c)
368+
end
369+
370+
local set_win_calls = {}
371+
local original_set_win = vim.api.nvim_set_current_win
372+
vim.api.nvim_set_current_win = function(win)
373+
table.insert(set_win_calls, win)
374+
end
375+
376+
local original_get_win = vim.api.nvim_get_current_win
377+
vim.api.nvim_get_current_win = function()
378+
return 2
379+
end
380+
381+
-- Mock neotree window detection
382+
local original_list_wins = vim.api.nvim_tabpage_list_wins
383+
local original_win_get_buf = vim.api.nvim_win_get_buf
384+
local original_buf_get_name = vim.api.nvim_buf_get_name
385+
local original_win_close = vim.api.nvim_win_close
386+
387+
vim.api.nvim_tabpage_list_wins = function()
388+
return { 1, 2 }
389+
end
390+
vim.api.nvim_win_get_buf = function(winid)
391+
return winid
392+
end
393+
vim.api.nvim_buf_get_name = function(bufnr)
394+
if bufnr == 1 then
395+
return "neo-tree filesystem [1]"
396+
end
397+
return "/tmp/test.txt"
398+
end
399+
400+
local closed_wins = {}
401+
vim.api.nvim_win_close = function(winid, force)
402+
table.insert(closed_wins, { winid = winid, force = force })
403+
end
404+
405+
neotree.open_file_close_others(state)
406+
407+
-- Verify vsplit was called
408+
local found_vsplit = false
409+
for _, c in ipairs(cmds) do
410+
if c == "rightbelow vsplit" then
411+
found_vsplit = true
412+
break
413+
end
414+
end
415+
assert.is_true(found_vsplit)
416+
417+
-- Verify edit command was called with the file path
418+
local found_edit = false
419+
for _, c in ipairs(cmds) do
420+
if c:match("^edit.*/tmp/test.txt$") then
421+
found_edit = true
422+
break
423+
end
424+
end
425+
assert.is_true(found_edit)
426+
427+
-- Restore original functions
428+
vim.cmd = original_cmd
429+
vim.api.nvim_set_current_win = original_set_win
430+
vim.api.nvim_get_current_win = original_get_win
431+
vim.api.nvim_tabpage_list_wins = original_list_wins
432+
vim.api.nvim_win_get_buf = original_win_get_buf
433+
vim.api.nvim_buf_get_name = original_buf_get_name
434+
vim.api.nvim_win_close = original_win_close
435+
end)
436+
437+
it("no-ops when selected node is not a file", function()
438+
local dir = make_node("d1", "directory", "/tmp/dir")
439+
local state = make_state(dir)
440+
441+
local cmd_called = false
442+
local original_cmd = vim.cmd
443+
vim.cmd = function()
444+
cmd_called = true
445+
end
446+
447+
neotree.open_file_close_others(state)
448+
449+
assert.is_false(cmd_called)
450+
451+
vim.cmd = original_cmd
452+
end)
453+
454+
it("no-ops when node is nil", function()
455+
local state = make_state(nil)
456+
457+
local cmd_called = false
458+
local original_cmd = vim.cmd
459+
vim.cmd = function()
460+
cmd_called = true
461+
end
462+
463+
neotree.open_file_close_others(state)
464+
465+
assert.is_false(cmd_called)
466+
467+
vim.cmd = original_cmd
468+
end)
469+
end)
470+
340471
describe("show_git_changes_tree", function()
341472
it("invokes Neotree with merge base and updates gitsigns base", function()
342473
-- avoid tab/window creation in this test

0 commit comments

Comments
 (0)