18

That is, when you hit the marks operator key ` or ' you get a list of the available marks - i.e. the list Vim gives from the ex command :marks. Then, when you press a letter to jump to the mark, you will be taken there - as usual. So if I want to jump to say mark m, with the normal mode command `m you would type:

  • `
  • the :marks window or similar would appear and you can see the available marks
  • m
  • cursor jumps to the m mark

For those people familiar with it, the ranger file manager already performs the exact way I would like Vim to regarding the usage of marks. Ranger is terminal file explorer that uses Vim key bindings and concepts, a ranger bookmark denotes a file and not a line and column position in a text file, but the concept is the same. Here is a screencast demonstration of ranger's marks feature that I want to make happen in vim.

Is it possible to do this in Vim, or is there a plugin that does this?

1
  • Referring :marks and then pressing a character mark to move there itself is a simple thing. It can't be simplified further. You may use mappings for that.
    – SibiCoder
    Jun 25, 2016 at 7:28

5 Answers 5

18

You can define a very simple custom mapping that lists the available marks and pre-populates the command-line with the right command stub, ready for you to type the desired mark name:

nnoremap <key> :<C-u>marks<CR>:normal! `

Note that this simply follows the same pattern as that famous mapping:

nnoremap <key> :ls<CR>:b<Space>

which can be expanded to other similar uses:

nnoremap <key> :undolist<CR>:u<Space>
6
  • thanks, its working nicely! this is cool because you can also set, as well as call marks, with the marks list in front of you, thanks Jun 25, 2016 at 9:31
  • Could someone, please, explain what's the deal with <C-u> in the nnoremap <key>... found in the answer above?
    – dsimic
    Sep 4, 2023 at 18:47
  • 2
    @dsimic it is the same deal as in every mapping where it is used: it removes any accidental range introduced by inadvertently pressing a number key before the mapping. The mapping works without it because it is not an integral part of the functionality but it is safer with it. In this case, 1. :help :marks throws an error if it is used with a range, 2. <C-u> removes any accidental range, 3. the mapping is safer.
    – romainl
    Sep 4, 2023 at 19:54
  • 1
    That would be :help c_ctrl-u.
    – romainl
    Sep 4, 2023 at 20:02
  • 1
    These days (since Vim 8.2.1978) you can use <Cmd> instead. See :help :map-cmd. Sep 5, 2023 at 14:25
5

This does exactly what my original question was

""""""""""""""""""""""""""""
" Ranger style marks command
"
""""""""""""""""""""""""""""
function! Marks()
    marks
    echo('Mark: ')

    " getchar() - prompts user for a single character and returns the chars
    " ascii representation
    " nr2char() - converts ASCII `NUMBER TO CHAR'

    let s:mark = nr2char(getchar())
    " remove the `press any key prompt'
    redraw

    " build a string which uses the `normal' command plus the var holding the
    " mark - then eval it.
    execute "normal! '" . s:mark
endfunction

nnoremap ' :call Marks()<CR>

This doesn't change the usage of using marks, i.e. setting then jumping to a mark, it simply displays the :marks listing when you hit the ' character for jumping to the mark.
Most of the time you will ignore it because you don't need the visual aid and its slower to look at something visually, but when you want a reference its there and it doesn't cost you anything in terms of learning a new mapping, extra keystrokes etc.

1
  • Nice approach! I went ahead and improved it further in my answer.
    – dsimic
    Sep 4, 2023 at 22:16
5

A variation on your own response is to install fzf.vim and then bind to :Marks, e.g.:

nnoremap ` :Marks<CR>

This has the benefit that it will show up in fzf's fuzzy search window.

(Caveat: It does require pressing <Enter> after you've found the item.)

2

Below is an excerpt from my ~/.vimrc that contains the vimscript code I implemented by building upon the very good "no new mappings" idea from the already existing answer provided by @the_velour_fog.

I improved the idea and the implementation further to be almost something like "change nothing". Just hit ' or ` as usual, and you'll get the list to select a mark from, but nothing else changes, not even the error messages displayed when trying to jump to unset or unknown marks.

Actually, if you press ' + a quickly, for example, or even ' + Esc depending on the configured ttimeoutlen value, you may even not notice the list of marks being displayed for a fraction of a second, but still have the desired jump operation performed or canceled, or the original error message displayed. That's how much the original behavior remains unchanged.

Here's the vimscript code:

" Display a list of marks and allow their easy selection, without
" remapping any keys or changing the original vim behavior, down
" to the error messages produced for unknown marks
"
function ListSelect(command, jump)
  execute a:command
  echohl Question
  echo "Enter mark (ESC to cancel): "
  echohl NONE
  let mark = nr2char(getchar())
  redraw
  if mark !=# "\e"
    try
      execute "normal! g" .. a:jump .. mark
    catch
      echohl ErrorMsg
      echo substitute(v:exception, "^Vim(.*):", "", "")
      echohl NONE
    endtry
  endif
endfunction

nnoremap <silent> ' :call ListSelect("marks", "'")<CR>
nnoremap <silent> ` :call ListSelect("marks", "`")<CR>

As visible in the vimscript code and as already described above, this version retains the ability to use Esc to cancel the whole operation, and it still produces the same E20: Mark not set and E78: Unknown mark error messages, without throwing any "executing function failed" errors at the user.

This version also produces a prompt message that looks just like all such messages produced by vim itself, furthering the "change nothing" approach.


Below is an improved version of the above-provided vimscript code, which still follows the same "change nothing" approach.

This improved version mainly brings some vimscript-specific programming style improvements, such as using a script-local function and <SID> to avoid "polluting" the global space, and using <Cmd> for so-called "command mapping", which neatly executes commands without changing the current mode.

This version also extends its support to visual mode, which unfortunately requires a small workaround that's described further in the comments below.

Here's the improved vimscript code:

" Display a list of the currently known marks and allow a mark to be
" selected from the list easily, without mapping any additional keys
" or changing the original vim behavior, down to still producing the
" original error messages for non-existent marks
"
" NOTE: A workaround is required in visual mode to produce the right
"       error message, because the message isn't displayed if jumping
"       to the non-existent mark is actually executed in visual mode,
"       which all works as expected in normal mode
"
function s:SelectMark(command)
  execute "marks"
  echohl Question
  echo "Enter mark (ESC to cancel): "
  echohl NONE
  let mark = nr2char(getchar())
  redraw
  if mark !=# "\e"
    try
      if mode("v:true") ==? "v" && line("'" .. mark) ==# 0
        throw "E20: Mark not set"
      endif
      execute "normal! " .. a:command .. mark
    catch
      echohl ErrorMsg
      echo substitute(v:exception, "^Vim(.*):", "", "")
      echohl NONE
    endtry
  endif
endfunction

nnoremap ' <Cmd>call <SID>SelectMark("'")<CR>
nnoremap ` <Cmd>call <SID>SelectMark("`")<CR>

xnoremap ' <Cmd>call <SID>SelectMark("'")<CR>
xnoremap ` <Cmd>call <SID>SelectMark("`")<CR>

I'll investigate further why the above-described workaround is needed, and possibly submit a patch for vim upstream.

-1

https://github.com/Yilin-Yang/vim-markbar is worth looking at. It's got a wonderful demo.

1
  • 3
    Hi Josh. Could you expand on this a bit and show a bit of what the plugin does so a reader can be informed about it before they go to the link? There's similar answers here that show a plugin and go over use on this question already.
    – Dom
    Jun 10, 2021 at 15:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.