Skip to content

Commit aa27c5c

Browse files
authored
fix(renderer): save cursor & window pos on CursorMoved (#1838)
1 parent fc42dce commit aa27c5c

File tree

2 files changed

+41
-27
lines changed

2 files changed

+41
-27
lines changed

lua/neo-tree/sources/manager.lua

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,26 @@ end
4747
---@field win_width integer
4848
---@field last_user_width integer
4949

50-
---@alias neotree.State.Position "top"|"bottom"|"left"|"right"|"current"|"float"
50+
---@alias neotree.State.CurrentPosition "top"|"bottom"|"left"|"right"|"current"|"float"
5151

5252
---@alias neotree.Internal.SortFieldProvider fun(node: NuiTree.Node):any
5353

54+
---@class neotree.State.Position
55+
---@field topline integer?
56+
---@field lnum integer?
57+
---@field node_id string?
58+
5459
---@class neotree.State : neotree.Config.Source
5560
---@field name string
5661
---@field tabid integer
5762
---@field id integer
5863
---@field bufnr integer?
5964
---@field dirty boolean
60-
---@field position table
65+
---@field position neotree.State.Position
6166
---@field git_base string
6267
---@field sort table
6368
---@field clipboard table
64-
---@field current_position neotree.State.Position?
69+
---@field current_position neotree.State.CurrentPosition?
6570
---@field disposed boolean?
6671
---@field winid integer?
6772
---@field path string?
@@ -70,6 +75,7 @@ end
7075
---private-ish
7176
---@field orig_tree NuiTree?
7277
---@field _ready boolean?
78+
---@field _in_pre_render boolean?
7379
---@field loading boolean?
7480
---window
7581
---@field window neotree.State.Window?
@@ -610,6 +616,8 @@ M.redraw = function(source_name)
610616
end
611617

612618
---Refreshes the tree by scanning the filesystem again.
619+
---@param source_name string
620+
---@param callback function?
613621
M.refresh = function(source_name, callback)
614622
if type(callback) ~= "function" then
615623
callback = nil

lua/neo-tree/ui/renderer.lua

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ M.close = function(state, focus_prior_window)
128128
window_existed = true
129129
if state.current_position == "current" then
130130
-- we are going to hide the buffer instead of closing the window
131-
M.position.save(state)
132131
local new_buf = vim.fn.bufnr("#")
133132
if new_buf < 1 then
134133
new_buf = vim.api.nvim_create_buf(true, false)
@@ -148,7 +147,7 @@ M.close = function(state, focus_prior_window)
148147
-- focus the prior used window if we are closing the currently focused window
149148
local current_winid = vim.api.nvim_get_current_win()
150149
if current_winid == state.winid then
151-
local pwin = require("neo-tree").get_prior_window()
150+
local pwin = nt.get_prior_window()
152151
if type(pwin) == "number" and pwin > 0 then
153152
pcall(vim.api.nvim_set_current_win, pwin)
154153
end
@@ -488,8 +487,7 @@ end
488487
---Sets the cursor at the specified node.
489488
---@param state neotree.State The current state of the source.
490489
---@param id string? The id of the node to set the cursor at.
491-
---@return boolean boolean True if the node was found and focused, false
492-
---otherwise.
490+
---@return boolean boolean True if the node was found and focused, false otherwise.
493491
M.focus_node = function(state, id, do_not_focus_window, relative_movement, bottom_scroll_padding)
494492
if not id and not relative_movement then
495493
log.debug("focus_node called with no id and no relative movement")
@@ -546,29 +544,28 @@ M.focus_node = function(state, id, do_not_focus_window, relative_movement, botto
546544
-- forget about cursor position as it is overwritten
547545
M.position.clear(state)
548546
-- now ensure that the window is scrolled correctly
549-
local execute_win_command = function(cmd)
550-
if vim.api.nvim_get_current_win() == state.winid then
551-
vim.cmd(cmd)
552-
else
553-
vim.cmd("call win_execute(" .. state.winid .. [[, "]] .. cmd .. [[")]])
554-
end
555-
end
556-
557547
-- make sure we are not scrolled down if it can all fit on the screen
558548
local lines = vim.api.nvim_buf_line_count(state.bufnr)
559549
local win_height = vim.api.nvim_win_get_height(state.winid)
560550
local virtual_bottom_line = vim.fn.line("w0", state.winid)
561551
+ win_height
562552
- bottom_scroll_padding
563553
if virtual_bottom_line <= linenr then
564-
execute_win_command("normal! " .. (linenr + bottom_scroll_padding) .. "zb")
554+
vim.api.nvim_win_call(state.winid, function()
555+
vim.cmd("normal! " .. (linenr + bottom_scroll_padding) .. "zb")
556+
end)
565557
pcall(vim.api.nvim_win_set_cursor, state.winid, { linenr, col })
566558
elseif virtual_bottom_line > lines then
567-
execute_win_command("normal! " .. (lines + bottom_scroll_padding) .. "zb")
559+
vim.api.nvim_win_call(state.winid, function()
560+
vim.cmd("normal! " .. (lines + bottom_scroll_padding) .. "zb")
561+
end)
568562
pcall(vim.api.nvim_win_set_cursor, state.winid, { linenr, col })
569563
elseif linenr < (win_height / 2) then
570-
execute_win_command("normal! zz")
564+
vim.api.nvim_win_call(state.winid, function()
565+
vim.cmd("normal! zz")
566+
end)
571567
end
568+
M.position.save(state)
572569
else
573570
log.debug("Failed to set cursor: " .. err)
574571
end
@@ -660,6 +657,8 @@ end
660657

661658
---Functions to save and restore the focused node.
662659
M.position = {}
660+
661+
---Saves a window position to be restored later
663662
---@param state neotree.State
664663
M.position.save = function(state)
665664
if state.position.topline and state.position.lnum then
@@ -674,7 +673,10 @@ M.position.save = function(state)
674673
log.debug("Saved window position with topline: " .. state.position.topline)
675674
end
676675
end
676+
677+
---Queues a node to focus
677678
---@param state neotree.State
679+
---@param node_id string?
678680
M.position.set = function(state, node_id)
679681
if type(node_id) ~= "string" or node_id == "" then
680682
return
@@ -687,6 +689,7 @@ M.position.set = function(state, node_id)
687689
end
688690
state.position.node_id = node_id
689691
end
692+
690693
---@param state neotree.State
691694
M.position.clear = function(state)
692695
log.debug("Forget about cursor position.")
@@ -697,6 +700,7 @@ M.position.clear = function(state)
697700
-- focus on it anymore
698701
state.position.node_id = nil
699702
end
703+
700704
---@param state neotree.State
701705
M.position.restore = function(state)
702706
if state.position.topline and state.position.lnum then
@@ -707,13 +711,14 @@ M.position.restore = function(state)
707711
end)
708712
end
709713
if state.position.node_id then
714+
print(state.position.node_id)
710715
log.debug("Focusing on node_id: " .. state.position.node_id)
711716
M.focus_node(state, state.position.node_id, true)
712717
end
713718
M.position.clear(state)
714719
end
715720

716-
---Redraw the tree without relaoding from the source.
721+
---Redraw the tree without reloading from the source.
717722
---@param state neotree.State State of the tree.
718723
M.redraw = function(state)
719724
if state.tree and M.tree_is_visible(state) then
@@ -730,7 +735,7 @@ M.redraw = function(state)
730735
end
731736
end
732737
---Visit all nodes ina tree recursively and reduce to a single value.
733-
---@param tree table NuiTree
738+
---@param tree NuiTree
734739
---@param memo any Value that is passed to the accumulator function
735740
---@param func function Accumulator function that is called for each node
736741
---@return any any The final memo value.
@@ -1097,6 +1102,10 @@ M.acquire_window = function(state)
10971102
vim.api.nvim_buf_set_name(state.bufnr, bufname)
10981103
vim.api.nvim_set_current_win(state.winid)
10991104
-- Used to track the position of the cursor within the tree as it gains and loses focus
1105+
win:on({ "CursorMoved" }, function()
1106+
M.position.clear(state)
1107+
M.position.save(state)
1108+
end)
11001109
win:on({ "BufDelete" }, function()
11011110
M.position.save(state)
11021111
end)
@@ -1185,15 +1194,12 @@ M.tree_is_visible = function(state)
11851194
end
11861195

11871196
---Renders the given tree and expands window width if needed
1188-
--@param state neotree.State The state containing tree to render. Almost same as state.tree:render()
1197+
---@param state neotree.State The state containing tree to render. Almost same as state.tree:render()
11891198
render_tree = function(state)
1190-
local add_blank_line_at_top = require("neo-tree").config.add_blank_line_at_top
1199+
local add_blank_line_at_top = nt.config.add_blank_line_at_top
11911200
local should_auto_expand = state.window.auto_expand_width and state.current_position ~= "float"
11921201
local should_pre_render = should_auto_expand or state.current_position == "current"
11931202

1194-
log.debug("render_tree: Saving position")
1195-
M.position.save(state)
1196-
11971203
if should_pre_render and M.tree_is_visible(state) then
11981204
log.trace("pre-rendering tree")
11991205
state._in_pre_render = true
@@ -1329,7 +1335,7 @@ M.show_nodes = function(sourceItems, state, parentId, callback)
13291335
state.longest_node = 0
13301336
end
13311337

1332-
local config = require("neo-tree").config
1338+
local config = nt.config
13331339
if config.hide_root_node then
13341340
if not parentId then
13351341
sourceItems[1].skip_node = true
@@ -1344,7 +1350,7 @@ M.show_nodes = function(sourceItems, state, parentId, callback)
13441350

13451351
if state.group_empty_dirs then
13461352
if parent then
1347-
local scan_mode = require("neo-tree").config.filesystem.scan_mode
1353+
local scan_mode = nt.config.filesystem.scan_mode
13481354
if scan_mode == "deep" then
13491355
for i, item in ipairs(sourceItems) do
13501356
sourceItems[i] = group_empty_dirs(item)

0 commit comments

Comments
 (0)