@@ -10,6 +10,7 @@ local events = require("neo-tree.events")
1010local keymap = require (" nui.utils.keymap" )
1111local autocmd = require (" nui.utils.autocmd" )
1212local log = require (" neo-tree.log" )
13+ local windows = require (" neo-tree.ui.windows" )
1314
1415local M = { resize_timer_interval = 50 }
1516local ESC_KEY = vim .api .nvim_replace_termcodes (" <ESC>" , true , false , true )
@@ -107,7 +108,13 @@ local start_resize_monitor = function()
107108 vim .defer_fn (check_window_size , interval )
108109end
109110
110- M .close = function (state )
111+ --- Safely closes the window and deletes the buffer associated with the state
112+ --- @param state table State of the source to close
113+ --- @param focus_prior_window boolean | nil if true or nil , focus the window that was previously focused
114+ M .close = function (state , focus_prior_window )
115+ if focus_prior_window == nil then
116+ focus_prior_window = true
117+ end
111118 local window_existed = false
112119 if state and state .winid then
113120 if M .window_exists (state ) then
@@ -125,16 +132,16 @@ M.close = function(state)
125132 end
126133 vim .api .nvim_win_set_buf (state .winid , new_buf )
127134 else
135+ events .fire_event (events .NEO_TREE_WINDOW_BEFORE_CLOSE , args )
128136 local win_list = vim .api .nvim_tabpage_list_wins (0 )
129- if # win_list > 1 then
137+ if focus_prior_window and # win_list > 1 then
130138 local args = {
131139 position = state .current_position ,
132140 source = state .name ,
133141 winid = state .winid ,
134142 tabnr = tabid_to_tabnr (state .tabid ), -- for compatibility
135143 tabid = state .tabid ,
136144 }
137- events .fire_event (events .NEO_TREE_WINDOW_BEFORE_CLOSE , args )
138145 -- focus the prior used window if we are closing the currently focused window
139146 local current_winid = vim .api .nvim_get_current_win ()
140147 if current_winid == state .winid then
@@ -143,21 +150,24 @@ M.close = function(state)
143150 pcall (vim .api .nvim_set_current_win , pwin )
144151 end
145152 end
146- -- if the window was a float, changing the current win would have closed it already
147- pcall (vim .api .nvim_win_close , state .winid , true )
148- events .fire_event (events .NEO_TREE_WINDOW_AFTER_CLOSE , args )
149153 end
154+ -- if the window was a float, changing the current win would have closed it already
155+ pcall (vim .api .nvim_win_close , state .winid , true )
156+ events .fire_event (events .NEO_TREE_WINDOW_AFTER_CLOSE , args )
150157 end
151158 end
152159 end
153160 state .winid = nil
154161 end
155162 local bufnr = utils .get_value (state , " bufnr" , 0 , true )
156- if bufnr > 0 then
157- if vim .api .nvim_buf_is_valid (bufnr ) then
158- vim .api .nvim_buf_delete (bufnr , { force = true })
159- end
163+ if bufnr > 0 and vim .api .nvim_buf_is_valid (bufnr ) then
160164 state .bufnr = nil
165+ local success , err = pcall (vim .api .nvim_buf_delete , bufnr , { force = true })
166+ if not success and err :match (" E523" ) then
167+ vim .schedule_wrap (function ()
168+ vim .api .nvim_buf_delete (bufnr , { force = true })
169+ end )()
170+ end
161171 end
162172 return window_existed
163173end
@@ -744,6 +754,7 @@ create_tree = function(state)
744754 if state .tree and state .tree .bufnr == state .bufnr then
745755 if buffer_is_usable (state .tree .bufnr ) then
746756 log .debug (" Tree already exists and buffer is valid, skipping creation" , state .name , state .id )
757+ state .tree .winid = state .winid
747758 return
748759 end
749760 end
@@ -780,7 +791,7 @@ local get_selected_nodes = function(state)
780791 return selected_nodes
781792end
782793
783- local set_window_mappings = function (state )
794+ local set_buffer_mappings = function (state )
784795 local resolved_mappings = {}
785796 local skip_this_mapping = {
786797 [" none" ] = true ,
@@ -883,16 +894,29 @@ local function create_floating_window(state, win_options, bufname)
883894 return win
884895end
885896
886- local get_existing_buffer = function (bufname )
897+ local get_buffer = function (bufname , state )
887898 local bufnr = vim .fn .bufnr (bufname )
888899 if bufnr > 0 then
889- if buffer_is_usable (bufnr ) then
900+ if vim . api . nvim_buf_is_valid ( bufnr ) and vim . api . nvim_buf_is_loaded (bufnr ) then
890901 return bufnr
891902 else
892903 pcall (vim .api .nvim_buf_delete , bufnr , { force = true })
904+ bufnr = 0
893905 end
894906 end
895- return 0
907+ if bufnr < 1 then
908+ bufnr = vim .api .nvim_create_buf (false , false )
909+ vim .api .nvim_buf_set_name (bufnr , bufname )
910+ vim .api .nvim_buf_set_option (bufnr , " buftype" , " nofile" )
911+ vim .api .nvim_buf_set_option (bufnr , " swapfile" , false )
912+ vim .api .nvim_buf_set_option (bufnr , " filetype" , " neo-tree" )
913+ vim .api .nvim_buf_set_option (bufnr , " modifiable" , false )
914+ vim .api .nvim_buf_set_option (bufnr , " undolevels" , - 1 )
915+ autocmd .buf .define (bufnr , " WinLeave" , function ()
916+ M .position .save (state )
917+ end )
918+ end
919+ return bufnr
896920end
897921
898922create_window = function (state )
@@ -944,29 +968,34 @@ create_window = function(state)
944968 log .warn (" Window " , winid , " is no longer valid!" )
945969 return
946970 end
947- local bufnr = get_existing_buffer (bufname )
948- if bufnr < 1 then
949- bufnr = vim .api .nvim_create_buf (false , false )
950- vim .api .nvim_buf_set_name (bufnr , bufname )
951- vim .api .nvim_buf_set_option (bufnr , " buftype" , " nofile" )
952- vim .api .nvim_buf_set_option (bufnr , " swapfile" , false )
953- vim .api .nvim_buf_set_option (bufnr , " filetype" , " neo-tree" )
954- vim .api .nvim_buf_set_option (bufnr , " modifiable" , false )
955- vim .api .nvim_buf_set_option (bufnr , " undolevels" , - 1 )
956- end
957971 state .winid = winid
958- state .bufnr = bufnr
959- vim .api .nvim_win_set_buf (winid , bufnr )
972+ state .bufnr = get_buffer ( bufname , state )
973+ vim .api .nvim_win_set_buf (state . winid , state . bufnr )
960974 else
961- win = NuiSplit (win_options )
962- local bufnr = get_existing_buffer (bufname )
963- if bufnr > 0 then
964- win .bufnr = bufnr
975+ local close_old_window = function (new_winid )
976+ if state .winid and new_winid ~= state .winid then
977+ -- This state may be showing in another window, close it first because
978+ -- each state can only be shown in one window at a time.
979+ M .close (state , false )
980+ end
965981 end
966- win :mount ()
967- state .winid = win .winid
968- state .bufnr = win .bufnr
969- vim .api .nvim_buf_set_name (state .bufnr , bufname )
982+ local location = windows .get_location (state .current_position )
983+ if location .winid > 0 then
984+ close_old_window (location .winid )
985+ state .bufnr = get_buffer (bufname , state )
986+ state .winid = location .winid
987+ vim .api .nvim_win_set_buf (state .winid , state .bufnr )
988+ else
989+ close_old_window ()
990+ win = NuiSplit (win_options )
991+ win :mount ()
992+ state .bufnr = win .bufnr
993+ state .winid = win .winid
994+ location .winid = state .winid
995+ vim .api .nvim_buf_set_name (state .bufnr , bufname )
996+ vim .api .nvim_set_current_win (state .winid )
997+ end
998+ location .source = state .name
970999 end
9711000 event_args .winid = state .winid
9721001 events .fire_event (events .NEO_TREE_WINDOW_AFTER_OPEN , event_args )
@@ -979,11 +1008,7 @@ create_window = function(state)
9791008 vim .api .nvim_buf_set_var (state .bufnr , " neo_tree_winid" , state .winid )
9801009 end
9811010
982- if win == nil then
983- autocmd .buf .define (state .bufnr , " WinLeave" , function ()
984- M .position .save (state )
985- end )
986- else
1011+ if win ~= nil then
9871012 -- Used to track the position of the cursor within the tree as it gains and loses focus
9881013 --
9891014 -- Note `WinEnter` is often too early to restore the cursor position so we do not set
@@ -999,7 +1024,7 @@ create_window = function(state)
9991024 end , { once = true })
10001025 end
10011026
1002- set_window_mappings (state )
1027+ set_buffer_mappings (state )
10031028 return win
10041029end
10051030
@@ -1048,16 +1073,14 @@ M.window_exists = function(state)
10481073 else
10491074 local isvalid = M .is_window_valid (winid )
10501075 window_exists = isvalid and (vim .api .nvim_win_get_number (winid ) > 0 )
1051- if not window_exists then
1052- state .winid = nil
1053- if bufnr > 0 and vim .api .nvim_buf_is_valid (bufnr ) then
1054- state .bufnr = nil
1055- local success , err = pcall (vim .api .nvim_buf_delete , bufnr , { force = true })
1056- if not success and err :match (" E523" ) then
1057- vim .schedule_wrap (function ()
1058- vim .api .nvim_buf_delete (bufnr , { force = true })
1059- end )()
1060- end
1076+ if window_exists then
1077+ local bufnr = vim .api .nvim_win_get_buf (winid )
1078+ if bufnr > 0 and bufnr ~= state .bufnr then
1079+ window_exists = false
1080+ end
1081+ local buf_position = vim .api .nvim_buf_get_var (bufnr , " neo_tree_position" )
1082+ if buf_position ~= position then
1083+ window_exists = false
10611084 end
10621085 end
10631086 end
0 commit comments