How to Override/Redefine Vim Search Command - vim

I need to override/redefine Vim's search operator "/" to also execute "zszH" after the search to center the search results on the screen horizontally.
For example, I want to enter: /varchar and have the search results (i.e., the string "varchar") displayed in the middle of the scren horizontally.
I can do that now by manually entering "zszH" after each search, but that is very tedious.

You can use the CmdlineLeave event. Add the following to your vimrc
augroup RecenterSearch
autocmd!
autocmd CmdlineLeave [/?] call feedkeys('zszH', 't')
augroup END
Note: CmdlineLeave requires Vim 8.1
Or you can map <cr>:
cnoremap <expr> <cr> "\<cr>" . (getcmdtype() =~ '[?/]' ? "zszH" : '')
Some mappings which might be helpful:
nnoremap n nzszH
nnoremap N NzszH
If you do not have a new enough version on Vim then maybe look into 'wrap' or create a mapping
For more help see:
:h CmdlineLeave
:h :autocmd
:h feedkeys()
:h expression-mapping
:h getcmdtype()

Related

How to do Vim mapping on help page only

I would like to go-to a tag when pressing enter (instead of clicking with the mouse when mouse=a) or pressing ctrl-], which is a bit of a stretch for me. Is it possible to do the mapping in the help section only, such as:
:nnoremap *help* <CR> <C-]>
I do exactly that in an ftplugin for :help files: put your mapping in ~/.vim/after/ftplugin/help.vim and use <buffer>:
nnoremap <buffer> <CR> <C-]>
Create a buffer-local mapping when a help file is loaded:
:autocmd BufReadPost $VIMRUNTIME/doc/help*.txt nnoremap <buffer> <CR> <C-]>
If the "help page" you meant is vim doc/help, they have ft=help. You can verify it by :echo &ft or :set ft?.
Then it is easy if you want to create mapping only for those filetypes. You can do it using autocommand:
autocmd FileType help map....
If you want it to be buffer local mapping, you add <buffer> in mapping.

How to avoid remap in vim

I have the following on my .vimrc
au FileType ruby nnoremap <expr> <leader>t ':!rspec ' . expand('%') . ':' . line('.')
This executes rspec on the line specified, and gives me option to edit the line before pressing enter. But I have to be on the test file so it get the file name and line number correctly.
While developing I run nnoremap <leader>t :!rspec some/spec/file.rb:123 manually to run the test I want from anywhere in the code. So I can code and fire the test without need to visit the test file.
The problem is that if I visit another ruby file the mapping in .vimrc runs again and I loose the nnoremap command I used before. Is there a command to only map (in normal mode) if there isn't already a map for that sequence?
Regards,
This should be a buffer-local mapping. Use <buffer>:
au FileType ruby nnoremap <buffer> <expr> <leader>t ':!rspec ' . expand('%') . ':' . line('.')
We can do better!
Use an augroup and make is self clearing to make it safe to re-:source.
augroup ruby_testing
autocmd!
autocmd FileType ruby nnoremap <buffer> <expr> <leader>t ':!rspec ' . expand('%') . ':' . line('.')
augroup END
Even better forgo the autocmd and put this mapping in the after directory. Add the following line to ~/.vim/after/ftplugin/ruby.vim:
nnoremap <buffer> <expr> <leader>t ':!rspec ' . expand('%') . ':' . line('.')
For more help see:
:h :map-local
:h :augroup
:h after-directory
Vim has the :help :map-<unique> modifier which makes the mapping fail if such mapping already exists.
au FileType ruby nnoremap <unique> <expr> <leader>t ...
You can suppress the error message with :silent!:
au FileType ruby silent! nnoremap <unique> <expr> <leader>t ...
Alternatively (and this is slightly better because it doesn't suppress any other errors in the mapping definition, like syntax errors), you could explicitly check for the mapping's existence via maparg():
au FileType ruby if empty(maparg('<leader>t', 'n')) | nnoremap <expr> <leader>t ... | endif
Note that this literally implements that (I understand) you're asking for; i.e. the first Ruby file will define the mapping, and any subsequent Ruby files are ignored; the mapping will always use the first file's name and line number. If you instead want to have different right-hand sides for the same mapping, depending on the currently edited file, the solution is a buffer-local mapping as per #PeterRincker's answer. But with that, you have to be inside the original Ruby buffer to trigger the correct mapping.
A remedy for that might be to recall the executed command-line from the command-line history (should happen automatically for your incomplete mapping, else via histadd()), so that you can easily recall the command from another file.

How to autoupdate vimgrep search result in quickfix window?

How to autoupdate search vimgrep results from quickfix window after file is autoudpated due to change?
I use :vim/pattern/% to search and put result in quickfix window.
You can always do <up> on the command line with a prefix of :vimgrep to make searching history easier. You may also want to check out q: and the use ?// to search for the command to re-execute.
Assuming the quickfix title is set correctly, you can use following the command:
:execute get(getqflist({'title':1}), 'title')
This however I am not certain this will work with all :grep/:make commands. You also need a newer Vim version to get the Quckfix list title (Vim 8+ I think).
If you find yourself doing this often you may want to bind a mapping or command.
command! -nargs=0 -bar QFRefresh execute get(getqflist({'title':1}), 'title')
Now how to add do this automatically? We can use FileChangedShellPost autocmd to run our QFRefresh command once a file change has been detected. Add the following to you vimrc file:
augroup QFRefresh
autocmd!
autocmd FileChangedShellPost * if get(b:, 'qfrefresh_auto', 0) | QFRefresh | endif
augroup END
command! -nargs=0 -bar QFAutoRefreshToggle let b:qfrefresh_auto = !get(b:, 'qfrefresh_auto', 0) | echo b:qfrefresh_auto ? 'Auto Refresh' : 'No Auto Refresh'
Now you can use :QFAutoRefreshToggle to toggle refreshing a file.
Note: As stated before QFRefresh uses the quickfix's title to get the quickfix command. If the title is not set correctly a refresh may not work correctly. Also I am not sure what guarantees Vim has on triggering FileChangedShellPost. You can force a check via :checktime command.
For more help see:
:h getqflist()
:h :execute
:h :get
:h q:
:h cmdwin
:h c_Up
:h FileChangedShellPost
:h :checktime

Automatically call HTMLBeaufity when exiting Insert mode in Vim

I'd like to automatically format html and js code when I exit insert mode. Currently I have ctrl f mapped to format the current file in my vimrc:
map <c-f> :call JSBeautify()<cr>
Is there a way I can trigger this command each time I exit insert mode?
Thanks
Try to put this
augroup AuJsBeautify
au!
au InsertLeave * call JsBeautify()
augroup END
in your .vimrc.
To know more about autocommands, read :h 40.3 and :h autocommand.
Or if you prefer mapping, you can just map it on your Esc
inoremap <Esc> <Esc>:call JsBeautify()<cr>

How to map tab to regular space only for fortran files on vim

I've switched from Emacs to Vim and when I edit fortran (.f) files, I'm used to hit tab on a new line. On my machine the indentation is fine, but on other machines, the indentation is off, how can I tell vim to map the tab key to a single space only on fortran files?
You need to do 2 things:
create a mapping local to a specific buffer by using the <buffer> option for inoremap.
load the mappings for just a specific filetype.
This can be done via an autocommand in your ~/.vimrc like so:
augroup FortranMappings
autocmd!
autocmd FileType fortran inoremap <buffer> <tab> <space>
augroup END
The other way option is by creating a filetype plugin. (see :h ftplugin for more details)
A simple example is do create a file named, ~/.vim/after/ftplugin/fortran.vim and place your mappings inside like so:
inoremap <buffer> <tab> <space>
I personally lean more towards the ftplugin approach but having a everything in your ~/.vimrc file can be nice.
Conclusion
I personally think this is an issue with your indention settings and working around it with a mapping more of a bandaid approach. There is a nice Vimcasts episodes that might be helpful: Tabs and Spaces and Whitespace preferences and filetypes. Check your indention settings with the following:
:verbose set ts? sts? sw? et?
For more help see:
:h :map-local
:h ftplugin
:h :aug
:h :au
:h FileType
:h :set
:h 'ts'
:h 'sts'
:h 'sw'
:h 'et'
To map the tab key to a single space only on fortran files (*.f, *.f90, *.F or *.F90), add the following in your ~/.vimrc
function! FortranTab()
inoremap <Tab> <Space>
endfunction
au BufNewFile,BufRead *.f,*.f90,*.F,*.F90 call FortranTab()

Resources