folke / todo-comments.nvim

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

bug: highlight is broken with multiple capture groups in `opts.highlight.pattern` #326

Open h3xOo opened 1 month ago

h3xOo commented 1 month ago

Did you check docs and existing issues?

Neovim version (nvim -v)

NVIM v0.10.2 Build type: RelWithDebInfo LuaJIT 2.1.1727870382

Operating system/version

Artix Linux 6.11.2-artix1-1

Describe the bug

I'm trying to match optional (nickname) after keyword, but I can't get it to highlight (either it doesn't work at all, or breaks default or highlights only part of parenthesis) [or I can't just write regex 🙃). I think it might be connected with fact, that I'm using extra capture group for optional (nick), but todo-comments expects at most 2?

I've added this prints for debugging

diff --git a/lua/todo-comments/highlight.lua b/lua/todo-comments/highlight.lua
index f4c7674..9884319 100644
--- a/lua/todo-comments/highlight.lua
+++ b/lua/todo-comments/highlight.lua
@@ -45,10 +45,14 @@ function M.match(str, patterns)

   for _, pattern in pairs(patterns) do
     local m = vim.fn.matchlist(str, [[\v\C]] .. pattern)
+    for i, value in pairs(m) do
+      print(string.format("match[%d] = %s", i, value))
+    end
     if #m > 1 and m[2] then
       local match = m[2]
       local kw = m[3] ~= "" and m[3] or m[2]
       local start = str:find(match, 1, true)
+      print(string.format("match = %s, kw = %s\nreturning start = %d, start + #match = %d, kw = %s", match, kw, start, start + #match, kw))
       return start, start + #match, kw
     end
   end

And on file

// FIXME:
//
// FIXME(nick):

I got

match[1] = // FIXME:
match[2] = FIXME                                                                                        
match[3] =                                                                                              
match[4] =                                                                                              
match[5] =                                                                                              
match[6] =                                                                                              
match[7] =                                                                                              
match[8] =                                                                                              
match[9] =                                                                                              
match[10] =                                                                                             
match = FIXME, kw = FIXME                                                                               
returning start = 4, start + #match = 9, kw = FIXME                                                     
match[1] = // FIXME(nick):                                                                              
match[2] = FIXME                                                                                        
match[3] = (nick)                                                                                       
match[4] =                                                                                              
match[5] =                                                                                              
match[6] =                                                                                              
match[7] =                                                                                              
match[8] =                                                                                              
match[9] =                                                                                              
match[10] =                                                                                             
match = FIXME, kw = (nick)                                                                              
returning start = 4, start + #match = 9, kw = (nick)  

Interestingly, if I use vim.fn.matchadd() it works, like this:

local function get_magic_regex(name)
        return "\\v\\c\\@?" .. name .. "(\\(\\w*\\))?(:)?"
end

vim.fn.matchadd("DiagnosticInfo", get_magic_regex("todo"))
vim.fn.matchadd("DiagnosticError", get_magic_regex("fixme"))
vim.fn.matchadd("DiagnosticWarn", get_magic_regex("warning"))

But I don't like it, since it ignores any context, is very limited etc.

Steps To Reproduce

  1. Create file with comment like FIXME(cool nickname): foo and FIXME: foo. Only second one should be highlighted.

Expected Behavior

Multiple capture groups are respected

Repro

vim.env.LAZY_STDPATH = ".repro"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()

require("lazy.minit").repro({
  spec = {
    {
      "folke/todo-comments.nvim",
      opts = function()
        -- @see: https://github.com/folke/todo-comments.nvim/blob/main/lua/todo-comments/config.lua
        local default_keywords = {
          FIX = {
            icon = " ", -- icon used for the sign, and in search results
            color = "error", -- can be a hex color, or a named color (see below)
            alt = { "FIXME", "BUG", "FIXIT", "ISSUE" }, -- a set of other keywords that all map to this FIX keywords
            -- signs = false, -- configure signs for some keywords individually
          },
          TODO = { icon = " ", color = "info" },
          HACK = { icon = " ", color = "warning" },
          WARN = { icon = " ", color = "warning", alt = { "WARNING", "XXX" } },
          PERF = { icon = " ", alt = { "OPTIM", "PERFORMANCE", "OPTIMIZE" } },
          NOTE = { icon = " ", color = "hint", alt = { "INFO" } },
          TEST = { icon = "⏲ ", color = "test", alt = { "TESTING", "PASSED", "FAILED" } },
        }

        -- Custom keywords
        local keywords = {
          SEE = {
            icon = " ",
            color = "info",
          },
        }

        keywords = vim.tbl_deep_extend("force", {}, default_keywords, keywords)
        -- Add lowercase versions of each keyword
        for key, val in pairs(keywords) do
          local alt = { key:lower(), key }
          if val.alt then
            for _, alt_key in ipairs(val.alt) do
              alt[#alt + 1] = alt_key
              alt[#alt + 1] = alt_key:lower()
            end
          end
          keywords[key].alt = alt
        end
        return {
          keywords = keywords,
          highlight = {
            pattern = { [[.*\@<(KEYWORDS)(\(\w*\))?\s*]], [[.*<(KEYWORDS)(\(\w*\))?\s*:]], },
          },
          search = {
            pattern = [[[\\\\@]*\b(KEYWORDS)(\s|:)]],
          }
        }
      end,
    },
  }
})
github-actions[bot] commented 4 days ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.