Open bjornevik opened 2 years ago
Does this problem occur after undoing a dot-repeat? That is a known Vim issue, according to vim-sneak's docs: https://github.com/justinmk/vim-sneak/blob/94c2de47ab301d476a2baec9ffda07367046bec9/doc/sneak.txt#L200-L202
However, except for the above scenario, dot-repeat should work fine.
Does this problem occur after undoing a dot-repeat?
If I run through nvim --clean
I'm able to dta
-> dot-repeat -> undo -> dot-repeat as expected. If I attempt to do the same with leap/flit
enabled I only get as far as dta
-> dot-repeat, before nvim seizes up. If that's what you mean.
Might still be related to the issue referred to in vim-sneak docs, tried completely uninstall nvim-surround since I thought it might intefere, but still having this problem with nvim-surround disabled.
edit: looks like the dot-repeat enters d~@ý
, at least it's displayed in the bottom right.
looks like the dot-repeat enters d~@ý, at least it's displayed in the bottom right.
Yep. It is also interesting that this only happens after one dot-repeat - that is, dot-repeat -> dot-repeat+ -> undo works).
Note that you can exit from this frozen state with C-c
, if necessary.
I only get as far as dta -> dot-repeat, before nvim seizes up
To be clear: you experience this problem without undoing the change first?
Yep. It is also interesting that this only happens after one dot-repeat - that is, dot-repeat -> dot-repeat+ -> undo works).
That isn't the case for me, I'm stuck in the state until I either kill neovim, or C-c
.
To be clear: you experience this problem without undoing the change first?
Yes. On both MacOS and Ubuntu.
Tested some more today, seems I did not read the README properly and never added the tpope/vim-repeat dependency 🙈
It works now, though dot-repeat -> undo -> dot-repeat still has the issue. I'll leave it up to you whether or not to close this issue.
Have you considered changing the dot-repeat implementation as described in this gist? Was thinking of trying to implement it and opening a PR, but am not really familiar with fennel. Also don't want to repeat work if you've already considered it and decided against it.
Tested some more today, seems I did not read the README properly and never added the tpope/vim-repeat dependency
Well... :D
Have you considered changing the dot-repeat implementation as described in this gist? Was thinking of trying to implement it and opening a PR, but am not really familiar with fennel. Also don't want to repeat work if you've already considered it and decided against it.
A PR is absolutely welcome, if the result is not significantly more verbose than the current implementation with vim-repeat. I've seen that gist, but haven't looked into it deeply yet, still don't really understand what we would need to do.
gitsigns recently implemented (not sure if based on that gist) its own support for dot-repeat (without pope's plugin) as well. Just FYI.
Looked into it a couple of afternoons this past week, but haven't had the time to write any code.
A lot of it became clearer when I found this fantastic blog post by numToStr
How I've understood it is that the general pattern is to have a function callback that sets vim.o.operatorfunc
to itself and returns g@
when it is called "without a motion" (aka. called by user), and otherwise does whichever action when it is called with a motion. When g@
is called the user is popped into operator-pending mode, and when the user enters the motion g@
will call whatever function is set in vim.o.operatorfunc
with the motion as an argument. Dot-repeat is automatically then set to g@[motion]
with the same motion the user did and will repeat as expected. You can also set vim.o.operatorfunc
Which should be relatively straight forward, but my non-existent experience with fennel (and lisp in general) is making it a bit harder to read the code and figure out what leap actually does and how everything fits together. Unsure if it's just a matter of changing a couple of lines in fn set-dot-repeat* []
or if there needs to be a separate callback function for handling the different operators, visual mode, etc. Or even if it would constitute a significantly more verbose solution.
changing to operatorfunc
instead of depending repeat.vim
is hard because the model for using operatorfunc
needs to save a state needed to repeat the motion outside the command doing the motion.
Alternatively, one can try to re-use the current model (handling registers and operators ourselves), but that would involve handling corner cases that repeat.vim already handles (would require re-writing lots of code).
Which should be relatively straight forward, but my non-existent experience with fennel (and lisp in general) is making it a bit harder to read the code and figure out what leap actually does and how everything fits together.
; repeat.vim support
; (see the docs in the script:
; https://github.com/tpope/vim-repeat/blob/master/autoload/repeat.vim)
(fn set-dot-repeat* []
; Note: dot-repeatable (i.e. non-yank) operation is assumed, we're not
; checking it here.
(let [op vim.v.operator
cmd (replace-keycodes
"<cmd>lua require'leap'.leap { dot_repeat = true }<cr>")
; We cannot getreg('.') at this point, since the change has not
; happened yet - therefore the below hack (thx Sneak).
change (when (= op :c) (replace-keycodes "<c-r>.<esc>"))
seq (.. op cmd (or change ""))]
; Using pcall, since vim-repeat might not be installed.
; Use the same register for the repeated operation.
(pcall vim.fn.repeat#setreg seq vim.v.register)
; Note: we're feeding count inside the seq itself.
(pcall vim.fn.repeat#set seq -1)))
The compiled Lua code, prettified:
local function set_dot_repeat_2a()
local op = vim.v.operator
local cmd = replace_keycodes("<cmd>lua require'leap'.leap { dot_repeat = true }<cr>")
local change = (op == "c") and replace_keycodes("<c-r>.<esc>") or ""
local seq = op .. cmd .. change
pcall(vim.fn["repeat#setreg"], seq, vim.v.register)
pcall(vim.fn["repeat#set"], seq, -1)
end
That is all, we just call this function in different places in the code, and it will set the dot-repeat action to <operation-trigger> lua require'leap'.leap { dot_repeat = true } <change>?
(i.e., seq
) with help of vim-repeat. In case of repeating a change operation, we also feed the change itself after the call: <c-r>.<esc>
inserts the contents of the .
register (:h c_CTRL-R
).
The special Leap call with the dot_repeat
argument will not prompt for input, but use the state that is saved for operator-pending mode invocations:
; State that is persisted between invocations.
(local state {:args nil ; arguments passed to the current call
:source_window nil
:repeat {:in1 nil
:in2 nil}
; >>>
:dot_repeat {:in1 nil
:in2 nil
:target_idx nil ; ~ count, so we don't need to feed it in set-dot-repeat*
:backward nil
:inclusive_op nil
:offset nil}
:saved_editor_opts {}})
The wrapper set-dot-repeat
, that is actually used in the main algorithm, updates state
before calling set-dot-repeat*
itself:
(fn set-dot-repeat [in1 in2 target_idx]
(when (and dot-repeatable-op?
(not (or dot-repeat? (= (type user-given-targets) :table))))
(set state.dot_repeat {:in1 (and (not user-given-targets) in1)
:in2 (and (not user-given-targets) in2)
:callback user-given-targets
: target_idx
: offset
: match-xxx*-at-the-end?
; Mind the naming conventions.
:backward backward?
:inclusive_op inclusive-op?})
(set-dot-repeat*)))
Nvim version: NVIM v0.8.0-dev-1132-g37a71d1f2
init.lua
Use
nvim -u init.lua
to load minimal configDo a movement like
dz12
orcz12
and try to dot-repeat it. Looks like the editor is locked into a sort of operator-pending mode to my eyes.Having the same problem with
flit.nvim
andlightspeed.nvim
. First noticed it using f/t motions with lightspeed.