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
|
|
@ -30,12 +30,11 @@ auto("BufWritePre", {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
-- FIXME: disable for now until I can do more work and make it work better
|
auto({ "BufEnter", "CursorMoved", "CursorMovedI" }, {
|
||||||
-- auto({ "BufEnter", "CursorMoved", "CursorMovedI" }, {
|
group = bufcheck,
|
||||||
-- group = bufcheck,
|
callback = function()
|
||||||
-- callback = function()
|
core.todo.todo_comments()
|
||||||
-- core.color.todo_comments()
|
end
|
||||||
-- end
|
})
|
||||||
-- })
|
|
||||||
|
|
||||||
core.color.setup_termbg_sync()
|
core.color.setup_termbg_sync()
|
||||||
|
|
|
||||||
|
|
@ -29,136 +29,6 @@ function M.copyhl(hlgroup, namespace)
|
||||||
return res
|
return res
|
||||||
end
|
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
|
-- Source: 'runtime/lua/vim/_defaults.lua' in Neovim source
|
||||||
local function parse_osc11(x)
|
local function parse_osc11(x)
|
||||||
local r, g, b = x:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$')
|
local r, g, b = x:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$')
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ local M = {
|
||||||
misc = require("core.misc"),
|
misc = require("core.misc"),
|
||||||
lsp = require("core.lsp"),
|
lsp = require("core.lsp"),
|
||||||
color = require("core.color"),
|
color = require("core.color"),
|
||||||
|
todo = require("core.todo"),
|
||||||
snippets = vim.fs.joinpath(vim.fn.stdpath("config"), "lua/core/snippets.lua"),
|
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