Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about auto sizing for vim.ui.select. #793

Closed
EmreDogann opened this issue Jun 23, 2023 · 9 comments
Closed

Question about auto sizing for vim.ui.select. #793

EmreDogann opened this issue Jun 23, 2023 · 9 comments
Labels
feature request New feature

Comments

@EmreDogann
Copy link

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.select menu fit the content.

The way I do it now is as follows:

require("fzf-lua").register_ui_select({
	winopts = {
		height = 0.3,
		width = 0.2,
		row = 0.5,
		col = 0.5,
	},
	fzf_opts = {
		["--layout"] = "reverse-list",
		["--info"] = "hidden",
	},
})

This is what it looks like using cmake-tools.nvim:
image
As can be seen above, there is a lot of space due to the height = 0.3 option.

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?

@ibhagwan ibhagwan added the feature request New feature label Jun 23, 2023
@ibhagwan
Copy link
Owner

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.

@ibhagwan
Copy link
Owner

ibhagwan commented 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 items to 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)

@ibhagwan
Copy link
Owner

I also eat my own dogfood :-)

https://github.com/ibhagwan/nvim-lua/blob/cffed8810e29664213611d634e4c83b6b0ea0896/lua/plugins/fzf-lua/init.lua#L15-L24

@EmreDogann
Copy link
Author

EmreDogann commented Jun 24, 2023

Just 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.

image

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 items to 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_fn although to be honest I see it being less useful there.

@ibhagwan
Copy link
Owner

Now 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).

@EmreDogann
Copy link
Author

Ah I see, that makes sense. Thanks.

@ibhagwan
Copy link
Owner

ibhagwan commented Jun 24, 2023

Now included in the wiki, ty @EmreDogann

https://github.com/ibhagwan/fzf-lua/wiki#ui-select-auto-size

@ShaolunWang
Copy link

RE: auto resize width

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:

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

@ibhagwan
Copy link
Owner

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature
Projects
None yet
Development

No branches or pull requests

3 participants