hl037_
hl037_

Reputation: 3907

How to do mark-like mapping in vim

The m normal command accepts a letter just after it to set a "letter" mark.

I would like to create a similar command that works across tabs... But my problem is with the binding : Is there a simple way to bind for example M<letter> to a function or a command or should I manually repeat all the possibilities ?

Upvotes: 0

Views: 664

Answers (1)

user16781553
user16781553

Reputation:

As romainl has already said, no.

Covering this for good measure (and in case someone else comes along later), you can only practically map upper-case letters. As is outlined in the documentation, lower-case marks are only valid within a single file. Upper-case ones, that the Vim docs calls "file marks", are valid from anywhere. Unless you have some dark magic function to resolve ambiguous file marks, you probably only need a single for loop mapping the upper-case letters, if you're going with the brute-force option.

That said, there are a couple alternatives here as well.

As far as I know, the only "dynamic" bit of a command is a count (or a range, but unless you want to map characters to a number (and handle ranges and other fun stuff:tm:), I don't recommend this approach:

" The <C-U> is required for all uses. If you want a function,
" you'd need :<C-U>call YourFunction()<cr>
nnoremap M :<C-U>echom v:count<cr>

See also :h v:count, which states:

Note: the <C-U> is required to remove the line range that you get when typing ':' after a count.

You can then run 26M, decode v:count as Z, and then do whatever fancy lookup from there.


The second alternative, and the one proposed by romainl and by far the most used one in cases like this (source: experience and lots of code browsing), is using a for loop to brute-force map letters:

for i in range(char2nr('A'), char2nr('Z'))
    exec 'nnoremap M' . nr2char(i) ':echo "This is where the appropriate function call goes"<cr>'
endfor

Which produces all 26 mappings.


And the final approach is abusing getchar(). This means a single mapping, but at the expense of doing additional processing:

func! Func()
    let c = getchar()
    echo c
    " Character processing (the `echo` isn't required) here
endfunc
nnoremap M :call Func()<cr>

You can decide which works for you, but I strongly suggest preferring option 2, as this gives you map timeouts and clear definitions, and more obvious conflict detection.

Upvotes: 2

Related Questions