Auto insert text at a newline in vim - 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>'.

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>

Vim command to comment out a selection of lines?

Say I have a bunch of lines:
#Override
public void draw(Graphics g) {
g.setColor(Color.MAGENTA);
g.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
g.setColor(Color.BLACK);
g.drawRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
}
When I want to comment them out with // (i prefer line comments instead of block comments), what I do is:
Place the cursor infront of the # symbol
Ctrl-V: Switch to enter block-select mode
Select the column down to the } closing parenthesis using multiple hits of j
Shift-I: to enter block-insert
Type //
ESC to excit
Enter to finish the command
--> The lines are now commented out.
Is there an easier way where I don't need to do the block-select? I found I can use a substitution like :'<, '>s/^/\/\///g but this has two problems:
Its very clumsy and error prone to type (multiple forward and backward slashes need to be
escaped)
It places the comment symbols (//) at the beginning of
the line (position 0), not at the position where the first character
of that line was (so indentation is lost).
How can I insert // on the selected lines at the position of the first character of each line using Vi?
You can define a custom mapping or command for your :substitute.
However, there are several commenter plugins that do this very well, and those are generic (and often extensible) so that they work for any filetype:
NERD Commenter plugin
tComment plugin
commentary.vim plugin
I'd highly recommend to use one of those plugins instead of trying to reinvent a poor solution yourself.
I use Commentary as in the other answer, but a few thoughts:
<C-v>jjjjj could be <C-v>} or <C-v>/}<CR>
:substitute doesn’t have to use / as a separator: :'<,'>s-^-//
with a visual selection, you can also do :'<,'>normal! I//
How can I insert // on the selected lines at the position of the first character of each line using Vi?
Although, I'm agree with others and the dedicated plugin is a must have, but, as it is formulated in the OP, that's quite an easy task which can be implemented as one-liner:
vnoremap <silent>gc :call setline(".", printf("%*s" . &cms, indent("."), "", trim(getline("."))))<CR>
Now select some text, press "gc", and, voila, it works. To force // usage instead of the default /**/ set the following option for your buffer: setlocal cms=//\ %s. See :h 'cms'.
" I have a 'toggle comment function' that looks like
" Reference: https://stackoverflow.com/a/24652257/2571881
" these lines are needed for ToggleComment()
" Reference: https://stackoverflow.com/a/24652257/2571881
autocmd FileType c,cpp,java let b:comment_leader = '//'
autocmd FileType arduino let b:comment_leader = '//'
autocmd FileType sh,ruby,python let b:comment_leader = '#'
autocmd FileType zsh let b:comment_leader = '#'
autocmd FileType conf,fstab let b:comment_leader = '#'
autocmd FileType matlab,tex let b:comment_leader = '%'
autocmd FileType vim let b:comment_leader = '"'
function! ToggleComment()
if exists('b:comment_leader')
let l:pos = col('.')
let l:space = ( &ft =~ '\v(c|cpp|java|arduino)' ? '3' : '2' )
if getline('.') =~ '\v(\s*|\t*)' .b:comment_leader
let l:space -= ( getline('.') =~ '\v.*\zs' . b:comment_leader . '(\s+|\t+)#!' ? 1 : 0 )
execute 'silent s,\v^(\s*|\t*)\zs' .b:comment_leader.'[ ]?,,g'
let l:pos -= l:space
else
exec 'normal! 0i' .b:comment_leader .' '
let l:pos += l:space
endif
call cursor(line("."), l:pos)
else
echo 'no comment leader found for filetype'
end
endfunction
nnoremap <Leader>t :call ToggleComment()<CR>
inoremap <Leader>t <C-o>:call ToggleComment()<CR>
xnoremap <Leader>t :'<,'>call ToggleComment()<CR>
" vnoremap <Leader>t :call ToggleComment()<CR>
So, once you have this function on your ~/.vimrc you can do:
vip ...................... visual inner paragraph
<leader>t ................ in order to call the function
Make a macro with q, lets put it into the a buffer, so hit qa on a given line. Then press I// to jump to start of line, and comment it out. hit Esc and q and now your macro is done. This macro will comment out the current line.
The full command is qaI//Escq
Now visually select a bunch of lines with V, and type :norm!#a to run your a macro over those lines. This will comment out a bunch of lines.
Record another macro to do the opposite with qb^xx. This can be invoked by visually selecting the lines you want to uncomment and typing norm!#b
You can save these macros in your .vimrc and map the specific macro to a key combination if you want to "save" these commands.

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

Make Vim Curly Braces, Square Braces, Parens act like Textmate

So I guess I'm not searching for the right thing but I'm looking to see how you can get VIM to act like Textmate when it comes to writing a set of curly braces, parens, or square brackets hit enter and you get this. Pipe indicates cursor.
function doSomething(){
|
}
#selector{
|
}
Instead of this garbage
function doSomething(){
|}
#selector{
|}
I already have the [{( closing each other when they are typed just the return and indentation is jacked. As usual any help would be appreciated.
I use the following mappings in my .vimrc:
inoremap {<cr> {<cr>}<c-o>O<tab>
inoremap [<cr> [<cr>]<c-o>O<tab>
inoremap (<cr> (<cr>)<c-o>O<tab>
So when I input:
function foo(){<cr>
I get:
function foo(){
|
}
Similar with (<cr> and [<cr>.
A note to delimitMate users
When using the delimitMate plugin, the mappings of the other answers interfere with the plugin. Luckily, this behavior is already available in delimitMate (but disabled by default), by setting the delmitMateExpansion options. E.g. add
let delimitMate_expand_cr = 1
to your .vimrc
This is my modification of Randy Moris' answer that works better for me:
inoremap {<cr> {<cr>}<c-o><s-o>
inoremap [<cr> [<cr>]<c-o><s-o>
inoremap (<cr> (<cr>)<c-o><s-o>
My solution for this was to put this little function (with corresponding insert-mode mapping) in my .vimrc:
fun! MyCR()
if strpart(getline('.'), col('.') - 2, 2) == '{}'
return "\<CR>\<CR>\<Up>\<Tab>"
endif
return "\<CR>"
endfun
autocmd FileType c,cpp inoremap <CR> <C-R>=MyCR()<CR>
You can change the autocmd so that it will work for your preferred file types.
It remaps <CR> in insert mode to check if the cursor is currently inside curly braces and adds the extra line and indentation where appropriate.
If you like Text make you should check Vim plugin, snipMate, as indicated by tarek11011.
For C/C++ it has by default a snippet for functions
# Function
snippet fun
${1:void} ${2:function_name}(${3}) {
${4:/* code */}
}
, which would solve the curly braces issue.
I have the following on my .vimrc
imap {<Space> {<Space><Space>}<left><left>
imap { {<CR>}
imap {<CR> {<CR><CR>}<Up>;<Esc>==i
imap ( ()
imap () ()
inoremap <silent> (. ().<C-x><C-o>
inoremap <silent> (- ()-><C-x><C-o>
imap (<space> (<space><space>)<left><left>
imap [ []
imap [<space> [<space><space>]<left><left>
inoremap " ""<left>
inoremap "" ""
ok, explanations:
when you hit {, sometimes you want to break a line and put and ending }, but sometimes you just want to stay in the same line, just like: a = {1,2,3};
# means where the cursor is:
So when you hit { and just after that you hit space -> { # }
when you hit { after a little delay or any other than space is used the line will be break
when you hit { just after an enter, the code will be:
foo(){
#
}
When you hit (. results in ().<call to omnicomplete> Just line namespace::Singleton::Create().
You have to use inoremap with ", to avoid infinite """""""""""""""""""""""
I have set ai in my vimrc which I believe does what you want?

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