Repository navigation
Question about auto sizing for vim.ui.select. #793
Description
Activity
Would it be possible to have an 'auto height' kind of feature so the height of the window is set to the maximum size of the content? Maybe this is already possible and I missed it?
You didn’t miss anything, it’s not possible ATM, not hard to implement, I’ll look into it.
Reacted by nyngwangReacted by Emre Dogan- added a commit that references this issue
on Jun 24, 2023 I struggled a bit to come up with the exact solution for this, not because it's hard but because there are many options:
- Should we take into consideration min/max height?
- As long as we're willing to take the performance penalty (enumerating all items), why not have adjustable width too?
- Line padding (do you wish to have the exact length or a few lines extra?)
- Other nuances...
I decided the best solution would be to add the ui select
itemsto the already existing options callback, this way each user can customize this to their liking, as for the request in the OP, below is what I came up with:Make sure to update to f9056ff or the below won't work
- min height of 0.15
- max height of 0.70
- 4 lines of padding (prompt/query line, borders and one extra empty line)
require("fzf-lua").register_ui_select(function(_, items) local min_h, max_h = 0.15, 0.70 local h = (#items + 4) / vim.o.lines if h < min_h then h = min_h elseif h > max_h then h = max_h end return { winopts = { height = h, width = 0.60, row = 0.40 } } end)
Modify the last return to add the other options you wish to register:
return { winopts = { height = h, width = 0.60, row = 0.40 }, fzf_opts = { ["--layout"] = "reverse-list", ["--info"] = "hidden", }, }
Test with different length items using:
-- `:=` is equal to `:lua` since neovim 0.9 := vim.ui.select({1,2}, {}, function() end) := vim.ui.select({1,2,3,4,5,6,7,8,9}, {}, function() end)
I also eat my own dogfood :-)
Reacted by Emre Dogan and pocreaganReacted by Emre DoganJust played around with it and it seems to work no problem! Thanks a lot!
It might also be worth putting your example up on the wiki.require("fzf-lua").register_ui_select(function(_, items) -- Auto-height local min_h, max_h = 0.15, 0.70 local h = (#items + 2) / vim.o.lines if h < min_h then h = min_h elseif h > max_h then h = max_h end -- Auto-width -- if (#items < 10000) then -- Maybe disable auto-width on large results? local min_w, max_w = 0.05, 0.70 local longest = 0 for i, v in ipairs(items) do local length = #v if length > longest then longest = length end end -- needs minimum 7 in my case due to the extra stuff fzf adds on the left side (markers, numbers, extra padding, etc). local w = (longest + 9) / vim.o.columns if w < min_w then w = min_w elseif w > max_w then w = max_w end -- end return { winopts = { height = h, width = w, row = 0.5, col = 0.5, }, fzf_opts = { ["--layout"] = "reverse-list", ["--info"] = "hidden", }, } end)
The only problem I see here is that the auto-width cannot adjust for the extra items taken up by the left side of the fzf window (markers/prompts, numbers, etc). Not a huge deal but it was something I noticed.
- Should we take into consideration min/max height?
- As long as we're willing to take the performance penalty (enumerating all items), why not have adjustable width too?
- Line padding (do you wish to have the exact length or a few lines extra?)
- Other nuances...
I decided the best solution would be to add the ui select
itemsto the already existing options callback, this way each user can customize this to their liking, as for the request in the OP, below is what I came up with:Yeah, I was wondering about those questions as well before. I think this is the best of both worlds, otherwise yeah so many edge cases to get this to work. This solution also follows similarly with the example in the wiki on dynamic resizing of the windows so things are more consistent.
Now that I think about it, this approach might also work for
winopts_fnalthough to be honest I see it being less useful there.Reacted by ibhagwanNow that I think about it, this approach might also work for winopts_fn although to be honest I see it being less useful there.
If you take a look at the Wiki’s advanced API you’d notice three types of content: table, function and string - this can work only for table contents when you know the number of items in advance, the other types generate async contents (for performance and UX).
Ah I see, that makes sense. Thanks.
Now included in the wiki, ty @EmreDogann
https://github.com/ibhagwan/fzf-lua/wiki#ui-select-auto-size
Reacted by Emre DoganRE: auto resize width
The one above from @EmreDogann didn't work for me. I spent some time investigating, and the issue was that
itemsparameter was not formatted here. I pre-formatted the string, and use the string length to resize it. It seems to be working:local min_w, max_w = 0.05, 0.70 local longest = 0 for i, e in ipairs(items) do -- this bit is from fzf-lua's source code for register ui select local format_entry = ui_opts.format_item and ui_opts.format_item(e) or tostring(e) -- local length = tostring(format_entry):len() if length > longest then longest = length end end local w = (longest + 9) / vim.o.columns if w < min_w then w = min_w elseif w > max_w then w = max_w end
The one above from @EmreDogann didn't work for me. I spent some time investigating, and the issue was that items parameter was not formatted here. I pre-formatted the string, and use the string length to resize it. It seems to be working:
@ShaolunWang, the snippet in the wiki only auto-adjusts the height, so you’re correct in the sense it wasn’t supposed to format the items and look at the width.
Reacted by Shaolun WangI'm failing when trying to use the snippet in the wiki to autosize the height of the
vim.ui.select window. This is what the window looks like by default before trying to resize it:After applying the wiki snippet, the window now becomes too small so that not all the three lines are visible in code actions and almost nothing of the diff is visible:
What I was expecting was something like this where both the section for the code actions and the section for the diff preview autosized based on the number of lines inside each:
I tested on both neovim 11.5 and 12 nightly with the same result. Any idea of what might be going awry here?
I tested on both neovim 11.5 and 12 nightly with the same result. Any idea of what might be going awry here?
The snippet only takes into account the amount of entires, for code preview you have to add a few more lines for the preview, increase height until it looks like what you want.
Thanks for the quick reply! The issue with just increasing the number of lines is that the extra vertical space seems to be divided evenly between between the two boxes in the pop up. So if I add extra lines to fit the output from the diff, it leads to several blank lines below the code actions, which pushes the diff preview further down on the screen:
The desired output would be something like this where each box is autosized to its content:
The issue with just increasing the number of lines is that the extra vertical space seems to be divided evenly between between the two boxes in the pop up. So if I add extra lines to fit the output from the diff, it leads to several blank lines below the code actions, which pushes the diff preview further down on the screen:
The issue here is that the dynamic sizing in ui.select wiki wasn’t meant for code actions with previews, the preview size is a percentage of the total window, if you want this to fit perfectly you’ll need to adjust the code for code actions differently (you can use the
ui_opts.kindto determine the type of interface) and reverse calculate the total size of window height needed for both the items+preview.
This is not a bug report or issue,
I wanted to know if it was possible to have the height of fzf-lua's
vim.ui.selectmenu fit the content.The way I do it now is as follows:
This is what it looks like using

cmake-tools.nvim:As can be seen above, there is a lot of space due to the
height = 0.3option.Would it be possible to have an 'auto height' kind of feature so the height of the window is set to the maximum size of the content? Maybe this is already possible and I missed it?