PR: fix opts.title behaviors of _make_floating_pop_size

PR: neovim#33016 fixes Issue: neovim#33009

How I found it

Hanging around in issues.

How to solve it

As the issue saying, we need to find out what the _make_floating_pop_size does. After travelling the codebase, I found that the opts.title works well as string and I don't know why it should be [string,string][].

After talking with the issue author, I knew that the vim.lsp.util.open_floating_preview using vim.api.neovim_open_win underhood. So it should follow the parameters definitions.

So, it's so easy to solve that _make_floating_pop_size should consider opts.title could be [string,string][].

Solve it

I wrote the first version code and sent it.

if opts.title then
  local title = opts.title
  local title_length = 0
  if type(title) == 'string' then
    title_length = vim.fn.strdisplaywidth(title)
  else
    if title ~= nil then
      for i = 1, #title do
        title_length = title_length + string.len(title[i][1])
      end
    end
  end
  width = math.max(width, title_length)

This version used the wrong api string.len which calculates the wrong length of cjk characters. Used vim.fn.strdisplaywidth instead.

On the another hand, this implementation of this piece is not so elegant.

The @luukvbaal recommends a better version,

local title_length = 0
local chunks = type(opts.title) == 'string' and { { opts.title } } or opts.title or {}
for _, chunk in
  ipairs(chunks --[=[@as [string, string][]]=])
do
  title_length = title_length + vim.fn.strdisplaywidth(chunk[1])

It's more elegant! I didn't know the --[=[@as [string, string][]]=] syntax of lua, and it really impressed me.

Before requesting code review, I wrote a simple unittest following the old unittests,

it('considers [string,string][] title when computing width', function()
  eq(
    { 17, 2 },
    exec_lua(function()
      return {
        vim.lsp.util._make_floating_popup_size(
          { 'foo', 'bar' },
          { title = { { 'A very ', 'Normal' }, { 'long title', 'Normal' } } }
        ),
      }
    end)
  )
end)

Then, pushed it and requested code review.

After a while, @zeertzjq merged it.

What I learnt

  • It's no so hard to finish a PR to a big codebase that it look like.