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.
: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.