folke / todo-comments.nvim

✅ Highlight, list and search todo comments in your projects
Apache License 2.0
2.94k stars 86 forks source link

feature: Add support for doublewidth Nerd Font icons #282

Open powerman opened 2 weeks ago

powerman commented 2 weeks ago

Did you check the docs?

Is your feature request related to a problem? Please describe.

Please read https://github.com/neovim/neovim/issues/29496 - it describes patch for Neovim which marks Nerd Font icons doublewidth and this result in breaking your plugin (described in details in https://github.com/neovim/neovim/issues/29496#issuecomment-2194662883).

Describe the solution you'd like

Not sure is mentioned in linked comment fix based on 'ambiwidth' vim option will works, but please consider some solution to the issue.

Describe alternatives you've considered

Manual copy&paste of default icons setup into own custom config and removing extra spaces after icons works. But it's not really convenient for new users who don't want to customize used icons.

Additional context

Sorry, I havn't read all the todo-comments.nvim docs - it's not relevant to the issue, but I had to check the box to submit.

folke commented 1 week ago

I don't really understand any of this. Can you give a repro that breaks todo-comments?

powerman commented 1 week ago

To make doublewidth Nerd Font icons work in Neovim we should mark their codepoints as doublewidth:

-- Fix icon width for Nerd Fonts v3.2.1.
vim.fn.setcellwidths {
    { 0x23fb, 0x23fe, 2 }, -- IEC Power Symbols
    { 0x2665, 0x2665, 2 }, -- Octicons
    { 0x2b58, 0x2b58, 2 }, -- IEC Power Symbols
    { 0xe000, 0xe00a, 2 }, -- Pomicons
    { 0xe0b8, 0xe0c8, 2 }, -- Powerline Extra
    { 0xe0ca, 0xe0ca, 2 }, -- Powerline Extra
    { 0xe0cc, 0xe0d7, 2 }, -- Powerline Extra
    { 0xe200, 0xe2a9, 2 }, -- Font Awesome Extension
    { 0xe300, 0xe3e3, 2 }, -- Weather Icons
    { 0xe5fa, 0xe6b5, 2 }, -- Seti-UI + Custom
    { 0xe700, 0xe7c5, 2 }, -- Devicons
    { 0xea60, 0xec1e, 2 }, -- Codicons
    { 0xed00, 0xefce, 2 }, -- Font Awesome
    { 0xf000, 0xf2ff, 2 }, -- Font Awesome
    { 0xf300, 0xf375, 2 }, -- Font Logos
    { 0xf400, 0xf533, 2 }, -- Octicons
    { 0xf0001, 0xf1af0, 2 }, -- Material Design
}

With this setup todo-comments (using it default config) show error on loading plugin:

Failed to run `config` for todo-comments.nvim

Vim:E239: Invalid sign text:                                                                      

# stacktrace:                                                                                       
  - /todo-comments.nvim/lua/todo-comments/config.lua:141 _in_ **signs**                             
  - /todo-comments.nvim/lua/todo-comments/config.lua:134 _in_ **_setup**                            
  - /todo-comments.nvim/lua/todo-comments/config.lua:95 _in_ **setup**                              

This happens because you define keywords elements with extra space after an icon. When icon itself became doublewidth that extra space makes sign value too long (3 columns instead of 2) - which result in above error.

I propose to add a check for actual icon width before defining keywords and add/remove that extra space after an icons depending on check result.

powerman commented 1 week ago

Here is example implementation:

local function fix_sign_width(keyword)
    local code = vim.fn.char2nr(keyword.icon, true)
    for _, value in ipairs(vim.fn.getcellwidths()) do
        if value[1] <= code and code <= value[2] and value[3] > 1 then
            return
        end
    end
    keyword.icon = keyword.icon .. ' '
end

---@param opts TodoOptions
local function fix_icons(opts)
    for _, keyword in pairs(opts.keywords) do
        fix_sign_width(keyword)
    end
end

--- Example:

-- Fix icon width for Nerd Fonts v3.2.1.
vim.fn.setcellwidths {
    { 0x23fb, 0x23fe, 2 }, -- IEC Power Symbols
    { 0x2665, 0x2665, 2 }, -- Octicons
    { 0x2b58, 0x2b58, 2 }, -- IEC Power Symbols
    { 0xe000, 0xe00a, 2 }, -- Pomicons
    { 0xe0b8, 0xe0c8, 2 }, -- Powerline Extra
    { 0xe0ca, 0xe0ca, 2 }, -- Powerline Extra
    { 0xe0cc, 0xe0d7, 2 }, -- Powerline Extra
    { 0xe200, 0xe2a9, 2 }, -- Font Awesome Extension
    { 0xe300, 0xe3e3, 2 }, -- Weather Icons
    { 0xe5fa, 0xe6b5, 2 }, -- Seti-UI + Custom
    { 0xe700, 0xe7c5, 2 }, -- Devicons
    { 0xea60, 0xec1e, 2 }, -- Codicons
    { 0xed00, 0xefce, 2 }, -- Font Awesome
    { 0xf000, 0xf2ff, 2 }, -- Font Awesome
    { 0xf300, 0xf375, 2 }, -- Font Logos
    { 0xf400, 0xf533, 2 }, -- Octicons
    { 0xf0001, 0xf1af0, 2 }, -- Material Design
}

---@type TodoOptions
local opts = {
    keywords = {
        FIX = { icon = '' },
        TODO = { icon = '' },
        HACK = { icon = '' },
        WARN = { icon = '' },
        PERF = { icon = '' },
        NOTE = { icon = '' },
        TEST = { icon = '󰝖' },
    },
}
fix_icons(opts)
vim.print(opts)
powerman commented 1 week ago

Can you give a repro that breaks todo-comments?

To repro just add that vim.fn.setcellwidths call before loading todo-comments.