Skip to content

Commit 5da3489

Browse files
authored
fix(hijack): hijack more often, restore cursor if window changed (#1746)
1 parent 69f798b commit 5da3489

File tree

6 files changed

+68
-72
lines changed

6 files changed

+68
-72
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,5 @@ tags
4646
.testcache
4747
.dependencies
4848
luacov.*.out
49+
50+
tests/repro

lua/neo-tree.lua

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ end
1313
local new_user_config = nil
1414

1515
---Updates the config of neo-tree using the latest user config passed through setup, if any.
16+
---@return neotree.Config._Full
1617
M.ensure_config = function()
1718
if not M.config or new_user_config then
1819
M.config = require("neo-tree.setup").merge_config(new_user_config)
1920
new_user_config = nil
2021
end
22+
return M.config
2123
end
2224

2325
M.get_prior_window = function(ignore_filetypes, ignore_winfixbuf)
@@ -91,12 +93,7 @@ local function try_netrw_hijack(path)
9193
return false
9294
end
9395

94-
local netrw = require("neo-tree.setup.netrw")
95-
if netrw.get_hijack_behavior() ~= "disabled" then
96-
vim.cmd("silent! autocmd! FileExplorer *")
97-
return netrw.hijack(path)
98-
end
99-
return false
96+
return require("neo-tree.setup.netrw").hijack()
10097
end
10198

10299
---@param config neotree.Config

lua/neo-tree/setup/init.lua

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ M.buffer_enter_event = function()
195195
end
196196
last_buffer_enter_filetype = vim.bo.filetype
197197

198+
-- if vim is trying to open a dir, then we hijack it
199+
if netrw.hijack() then
200+
return
201+
end
202+
198203
-- For all others, make sure another buffer is not hijacking our window
199204
-- ..but not if the position is "current"
200205
local prior_buf = vim.fn.bufnr("#")
@@ -209,11 +214,6 @@ M.buffer_enter_event = function()
209214
return
210215
end
211216

212-
-- if vim is trying to open a dir, then we hijack it
213-
if netrw.hijack() then
214-
return
215-
end
216-
217217
if prior_type == "neo-tree" then
218218
local success, position = pcall(vim.api.nvim_buf_get_var, prior_buf, "neo_tree_position")
219219
if not success then
@@ -496,8 +496,10 @@ M.merge_config = function(user_config)
496496
events.clear_all_events()
497497
define_events()
498498

499-
-- Prevent accidentally opening another file in the neo-tree window.
499+
-- Prevent netrw hijacking lazy-loading from conflicting with normal hijacking.
500500
vim.g.neotree_watching_bufenter = 1
501+
502+
-- Prevent accidentally opening another file in the neo-tree window.
501503
events.subscribe({
502504
event = events.VIM_BUFFER_ENTER,
503505
handler = M.buffer_enter_event,
@@ -670,6 +672,21 @@ M.merge_config = function(user_config)
670672
)
671673
end
672674

675+
---@type neotree.Config.HijackNetrwBehavior[]
676+
local disable_netrw_values = { "open_default", "open_current" }
677+
local hijack_behavior = M.config.filesystem.hijack_netrw_behavior
678+
if vim.tbl_contains(disable_netrw_values, hijack_behavior) then
679+
-- Disable netrw autocmds
680+
vim.cmd("silent! autocmd! FileExplorer *")
681+
elseif hijack_behavior ~= "disabled" then
682+
require("neo-tree.log").error(
683+
"Invalid value for filesystem.hijack_netrw_behavior: '"
684+
.. hijack_behavior
685+
.. "', will default to 'disabled'"
686+
)
687+
M.config.filesystem.hijack_netrw_behavior = "disabled"
688+
end
689+
673690
if not M.config.enable_git_status then
674691
M.config.git_status_async = false
675692
end
@@ -678,14 +695,7 @@ M.merge_config = function(user_config)
678695
-- aren't, remove them
679696
local source_selector_sources = {}
680697
for _, ss_source in ipairs(M.config.source_selector.sources or {}) do
681-
local source_match = false
682-
for _, source in ipairs(M.config.sources) do
683-
if ss_source.source == source then
684-
source_match = true
685-
break
686-
end
687-
end
688-
if source_match then
698+
if vim.tbl_contains(M.config.sources, ss_source.source) then
689699
table.insert(source_selector_sources, ss_source)
690700
else
691701
log.debug(string.format("Unable to locate Neo-tree extension %s", ss_source.source))

lua/neo-tree/setup/netrw.lua

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8,88 +8,80 @@ local get_position = function(source_name)
88
return pos
99
end
1010

11+
---@return neotree.Config.HijackNetrwBehavior
1112
M.get_hijack_behavior = function()
1213
nt.ensure_config()
13-
local option = "filesystem.hijack_netrw_behavior"
14-
local hijack_behavior = utils.get_value(nt.config, option, "open_default", true)
15-
if hijack_behavior == "disabled" then
16-
return hijack_behavior
17-
elseif hijack_behavior == "open_default" then
18-
return hijack_behavior
19-
elseif hijack_behavior == "open_current" then
20-
return hijack_behavior
21-
else
22-
require("neo-tree.log").error("Invalid value for " .. option .. ": " .. hijack_behavior)
23-
return "disabled"
24-
end
14+
return nt.config.filesystem.hijack_netrw_behavior
2515
end
2616

27-
---@param path string? Path to hijack (sometimes bufname doesn't set in time)
2817
---@return boolean hijacked Whether the hijack was successful
29-
M.hijack = function(path)
18+
M.hijack = function()
3019
local hijack_behavior = M.get_hijack_behavior()
3120
if hijack_behavior == "disabled" then
3221
return false
3322
end
3423

3524
-- ensure this is a directory
36-
local bufname = vim.api.nvim_buf_get_name(0)
37-
if not utils.truthy(bufname) then
38-
bufname = path or ""
39-
end
40-
local stats = uv.fs_stat(bufname)
41-
if not stats then
42-
return false
43-
end
44-
if stats.type ~= "directory" then
25+
local dir_bufnr = vim.api.nvim_get_current_buf()
26+
local path_to_hijack = vim.api.nvim_buf_get_name(dir_bufnr)
27+
local stats = uv.fs_stat(path_to_hijack)
28+
if not stats or stats.type ~= "directory" then
4529
return false
4630
end
4731

4832
-- record where we are now
4933
local pos = get_position("filesystem")
5034
local should_open_current = hijack_behavior == "open_current" or pos == "current"
51-
local winid = vim.api.nvim_get_current_win()
52-
local dir_bufnr = vim.api.nvim_get_current_buf()
35+
local dir_window = vim.api.nvim_get_current_win()
5336

5437
-- Now actually open the tree, with a very quick debounce because this may be
5538
-- called multiple times in quick succession.
56-
utils.debounce("hijack_netrw_" .. winid, function()
39+
utils.debounce("hijack_netrw_" .. dir_window, function()
5740
local manager = require("neo-tree.sources.manager")
5841
local log = require("neo-tree.log")
5942
-- We will want to replace the "directory" buffer with either the "alternate"
6043
-- buffer or a new blank one.
61-
local replace_with_bufnr = vim.fn.bufnr("#")
44+
local replacement_buffer = vim.fn.bufnr("#")
6245
local is_currently_neo_tree = false
63-
if replace_with_bufnr > 0 then
64-
if vim.bo[replace_with_bufnr].filetype == "neo-tree" then
46+
if replacement_buffer > 0 then
47+
if vim.bo[replacement_buffer].filetype == "neo-tree" then
6548
-- don't hijack the current window if it's already a Neo-tree sidebar
66-
local _, position = pcall(vim.api.nvim_buf_get_var, replace_with_bufnr, "neo_tree_position")
67-
if position ~= "current" then
68-
is_currently_neo_tree = true
49+
local position = vim.b[replacement_buffer].neo_tree_position
50+
if position == "current" then
51+
replacement_buffer = -1
6952
else
70-
replace_with_bufnr = -1
53+
is_currently_neo_tree = true
7154
end
7255
end
7356
end
7457
if not should_open_current then
75-
if replace_with_bufnr == dir_bufnr or replace_with_bufnr < 1 then
76-
replace_with_bufnr = vim.api.nvim_create_buf(true, false)
77-
log.trace("Created new buffer for netrw hijack", replace_with_bufnr)
58+
if replacement_buffer == dir_bufnr or replacement_buffer < 1 then
59+
replacement_buffer = vim.api.nvim_create_buf(true, false)
60+
log.trace("Created new buffer for netrw hijack", replacement_buffer)
7861
end
7962
end
80-
if replace_with_bufnr > 0 then
81-
log.trace("Replacing buffer in netrw hijack", replace_with_bufnr)
82-
pcall(vim.api.nvim_win_set_buf, winid, replace_with_bufnr)
63+
if replacement_buffer > 0 then
64+
log.trace("Replacing buffer in netrw hijack", replacement_buffer)
65+
pcall(vim.api.nvim_win_set_buf, dir_window, replacement_buffer)
8366
end
84-
local remove_dir_buf = vim.schedule_wrap(function()
67+
68+
-- If a window takes focus (e.g. lazy.nvim installing plugins on startup) in the time between the method call and
69+
-- this debounced callback, we should focus that window over neo-tree.
70+
local current_window = vim.api.nvim_get_current_win()
71+
local should_restore_cursor = current_window ~= dir_window
72+
73+
local cleanup = vim.schedule_wrap(function()
8574
log.trace("Deleting buffer in netrw hijack", dir_bufnr)
8675
pcall(vim.api.nvim_buf_delete, dir_bufnr, { force = true })
76+
if should_restore_cursor then
77+
vim.api.nvim_set_current_win(current_window)
78+
end
8779
end)
8880

8981
local state
9082
if should_open_current and not is_currently_neo_tree then
9183
log.debug("hijack_netrw: opening current")
92-
state = manager.get_state("filesystem", nil, winid)
84+
state = manager.get_state("filesystem", nil, dir_window)
9385
state.current_position = "current"
9486
elseif is_currently_neo_tree then
9587
log.debug("hijack_netrw: opening in existing Neo-tree")
@@ -99,7 +91,8 @@ M.hijack = function(path)
9991
manager.close_all_except("filesystem")
10092
state = manager.get_state("filesystem")
10193
end
102-
require("neo-tree.sources.filesystem")._navigate_internal(state, bufname, nil, remove_dir_buf)
94+
95+
require("neo-tree.sources.filesystem")._navigate_internal(state, path_to_hijack, nil, cleanup)
10396
end, 10, utils.debounce_strategy.CALL_LAST_ONLY)
10497

10598
return true

lua/neo-tree/utils/init.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,7 @@ M.is_filtered_by_pattern = function(pattern_list, path, name)
573573
return false
574574
end
575575

576+
---@param win_id integer?
576577
M.is_floating = function(win_id)
577578
win_id = win_id or vim.api.nvim_get_current_win()
578579
local cfg = vim.api.nvim_win_get_config(win_id)

plugin/neo-tree.lua

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,15 @@ local function try_netrw_hijack(path)
2222
return false
2323
end
2424

25-
local netrw = require("neo-tree.setup.netrw")
26-
if netrw.get_hijack_behavior() ~= "disabled" then
27-
vim.cmd("silent! autocmd! FileExplorer *")
28-
return netrw.hijack(path)
29-
end
30-
return false
25+
return require("neo-tree.setup.netrw").hijack()
3126
end
3227

3328
local augroup = vim.api.nvim_create_augroup("NeoTree_NetrwDeferred", { clear = true })
3429

35-
vim.api.nvim_create_autocmd("BufEnter", {
30+
vim.api.nvim_create_autocmd({ "BufEnter" }, {
3631
group = augroup,
3732
callback = function(args)
38-
if vim.g.neotree_watching_bufenter == 1 or try_netrw_hijack(args.file) then
39-
vim.api.nvim_del_augroup_by_id(augroup)
40-
end
33+
return vim.g.neotree_watching_bufenter == 1 or try_netrw_hijack(args.file)
4134
end,
4235
})
4336

0 commit comments

Comments
 (0)