From 2672029a3c87b21b051c89990f51710cf0254f29 Mon Sep 17 00:00:00 2001 From: Will Hopkins Date: Wed, 27 Dec 2023 01:09:51 -0800 Subject: [PATCH] feat: basic hinting behavior with ^ and $ motions --- lua/precognition/init.lua | 80 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/lua/precognition/init.lua b/lua/precognition/init.lua index 1b8267b..8e61116 100644 --- a/lua/precognition/init.lua +++ b/lua/precognition/init.lua @@ -20,7 +20,7 @@ local default = { } ---@type Precognition.Config -local config = {} +local config = default --- Show the hints until the next keypress or CursorMoved event function M.peek() @@ -46,14 +46,86 @@ end function M.setup(opts) config = vim.tbl_deep_extend("force", default, opts or {}) - vim.api.nvim_create_autocmd("CursorMoved", { + local ns = vim.api.nvim_create_namespace("precognition") + local au = vim.api.nvim_create_augroup("precognition", { clear = true }) + + -- This is a test with basic functionality, definitely should be moved out of the setup function and into + -- functions that the public methods can call. + + local re_line_start = vim.regex("^\\s*[^\\s]") --[[@as vim.regex]] + + ---@type integer? + local extmark -- the active extmark in the current buffer + + -- clear the extmark entirely when leaving a buffer (hints should only show in current buffer) + vim.api.nvim_create_autocmd("BufLeave", { + group = au, + callback = function(ev) + vim.api.nvim_buf_clear_namespace(ev.buf, ns, 0, -1) + extmark = nil + end, + }) + + -- clear the extmark when the cursor moves, or when insert mode is entered + vim.api.nvim_create_autocmd({ "CursorMoved", "InsertEnter" }, { + group = au, callback = function() - -- todo: hide the hints + if extmark then + vim.api.nvim_buf_del_extmark(0, ns, extmark) + extmark = nil + end end, }) + vim.api.nvim_create_autocmd("CursorHold", { + group = au, + -- TODO: add debounce / delay before showing hints to reduce flickering + -- during fast movements callback = function() - -- todo: show the hints if they're hidden + if extmark then + return + end + + local cursorline, _cursorcol = unpack(vim.api.nvim_win_get_cursor(0)) + local cur_line = vim.api.nvim_get_current_line() + + -- vim.fn.col("^") doesn't work :( + local line_end = vim.fn.col("$") - 1 + + -- FIXME: does not play nice with utf-8, we need a better way to + -- get char offsets. + -- + -- Notice that on a line with a string containing utf-8 symbols, the marks to not + -- appear in the correct place. We need to treat this as a char array, it seems that vim regex + -- treats it like a byte array. + local line_start = select(2, re_line_start:match_str(cur_line)) + + local virt_line = {} + + -- create the list of hints to show in { hint, column } format + -- TODO: extract this into a function, add hints for other motions + local marks = {} + table.insert(marks, { "^", math.max(0, line_start - 1) }) + table.insert(marks, { "$", line_end - 1 }) + + -- build the virtual line out of virt text chunks + local last_col = 0 + for _, mark in ipairs(marks) do + local hint = config.hints[mark[1]] or mark[1] + local col = mark[2] + if col > last_col then + -- add padding between hints + table.insert(virt_line, { string.rep(" ", (col - last_col)) }) + last_col = col + 1 + end + table.insert(virt_line, { hint, "Comment" }) + end + + -- create (or overwrite) the extmark + extmark = vim.api.nvim_buf_set_extmark(0, ns, cursorline - 1, line_start, { + id = extmark, -- reuse the same extmark if it exists + virt_lines = { virt_line }, + }) end, }) end