Every time I'm in insert mode, when I press backspace, something like on image below happens. On save everything is saved properly, but until then - it looks broken.
It seems like shell colour characters, but I'm not really sure.
After some testing, and removing pieces of .vimrc, seems like it's issue of delimitMate.
What could be the reason?
s:ExtraMappings() defines a map for Backspace in plugin/delimitMate.vim:
" If pair is empty, delete both delimiters:
inoremap <silent> <Plug>delimitMateBS <C-R>=delimitMate#BS()<CR>
if !hasmapto('<Plug>delimitMateBS','i')
if empty(maparg('<BS>', 'i'))
silent! imap <unique> <buffer> <BS> <Plug>delimitMateBS
endif
if empty(maparg('<C-H>', 'i'))
silent! imap <unique> <buffer> <C-h> <Plug>delimitMateBS
endif
endif
Note that <Plug>delimitMateBS is mapped to <C-R>=delimitMate#BS()<CR>. <C-R>= enters an expression, and that expression will be returned by delimitMate#BS(). See :help c_CTRL-R_=:
'=' the expression register: you are prompted to
enter an expression (see expression)
delimitMate#BS() returns key inputs to handle pairs in autoload/delimitMate.vim:
function! delimitMate#BS() " {{{
if s:is_forbidden("")
let extra = ''
elseif &bs !~ 'start\|2'
let extra = ''
elseif delimitMate#WithinEmptyPair()
let extra = "\<Del>"
elseif s:is_space_expansion()
let extra = "\<Del>"
elseif s:is_cr_expansion()
let extra = repeat("\<Del>",
\ len(matchstr(getline(line('.') + 1), '^\s*\S')))
else
let extra = ''
endif
return "\<BS>" . extra
endfunction " }}} delimitMate#BS()
By looking into the code, you can know the return value can be:
"\<BS>"
"\<BS>\<Del>"
"\<BS>\<Del>\<Del>"
…
So as I think, it's an issue of handling Backspace or Delete. See :help :fixdel for additional information.
:fix[del] Set the value of 't_kD':
't_kb' is 't_kD' becomes
CTRL-? CTRL-H
not CTRL-? CTRL-?
(CTRL-? is 0177 octal, 0x7f hex) {not in Vi}
If your delete key terminal code is wrong, but the
code for backspace is alright, you can put this in
your .vimrc:
:fixdel
This works no matter what the actual code for
backspace is.
If the backspace key terminal code is wrong you can
use this:
:if &term == "termname"
: set t_kb=^V<BS>
: fixdel
:endif
Where "^V" is CTRL-V and "<BS>" is the backspace key
(don't type four characters!). Replace "termname"
with your terminal name.
If your <Delete> key sends a strange key sequence (not
CTRL-? or CTRL-H) you cannot use ":fixdel". Then use:
:if &term == "termname"
: set t_kD=^V<Delete>
:endif
Where "^V" is CTRL-V and "<Delete>" is the delete key
(don't type eight characters!). Replace "termname"
with your terminal name.
Related
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>
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.
So I'm trying to write a function that makes inserting semi colons a bit more pleasant:
inoremap <leader>; <esc>:call InsertSemiColin()<cr>
Basically it checks to see if I'm standing at the end of the current line, if so I auto-format the code, insert the semi-colon at the end and break down to the next line (carriage return)
fun! InsertSemiColin()
if (!IsEOL()) | exec "normal! a;" | return | endif
exec "normal! \<esc>:OmniSharpCodeFormat\<cr>A;\<cr>"
endf:
fun! IsEOL()
" col number == length of current line?
return col('.') == strlen(getline(line('.'))) " or just getline('.')
endf
Expectation:
Result:
To try it out on your own, you can remove the code-formatting and just do:
exec "normal! a;\<cr>"
My indentation settings:
set smartindent
set tabstop=4
set shiftwidth=4
filetype plugin indent on
The weird thing is that if I don't insert the carriage return from a function, it works as expected!
inoremap <leader>; ;<cr>
Why is this happening? and how can I get the result I'm expecting?
Very frustrating, any help would be appreciated!
I would avoid leaving and re-entering insert mode for this via :help :map-expr:
inoremap <expr> <leader>; ';' . (IsEOL() ? '<esc>:OmniSharpCodeFormat<cr>A<cr>' : '')
For this to work, you need to change the comparison in the IsEOL() function:
fun! IsEOL()
" col number == length of current line?
return col('.') > strlen(getline(line('.'))) " or just getline('.')
endf
This also fixes the indent problem.
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>
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>'.