automate and attach a VIM script to an event - vim

I have a small vim function say myFunc() defined in my .vimrc and have this function mapped to to keyword in normal mode say cl and i am successfully able to call this function whenever i type cl in normal mode, myFunc() is invoked.
Now I want to go one step further, I want this function myFunc automatically called whenever press i to go from normal mode to insert mode in vim
Please suggest how can I achieve that.

I think you want to use an auto command on InsertEnter.
autocmd InsertEnter * call MyFunc()
Noter user defined functions must start with a capital letter.
Take a look at :help autocmd and :help InsertEnter.

Related

Vim key binding to call a function with input from user

There might be a simple solution for this. I couldn't find any solution to it (I might be searching with wrong context)
Here is my requirement.
I wrote the below key mapping in vimrc. It should print the line "Hello user_name." n times, where n and user_name are the user input once the key is pressed.
autocmd FileType ruby nnoremap <expr> <C-h> :call FuncPrnt(<-syntax to pass input from user->)
function! FuncPrnt(count, uname)
let c=a:count
let i=0
while i<c
call append(line("."), "Hello ".a:uname.".")
let i+=1
endwhile
endfunction
On Pressing the key user enters 3 and 'Ironman'. The output would be like
Hello Ironman.
Hello Ironman.
Hello Ironman.
Thanks in advance
A simpler approach is to just use a non-<expr> mapping to prepare the Ex command without executing it:
nnoremap <C-h> :call FuncPrnt(,"")<left><left><left><left>
If you associate that with a filetype (such as "ruby" in your case), make sure you create a local mapping using <buffer>. Otherwise the mapping will be global and will work on every buffer and not only those with Ruby source files.
If you use an autocmd in your vimrc, make sure you wrap it in an augroup to prevent getting duplicated commands if you reload your vimrc.
Alternatively, you can add filetype mappings for Ruby in a file ~/.vim/ftplugin/ruby.vim which gets automatically loaded by Vim whenever a file of type Ruby is loaded. (That way you don't need to use explicit autocmds, Vim will take care of those details on your behalf.)
Got the answer. Just in case someone else is searching for similar solution
autocmd FileType ruby nnoremap <expr> <C-h> input("", ":call FuncPrnt(,\"\")<left><left><left><left>")
will print the command and waits for the user to edit. Once the user edits and enters it is executed
Thinking outside of the box a little bit (questioning the premise), perhaps the best in this case is to define a user-defined command instead of a mapping.
You can define one here with:
command! -buffer -bar -count=1 -nargs=1 FuncPrnt
\ call FuncPrnt(<count>, <q-args>)
That way you can use it with:
:3FuncPrnt Ironman
If you omit the count, 1 will be used. (You can pick a different default as the argument to -count=N.)
You can use Tab completion for FuncPrnt, so perhaps :3Fu<Tab> or even :3F<Tab> might be enough to complete the command.
This might end up being quicker or more convenient to type than <C-H>3<right><right>, since it doesn't involve moving your hand to the arrow keys.

Using "z=" in a mapping

If I use <Esc>[s1z=`]a in an inoremap mapping (jump to normal mode, find previous spelling error, replace it with the first choice, jump back to last edit and append), everything works fine. The problem is I often don't want the first spelling choice. If I remove the 1 I will be given the spelling menu, but the `]a seems to get swallowed up and lands me at the first character of the corrected word still in normal mode. The mapping itself shouldn't be looking for input, perse, as the z= itself should handle the menu entry. Indeed if I run these commands manually (without the 1, it works as expected. I have tried making named marks and jumping back to those, but it seems z= and everything after it gets consumed as one thing. Does anyone have any suggestion as to how to make the mapping continue after I make a spelling menu selection? Thanks.
I think that Vim stops processing the right-hand side of the mapping as soon as it presses z= because it's not a complete command (you have to provide the index of a suggestion in the menu for it to be complete).
The :normal command has the same issue:
:norm[al][!] {commands}
...
{commands} should be a complete command. If
{commands} does not finish a command, the last one
will be aborted as if <Esc> or <C-C> was typed.
As an alternative, you could invoke the feedkeys() function to press z=.
For example:
ino <c-j> <c-r>=<sid>fix_typo()<cr>
fu! s:fix_typo() abort
let spell_save = &l:spell
try
setl spell
call feedkeys("\e\e[sz=", 'int')
augroup fix_typo
au!
au TextChanged * call feedkeys('`]a', 'int')
\ | exe 'au! fix_typo'
\ | aug! fix_typo
augroup END
finally
call timer_start(0, {-> execute('let &l:spell = '.spell_save)})
endtry
return ''
endfu
This code installs a mapping in insert mode using the C-j key. You could use another key if you don't like this one.
The mapping calls the s:fix_typo() function which:
temporarily enables 'spell' to avoid the error E756
presses the keys Esc Esc [s z= to prompt the suggestions
installs a fire-once autocmd listening to TextChanged to press the keys `]a once you've selected a word in the menu
restores the original value of 'spell'

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.

Can I create an autocommand to be launched when I execute :update?

I would like to do some code reformatting whenever :update command is executed, is this possible?
I can't find any autocommand hook for updating, only for :w command.
:update basically is execute :write if buffer is modified, else do nothing. The same BufWritePre / BufWrite events apply to it (when the former case is true). That should be perfectly suitable for your reformatting trigger.
To only trigger on :update, but not on :write would require re-writing the :update command itself. For interactive use, that could be done via the cmdalias.vim plugin, which allows redefinition of lowercase built-in commands.

Vim - how to store and execute commonly used commands?

If I wanted to process a batch of text files with the same set of commands for example:
:set tw=50
gggqG
Can I save the above and run it with a shortcut command?
If you want to use it only once, use a macro as specified in some of the other answers. If you want to do it more often, you can include the following line in your .vimrc file:
:map \r :set tw=50<CR>gggqG
This will map \r to cause your two lines to be executed whenever you press \r. Of course you can also choose a different shortcut, like <C-R> (Ctrl+R) or <F12> or something.
The following in .vimrc will define a new command Wrap that does what you want.
command! Wrap :set tw=50 | :normal gggqG
Call it with :Wrap
As a very quick start, put this in your .vimrc:
" define the function
" '!' means override function if already defined
" always use uppercase names for your functions
function! DoSomething()
:set tw=50
gggqG
endfunction
" map a keystroke (e.g. F12) in normal mode to call your function
nmap <F12> :call DoSomething()<CR>
note: the formatted code above looks rather horrible, but lines starting with " are comments.
Other than macros, you can use argdo. This command will perform the same operation on all open files. Here is how you format all open files using :argdo and :normal:
shell> vim *.txt
:argdo exe "normal gggqG"|up
Before you go for writing a thousands-lines .vimrc (which is a good thing, but you can postpone it for a while), I think you might want to look at the plain recording, in particular you may consider using the qx (where x is any key) for recording, q to finish recording and #x to execute recorded macro.
Yes, the important word is macro
But it seems like a 'command' such as :set tw=50 would be better included in the .vimrc file so vim uses it every time you start it up.

Resources