update and enable my todo comment highlighter
This commit is contained in:
parent
fac895e919
commit
30924f12cf
4 changed files with 225 additions and 137 deletions
|
|
@ -29,136 +29,6 @@ function M.copyhl(hlgroup, namespace)
|
|||
return res
|
||||
end
|
||||
|
||||
local todo_comments_conf = {
|
||||
TODO = {
|
||||
-- TODO:
|
||||
-- NOTE:
|
||||
-- INFO:
|
||||
"TODO", "NOTE", "INFO",
|
||||
hlgroup = "TodoTODO"
|
||||
},
|
||||
BUG = {
|
||||
-- BUG:
|
||||
-- FIXME:
|
||||
"BUG", "FIXME",
|
||||
hlgroup = "TodoBUG"
|
||||
},
|
||||
TEST = {
|
||||
-- TEST:
|
||||
-- PERF:
|
||||
"TEST", "PERF",
|
||||
hlgroup = "TodoTEST"
|
||||
},
|
||||
WARN = {
|
||||
-- WARN:
|
||||
-- HACK:
|
||||
"WARN", "HACK",
|
||||
hlgroup = "TodoWARN"
|
||||
}
|
||||
}
|
||||
|
||||
local todo_hl_ns = vim.api.nvim_create_namespace("todo_highlights")
|
||||
|
||||
--- highlight todo comments in the current buffer.
|
||||
--- No I won't use folke's super bloated plugin.
|
||||
---
|
||||
--- TODO: make this work with coniguious comment blocks like this one.
|
||||
--- currently this line won't be highlighted, but I'd like it to be
|
||||
---
|
||||
--- TEST: We could make this a plugin called ts-todo-hl or smthn like that, but
|
||||
--- I'd be willing to bet no one would use it cause everyone loves folke too
|
||||
--- much
|
||||
function M.todo_comments()
|
||||
local bufnr = vim.api.nvim_win_get_buf(0)
|
||||
local ok, parser = pcall(vim.treesitter.get_parser, bufnr)
|
||||
if not ok or not parser then
|
||||
return
|
||||
end
|
||||
|
||||
-- Construct the query for comments.
|
||||
-- We're using treesitter so that I don't have to use external tooling.
|
||||
local ok, comment_query = pcall(vim.treesitter.query.parse,
|
||||
parser:lang(),
|
||||
"(comment) @comment"
|
||||
)
|
||||
if not ok then
|
||||
return
|
||||
end
|
||||
|
||||
parser:parse(false, function(err, trees)
|
||||
if err then
|
||||
return
|
||||
end
|
||||
|
||||
local root = trees[1]:root()
|
||||
for _, match in comment_query:iter_matches(root, bufnr, 0, -1) do
|
||||
for _, nodes in pairs(match) do
|
||||
for _, node in ipairs(nodes) do
|
||||
if not node or node:type() ~= "comment" then
|
||||
goto continue
|
||||
end
|
||||
local text = vim.treesitter.get_node_text(node, bufnr)
|
||||
-- TODO: instead of doing everything relative to the node we at this
|
||||
-- point should obtain the node start and use a for loop to iterate
|
||||
-- over the lines until we're no longer in a comment. This should
|
||||
-- make dealing with comment blocks easier, and working with these
|
||||
-- multiline comments easier.
|
||||
for _, type in pairs(todo_comments_conf) do
|
||||
for _, v in ipairs(type) do
|
||||
local s, e = string.find(text, v..":")
|
||||
if not s or not e then
|
||||
s, e = string.find(text, v.."%b():")
|
||||
end
|
||||
if s and e then
|
||||
local s_row, s_col = node:start()
|
||||
local e_row, e_col = node:end_()
|
||||
|
||||
-- ensure that our string indicies are relative to the line
|
||||
s = s + s_col
|
||||
e = e + s_col
|
||||
|
||||
ok, err = pcall(vim.api.nvim_buf_set_extmark, bufnr, todo_hl_ns, s_row, e, {
|
||||
hl_mode = "replace",
|
||||
hl_group = type.hlgroup,
|
||||
end_col = e_col,
|
||||
end_row = e_row
|
||||
})
|
||||
if not ok then
|
||||
print("fg", s_row, e, e_col, e_row)
|
||||
print("fg", err)
|
||||
end
|
||||
|
||||
ok, err = pcall(vim.api.nvim_buf_set_extmark, bufnr, todo_hl_ns, s_row, s - 2, {
|
||||
hl_mode = "replace",
|
||||
hl_group = type.hlgroup.."BG",
|
||||
end_col = e - 1,
|
||||
end_row = s_row
|
||||
})
|
||||
if not ok then
|
||||
print("bg", s_row, s - 2, e - 1, s_row)
|
||||
print("bg", err)
|
||||
end
|
||||
|
||||
ok, err = pcall(vim.api.nvim_buf_set_extmark, bufnr, todo_hl_ns, s_row, e - 1, {
|
||||
hl_mode = "replace",
|
||||
hl_group = type.hlgroup.."SIGN",
|
||||
end_col = e,
|
||||
end_row = s_row
|
||||
})
|
||||
if not ok then
|
||||
print("sn", s_row, e - 1, e, s_row)
|
||||
print("sn", err)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Source: 'runtime/lua/vim/_defaults.lua' in Neovim source
|
||||
local function parse_osc11(x)
|
||||
local r, g, b = x:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$')
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ local M = {
|
|||
misc = require("core.misc"),
|
||||
lsp = require("core.lsp"),
|
||||
color = require("core.color"),
|
||||
todo = require("core.todo"),
|
||||
snippets = vim.fs.joinpath(vim.fn.stdpath("config"), "lua/core/snippets.lua"),
|
||||
}
|
||||
|
||||
|
|
|
|||
218
lua/core/todo.lua
Normal file
218
lua/core/todo.lua
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
---@class data.buf.node
|
||||
---@field size number size of the node
|
||||
---@field extmark_bg number? extmark id for the bg
|
||||
---@field extmark_fg number? extmark id for the fg
|
||||
---@field extmark_sn number? extmark id for the sign
|
||||
|
||||
---@class data.buf
|
||||
---@field [integer] data.buf.node a list of nodes where the index is the row in file where the node resides
|
||||
|
||||
---@class data
|
||||
---@field [integer] data.buf buffer number
|
||||
local data = {}
|
||||
|
||||
local M = {}
|
||||
|
||||
local todo_comments_conf = {
|
||||
TODO = {
|
||||
-- TODO:
|
||||
-- NOTE:
|
||||
-- INFO:
|
||||
"TODO", "NOTE", "INFO",
|
||||
hlgroup = "TodoTODO"
|
||||
},
|
||||
BUG = {
|
||||
-- BUG:
|
||||
-- FIXME:
|
||||
"BUG", "FIXME",
|
||||
hlgroup = "TodoBUG"
|
||||
},
|
||||
TEST = {
|
||||
-- TEST:
|
||||
-- PERF:
|
||||
"TEST", "PERF",
|
||||
hlgroup = "TodoTEST"
|
||||
},
|
||||
WARN = {
|
||||
-- WARN:
|
||||
-- HACK:
|
||||
"WARN", "HACK",
|
||||
hlgroup = "TodoWARN"
|
||||
}
|
||||
}
|
||||
|
||||
local todo_hl_ns = vim.api.nvim_create_namespace("todo_highlights")
|
||||
|
||||
--- create a new highlight or override an existing one
|
||||
---@param bufnr number
|
||||
---@param group string
|
||||
---@param s_col number
|
||||
---@param e_col number
|
||||
---@param s_row number
|
||||
---@param e_row number
|
||||
---@param id number?
|
||||
---@return number?
|
||||
local function set_hl_at(bufnr, group, s_col, e_col, s_row, e_row, id)
|
||||
local ok, res = pcall(
|
||||
vim.api.nvim_buf_set_extmark,
|
||||
bufnr,
|
||||
todo_hl_ns,
|
||||
s_row,
|
||||
s_col,
|
||||
{
|
||||
hl_mode = "replace",
|
||||
hl_group = group,
|
||||
end_col = e_col,
|
||||
end_row = e_row,
|
||||
id = id,
|
||||
})
|
||||
|
||||
if ok then
|
||||
return res
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- I'm wayyyyyy too lazy to make this function take a real list of arguments
|
||||
---@param tab table everything in the whole universe in the most backwards incompatable way
|
||||
local function create_extmarks(tab)
|
||||
local bufnr, s, e, node, only_continuation, t = vim.F.unpack_len(tab)
|
||||
|
||||
local s_row, s_col = node:start()
|
||||
local e_row, e_col = node:end_()
|
||||
|
||||
-- ensure that our string indicies are relative to the line
|
||||
s = s + s_col
|
||||
e = e + s_col
|
||||
|
||||
if not data[bufnr][s_row] then
|
||||
local _, _, bytes = node:start()
|
||||
table.insert(data[bufnr], s_row, { size = bytes })
|
||||
end
|
||||
|
||||
do
|
||||
local id = data[bufnr][s_row].extmark_fg
|
||||
local ext_id = set_hl_at(bufnr, t.hlgroup, only_continuation and s - 2 or e, e_col, s_row, e_row, id)
|
||||
if not id then
|
||||
data[bufnr][s_row].extmark_fg = ext_id
|
||||
end
|
||||
end
|
||||
|
||||
if not only_continuation then
|
||||
do
|
||||
local id = data[bufnr][s_row].extmark_bg
|
||||
local ext_id = set_hl_at(bufnr, t.hlgroup.."BG", s - 2, e - 1, s_row, e_row, id)
|
||||
if not id then
|
||||
data[bufnr][s_row].extmark_bg = ext_id
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local id = data[bufnr][s_row].extmark_sn
|
||||
local ext_id = set_hl_at(bufnr, t.hlgroup.."SIGN", e - 1, e, s_row, e_row, id)
|
||||
if not id then
|
||||
data[bufnr][s_row].extmark_sn = ext_id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- highlight todo comments in the current buffer.
|
||||
--- No I won't use folke's super bloated plugin.
|
||||
--- TODO: check if there's already an extmark at the location we're trying to
|
||||
--- highlight, and if so don't add it again unless the node has changed.
|
||||
---
|
||||
--- ensure that we only change the extmark when the node has changed
|
||||
function M.todo_comments()
|
||||
local bufnr = vim.api.nvim_win_get_buf(0)
|
||||
local ok, parser = pcall(vim.treesitter.get_parser, bufnr)
|
||||
if not ok or not parser then
|
||||
return
|
||||
end
|
||||
|
||||
-- create an entry for the buffer in the data
|
||||
if not data[bufnr] then
|
||||
data[bufnr] = {}
|
||||
end
|
||||
|
||||
-- Construct the query for comments.
|
||||
-- We're using treesitter so that I don't have to use external tooling.
|
||||
local ok, comment_query = pcall(vim.treesitter.query.parse,
|
||||
parser:lang(),
|
||||
"(comment) @comment"
|
||||
)
|
||||
if not ok then
|
||||
return
|
||||
end
|
||||
|
||||
parser:parse(false, function(err, trees)
|
||||
if err then
|
||||
return
|
||||
end
|
||||
|
||||
-- store the previous todo comment's location information
|
||||
local start_loc = nil
|
||||
local ls, le, lt = nil, nil, nil
|
||||
|
||||
local root = trees[1]:root()
|
||||
for _, match in comment_query:iter_matches(root, bufnr, 0, -1) do
|
||||
for _, nodes in pairs(match) do
|
||||
for _, node in ipairs(nodes) do
|
||||
if not node or node:type() ~= "comment" then
|
||||
goto continue
|
||||
end
|
||||
local text = vim.treesitter.get_node_text(node, bufnr)
|
||||
|
||||
-- is the node previous to this node a todo comment?
|
||||
local continuation = (start_loc and start_loc + 1 == node:start())
|
||||
|
||||
-- the current todo comment's information
|
||||
local s, e = nil, nil
|
||||
local t = nil
|
||||
for _, type in pairs(todo_comments_conf) do
|
||||
for _, v in ipairs(type) do
|
||||
s, e = string.find(text, v..":")
|
||||
if not s or not e then
|
||||
s, e = string.find(text, v.."%b():")
|
||||
end
|
||||
if s and e then
|
||||
t = type
|
||||
goto work;
|
||||
end
|
||||
end
|
||||
end
|
||||
::work::
|
||||
|
||||
-- is the node previous to this node a todo comment and is this node
|
||||
-- not a todo comment?
|
||||
local only_continuation = (not s or not e) and continuation
|
||||
|
||||
-- let's render this bad boy
|
||||
if (s and e) or continuation then
|
||||
if only_continuation then
|
||||
s, e, t = ls, le, lt
|
||||
end
|
||||
start_loc = node:start()
|
||||
|
||||
if s and e then
|
||||
ls, le, lt = s, e, t
|
||||
end
|
||||
|
||||
create_extmarks(vim.F.pack_len(
|
||||
bufnr,
|
||||
s,
|
||||
e,
|
||||
node,
|
||||
only_continuation,
|
||||
t
|
||||
))
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return M
|
||||
Loading…
Add table
Add a link
Reference in a new issue