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

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.

Related

Is it possible to map to execute normal command?

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"

Vim search without overwriting "/ register

I would like to use a slash (/) for a search during a vimscript, but I don't want to overwrite the "/ register. How do I do this?
In my particular example, I am working on a custom vim text object for LaTeX, a$, to specify the region between and including the previous and next dollar signs ($ characters, which delimit math mode in LaTeX). I'm following a guide found here which suggests using a vnoremap and an omap command, which is a simple enough approach. What I would like to write is:
vnoremap a$ :<C-U> execute "normal! ?\\$\rvN"<CR>
omap a$ :normal va$<CR>
However, this implementation has a fatal flaw: the "/ register becomes overwritten with the search for the dollar sign character, clearing any previous search and causing confusion and inefficiencies when trying to use n or N next.
Save #/. Search. Restore #/. You might not be able to squeeze all that into a mapping so I'd recommend a function instead:
function! VisualAroundDollar()
let search = #/
execute "normal! ?\\$\rvN"
let #/ = search
endfunction
vnoremap a$ :<C-U>call VisualAroundDollar()<CR>
omap a$ :normal va$<CR>
May I suggest to consider the command keeppatterns
As :h keeppatterns says "Execute {command}, without adding anything to the search history" it may help you to build you mapping
If $ are always on the same line then it is often best to use f & t to make your custom text-objects.
xnoremap a$ :<c-u>normal! F$vf$"<cr>
onoremap a$ :normal va$<cr>
If your text-object goes over multiple lines then you need to do some kind of searching. Here is an example using search() which does not change the search register.
xnoremap a$ :<c-u>call search('\$', 'bcW')<cr>m<:call search('\$', 'W')<cr>m>gv
onoremap a$ :normal va$<cr>
As #ViVeteran stated you can also use :keeppatterns with / or ? to avoid changes to the search register and history.
xnoremap :<c-u>execute "keeppatterns normal! ?\\$\<cr>v/\\$"<cr>
onoremap a$ :normal va$<cr>
Note: :keeppatterns requires Vim 7.4.083+
For more complicated custom text-objects there is vim-textobj-user. You may want to look into vim-textobj-latex which use vim-textobject-user to create an assortment of Latex specific text-objects.
For more help see:
:h Operator-pending
:h :map-modes
:h c_CTRL-U
:h search()
:h :keeppatterns
My SearchAsQuickJump plugin provides an implementation of this. You can use the normal search (/{pattern}), but conclude it (in GVIM) via <S-CR> instead of <CR>. That will search but keep the original search pattern. It also has commands that correspond to the built-in * and # searches.

how to get matchit to work with % with key mapping on vim?

i'm trying to get vim to select between matching html tags including the parent tags..
Following are two mappings i tried..
nnoremap <leader>h <s-v><s-5>
or
nnoremap <leader>h <s-v>%
but nothing seems to work. the problem is '%' doesn't perform the extended(with the matchit plugin) action which is selecting the matching closing html tag..
You can use :normal! and :execute to run normal commands without remapping. e.g.
nmap <leader>h :execute "normal! V"<cr>%
This command is really similar to using the "a tag block", at, text-object. e.g. vat. Of course you can do what you are doing and just execute V% as it is the same number of characters as <leader>h.

Programmatically equalize windows inside a function

I've got the following vimscript function:
function! WindowCommand(cmd)
execute a:cmd
if !g:golden_ratio_enabled
normal <C-w>=
endif
endfunction
And I use it like so:
map <space>w/ :call WindowCommand(':vs')<cr>
It's supposed to equalize the windows, but only if g:golden_ratio_enabled is 0, otherwise it should do nothing.
It doesn't work, though, and I'm not sure why, because the following DOES work:
map <space>w/ :vs<cr><C-w>=
What am I doing wrong here?
There are a couple fixes. Thankfully, the fix is really simple
For whatever reason, normal <C-w>foo does not work; You must use wincmd instead. From :h wincmd
*:winc* *:wincmd*
These commands can also be executed with ":wincmd":
:[count]winc[md] {arg}
Like executing CTRL-W [count] {arg}. Example: >
:wincmd j
Moves to the window below the current one.
This command is useful when a Normal mode cannot be used (for
the |CursorHold| autocommand event). Or when a Normal mode
command is inconvenient.
The count can also be a window number. Example: >
:exe nr . "wincmd w"
This goes to window "nr".
So in this case, you should do
wincmd =
Alternatively, you could enter a literal <C-w> character, by typing <C-v><C-w>. In your vim session, this character will be displayed as ^W.
To execute actions with <notation>, use instead:
:exe "normal \<notation>"
I use it a lot to debug mappings.
But in this case, prefer indeed wincmd.

map execute command vim

I found the following execute command to be useful in vim:
:execute "normal! mqA;\<esc>`q"
it goes to normal mode, then it makes a mark "q" at cursor position,
goes to end of the line and adds a semicolon ";", then it goes to
normal mode again and returns to the original cursor position.
How could I map all this command to a key called "scc"?
I have tried:
imap scc <Esc>:execute "normal! mqA;\<esc>`q"<CR>
however it didn't work. Thanks.
You don't need :execute - normal, you can simply do (and use the "noremap" form):
inoremap scc <Esc>mqA;<Esc>`q
But your map keys are not very good chosen(?), try e.g. <F3> for function key 3.
Others have dealt with the core problem but I should had that, instead of creating an alphabetical mark, you could use a "context mark":
inoremap <something> <Esc>m`A;<Esc>``
Using an alphabetical mark is not wrong, mind you, but I think they are more useful elsewhere.

Resources