.vimrc function - How to call "normal" mode keypress of equals (=) key - vim

I am trying to write a function that I can call from a command, that will allow me to re-set all open panes to equal size. I started with this:
command Equal execute "normal! <C-w>="
Which allows me to call
:Equal
Which works the way I would expect it to. However, I need to add a little more functionality to this (an if statement, etc), so I need to declare it as a function. However, I cannot figure out how to call the "equals sign" key from within my function. Here is what I have:
command Equal call EqualizePanes()
function! EqualizePanes()
execute "normal! <C-w>="
endfunction
I know that my function declaration and method of calling it is correct, because I have replaced the contents of my function with something simple, like "echo foobar", which works as expected. However, as it stands, when I call :Equal, nothing happens. I have tried other things like:
command Equal call EqualizePanes()
function! EqualizePanes()
normal <C-w>=
endfunction
as well, without any luck. Any thoughts on what I am doing wrong here? Thanks in advance for your help.

Note that there's a special :wincmd Ex command that you can use instead of :normal; this avoids the :execute that is normally necessary to process the \<C-w> notation:
command Equal wincmd =

The problem is that normal doesn't parse special character sequences like <C-w>. So escape
command Equal call EqualizePanes()
function! EqualizePanes()
execute "normal! \<C-w>="
endfunction
:help expr-quote
:h execute
:h normal

Related

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.

vim function only works properly the first time

I wrote a function in vim to insert text in "paste"-mode. If I leave the insert mode, the script also leaves the paste mode (set nopaste). Therefore I used the autocommand InsertLeave.
The Problem is, that the "set paste" command works only the first time I call the function. If I want to call it once more I have to restart vim.
This is the vim function:
function Paste_from_clipboard()
execute "normal! :set paste\<CR>\<Esc>o"
execute "startinsert"
autocmd InsertLeave * execute "normal! :set nopaste\<CR>"
endfunction
map <Leader>p :call Paste_from_clipboard()<CR>
What did I do wrong?
I think you are misunderstanding how VimScript works. Every line (be it
on .vimrc, a plugin, a syntax file) is just an ex command, where the
starting : is not needed. So when you write this:
execute "normal! :set paste\<CR>\<Esc>o"
You're basically calling a ex command (:exec) which calls another ex
command (:normal) which then simulates normal mode to what? To call
yet another ex command (:set) and using key codes to execute it. Why?
You can just use the final ex command directly:
set paste
This is also happening in your auto command. Also, it is important to
notice that you're recreating an auto command every time you call your
function. A simple fix is then to remove your extra commands and move
the auto command outside the function, so it is created only once. The
execution will then happen every time the event is triggered (without
another event listener being created over and over.
function Paste_from_clipboard()
set paste
startinsert
endfunction
autocmd InsertLeave * set nopaste
map <Leader>p :call Paste_from_clipboard()<CR>
Check the :h pt for the pastetoggle option. It might be an
alternative to what you are doing.

Function arguments not evaluating

I'm trying to set up a couple of maps to quickly go through merge conflicts. Here's my code:
func! DiffAccept(w)
diffget a:w
diffupdate
normal ]c
endfunc
noremap dh :exec DiffAccept("//2")<CR>
noremap dl :exec DiffAccept("//3")<CR>
Every time I try to use this I get "No matching buffer for a:w". I'm clearly using this variable wrong, but it acts as expected when I change the line to "echo a:w".
Vim's evaluation rules are different than most programming languages. You need to use :execute in order to evaluate the (function argument) variable; otherwise, it's taken literally (as a buffer name):
execute 'diffget' a:w
PS: Prefer using :normal! (with !); this avoids interference from mappings.

How to create an alias for ctags in vimscript

I have a function that is invoked based on a simple key mapping
function! JumpToDefinition()
let filetype=&ft
if filetype == 'coffee'
exe '<C-]>'
endif
endfunction
This works when I manually do <C-]> but when I try to "exe" it above I get a "trailing whitespace" error.
How can I invoke this in a standalone function like I have above?
Note that :execute runs the resulting expression as an Ex command,
which isn't probably what you want since there is no <C-]> Ex command. You
should be using :normal.
However, to be able to use these "special keys", instead of the characters
they represent, you have to pay attention to three things:
The correct way to represent them is with a backslash \<xxx>. Check the
help for expr-string.
Use double quotes, not single quotes
:normal accepts commands, not an expression like :execute
So, from items 1 and 2 above we know that "\<C-]>" should be used, but you
can't put this in front of :normal. Well, you can, but then it will be
executed as "quote, backslash, C, ...". The solution is to go back to using
:execute, this time to build the string with the visible "\<xxx>" in front
of :normal, which will be expanded to the actual character and executed.
:exe "norm \<C-]>"

How can I call an editor command from a vimscript?

I want to remove an unwanted scrollbar from taglist. I created a function and a command like this:
function s:TlistWaToggle()
normal :TlistToggle<cr> " <- this does not work
set guioptions-=r
endfunction
command! -nargs=0 -bar TlistWaToggle call s:TlistWaToggle()
I want to wrap the call to :TlistToggle together with the command to remove the right scrollbar (I have that setting of course, but it always reappears, so this is a workaround). Currently my :TlistWaToggle doesn't do anything. How can I make it work?
Vim script uses ex commands, and apparently :TlistToggle is an ex command…
function! s:TlistWaToggle()
TlistToggle
set guioptions-=r
endfunction
In addition to #sidyll's answer: :normal is not a :*map, it accepts only raw character strings. Correct command will be execute "normal! :TlistToggle\<CR>" (or execute "normal! :TlistToggle\n"). Note that you should not use non-banged version in your scripts.
I don't think you will ever use :normal! to execute an ex command, but my answer would be useful when you want to pass any other special character. It also applies to feedkeys() call.
By the way, comments and other commands will be considered part of string passed to :normal command.

Resources