Skip to content

Feature suggestion: Provide a way to get actual display width of the string returned by get_location() #148

@SirWrexes

Description

@SirWrexes

First of, very nifty little plugin, it pairs wonderfully with nvim-treesitter-context and they complement each other well~

However I have one small grudge with it at the moment.
I have set my config to display a thin line as my statusline using fillchars, since I prefer using winbar
Untitled
Here's the config in question, I put it in my plugin spec for coloful-winsep.nvim because I thought that's how it made the most sense, given the nature of said plugin.

---@type LazyPluginSpec
local splitborders = {
  "nvim-zh/colorful-winsep.nvim",

  event = "WinLeave",

  init = function()
    -- Make the horizontal split separator be a thin straight line
    -- We override whatever has been set in order to make it look nice with this plugin.
    -- Did you set fillchars somewhere else but they kept getting overridden and you have been looking for minutes,
    -- hours, days, years even? You have come to the right place and I'm sorry.
    vim.opt.fillchars:append { stl = "", stlnc = ""}

    -- Couldn't find a way to do this in "pure lua"
    vim.cmd [[highlight! link StatusLine WinSeparator]]
  end,

  config = true,
}

return splitborders

Problem is: Using fillchars=...stl:─,stlnc:─ with nvim-navic ends up being very ugly and hardly legible.
image

To fix this issue, I've made it so my hook to attach nvim-navic to a buffer overrides these values again with a whitespace if the LSP supports documentSymbolProvider and thus navic gets required and attached... But!
I would like to keep the thin line after the displayed location so I also made the hook build a """simple""" status line with 1. location, 2. a repeated sequence of whatever the fillchar originally was:

---@type table<string, LspHookFunction>
local hooks = {
  format_on_save = function(client, buffer)
    if client.supports_method "textDocument/formatting" then
      vim.api.nvim_create_autocmd("BufWritePre", {
        group = vim.api.nvim_create_augroup("FormatOnSave", {}),
        buffer = buffer,
        callback = function()
          -- TODO: Find some better way than using _G.
          --       Sadly, I couldn't get it to work yet.
          --       Probably some module with a local state variable + a getter/setter pair ?
          --
          -- selene: allow(global_usage)
          _G["PLF_SHOULD_OPEN_PICKER"] = false
          require("plf").format {
            async = false,
          }
          -- selene: allow(global_usage)
          _G["PLF_SHOULD_OPEN_PICKER"] = true
        end,
      })
    end
  end,

  statusline_context = function(client, buffer)
    if client.server_capabilities.documentSymbolProvider then
      require("nvim-navic").attach(client, buffer)

      local location = "v:lua.require'nvim-navic'.get_location()"
      local locationlen = string.format("len(%s)", location)

      local fillchars = vim.opt.fillchars:get()
      local filling = fillchars.stl or fillchars.stlnc or ""
      local fillerlen = string.format("%d - %s", vim.o.columns - 1, locationlen)
      local filler = string.format("repeat('%s', %s)", filling, fillerlen)

      local status = "%#Title#%{%" .. location .. "%}"
      .. " %#StatusLine#%{"
      .. filler
      .. "}"

      vim.opt.fillchars:remove { "stl", "stlnc" }
      vim.o.statusline = status
    end
  end,
}

---@type LspHookFunction
local function default_on_attach(client, buffer)
  vim
    .iter(pairs(hooks))
    :each(function(_, on_attach) on_attach(client, buffer) end)
end

return default_on_attach

image
Great, that looks fantastic, I am very pleased! Here's the catch, though: VimScript len() or lua # operator both return the number of bytes in the string, and it doesn't correspond to the actual number of columns the string takes: it's bigger.
For instance, when nvim-navic says 󰊕 get_fillchar, doing :lua vim.print(#require'nvim-navic'.get_location()) or echo len(v:lua.require'nvim-navic'.get_location()) respond with 17, whereas the actual column width is in fact 14.

The result is this:
Untitled
The bar gets shrunk noticeably.

It would be nice if we could do something like

vim.o.statusline =
  [[%{%v:lua.require 'nvim-navic'.get_location()} %{repeat('─',]]
    .. vim.o.columns - 1
    .. [[- v:lua.require'nvim-navic'.get_location_width())}]]

I think it can make integrations more easy, and surely be a welcome feature for all hackers like me out there who like to style their UI manually.
Thank you for your time (and the plugin) ! ❤️

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions