@@ -27,8 +27,9 @@ local opts = {
2727 bottom = {},
2828 left = { { filetype = " *" , min_width = 46 } },
2929}
30+ --- @type table<number , { left : number , right : number } >
3031local state = {
31- [vim .api .nvim_get_current_tabpage ()] = { left = nil , right = nil },
32+ [vim .api .nvim_get_current_tabpage ()] = { left = - 1 , right = - 1 },
3233}
3334
3435local function get_main_width ()
@@ -77,18 +78,19 @@ local function is_filetype(target, filetype)
7778 return false
7879end
7980
80- --- @param position " left " | " right"
81+ --- @param position " top " | " right" | " bottom " | " left "
8182--- @param filetype string
8283--- @return number
8384local function get_min_width (position , filetype )
8485 local wildcard_width = 0
8586 for _ , integration in ipairs (opts [position ]) do
8687 if type (integration ) == " table" then
87- if integration .min_width and integration .filetype ~= " *" and is_filetype (filetype , integration .filetype ) then
88- return integration .min_width
88+ local min_w = integration .min_width or 0
89+ if min_w > 0 and integration .filetype ~= " *" and is_filetype (filetype , integration .filetype ) then
90+ return min_w
8991 end
90- if integration .filetype == " *" and integration . min_width then
91- wildcard_width = integration . min_width
92+ if integration .filetype == " *" and min_w > 0 then
93+ wildcard_width = min_w
9294 end
9395 end
9496 end
@@ -130,6 +132,18 @@ local function filetypes_visible(filetypes)
130132 return false
131133end
132134
135+ --- @param list string[]
136+ --- @param filetype Filetype
137+ local function append_filetype (list , filetype )
138+ if type (filetype ) == " table" then
139+ for _ , ft in ipairs (filetype ) do
140+ table.insert (list , ft )
141+ end
142+ else
143+ table.insert (list , filetype )
144+ end
145+ end
146+
133147--- @param filetypes string[]
134148--- @param type_to_remove string
135149local function remove_file_type (filetypes , type_to_remove )
@@ -150,8 +164,7 @@ local function is_buff_integration(buf)
150164 end
151165 for _ , position in ipairs ({ " left" , " right" , " top" , " bottom" }) do
152166 for _ , integration in ipairs (opts [position ] or {}) do
153- --- @diagnostic disable-next-line : undefined-field
154- if type (integration ) == " table" and is_filetype (filetype , integration .filetype ) then
167+ if type (integration ) == " table" and is_filetype (filetype , integration .filetype ) then
155168 return true
156169 end
157170 end
@@ -195,14 +208,6 @@ local function get_vsplits()
195208 return vsplits
196209end
197210
198- --- @return boolean
199- local function is_hsplit (buf )
200- local win_id = vim .fn .bufwinid (buf )
201- local width = vim .api .nvim_win_get_width (win_id )
202- local height = vim .api .nvim_win_get_height (win_id )
203- return width > height
204- end
205-
206211--- @param position " top" | " right" | " bottom" | " left"
207212--- @return boolean
208213local function is_integration_open (position )
@@ -232,11 +237,55 @@ local function get_window_by_filetype(filetype)
232237 return nil
233238end
234239
235- local function adjust_top_bottom_window_hack (target_window , position )
236- if target_window then
237- vim .api .nvim_win_call (target_window , function ()
238- vim .cmd (" wincmd " .. position )
239- end )
240+ local _saved_position_heights = {}
241+ local _in_handler = false
242+
243+ local function save_top_bottom_heights ()
244+ for _ , position in ipairs ({ " top" , " bottom" }) do
245+ for _ , integration in pairs (opts [position ]) do
246+ if type (integration ) == " table" then
247+ local win = get_window_by_filetype (integration .filetype )
248+ if win then
249+ local w = vim .api .nvim_win_get_width (win )
250+ -- only save when integration spans full width (properly positioned)
251+ if w == vim .o .columns then
252+ _saved_position_heights [position ] = vim .api .nvim_win_get_height (win )
253+ end
254+ break
255+ end
256+ end
257+ end
258+ end
259+ end
260+
261+ local function reposition_top_bottom_integrations ()
262+ for _ , integration in pairs (opts .top ) do
263+ local win = get_window_by_filetype (integration .filetype )
264+ if win then
265+ local needs_reposition = vim .api .nvim_win_get_width (win ) ~= vim .o .columns
266+ if needs_reposition then
267+ local height_before = vim .api .nvim_win_get_height (win )
268+ vim .api .nvim_win_set_config (win , { split = " above" , win = - 1 })
269+ vim .api .nvim_win_set_height (win , _saved_position_heights .top or height_before )
270+ elseif _saved_position_heights .top then
271+ vim .api .nvim_win_set_height (win , _saved_position_heights .top )
272+ end
273+ _saved_position_heights .top = vim .api .nvim_win_get_height (win )
274+ end
275+ end
276+ for _ , integration in pairs (opts .bottom ) do
277+ local win = get_window_by_filetype (integration .filetype )
278+ if win then
279+ local needs_reposition = vim .api .nvim_win_get_width (win ) ~= vim .o .columns
280+ if needs_reposition then
281+ local height_before = vim .api .nvim_win_get_height (win )
282+ vim .api .nvim_win_set_config (win , { split = " below" , win = - 1 })
283+ vim .api .nvim_win_set_height (win , _saved_position_heights .bottom or height_before )
284+ elseif _saved_position_heights .bottom then
285+ vim .api .nvim_win_set_height (win , _saved_position_heights .bottom )
286+ end
287+ _saved_position_heights .bottom = vim .api .nvim_win_get_height (win )
288+ end
240289 end
241290end
242291
@@ -271,28 +320,6 @@ local function setup(options)
271320 --- @type ConfigOptions
272321 opts = vim .tbl_extend (" force" , opts , options or {})
273322
274- vim .api .nvim_create_autocmd (" CursorMoved" , {
275- -- TODO: use pattern for better perf
276- callback = function (args )
277- if is_buff_integration (args .buf ) then
278- local buf_info = vim .fn .getbufinfo (args .buf )
279-
280- local filetype = vim .api .nvim_get_option_value (" filetype" , { buf = args .buf })
281- for _ , position in ipairs ({ " right" , " left" }) do
282- for _ , integration in pairs (opts [position ]) do
283- --- @diagnostic disable-next-line : undefined-field
284- if type (integration ) == " table" and is_filetype (filetype , integration .filetype ) then
285- local new_width = math.max (get_min_width (position , filetype ), math.floor ((vim .o .columns - get_main_width ()) / 2 ))
286- vim .api .nvim_win_set_width (buf_info [1 ].windows [1 ], new_width )
287- return
288- end
289- end
290- end
291- end
292- end ,
293- desc = " HACK: adjust the integration when opening" ,
294- })
295-
296323 vim .api .nvim_create_autocmd ({ " VimEnter" , " TabNew" }, {
297324 callback = function ()
298325 -- disable when window is too small
@@ -317,9 +344,10 @@ local function setup(options)
317344 callback = function ()
318345 if vim .bo .filetype == " zen-left" then
319346 vim .cmd (" wincmd l" )
320- end
321- if vim .bo .filetype == " zen-right" then
347+ elseif vim .bo .filetype == " zen-right" then
322348 vim .cmd (" wincmd h" )
349+ else
350+ save_top_bottom_heights ()
323351 end
324352 end ,
325353 desc = " Prevent the cursor from moving to the side buffers." ,
@@ -419,25 +447,37 @@ local function setup(options)
419447 return
420448 end
421449
422- local left_file_types = { " fugitiveblame" , " fyler" , " undotree" , " dbui" , " zen-left" }
450+ -- save top/bottom integration heights before recreating zen buffers
451+ if not _in_handler then
452+ save_top_bottom_heights ()
453+ end
454+
455+ local left_file_types = { " zen-left" }
456+ for _ , integration in ipairs (opts .left ) do
457+ if type (integration ) == " table" and integration .filetype ~= " *" then
458+ append_filetype (left_file_types , integration .filetype )
459+ end
460+ end
423461 remove_file_type (left_file_types , file_type )
424462 if not filetypes_visible (left_file_types ) then
425463 state [vim .api .nvim_get_current_tabpage ()].left = create_window (" left" )
426464 vim .cmd (" wincmd l" )
427465 end
428466
429- local right_file_types = { " dapui_scopes" , " neotest-summary" , " zen-right" }
467+ local right_file_types = { " zen-right" }
468+ for _ , integration in ipairs (opts .right ) do
469+ if type (integration ) == " table" and integration .filetype ~= " *" then
470+ append_filetype (right_file_types , integration .filetype )
471+ end
472+ end
430473 remove_file_type (right_file_types , file_type )
431474 if not filetypes_visible (right_file_types ) then
432475 state [vim .api .nvim_get_current_tabpage ()].right = create_window (" right" )
433476 vim .cmd (" wincmd h" )
434477 end
435478
436- for _ , integration in pairs (opts .top ) do
437- adjust_top_bottom_window_hack (get_window_by_filetype (integration .filetype ), " K" )
438- end
439- for _ , integration in pairs (opts .bottom ) do
440- adjust_top_bottom_window_hack (get_window_by_filetype (integration .filetype ), " J" )
479+ if not _in_handler then
480+ reposition_top_bottom_integrations ()
441481 end
442482 resize_side_buffers ()
443483 end ,
@@ -464,11 +504,15 @@ local function setup(options)
464504 return
465505 end
466506
467- for _ , position in ipairs ({ " top" , " right" , " bottom" , " left" }) do
507+ _in_handler = true
508+
509+ --- @type (" top" | " right" | " bottom" | " left" )[]
510+ local positions = { " top" , " right" , " bottom" , " left" }
511+ for _ , position in ipairs (positions ) do
468512 for _ , integration in pairs (opts [position ]) do
469513 if type (integration ) == " table" and is_filetype (filetype , integration .filetype ) then
470514 close_side_buffer (position )
471- for _ , position_inner in ipairs ({ " top " , " right " , " bottom " , " left " } ) do
515+ for _ , position_inner in ipairs (positions ) do
472516 for _ , integration_inner in pairs (opts [position_inner ]) do
473517 if
474518 position_inner == position
@@ -481,32 +525,19 @@ local function setup(options)
481525 end
482526
483527 if position == " left" or position == " right" then
484- local min_width = get_min_width (position , filetype )
485- if min_width > 0 then
486- local win = vim .fn .bufwinid (args .buf )
487- if win ~= - 1 then
488- local current_width = vim .api .nvim_win_get_width (win )
489- if current_width < min_width then
490- vim .api .nvim_win_set_width (win , min_width )
491- end
492- end
528+ local new_width = math.max (get_min_width (position , filetype ), math.floor ((vim .o .columns - get_main_width ()) / 2 ))
529+ local win = vim .fn .bufwinid (args .buf )
530+ if win ~= - 1 then
531+ vim .api .nvim_win_set_width (win , new_width )
493532 end
494533 end
495534 end
496535 end
497536 end
498537
499- for _ , integration in pairs (opts .top ) do
500- if not is_hsplit (args .buf ) then
501- adjust_top_bottom_window_hack (get_window_by_filetype (integration .filetype ), " K" )
502- end
503- end
504- for _ , integration in pairs (opts .bottom ) do
505- if not is_hsplit (args .buf ) then
506- adjust_top_bottom_window_hack (get_window_by_filetype (integration .filetype ), " J" )
507- end
508- end
538+ reposition_top_bottom_integrations ()
509539 resize_side_buffers ()
540+ _in_handler = false
510541 end ,
511542 desc = " Close side buffer plugins if another plugin is already occupying that side." ,
512543 })
0 commit comments