mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	fix(api): win_set_config autocmds crash when moving win to other tabpage
Problem: win_enter autocommands can close new_curwin, crashing if it was the last window in its tabpage after removing win, or can close parent, crashing when attempting to split it later. Solution: remove win first, check that parent is valid after win_enter. NOTE: This isn't actually quite right, as this means win is not in the window list or even has a frame when triggering enter autocommands (so it's not considered valid in the tabpage). This is addressed in later commits.
This commit is contained in:
		| @@ -478,12 +478,17 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) | |||||||
|         int dir; |         int dir; | ||||||
|         new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp); |         new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp); | ||||||
|       } |       } | ||||||
|  |       win_remove(win, win_tp == curtab ? NULL : win_tp); | ||||||
|       // move to neighboring window if we're moving the current window to a new tabpage |       // move to neighboring window if we're moving the current window to a new tabpage | ||||||
|       if (curwin == win && parent != NULL && new_curwin != NULL |       if (curwin == win && parent != NULL && new_curwin != NULL | ||||||
|           && win_tp != win_find_tabpage(parent)) { |           && win_tp != win_find_tabpage(parent)) { | ||||||
|         win_enter(new_curwin, true); |         win_enter(new_curwin, true); | ||||||
|  |         if (!win_valid_any_tab(parent)) { | ||||||
|  |           // win_enter autocommands closed the `parent` to split from. | ||||||
|  |           api_set_error(err, kErrorTypeException, "Window to split was closed"); | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|       win_remove(win, win_tp == curtab ? NULL : win_tp); |  | ||||||
|     } else { |     } else { | ||||||
|       win_remove(win, win_tp == curtab ? NULL : win_tp); |       win_remove(win, win_tp == curtab ? NULL : win_tp); | ||||||
|       ui_comp_remove_grid(&win->w_grid_alloc); |       ui_comp_remove_grid(&win->w_grid_alloc); | ||||||
|   | |||||||
| @@ -1663,6 +1663,27 @@ describe('API/win', function() | |||||||
|         }, |         }, | ||||||
|       }, fn.winlayout()) |       }, fn.winlayout()) | ||||||
|     end) |     end) | ||||||
|  |  | ||||||
|  |     it('closing new curwin when moving window to other tabpage works', function() | ||||||
|  |       command('split | tabnew') | ||||||
|  |       local w = api.nvim_get_current_win() | ||||||
|  |       local t = api.nvim_get_current_tabpage() | ||||||
|  |       command('tabfirst | autocmd WinEnter * ++once quit') | ||||||
|  |       api.nvim_win_set_config(0, { win = w, split = 'left' }) | ||||||
|  |       -- New tabpage is now the only one, as WinEnter closed the new curwin in the original. | ||||||
|  |       eq(t, api.nvim_get_current_tabpage()) | ||||||
|  |       eq({ t }, api.nvim_list_tabpages()) | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('closing split parent when moving window to other tabpage aborts', function() | ||||||
|  |       command('split | tabnew') | ||||||
|  |       local w = api.nvim_get_current_win() | ||||||
|  |       command('tabfirst | autocmd WinEnter * call nvim_win_close(' .. w .. ', 1)') | ||||||
|  |       eq( | ||||||
|  |         'Window to split was closed', | ||||||
|  |         pcall_err(api.nvim_win_set_config, 0, { win = w, split = 'left' }) | ||||||
|  |       ) | ||||||
|  |     end) | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   describe('get_config', function() |   describe('get_config', function() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Sean Dewar
					Sean Dewar