Is it possible to map to execute normal command? - vim

The following command appears to invoke the desired function.
:execute "normal \<Plug>VimwikiAddHeaderLevel<CR>"
However, putting it inside a mapping seems to cause problems.
:nmap <buffer> = execute "normal \<Plug>VimwikiAddHeaderLevel<CR>"
Here's the output when I type =.
E114: Missing quote: "normal \<Plug>VimwikiAddHeaderLevel
E15: Invalid expression: "normal \<Plug>VimwikiAddHeaderLevel
Is there some special syntax that would allow me to perform this mapping?

You don't enter command-line mode (for :execute) from the normal mode mapping; the : is missing.
The <Plug> and <CR> are already evaluated by the mapping; the double quotes do not protect them. The <CR> submits the (incomplete, as Vim hasn't seen the trailing ") command-line, and that causes the E114.
After escaping < as <lt>, you still need another <CR> to conclude the :execute command.
:nmap <buffer> = :execute "normal \<lt>Plug>VimwikiAddHeaderLevel\<lt>CR>"<CR>
As I've noted in your other question, you need a :for loop if you really want to work around the plugin's failure to accept a count. Though it would be possible to do all that inline in the mapping's right-hand side, separating the loop into a separate :function is highly recommended, exactly to avoid such escaping issues. Inside a function, the plugin invocation is a simple
:execute "normal \<Plug>VimwikiAddHeaderLevel"

Related

inoremap: variable timeoutlen

I have two remaps in my .vimrc for the insert mode:
inoremap jk <ESC>
inoremap {<CR> {<CR>}
The first remap should have a short timeoutlen, whereas the latter should have no timeout at all. Reason: I need a timeout for the first remap, as jk might be used as regular characters. The latter on the other hand is code completion, where a timeout makes no sense.
Is it possible to assign different timeoutlen's for different remaps? Thanks & BR
One way to extend the timeout of your second mapping is to actually only map <CR> and then use an expression to check that it's being typed after a { character.
The behavior is somewhat different from a two-character mapping in that the mapping will also work if you're typing a <CR> after a { that was already there, which might be acceptable to you (or might even be exactly what you wanted.)
Since you're using an expression to do checks, you can do additional checks such as only applying the mapping if you're typing the <CR> at the end of a line (so you avoid it if you're using it to split an existing long line.)
A possible implementation of that would be:
inoremap <expr> <CR>
\ col('.') ==# col('$')
\ && getline('.')[col('.')-2] ==# '{'
\ ? "\<CR>}\<C-O>O"
\ : "\<CR>"
We're using a ternary operator here to produce a different output based on the condition holding or not. If it doesn't, we simply map back to the keystroke itself, so it keeps working as it usually does in all other contexts.
For the part that inserts a closing curly brace, I also added a CTRL-O O to the end, so after inserting the brace, it will add a new line before it and leave the cursor in an indented column inside the block. I hope you'll find this helpful, but feel free to disregard that part if it's not really what you had in mind.

vim: Bind leader key to open .vimrc in a different path

I have my .vimrc in a different path, that I source from my main ~/.vimrc (so I can share same settings across Windows, bash on Windows, etc).
I'm trying to write something in the .vimrc in question, that would make a hotkey for editing said .vimrc, without hard coding the path.
What I currently have is this:
let g:vimrc_path = expand('<sfile>')
:map <Leader>v exec(":e " + g:vimrc_path + "<CR>")
But this doesn't seem to do anything. I've verified that g:vimrc_path is the right value, and that the <Leader>v ends up being called by subbing in echo messages, but I'm not wrapping my head around why the variable I'm trying to define doesn't get expanded correctly.
String concatenation is done with ., not with +, which performs coercion into numbers and addition. But :execute takes multiple arguments (which it space-separates), so you don't actually need this here.
You should use :noremap; it makes the mapping immune to remapping and recursion.
Also, I doubt you need visual and operator-pending modes (:help map-modes), so define this just for normal mode.
:exec[ute is an Ex command, so for a normal-mode mapping, you need to first enter command-line mode. So :exec 'edit' instead of exec ':edit'.
Also, this is not a function (though Vim 8 now also has execute()), so the parentheses are superfluous.
The <silent> avoids the printing of the whole command (you'll notice the loading of the vimrc file, anyway); it's optional.
The fnameescape() ensures that pathological path names are also handled; probably not necessary here.
let g:vimrc_path = expand('<sfile>')
nnoremap <silent> <Leader>v :execute 'edit' fnameescape(g:vimrc_path)<CR>
Alternative
As the script path is static, you can move the variable interpolation from runtime (mapping execution) to mapping definition, and get rid of the variable:
execute 'nnoremap <Leader>v :edit' fnameescape(expand('<sfile>')) . '<CR>'
Strings in vimscript are concatenated with ., not with +. For example:
:echo "Hello"." world!"
will echo
Hello world!
If you were to type
:echo "Hello" + " world!"
vim would echo
0
This is because the + operator is only for numbers, so vim attempts to cast these strings to numbers. If you were to run
:echo "3" + "1"
vim would echo "4".
So basically, you just need to change
:map <Leader>v exec(":e " + g:vimrc_path + "<CR>")
to
:map <Leader>v exec(":e ".g:vimrc_path."<CR>")
Another problem you might have not seen is that "<CR>" evaluates to the literal text "<CR>", so it only messes up your function. If you want a literal carriage return, you would need a backslash. However, you definitely do not want to do this! Seriously, try it out and see.
You can see the issue. It looks for a file that has a literal carriage return at the end of the filename! There is a very simple fix though. Remove the "\<cr>" completely. Since :exec runs ex commands by default, the carriage return (and the colon too for that matter) are unnecessary.
Also, as a nitpick,
The parenthesis are not needed for the "exec" function, and
Use nnoremap instead to avoid recursive mappings.
Taking all of this into consideration, I would simplify it to
:nnoremap <Leader>v :exec "e ".g:vimrc_path<cr>

Prevent map from breaking on motion command error

The idea is to have a map that allows me to fold blocks of code enclosed in curly braces.
nnoremap zff 0f{zf%
This works as expected but only on the opening brace.
The following version seems to work as long as { and } are on the same line. Should they be on different lines though the cursor only jumps to the opening { and no fold is created.
nnoremap zff 0f{f}zf%
edit:
The problem appears to be that once there is an error in one of the motion commands the map breaks.
:silent! prevents ex commands from breaking a map in case of an error. Is there an equivalent for motion commands?
Your first mapping should work, unless you have a filetype detection or syntax problem that prevents proper pair-matching.
Your second mapping can't work because f (and FtT) only works on the current line. Alternatives:
f{v/}<CR>zf
f{zf/}<CR>
But you can use zf with text-objects:
zfi{
zfat
zfip
so… why bother with a mapping?
You're right that an error in a command sequence breaks the sequence, and this is usually right. If you want to continue even in case of errors, just execute the commands separately through :normal!. This can be chained in a single command-line via :execute:
nnoremap zff :exe 'normal! 0f{' | exe 'normal! f}' | exe 'normal! zf%'

don't stop mapping on not found

There is a important part of vim mapping:
:map <C-j>r f{^
I noticed, that when the { character is not found in the line, then the rest of the mapping is not executed.
Is there a way, how to force the mapping to continue even though the search character is not found? (In this case execute the return to the beginning of the file)
Yes, Vim aborts on an error in a mapping. You can use :silent! normal! ... to continue regardless of errors. With a sequence of :normal! commands, you can even check (e.g. whether the cursor moved) and react to it. Sketch:
:map <C-j>r :exe 'normal! maf{'<Bar>if getpos("'a") == getpos(".")<Bar>echo "no move"<Bar>endif<CR>
Note that this doesn't scale well. You're better of moving the commands into a :function.
Also, you should probably use :noremap; it makes the mapping immune to remapping and recursion.
The literal answer to this question would be:
:map <C-j>r :silent! exe "normal f{^"<CR>

Why :execute is not working as expected in Vim: LearnVimscriptTheHardWay

I am trying to learn Vimscript from LearnVimscriptTHW and I came across the use of :execute and :normal.
Example from LVSTHW:
:normal! gg/a<cr>
From book:
The problem is that normal! doesn't recognize "special characters" like <cr>. There are a number of ways around this, but the easiest to use and read is execute.
Now when I use :execute "normal! gg/a<cr>" it doesn't work for me. It doesn't search for a(char) in my current file instead of that it just executes gg and than do nothing but if is use :execute "normal! gg/a\r" it works and successfully highlights the char a in my file.
I also tried the below following ways but none of them worked.
:execute "normal! gg/a"<cr>
:execute normal! gg/a<cr>
:execute "normal! gg/a<cr>"<cr>
From the book it seems that execute internally converts <cr> to \r. So, why it is not happening in my case.
You need to escape the <cr> with a backslash: exe "norm! iHello\<cr>World"
A look at :help :execute may be useful, here. You must escape any <CR> or <ESC> with a backslash when you use them in an expression: \<CR>, \<Esc>… These notations are valid only in mappings, if I understand correctly.
Another option is to input the key "literally":
i get into insert mode, unneeded if yoou are on the command line
<C-v>
<CR>
You'll obtain a single character that looks like ^M and doesn't need to be escaped.

Resources