vim function only works properly the first time - vim

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.

Related

Close Multiple Buffers Programatically in Vim

I'm trying to write a function that allows me to toggle TPope's Vim Fugitive git-log viewer.
The plugin allows you to view the history of your project, by opening up git objects as buffers that begin with fugitive://
I'm trying to write a function in vimscript that will allow me to close all of these buffers at once, when they're open. The function currently looks like this, and is quite close to working:
function! ToggleGLog()
if buflisted(bufname('fugitive'))
:cclose
:bd fugitive*<C-a><cr>
else
Glog
endif
endfunction
command! ToggleGLog :silent :call ToggleGLog()
nnoremap <silent> <leader>gl :ToggleGLog<CR>
The problem that I'm encountering is that the <C-a><cr> portion of the function doesn't work. Normally, the <C-a> would expand the * selector to match all the buffers that start with "fugitive."
How can I write this so that the names of those buffers are automatically expanded and the :bd command will close them all?
How about the following?
execute "normal! :bdelete fugitive*\<C-a>\<CR>"
normal lets Vim run the command to its right as if you typed it, including keys like <C-a>. But as the latter is somewhat special, it needs to be interpreted; this is what execute is doing here. (See the end part of :help normal.)

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.

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.

open a completion popup from normal mode

Gived this script (packages suggestion was simplified, original takes care of <cword>)
function! CompleteImport()
let packages = ['java.util.Vector','java.lang.String']
call complete(col('.'),packages)
return ''
endfunction
inoremap <F8> import <C-R>=CompleteImport()<CR>
while on insert mode you can add an import and choose between suggested packages pressing F8
But I want to be enable to reach that popup selection from normal mode
function! InsertImport()
exe "normal iimport \<C-R>=CompleteImport()\<CR>"
"this commented line would work too
"exe "normal i\<F8>"
endfunction
map <Leader>ji :call InsertImport()<CR>
so from normal mode ,ji (stands for java import) add an import to word under cursor if it is found
(Move to right position is not a problem so I ommit here)
By now ,ji adds first suggestion from popup and exists insert mode
I have tried :startinsert but no luck.
see on http://vimdoc.sourceforge.net/htmldoc/eval.html#:execute there is a suggested code:
:execute "normal ixxx\<Esc>"
but that final Esc doesn't matter at all (for my vim install at least) This do exactly the same for me:
:execute "normal ixxx"
I would think this is not possible if I haven't found that on docs. So, it's possible to stay on a popup calling from a function?
Other interested docs:
http://vimdoc.sourceforge.net/htmldoc/various.html#:normal
http://vimdoc.sourceforge.net/htmldoc/insert.html#:startinsert
:startinsert usually is the right approach, but it indeed gives control back to the user, so you cannot automatically trigger the completion.
Through the feedkeys() function, you can send arbitrary keys "as if typed". This allows you to start insert mode and trigger the completion:
function! InsertImport()
call feedkeys("iimport \<C-R>=CompleteImport()\<CR>", 't')
endfunction
nnoremap <Leader>ji :call InsertImport()<CR>
PS: You should use :noremap for the normal mode mapping, too; it makes the mapping immune to remapping and recursion.

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