user755921
user755921

Reputation:

Is it possible to cycle around marks in vim?

I am starting to use [' and ]' to jump between my marks in a file, as mentioned here:

http://vim.wikia.com/wiki/Using_marks

However, when I get to the last mark in the file these commands don't wrap around to the top.

I searched around for "cycling" or "wrapping" when it comes to navigating marks but everything I see mentions Ctrl-o and Ctrl-i which is nice but doesn't answer my question.

Is it possible to set an option to wrap top-to-bottom or bottom-to-top when using these shortcuts?

Upvotes: 4

Views: 382

Answers (1)

Brett Y
Brett Y

Reputation: 7678

You can create a function to check if you have moved, and if not then go to the beginning of the file and call ]' again. Like this:

nnoremap ]' :call CycleMarksForward()<cr>
function! CycleMarksForward()
  let currentPos = getpos(".")
  execute "normal! ]'"
  let newPos = getpos(".")   
  if newPos == currentPos
    execute "normal! gg]'"
  endif
endfunction

You'll need to the same thing for [` ]` and [', although there is probably a way to come up with a generic solution.


Fleshed out:

nnoremap <silent> ]' :call CycleMarks("]'")<cr>
nnoremap <silent> [' :call CycleMarks("['")<cr>
nnoremap <silent> ]` :call CycleMarks("]`")<cr>
nnoremap <silent> [` :call CycleMarks("[`")<cr>
function! CycleMarks(arg)
  let currentPos = getpos(".")
  execute "normal! " . a:arg
  let newPos = getpos(".")
  if newPos == currentPos
    if a:arg == "]'" || a:arg == "]`"
      execute "normal! gg0" . a:arg
    else
      execute "normal! G$" . a:arg
    endif
  endif
endfunction

Note: this solution does not handle marks on the first and last line very well, i.e. marks on the last line will be skipped when cycling backwards and marks on the first line will be skipped when cycling forward.

Upvotes: 3

Related Questions