From 3966014dbcb5d7c11918ac9ab3f77638b3426f7c Mon Sep 17 00:00:00 2001 From: Iron-E <36409591+Iron-E@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:16:59 +0000 Subject: [PATCH] fix(Mode): cursor position doesn't update because of `getchar` (#27) The solution here has been to use `vim.highlight.range` and hide the real cursor. SEE neovim/neovim#20793 --- lua/libmodal/Mode.lua | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/lua/libmodal/Mode.lua b/lua/libmodal/Mode.lua index a1a4ef5..18d563d 100644 --- a/lua/libmodal/Mode.lua +++ b/lua/libmodal/Mode.lua @@ -11,6 +11,7 @@ local utils = require 'libmodal.utils' --- @type libmodal.utils --- @field private instruction fun()|{[string]: fun()|string} --- @field private mappings libmodal.collections.ParseTable --- @field private name string +--- @field private ns number the namespace where cursor highlights are drawn on --- @field private popups libmodal.collections.Stack --- @field private show_name fun() --- @field private supress_exit boolean @@ -29,12 +30,14 @@ TIMEOUT.CHAR_NUMBER = TIMEOUT.CHAR:byte() --- execute the `instruction`. --- @param instruction fun()|string a Lua function or Vimscript command. --- @return nil -function Mode.execute_instruction(instruction) +function Mode:execute_instruction(instruction) if type(instruction) == 'function' then instruction() else vim.api.nvim_command(instruction) end + + self:redraw_virtual_cursor() end --- check the user's input against the `self.instruction` mappings to see if there is anything to execute. @@ -67,7 +70,7 @@ function Mode:check_input_for_mapping() TIMEOUT:SEND() -- if there is a command, execute it. if cmd[ParseTable.CR] then - self.execute_instruction(cmd[ParseTable.CR]) + self:execute_instruction(cmd[ParseTable.CR]) end -- clear input self.input_bytes = {} @@ -76,13 +79,18 @@ function Mode:check_input_for_mapping() ) else -- the command was an actual vim command. --- @diagnostic disable-next-line:param-type-mismatch already checked `cmd` != `table` - self.execute_instruction(cmd) + self:execute_instruction(cmd) self.input_bytes = {} end self.popups:peek():refresh(self.input_bytes) end +--- clears the virtual cursor from the screen +function Mode:clear_virt_cursor() + vim.api.nvim_buf_clear_namespace(0, self.ns, 0, -1); +end + --- enter this mode. --- @return nil function Mode:enter() @@ -92,6 +100,11 @@ function Mode:enter() self.popups:push(utils.Popup.new()) end + --- HACK: https://github.com/neovim/neovim/issues/20793 + vim.api.nvim_command 'highlight Cursor blend=100' + vim.schedule(function() vim.opt.guicursor:append { 'a:Cursor/lCursor' } end) + self:render_virt_cursor() + self.previous_mode_name = vim.g.libmodalActiveModeName vim.g.libmodalActiveModeName = self.name @@ -170,6 +183,11 @@ function Mode:tear_down() self.popups:pop():close() end + --- HACK: https://github.com/neovim/neovim/issues/20793 + self:clear_virt_cursor() + vim.schedule(function() vim.opt.guicursor:remove { 'a:Cursor/lCursor' } end) + vim.api.nvim_command 'highlight Cursor blend=0' + if self.previous_mode_name and #vim.trim(self.previous_mode_name) < 1 then vim.g.libmodalActiveModeName = nil else @@ -179,6 +197,19 @@ function Mode:tear_down() utils.api.redraw() end +--- clears and then renders the virtual cursor +function Mode:redraw_virtual_cursor() + self:clear_virt_cursor() + self:render_virt_cursor() +end + +--- render the virtual cursor using extmarks +function Mode:render_virt_cursor() + local line_nr, col_nr = unpack(vim.api.nvim_win_get_cursor(0)) + line_nr = line_nr - 1 -- win_get_cursor returns +1 for our purpose + vim.highlight.range(0, self.ns, 'Cursor', { line_nr, col_nr }, { line_nr, col_nr + 1 }, {}) +end + --- create a new mode. --- @param name string the name of the mode. --- @param instruction fun()|string|table a Lua function, keymap dictionary, Vimscript command. @@ -193,6 +224,7 @@ function Mode.new(name, instruction, supress_exit) input = utils.Vars.new('input', name), instruction = instruction, name = name, + ns = vim.api.nvim_create_namespace('libmodal' .. name), }, Mode )