Vim magic closing bracket - vim

It would be great in vim if I could type ] (or some other character, maybe <C-]>) and have it automatically insert whichever bracket properly closes the opening bracket. Eg. if I have this in my buffer:
object(function(x) { x+[1,2,3
And I press ]]], the characters ]}) would be inserted. How might one accomplish this this?

Here's a sketch of what you probably wanted. The builtin functions searchpair and searchpairpos are of enormous help for various text editing tasks :)
" Return a corresponding paren to be sent to the buffer
function! CloseParen()
let parenpairs = {'(' : ')',
\ '[' : ']',
\ '{' : '}'}
let [m_lnum, m_col] = searchpairpos('[[({]', '', '[\])}]', 'nbW')
if (m_lnum != 0) && (m_col != 0)
let c = getline(m_lnum)[m_col - 1]
return parenpairs[c]
endif
return ''
endfun
To use it comfortably, make an imap of it:
imap <C-e> <C-r>=CloseParen()<CR>
Edit: over-escaped the search regexp so \ got included in the search. One less problem now.

Combined with the autoclose plugin, you can set:
imap <c-l> <c-o>l
Autoclose will insert the matching bracket, then ctrl-L will skip over it without leaving insert mode. Ctrl-L makes more sense to me than ctrl-].
This is as close as I can get to what I'd say you're asking for: "let me just press the same key every time to skip entering the correct bracket, no matter what that bracket is". I'd not imap ] (without modifier) to this, but there's nothing stopping you if you want to try it out.

You can add that to your .vimrc and it will autoclose brackets
inoremap ( ()<Left>
inoremap [ []<Left>
inoremap { {}<Left>

Related

Fix cursor position [duplicate]

I'm a C# developer and I'm new to using Vim. I'm curious, what would you put in your .vimrc file so that when you type a curly brace and hit Enter, like this:
public void Foo() {<Enter>
that brace gets put on a new line, and the caret moves to the innards of the braces, like this:
public void Foo()
{
|
}
Any help would be appreciated, thanks!
Your question is very close to auto-close plugin issuse with curly brackets where
inoremap <expr> <cr> getline(".")[col(".")-2:col(".")-1]=="{}" ? "<cr><esc>O" : "<cr>"
answers the question -- this is somewhat what I use in lh-brackets.
Here, it seems you aren't using any bracketing plugin. The text to search becomes '\S\s*{$', and you can insert instead: <BS><cr>{<cr>}<esc>O, or just {<cr>}<esc>O if there is only { on the line. If the cursor is within {}, you should also integrate the previous test.
This becomes:
inoremap <expr> <cr>
\ getline(".") =~ '\S\s*{$' ? "<bs><cr>{<cr>}<esc>O"
\ : getline('.') =~ '^\s*{$' ? "<cr>}<esc>O"
\ : getline(".")[col(".")-2:col(".")-1]=="{}" ? "<cr><esc>O"
\ : "<cr>"
There are a lot of ways to program this. Just as an example I might do this:
inoremap {<Cr> <Esc>:call AutoBracketDrop()<Cr>a
function! AutoBracketDrop()
if col('.') == col('$') - 1
substitute /\s*$//
exec "normal! A\<Cr>{\<Cr>X\<Cr>}\<Esc>k$x"
else
exec "normal! a{\<Cr>\<Esc>"
endif
endfunction
First I add a insert map that will break out of insert and call the AutoBracketDrop function and when finished enter back into insert mode.
The function simply checks to see if the cursor column matches the last column of the line. If so we remove the trailing whitespace and append the test:
cursor is here>
{
X
}
Because the use of <Cr> it should keep the indentation as if you typed them. We have to have a marker X otherwise Vim will remove whitespace from the empty line and continuing with an append (a) will loose the indentation. This way the text ends up as:
cursor was here>
{
X
}
Then we move the cursor up a line, delete the X and exit the function.
In the case of it being in the middle of the line we just simple recreate the characters typed that were used to trigger the mapping.

Create a mapping for Vim's command-line that escapes the contents of a register before inserting it

Suppose that I have a document like this, and I want to search for all occurences of the URL:
Vim resources: [http://example.com/search?q=vim][q]
...
[q]: http://example.com/search?q=vim
I don't want to type it out in full, so I'll place my cursor on the first URL, and run "uyi[ to yank it into the 'u' register. Now to search for it, I'd like to just paste the contents of that register into the search field by running:
/\V<c-r>u<CR>
This results in Vim searching for the string 'http:' - because the '/' character terminates the search field.
I can get around the problem by running this instead:
/\V<c-r>=escape(#u, '\/')<CR><CR>
But it's a lot of typing!
How can I create a mapping for Vim's commandline that simplifies this workflow?
My ideal workflow would go something like this:
press /\V to bring up the search prompt, and use very nomagic mode
hit ctrl-x to trigger the custom mapping (ctrl-x is available)
Vim listens for the next key press... (pressing <Esc> would cancel)
pressing 'u' would escape the contents of the 'u' register, and insert on the command line
Try this:
cnoremap <c-x> <c-r>=<SID>PasteEscaped()<cr>
function! s:PasteEscaped()
" show some kind of feedback
echo ":".getcmdline()."..."
" get a character from the user
let char = getchar()
if char == "\<esc>"
return ''
else
let register_content = getreg(nr2char(char))
return escape(register_content, '\/')
endif
endfunction
By the way, something that might be useful to know (if you don't already) is that you can use ? as the delimiter for :s. Which means that you could write a search-and-replace for an url like so:
:s?http://foo.com?http://bar.com?g
I've accepted Andrew Radev's solution, which solved the hard parts. But here's the version that I've added to my vimrc file, which adds a couple of enhancements:
cnoremap <c-x> <c-r>=<SID>PasteEscaped()<cr>
function! s:PasteEscaped()
echo "\\".getcmdline()."\""
let char = getchar()
if char == "\<esc>"
return ''
else
let register_content = getreg(nr2char(char))
let escaped_register = escape(register_content, '\'.getcmdtype())
return substitute(escaped_register, '\n', '\\n', 'g')
endif
endfunction
This should work:
whether you use / or ? (to search forwards, or backwards)
and when the pasted register includes multiple lines
Also, I changed the prompt. While waiting for a register, the prompt switches to \ - which seems like a suitable cue for 'PasteEscaped'. Also, I've appended a ", which mimics Vim's behavior after pressing <c-r> at the command line.
If you've any further suggestions for improvements, please leave a comment.
How about different workflow? For example, creating your own operator to search target text as is:
" https://gist.github.com/1213642
" Requiement: https://github.com/kana/vim-operator-user
map YourFavoriteKeySequence <Plug>(operator-search-target-text)
call operator#user#define('search-target-text', 'OperatorSerachTargetText')
function! OperatorSerachTargetText(motion_wise)
execute 'normal!' '`['.operator#user#visual_command_from_wise_name(a:motion_wise).'`]"xy'
let #/ = '\V' . escape(substitute(#x, '[\r\n]$', '', ''), '\')
normal! n
endfunction
I like #nelstrom's solution and made a small change to support escaping [ and ].
cnoremap <c-x> <c-r>=<SID>PasteEscaped()<cr>
function! s:PasteEscaped()
echo "\\".getcmdline()."\""
let char = getchar()
if char == "\<esc>"
return ''
else
let register_content = getreg(nr2char(char))
let escaped_register = escape(register_content, '\'.getcmdtype())
let escaped_register2 = substitute(escaped_register,'[','\\[','g')
let escaped_register3 = substitute(escaped_register2,']','\\]','g')
return substitute(escaped_register3, '\n', '\\n', 'g')
endif
endfunction

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?

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