How do I move to the next capital letter? - vim

In vim I can use f followed by a character to go to the next occurrence of that character on the current line. For example, if I have the following (cursor position marked with |):
m|akeBinExprNode = undefined
I can use fB to move to B and dtE to delete until before the E, leaving me with:
make|ExprNode = undefined
I wonder if there's a way to do this that doesn't involve typing the exact character, i.e. some kind of motion that means "go to the next capital letter" and/or "go to right before the next capital letter".

When I searched for that I would be happy to just have the "native" solution: just enter in command mode:
/\u
which stands for "search for an uppercase letter". After that just move between capital letters with n and N (shift + n).

I would recommand the following script : camelcasemotion. It allows you to jump , delete inner 'camel case words', using ,+ normal navigation [w,b,e] etc...

I have found this vim tip for moving within CamelCaseWords that might be useful:
" Use one of the following to define the camel characters.
" Stop on capital letters.
let g:camelchar = "A-Z"
" Also stop on numbers.
let g:camelchar = "A-Z0-9"
" Include '.' for class member, ',' for separator, ';' end-statement,
" and <[< bracket starts and "'` quotes.
let g:camelchar = "A-Z0-9.,;:{([`'\""
nnoremap <silent><C-Left> :<C-u>call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%^','bW')<CR>
nnoremap <silent><C-Right> :<C-u>call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%$','W')<CR>
inoremap <silent><C-Left> <C-o>:call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%^','bW')<CR>
inoremap <silent><C-Right> <C-o>:call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%$','W')<CR>
vnoremap <silent><C-Left> :<C-U>call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%^','bW')<CR>v`>o
vnoremap <silent><C-Right> <Esc>`>:<C-U>call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%$','W')<CR>v`<o

wilhelmtell's answer will work unless 'ignorecase' parameter is set. If 'smartcase' is activated or 'noignorecase' then it is okay.
However a pattern that can replace [A-Z] is \u (see :help /\u or more globally :help pattern). Therefore you can replace your mapping with:
:nnoremap <leader>C /\u<CR>:nohlsearch<CR>

:nmap <leader>C /[A-Z]<CR>:nohlsearch<CR>
Then in normal mode <leader>C (which by default means \C)

Related

How to make f and t wrap around the current line in vim

Is there a way to make the 'f' and 't' command wrap around the line? For example, if I have
Hello, my name is _intz,
where _ denotes my cursor position, I would like to be able to press fl for vim to place my cursor on the first l on the line.
Similarly, I would ideally like the , and ; commands to also wrap on the current line.
Thank you
No, this is not possible without implementing the feature yourself.
Note that fF are universally expected to mean "next on the line" and tT to mean "previous on the line", both of which being extremely useful in their own right. Instead of changing their meaning, and thus reducing the overall usefulness of Vim, you should consider making new commands.
Something like these quick and dirty mappings:
" move the cursor on first occurrence of character on the line
nnoremap <expr> <key> '0f' . nr2char(getchar())
" move the cursor before first occurrence of character on the line
nnoremap <expr> <key> '0t' . nr2char(getchar())
See :help <expr>, :help nr2char(), :help getchar().
With the help of this answer https://vi.stackexchange.com/questions/29167/determine-if-there-is-a-matching-character-on-the-current-line-past-the-cursor, the following maps <c-f> to allow that gives it the functionality of f with same line wrapping.
function!Neweff()
let character = nr2char(getchar())
let beforejump = getpos('.')
execute 'norm! f'.character.''
let afterjump = getpos('.')
if beforejump == afterjump
let firstcharacter = getline(".")[0]
execute 'norm! 0'
if character !=# firstcharacter
execute 'norm! f'.character.''
endif
endif
endfunction
nnoremap <c-f> :call Neweff()<CR>

Understand :iabbrev <buffer> iff if:<left>

I typed :autocmd FileType python :iabbrev <buffer> iff if:<left> as this tutorial told.
The output was
if :
Why is there a space between if and ":"?
I assume you're using the space bar after you type iff? If so, it's because of the <left>. This is positioning your cursor one to the left, i.e. between the f and the ":". Once the space bar is accepted your cursor is in between the two characters so it puts a space between them. You can try the command without the <left> and see if that does what you need. If not, you'll need to let us know exactly what output you're looking for us to be able to help you. Also see: :help abbrev if you haven't already.
Abbreviation's are triggered by non-keyword (e.g. ., <cr>, <space>, etc), <esc>, or <c-]>. Typing iff alone will is not enough to expand the abbreviation. You typed iff<space> which is enough to expand the abbreviation and puts the <space> inside your expanded abbreviation. You can use <c-]> to expand abbreviations without inserting any extra characters. e.g. iff<c-]>
Eatchar
I however find using <c-]> to be unappealing. Vim's documentation gives us an alternative, the Eatchar function. This function will consume a key matching some pattern and not output it.
function! Eatchar(pat)
let c = nr2char(getchar(0))
return (c =~ a:pat) ? '' : c
endfunction
iabbr <buffer> iff if:<left><c-r>=Eatchar('\s')<cr>
Rails.vim like abbreviations
You can take this even further and make Rails.vim-esque abbreviations which only expand on <tab> or a supplied pattern. Think of these as lightweight snippets.
function! RailsExpand(root, good, ...)
let c = nr2char(getchar(0))
if c == "" || c =~ (a:0 ? a:1 : "\t")
return a:good
else
return a:root . c
endif
endfunction
iabbr <buffer> iff <c-r>=RailsExpand('iff', "if:\<left>")<cr>
Now iff<tab> will expand properly. However defining abbreviations like this is a mess.
function! Railsabbrev(root, good)
let good = substitute(a:good, '[\"|]', '\\&', "g")
let good = substitute(good, '<', '\\<lt>', "g")
let root = substitute(a:root, '[\"|]', '\\&', "g")
let root = substitute(root, '<', '\\<lt>', "g")
execute "iabbr <buffer> " . a:root . " <c-r>=RailsExpand(\"" . root . "\", \"" . good . "\")<cr>"
endfunction
command! -nargs=* Railsabbrev call Railsabbrev(<f-args>)
Now you can use :Railsabbrev to define your <tab> expanding abbreviation. Example:
Railsabbrev iff if:<left>
Snippets
Sometimes abbreviations are just too simple or too tricky to maintain for multiline expansions. If this is the case I suggest you look for a good snippet plugin. Good choices are UltiSnips or vim-snipmate. Look at their documentation on how to expand and create your own snippets.
More help
:h Abbreviations
:helpg Eatchar

Vim smart insert semicolon

Is there a Vim plugin that can handle smart semicolon insertion, like the one in Eclipse?
Example (pipe character is insertion cursor):
foobar(|)
I type a semicolon:
foobar();|
Similarly:
foobar("blah|")
I type a semicolon:
foobar("blah");|
If I want a semicolon at the original cursor position, I press backspace after the smart re-position:
foobar("hello|")
foobar("hello");|
foobar("hello;|")
I use this mapping:
inoremap <leader>; <C-o>A;
It's not ; because I use semicolons often and in more than one context.
<C-o> is used to input a single normal mode command.
A; means "add a ; at the end of the line".
I want to do the same thing, I works on it whole night, tons of code, but at last, I got a simple solution.
inoremap ;<cr> <end>;<cr>
and if I am in a brace, I want to add a semicolon or a dot at the end, like this
foo({
|
})
I press ;;<cr> or ..<cr> to do this
inoremap ;<cr> <end>;<cr>
inoremap .<cr> <end>.
inoremap ;;<cr> <down><end>;<cr>
inoremap ..<cr> <down><end>.
You should try Cosco.vim plugin.
For vscode vim users:
"vim.insertModeKeyBindings": [
{
"before": [";", ";"],
"after": ["<Esc>","A",";"]
},
],
I was inspired by romainl's answer above, but <C-o> seems have a switch problem in vocode vim, so just use <Esc> will work.
I use the following function and a mapping to insert a semicolon to the end of the line and to delete the remaning spaces:
imap <leader>. <C-R>=Semicolonfun()<CR>
fun! Semicolonfun() "{{{
call setline(line('.'), substitute(getline('.'), '\s*$', ';', ''))
return "\<End>"
endfunction "}}}
So if you have something like:
log.warning("you miss the |identifier")
Pressing . or ,. if you remap the leader, you get the following:
log.warning("you miss the identifier");|
inoremap <expr> ;<cr> getline('.')[-1:] == ';' ? '\<Nop>' : '<End>;<CR>'
The code above will check if there is ; at the end of the line.
If ; not exists, then it will add ; otherwise do nothing.
" ftplugin/c/c_snippet.vim
inoremap <expr> <buffer> ; getline('.')[col('.')-1:-1]=~')$' ? '<right>;' : ';'
This version shall not pose problems with for if your snippets engine expands it into
for (...|) {
<+code+>
}<++>
If the open bracket is on a newline, it will mess things up.
You could easily change the regex to '"\=)\+$' to answer your initial question.
inoremap <expr> <buffer> ; getline('.')[col('.')-1:-1]=~'"\=)\+$' ? '<end>;' : ';'
However, I don't think it's a good idea. In that case, the mapping for <bs>will be:
inoremap <expr> <buffer> <bs> getline('.')[:col('.')-2] =~ '.*")\+;$' ? '<bs><c-o>F";' : '<bs>'

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>'.

How to paste over without overwriting register

Does anyone know of a way to paste over a visually selected area without having the selection placed in the default register?
I know I can solve the problem by always pasting from an explicit register. But it's a pain in the neck to type "xp instead of just p
Use the following:
xnoremap p pgvy
this will reselect and re-yank any text that is pasted in visual mode.
Edit: in order this to work with "xp you can do:
xnoremap p pgv"#=v:register.'y'<cr>
v:register expands to the last register name used in a normal mode command.
I don't like the default vim behavior of copying all text deleted with d, D, c, or C into the default register.
I've gotten around it by mapping d to "_d, c to "_c, and so on.
From my .vimrc:
"These are to cancel the default behavior of d, D, c, C
" to put the text they delete in the default register.
" Note that this means e.g. "ad won't copy the text into
" register a anymore. You have to explicitly yank it.
nnoremap d "_d
vnoremap d "_d
nnoremap D "_D
vnoremap D "_D
nnoremap c "_c
vnoremap c "_c
nnoremap C "_C
vnoremap C "_C
"{register}p won't work as you describe. It will replace the selection with the content of the register. You will have instead to do something like:
" I haven't found how to hide this function (yet)
function! RestoreRegister()
let #" = s:restore_reg
return ''
endfunction
function! s:Repl()
let s:restore_reg = #"
return "p#=RestoreRegister()\<cr>"
endfunction
" NB: this supports "rp that replaces the selection by the contents of #r
vnoremap <silent> <expr> p <sid>Repl()
Which should be fine as long as you don't use a plugin that has a non-nore vmap to p, and that expects a register to be overwritten.
This code is available as a script there. Ingo Karkat also defined a plugin solving the same issue.
In your .vimrc
xnoremap p "_dP
I found this from a response on a similar thread, but the original source was http://vim.wikia.com/wiki/Replace_a_word_with_yanked_text. It mentions some drawbacks, however it works fine for me.
Luc Hermitte's solution works like a charm. I was using it for about a week or so. Then I discovered a solution from Steve Losh's .vimrc that works nicely if YankRing is part of your plugin/bundle lineup:
function! YRRunAfterMaps()
" From Steve Losh, Preserve the yank post selection/put.
vnoremap p :<c-u>YRPaste 'p', 'v'<cr>gv:YRYankRange 'v'<cr>
endfunction
Try this in your ~/.vimrc:
xnoremap <expr> p 'pgv"'.v:register.'y'
xnoremap means that this is only for Visual mode, not Visual + Select modes.
<expr> means that {rhs} of the xnoremap {lhs} {rhs} setting is evaluated as an expression.
In this case, our expression of 'pgv"'.v:register.'y' is using . for concatenation.
v:register is evaluated to the register being used during the fulfillment of the mapping.
The result of "xp would evaluate to pgv"xy, where x is the register.
I was helped by an answer to this stackoverflow question: Vim - mapping with an optional register prefix
in conjunction with Benoit's answer on this page
Luc's function worked well for me after I made a change to support the fact that I have clipboard=unnamed set:
function! RestoreRegister()
let #" = s:restore_reg
if &clipboard == "unnamed"
let #* = s:restore_reg
endif
return ''
endfunction
Use P to paste without yanking the deleted text.
:help v_P
With P the unnamed register is not changed (and neither the selection or clipboard), you can repeat the same change.
This behavior was introduced in v8.2.4242 (2022-01-28) and refined in v8.2.4881 (2022-05-06).
Or if your muscle memory is too strong:
xnoremap p P
Luc Hermitte's did the trick! Really good. Here's his solution put in a toggle function, so you can switch between normal behavior and no-replace-register put.
the command ,u toggles the behavior
let s:putSwap = 1
function TogglePutSwap()
if s:putSwap
vnoremap <silent> <expr> p <sid>Repl()
let s:putSwap = 0
echo 'noreplace put'
else
vnoremap <silent> <expr> p p
let s:putSwap = 1
echo 'replace put'
endif
return
endfunction
noremap ,p :call TogglePutSwap()<cr>
This is my solution.
vnoremap p p:let #+=#0<CR>
vnoremap P P:let #+=#0<CR>
I find out after paste, the old content is still stored in "0 register.
Just restore it to current clipboard by
:let #+=#0
duct-tape programming, but works for me:
nmap viwp viwpyiw
nmap vi'p vi'pyi'
nmap vi"p vi"pyi"
nmap vi(p vi(pyi(
nmap vi[p vi[pyi[
nmap vi<p vi<pyi<
Select the text and paste by P(uppercase).
Example:
viwP
See h: v_P for more infomation.
try -
:set guioptions-=a
:set guioptions-=A

Resources