hadronized / hop.nvim

Neovim motions on speed!
Other
2.49k stars 140 forks source link

Support for dot repeat #58

Open ecosse3 opened 3 years ago

ecosse3 commented 3 years ago

Hi,

I have a feature request which I actually yes pretty often because I'm addicted to repeating motions via dot. Is it possible to add dot repeat support?

For example, if I have mapped :HopChar2 to f key and I press motion like: dfvi (delete find vi) it shows me the first occurrence in line as s. I click "s" and everything to "vi" is deleted as expected. Then I would like to go to next line where there is some word starting on "vi" and just delete find vi again via simply clicking dot.

Thanks!

ouuan commented 3 years ago

I also want to repeat the motions. However, I don't think it should be a dot-repeat. I'd rather like commands/functions for repeating the last HopChar1 and HopChar2.

ouuan commented 3 years ago

Sorry, I didn't notice that you were using Hop with operators. In that case it would be good to be dot-repeatable.

hadronized commented 3 years ago

I have honestly no idea what it would mean. If it means depending on another plugin, why not, but I haven’t planned anything yet for this.

hadronized commented 3 years ago

Going through this again. If you could scratch a scenario / an image showing exactly what kind of feature you had on your mind, that would be great. Something like what @ouuan described seems useful (repeating the last Hop command, not motion).

lucax88x commented 2 years ago

Actually in love with this plugin, I found it more comfortable than easymotion, ligthspeed, and other competitors.

Thanks you very much.

Anyway, my trouble is that I cannot repeat actions.

example:

import useErrorHandling from '@hooks/useErrorHandling';
import useIsInRole from '../../../../hooks/useIsInRole';
import useIsReadOnly from '../../../../hooks/useIsReadOnly';

I want to make 2nd line and 3rd line same as 1st liine (using @import instead of relative imports) I would go to second line, place my cursor after ', then I would do

cth@<ESC>

but then, at 3rd line I cannot repeat this, even if it's the only match. it goes in some weird infinite state that It's hard to exit. I can only do CTRL-C.

video:

https://user-images.githubusercontent.com/6294464/150967887-f9b788eb-19d1-46da-9d0b-19894b683dd9.mp4

lucax88x commented 2 years ago

That's even a simpler scenario, just searching the first h and repeating it.

https://user-images.githubusercontent.com/6294464/150967942-1fc66df6-c9e0-460d-9ab1-271b371937c3.mp4

megalithic commented 2 years ago

Oh man, I came here to say this, i'd LOVE to repeat previous df/ motion (as example). @phaazon any more updates on this being a possibility, or a "no, will not do" is sufficient at this point. thankms so much for this great plugin!

megalithic commented 2 years ago

đź‘‹ Just bumping this @phaazon to see if you had/have any interest or thoughts on implementation of dot repeat support with hop?

Strongleong commented 2 years ago

Bump. I am in love with this plugin and I am suffering without ability to dot-repeat last hop-function

iroedius commented 2 years ago

Another bump. The plugin is great, in my opinion the only major thing it's missing at this point is the ability to dot-repeat hop jumps (hops?). I really hope it gets implemented.

Strongleong commented 2 years ago

A little update what I found. Turns out that's there IS dot-repeat, but it is done a little weird. I have bind hint_char1 to f and t (inclusive and exclusive respectively), and if I prees fsa (go to first a inclusive) and press ., it will repeat only f. I mean that you need to again specify letter you want to go

haolian9 commented 2 years ago

can tpope/vim-repeat be considered?

---updates--- actually i made a repeatable approach for hop.hint_with using tpope/vim-repeat before comment. although i played happily with it so far, i still wanna this feature can be provided by the upstream itself.

---updates: i really dont want to polute this issue--- here is how i use vim-repeat with hop.nvim (in a very limited way).

snippet ``` local function repeatable_hop(chars) assert(chars ~= nil) last_chars = chars hop.hint_with(builtin_targets.jump_targets_by_scanning_lines(builtin_targets.regex_by_case_searching(chars, true, {})), hop.opts) vim.fn["repeat#set"](":lua require'change-me-to-a-real-moudle-name'.repeats()\r") end M.repeats = function() if last_chars == nil then return end repeatable_hop(last_chars) end ```
Strongleong commented 2 years ago

can tpope/vim-repeat be considered?

I have one. You can see how dot works with this in my previous message

lubaroli commented 2 years ago

can tpope/vim-repeat be considered? ---updates--- actually i made a repeatable approach for hop.hint_with using tpope/vim-repeat before comment. although i played happily with it so far, i still wanna this feature can be provided by the upstream itself.

Would you mind sharing your solution? I've tried using repeat.vim but had no success...

Thanks!

megalithic commented 2 years ago

can tpope/vim-repeat be considered?

---updates--- actually i made a repeatable approach for hop.hint_with using tpope/vim-repeat before comment. although i played happily with it so far, i still wanna this feature can be provided by the upstream itself.

---updates: i really dont want to polute this issue--- here is how i use vim-repeat with hop.nvim (in a very limited way).

local function repeatable_hop(chars)
  assert(chars ~= nil)
  last_chars = chars
  hop.hint_with(builtin_targets.jump_targets_by_scanning_lines(builtin_targets.regex_by_case_searching(chars, true, {})), hop.opts)
  vim.fn["repeat#set"](":lua require'change-me-to-a-real-moudle-name'.repeats()\r")
end

M.repeats = function()
  if last_chars == nil then return end
  repeatable_hop(last_chars)
end

hey this is great! thanks for sharing!

@haolian9 would you mind expanding just a bit more on your example? for instance, what is invoking your repeatable_hop/1 function? thanks!

I've adapted to my config, however, am missing the piece of how to actually call repeatable_hop/1:

  local hop = require("hop")
  local jump_target = hop.jump_target
  local last_chars

  local function repeatable_hop(chars)
    assert(chars ~= nil)
    last_chars = chars
    hop.hint_with(
      jump_target.jump_targets_by_scanning_lines(jump_target.regex_by_case_searching(chars, true, {})),
      hop.opts
    )
    vim.fn["repeat#set"](":lua mega.fn.hop_repeater()\r")
  end

  mega.fn.hop_repeater = function()
    if last_chars == nil then return end
    repeatable_hop(last_chars)
  end
haolian9 commented 2 years ago

@megalithic glad you liked it, i scratched a simple rewrite of hop.hint_char1. for more complicate uses, the behavior of Hop may vary between people's needs.

snippet prerequisites: * install vim-repeat * put the following snippet in a proper location. * there are several fixme ``` local M = {} local hop = require("hop") local builtin_targets = require("hop.jump_target") local last_chars = nil ---@param chars string local function repeatable_hop(chars) assert(chars ~= nil) last_chars = chars hop.hint_with(builtin_targets.jump_targets_by_scanning_lines(builtin_targets.regex_by_case_searching(chars, true, {})), hop.opts) -- fixme: change to a real module vim.fn["repeat#set"](":lua require'my.local.hop'.repeats()\r") end M.repeats = function() if last_chars == nil then return end repeatable_hop(last_chars) end M.hint_char1 = function() -- a rewrite of hop.hint_char1 local char while true do vim.api.nvim_echo({ { "hop 1 char:", "Search" } }, false, {}) local code = vim.fn.getchar() -- fixme: custom char range by needs if code >= 61 and code <= 0x7a then -- [a-z] char = string.char(code) break elseif code == 0x20 or code == 0x1b then -- press space, esc to cancel char = nil break end end if not char then return end repeatable_hop(char) end M.setup = function() hop.setup({}) -- fixme: change to a real module vim.api.nvim_set_keymap("n", [[f]], [[lua require'my.local.hop'.hint_char1()]], { noremap = true }) end return M ```
FelipeLema commented 1 year ago

here's that same script without the need for vim-repeat (I haven't tested it thoroughly, though)

-- https://gist.github.com/kylechui/a5c1258cd2d86755f97b10fc921315c3
-- https://www.vikasraj.dev/blog/vim-dot-repeat
local hop = require("hop")
local builtin_targets = require("hop.jump_target")

_G._repeated_hop_state = {
  last_chars = nil,
  count = 0,
}

_G._repeatable_hop = function ()
  for i=1,_G._repeated_hop_state.count  do
    hop.hint_with(builtin_targets.jump_targets_by_scanning_lines(builtin_targets.regex_by_case_searching(
      _G._repeated_hop_state.last_chars, true, {})), 
    hop.opts)
  end
end

hop.setup({})
vim.api.nvim_set_keymap("n", [[f]], 
function()

  local char
  while true do
    vim.api.nvim_echo({ { "hop 1 char:", "Search" } }, false, {})
    local code = vim.fn.getchar()
    -- fixme: custom char range by needs
    if code >= 61 and code <= 0x7a then
      -- [a-z]
      char = string.char(code)
      break
    elseif code == 0x20 or code == 0x1b then
      -- press space, esc to cancel
      char = nil
      break
    end
  end
  if not char then return end

  -- setup the state to pickup in _G._repeatable_hop
  _G._repeated_hop_state = {
    last_chars = char,
    count = (vim.v.count or 0) + 1
  }

  vim.go.operatorfunc = "v:lua._repeatable_hop"
  -- return this↓ to run that↑
  return "g@l" -- see expr=true
end , { noremap = true, 
-- ↓ see "g@l"
expr = true})

this whole code can go anywhere, your init.lua or a separate lua source file