Vim searched patterns in middle screen - vim

Is there any working command / remapping so that when I do
:grep *mysearch* *here*
the results I iterate with cnext, can appear in the middle of the screen directly ?
Ideally I want n to iterate over the results and have the line in the middle screen so I don't have to find where is the cursor in my file each time I see the next results.
I tried many things such as
map :<Leader>n :cnext zz<CR> OR :cnext | :zz | <CR>
or any variations but nothing works ...
Any ideas ?
Thank you !

Based on the technique described here, you can do something like this:
" Keep quickfix result centered, if possible, when jumping from result to result.
cabbrev <silent> <expr> cn ((getcmdtype() == ':' && getcmdpos() == 3) ? 'cn <bar> normal zz<cr>' : 'cn')
cabbrev <silent> <expr> cnf ((getcmdtype() == ':' && getcmdpos() == 4) ? 'cnf <bar> normal zz<cr>' : 'cnf')
cabbrev <silent> <expr> cp ((getcmdtype() == ':' && getcmdpos() == 3) ? 'cp <bar> normal zz<cr>' : 'cp')
cabbrev <silent> <expr> cpf ((getcmdtype() == ':' && getcmdpos() == 4) ? 'cpf <bar> normal zz<cr>' : 'cpf')
I originally had this in my dotfiles but have since extracted it into a plugin with a few search-related features called Ferret.

Mappings are not really a good solution for command-line mode; but the main error with your try was some mistakes around zz, which is a normal-mode command. It could be:
:cmap <Leader>n :cnext<bar>normal zz
But :cabbr is really better for this case.
An simplified version of wincent's answer is both of these:
:cabbr cn cnext<bar>normal zz
:cabbr cn cnext\|normal zz
But you can't access to the original command by doing this : cn (with a space), like with wincent's answer.
Another good way to abbreviate commands : cmdalias.vim, which allows to only recognize abbreviations at start of command-line.

Related

How to shortcut (nmap) windo command expression?

For closing all quickfix windows, I use the following vim command expression:
:windo if &buftype == 'quickfix' || &buftype == 'locationlist' | lclose | endif
Whenever I try to shortcut it like:
nmap <S-q> :let #a = "%:windo if &buftype == 'quickfix' || &buftype == 'locationlist' | lclose | endif"
by using nmap in my init.vim, I got an error:
E749: empty buffer
E488: Trailing characters
How to solve that?
Explanation
The | is a command separator; unfortunately (this is a common pitfall), it also ends any :map command, and the remainder is interpreted immediately, instead of being part of the mapping.
:help map-bar lists three different solutions; the most common is using the special <Bar> notation instead of |.
Your mapping
nmap <S-q> :let #a = "%:windo if &buftype == 'quickfix' <Bar><Bar> &buftype == 'locationlist' <Bar> lclose <Bar> endif"
Is the %:windo a typo? The % is suspicious.
The mapping is missing the trailing <CR>; it will linger until you press <Enter> yourself. Is that intended?
Why do you assign the commands to register a instead of executing it?
You should use :noremap; it makes the mapping immune to remapping and recursion.
'buftype' is always quickfix, also for location lists; you can drop the second branch in the test.
noremap <S-q> :windo if &buftype == 'quickfix' <Bar> lclose <Bar> endif<CR>

Neovim change te and terminal command

I'm trying to change the behaviour of the :te and :terminal in neovim. I added
cmap VTerm te
to my init.vim. This is supposed to open a erminal in a vertical split, but it doesn't seem to work. I also wanted to remap the :terminal command to do the same thing. What am I doing wrong?
Also I'm using this plugin
You could try these abbreviations:
cnorea <expr> te getcmdtype() == ':' && getcmdline() ==# 'te' ? 'VTerm' : 'te'
cnorea <expr> terminal getcmdtype() == ':' && getcmdline() ==# 'terminal' ? 'VTerm' : 'terminal'
Both of them check whether you're on a regular Ex command-line (getcmdtype() == ':') and whether you've typed te or terminal at the beginning of the line (getcmdline() ==# 'te', getcdmline() ==# 'terminal').
If you aren't on a regular Ex command-line (search, input, debug, ...), or if you've typed te / terminal anywhere else than the beginning of the line, they won't be expanded into VTerm. Otherwise they will.

How to map a key in command-line mode but not in search mode

I want to map a key in VIM in command-line mode but not in search mode(with a leading /), like below:
Map Q to q
Map W to w
Sometimes I typed the wrong command in VIM, like :Q and :W, and I want to make these wrong commands to be right.
If I can map Q to q and W to w, I can make the wrong commands to be right.
I tried cmap Q q and cmap W w, but this will also affect the search mode, i.e. /Query to be /query (actually you can't type the upper Q).
And I also tried cabbrev Q q, and this will also affect the search mode.
So, is there any other command that can meet my requirement?
Thanks.
There are a number of ways to do it, and neither is really straightforward.
With command you need to take care of attributes:
command! -nargs=* -complete=file -range=% -bang -bar W w
command! -bang -bar Q q
With cabbrev the pitfalls are described in the wiki, so you need to do it like this:
cnoreabbrev W <C-r>=(getcmdtype()==':' && getcmdpos()==1 ? 'w' : 'W')<CR>
I have a function for this purpose:
function! s:CAbbrev(from, to)
execute 'cnoreabbrev ' . a:from . ' <C-r>=(getcmdtype()==#'':'' && getcmdpos()==1 ? ' . string(a:to) . ' : ' . string(a:from) . ')<CR>'
endfunction
With cmap you need the <expr> qualifier, and you need more or less the same precautions as with cabbrev:
cnoremap <nowait> <expr> W getcmdtype() ==# ':' && getcmdpos() == 1 ? 'w' : 'W'
The safest is probably the cabbrev way.
In this case, you can define a user command because it starts in upper case.
:command! Q q
:command! W w

vim function for toggling colorschemes

At the moment I'm using two different keys to toogle the colorscheme
map <F8> :colors wombat256 <cr>
map <F9> :colors dimtag <cr>
I want to achieve a toggle behavior like this
function! ToggleDimTags()
if (g:colors_name == "wombat256")
colors dimtag
else
colors wombat256
endif
endfunction
My problem is that ToogleDimTags() is resetting the cursor position to the first line on every call, which is undesirable. Any suggestions appreciated.
As discussed in the comments, the problem is that your map calling :execute
behaves a little differently, what you probably want is :call instead:
nnoremap <F5> :call ToggleDimTags()
To clarify what #ZyX was saying, :h :exec contains the following text:
:exe :execute
:exe[cute] {expr1} .. Executes the string that results from the evaluation
of {expr1} as an Ex command.
[...]
So what :execute really does is evaluating the expression looking for a string
that will be executed as an Ex command (also called colon commands). In other words:
exec ToggleDimTags() | " <-- ToggleDimTags() is evaluated and returns 0
exec 0
Which is:
:0
Now, :h :call:
:cal :call E107 E117
:[range]cal[l] {name}([arguments])
Call a function. The name of the function and its arguments
are as specified with |:function|. Up to 20 arguments can be
used. **The returned value is discarded**.
[...]
Update
I've been thinking about your function, and using the ternary operator and a bit
of :execute magic, you can simplify it up to a point where you discard the extra
function:
nnoremap <silent> <F9> :exec "color " .
\ ((g:colors_name == "wombat256") ? "dimtag" : "wombat256")<CR>
Here, this nnoremap will not produce output (<silent>) and is based on
:exec, which is followed by this expression:
"color " . ((g:colors_name == "wombat256") ? "dimtag" : "wombat256")
When g:colors_name is set to wombat256, the expression evaluates to:
"color dimtag"
Or, otherwise:
"color wombat256"
Then either one is evaluated by :exec. Of course you can join the lines
(without forgetting to remove the backslash), I did it like this simply to avoid
a too long line.

Auto insert text at a newline in vim

I am editing a LaTeX file with vim. When I am in the \begin{itemize} environment, is there any way to tell vim to autoinsert \item whenever I open a new line?
function CR()
if searchpair('\\begin{itemize}', '', '\\end{itemize}', '')
return "\r\\item"
endif
return "\r"
endfunction
inoremap <expr><buffer> <CR> CR()
Put this into your .vim/ftplugins/tex.vim file (or any .vim inside .vim/ftplugins/tex directory).
I would recommend http://vim-latex.sourceforge.net. This package defines several maps useful for latex.
In particular for inserting \item you press <ATL-I>
I know noting about latex but I think it is a good idea to search in vim scripts
use the search button up left :D
for example search for
latex auto completion
I can hit Cntl-I and it'll put it in for me in either normal mode or insert mode. This is what I put in my .vimrc:
:imap <C-i> \item
:nmap <C-i> o\item
Note that there is a space at the end of \item.
I hacked the script ZyX supplied and came up with this. It adds support for the o and O commands. It does not require LaTeX-VIM.
function AddItem()
if searchpair('\\begin{itemize}', '', '\\end{itemize}', '')
return "\\item "
else
return ""
endif
endfunction
inoremap <expr><buffer> <CR> "\r".AddItem()
nnoremap <expr><buffer> o "o".AddItem()
nnoremap <expr><buffer> O "O".AddItem()
Extended Version of Answer by Samad Lotia and ZyX
Place this in your ~/.vim/after/ftplugin/tex.vim
function! AddItem()
let [end_lnum, end_col] = searchpairpos('\\begin{', '', '\\end{', 'nW')
if match(getline(end_lnum), '\(itemize\|enumerate\|description\)') != -1
return "\\item "
else
return ""
endif
endfunction
inoremap <expr><buffer> <CR> getline('.') =~ '\item $'
\ ? '<c-w><c-w>'
\ : (col(".") < col("$") ? '<CR>' : '<CR>'.AddItem() )
nnoremap <expr><buffer> o "o".AddItem()
nnoremap <expr><buffer> O "O".AddItem()
Improvements
auto-insert of \item also happens for environments enumerate and description
auto-insert of \item only happens if the immediate surrounding environment is one of the three (itemize/enumerate/description). It does not happen in following circumstance
\begin{itemize}
\item
\begin{minipage}
<CURSOR>
\end{minipage}
\end{itemize}
auto-insert of \item only happens if you are at the end of the line
deletion of auto inserted \item by pressing <CR> a second time. If one wants to add some indention in this case, change '<c-w><c-w>' to '<c-w><c-w><c-t>'.

Resources