What are ways to reduce mode errors while learning vim? - vim

I frequently make mode errors while using vim, i.e. I'll start typing text while in Normal mode, or start typing commands while in Insert mode. I understand this goes away with time as vim's quirks seep into your bones, but are there any ways to speed the process?

I use these autocmd's to highlight the entire line containing the cursor while in insert mode, and not while in normal mode:
if v:version >= 700
autocmd InsertEnter * set cursorline
autocmd InsertLeave * set nocursorline
endif
This provides a little bit more visual feedback about the mode.

If you haven't done so already you can display the current mode by using :set showmode. That'll display -- INSERT -- in the status bar when in insert mode.

Try to remember to always leave vim in normal mode.

Switch "Esc" and "Caps Lock" keys.
If you accidentally click on "Caps Lock" you will start inputing commands that has nothing to do with what you like to do. It is annoying if you are an experienced user; if you are a beginner it may be a hassle to understand what went wrong.
Every time you need to press the Esc key you have to move you entire hand and to get your pinky finger to touch the Esc key and then replace the entire hand again.
Some Vim users will tell you that after a while you get used to doing that and it is not a big deal. I think that argument falls short because you can pretty much get used to mapping any key any where. It is a matter of efficiency.
I believe "Esc" is used very frequently and "Caps Lock" is used seldomly if it is used at all.
So switching the two makes sense as it prevents errors and increases typing speed.

With gvim, the cursor changes from a block to a vertical bar when going between modes. This at least gives you a little visual feedback.

Insert mode should only be temporary. Normal mode is, as its name tells, the favourite mode for edition tasks.
Usually, you should spend more time in normal mode, and always hit ESC when you are done inserting something.
Maybe I speak only for myself, but now I have the habit of assuming that I am in normal mode at all times, and I am almost never wrong.

Here is my variant of Ned's Answer. It toggles on window switches (window focus is another modal behavior that provides little visual feedback).
if v:version >= 700
set cursorline cursorcolumn
au WinLeave * set nocursorline nocursorcolumn
au WinEnter * set cursorline cursorcolumn
au InsertEnter * set nocursorline nocursorcolumn
au InsertLeave * set cursorline cursorcolumn
endif
I use it with the zenburn color scheme, and I also turn off cursor blink:
if has("gui_running")
colorscheme zenburn
set guicursor+=a:blinkon0
endif

Related

vim: remove delay when inserting text in visual block mode [duplicate]

In Vim, when in Visual mode, I have to press Esc twice to exit it and turn off the selection. After one press of Esc I have to wait 2 seconds for the selection to turn off.
What can I do to exit Visual mode immediately when Esc is pressed?
Executing following command helped me:
set timeoutlen=1000 ttimeoutlen=0
see: http://www.johnhawthorn.com/2012/09/vi-escape-delays/.
As Ingo explained. Just thought I would post the solution:
https://github.com/Greduan/dotfiles/blob/47f92e4db29d4ead778d877a85082b271de130ed/vim/vimrc.vim#L332-L346
Works pretty well. It's a little bit confusing for me as well, so I can't really explain, but the code explains itself pretty well.
The point is it works, it simply makes <Esc> work immediately even when on Terminal. I believe if you do have mappings set to <Esc> it'll give you time to do those as well. However I'm not sure.
EDIT
Studied a bit and I can now explain it. Basically, if you're not using a GUI (like MacVim) then when you enter insert mode the ttimeoutlen will be set to 0. Meaning that as soon as you click <Esc> that'll work. However once you're in normal mode then it'll set the ttimeoutlen to the number you prefer, letting you do mappings with <Esc>.
Perfect solution I think, since if you have mappings in insert mode it'll be using control or something like that.
EDIT 2
Here's the code:
set timeout " Do time out on mappings and others
set timeoutlen=2000 " Wait {num} ms before timing out a mapping
" When you’re pressing Escape to leave insert mode in the terminal, it will by
" default take a second or another keystroke to leave insert mode completely
" and update the statusline. This fixes that. I got this from:
" https://powerline.readthedocs.org/en/latest/tipstricks.html#vim
if !has('gui_running')
set ttimeoutlen=10
augroup FastEscape
autocmd!
au InsertEnter * set timeoutlen=0
au InsertLeave * set timeoutlen=1000
augroup END
endif
With time I've removed the condition that the GUI isn't running and it still works as far as I can tell.
A quick workaround is using <C-c> instead, but you probably want to fix the timeout on <Esc>, which is caused by a mapping that starts with <Esc>, which makes Vim wait for 'timeoutlen' to check whether the mapping is complete.
This does not necessarily need to be a "real" mapping; many terminal workarounds (e.g. to make certain keys work) advise to set up such a mapping. (Unfortunately, this is a difficult and complex issue.)
You can find the mapping via:
:verbose map <Esc>
I have no mapping bound to <ESC> globally or for Visual mode (calling :verbose vmap <ESC> gives no results) but there is still a significant delay when exiting Visual mode. Even on fresh installs with no vimrc the delay is present. Using <C-c> does exit visual mode without delay.
Since I don't like pressing <C-c> to exit any mode, I currently map <ESC> to <C-c> in visual mode. This exits visual mode using <ESC> without any delay.
:vmap <ESC> <C-c>
Or put the following line in your vimrc
vnoremap <ESC> <C-c>
This will not work if you do have global or visual mode mappings bound to <ESC>.
First try the accepted answer of adding the following to .vimrc
set timeoutlen=1000 ttimeoutlen=0
If that doesn't work check if you have any keybindings to <esc>
:imap <esc>
If you use tmux you also need:
set -sg escape-time 0

Vim -- detecting ex mode in vimrc

I have previously asked this in comp.editors, but without getting any replies.
This ought to be simple: I want to configure vim to set number whenever the editor is in ex mode (to get visible line numbers), but never have that option set in visual mode. How?
If the solution involves having to start ex instead of vim, that's fine, but the solution should ideally also cover the case of entering ex mode from visual mode (using Q in vim visual mode, for example).
A solution that also works in nvi would be nice, but not necessary.
You can try something like this:
let &number = mode(1) ==# 'ce'
nnoremap <silent> Q :set number<CR>Q
This will set number when you run vim -e and when you enter ex mode with Q, but it won't clear it when you go back to visual mode. As far as I can tell there is no way to detect the actual event of switching modes. shrug
Vim's Autocmd seemed like your best bet, since it has event listeners. An example would be
:autocmd InsertLeave * :set nonumber
:autocmd InsertEnter * :set number
which shows/hides line numbers
However, I couldn't find any events for Ex mode when I looked.

Vim's key mapping behaving differently between gui mode and cli mode

I've been trying to figure this out for so long but still failed, some of my customized key-mapping (majority of them are for plugins) behaves totally different between gui-mode and cli-mode, even if I use gui-mode command with -v flag (like mvim -v) or using :gui command in terminal Vi.
For example, the Emmet plugin which is handy for expanding HTML/CSS expressions, the default trigger key <C-y> never works at first (in Cli-mode which I often used to), I always don't know why, until one day I use MacVim for a while and suddenly find out it works!
After that, I try to re-map the default trigger from <C-y> to <C-e> or <C-k>, both of them works fine in MacVim but still unlucky in terminal Vim.
Is there any particular reason to cause this issue? Maybe something wrong with my configuration?
Any suggestion will be appreciated, thanks!
Finally I solved it by myself, but thank for #ebenezer 's reminding.
We often use set timeoutlen and set ttimeoutlen to tweak the latency for a key code or a mapping sequence to complete. Most of us can't tolerate with the default value for ttimeoutlen (which is -1), because it forces us to waiting for so long when quit from Insert mode by press ESC or Ctrl-[.
For this particular reason, I changed this value to 10 (in ms), but I copy this setting from somewhere I don't remember now, and it place set ttimeoutlen in a autocmd for all filetypes, like below:
if ! has('gui_running')
set ttimeoutlen=10
autocmd InsertEnter * set timeoutlen=0
autocmd InsertLeave * set timeoutlen=1000
endif
I don't know why this will make some plugins not work properly, and I change it a little to make it works for me now:
if ! has('gui_running')
autocmd InsertEnter * set ttimeoutlen=100
autocmd InsertLeave * set ttimeoutlen=-1
endif
Hope this will help you if you encounter same problems.

How to exit visual mode without a delay in Vim?

In Vim, when in Visual mode, I have to press Esc twice to exit it and turn off the selection. After one press of Esc I have to wait 2 seconds for the selection to turn off.
What can I do to exit Visual mode immediately when Esc is pressed?
Executing following command helped me:
set timeoutlen=1000 ttimeoutlen=0
see: http://www.johnhawthorn.com/2012/09/vi-escape-delays/.
As Ingo explained. Just thought I would post the solution:
https://github.com/Greduan/dotfiles/blob/47f92e4db29d4ead778d877a85082b271de130ed/vim/vimrc.vim#L332-L346
Works pretty well. It's a little bit confusing for me as well, so I can't really explain, but the code explains itself pretty well.
The point is it works, it simply makes <Esc> work immediately even when on Terminal. I believe if you do have mappings set to <Esc> it'll give you time to do those as well. However I'm not sure.
EDIT
Studied a bit and I can now explain it. Basically, if you're not using a GUI (like MacVim) then when you enter insert mode the ttimeoutlen will be set to 0. Meaning that as soon as you click <Esc> that'll work. However once you're in normal mode then it'll set the ttimeoutlen to the number you prefer, letting you do mappings with <Esc>.
Perfect solution I think, since if you have mappings in insert mode it'll be using control or something like that.
EDIT 2
Here's the code:
set timeout " Do time out on mappings and others
set timeoutlen=2000 " Wait {num} ms before timing out a mapping
" When you’re pressing Escape to leave insert mode in the terminal, it will by
" default take a second or another keystroke to leave insert mode completely
" and update the statusline. This fixes that. I got this from:
" https://powerline.readthedocs.org/en/latest/tipstricks.html#vim
if !has('gui_running')
set ttimeoutlen=10
augroup FastEscape
autocmd!
au InsertEnter * set timeoutlen=0
au InsertLeave * set timeoutlen=1000
augroup END
endif
With time I've removed the condition that the GUI isn't running and it still works as far as I can tell.
A quick workaround is using <C-c> instead, but you probably want to fix the timeout on <Esc>, which is caused by a mapping that starts with <Esc>, which makes Vim wait for 'timeoutlen' to check whether the mapping is complete.
This does not necessarily need to be a "real" mapping; many terminal workarounds (e.g. to make certain keys work) advise to set up such a mapping. (Unfortunately, this is a difficult and complex issue.)
You can find the mapping via:
:verbose map <Esc>
I have no mapping bound to <ESC> globally or for Visual mode (calling :verbose vmap <ESC> gives no results) but there is still a significant delay when exiting Visual mode. Even on fresh installs with no vimrc the delay is present. Using <C-c> does exit visual mode without delay.
Since I don't like pressing <C-c> to exit any mode, I currently map <ESC> to <C-c> in visual mode. This exits visual mode using <ESC> without any delay.
:vmap <ESC> <C-c>
Or put the following line in your vimrc
vnoremap <ESC> <C-c>
This will not work if you do have global or visual mode mappings bound to <ESC>.
First try the accepted answer of adding the following to .vimrc
set timeoutlen=1000 ttimeoutlen=0
If that doesn't work check if you have any keybindings to <esc>
:imap <esc>
If you use tmux you also need:
set -sg escape-time 0

Is there anyway to dynamically enable / disable the highlighting in Vim?

Ok so basically the way Vim highlights searches displeases me. Basically you do a search, then you have to type /asdf or have a shortcut like this in your vimrc:
nn <silent> <leader><space> :noh<CR>
Which is what I have. But it's still too much mental work. Basically, when I do a search, I want highlighting to enable (like it does now) but if I do anything other than cycle through the searches (with n/N) then I want highlighting to turn off. That's basically my workflow, so I'm wondering if I can automate it. Also if I search, do something other than n/N (which should turn highlighting off) and then press n/N again, it should re-enable.
Any ideas?
That's difficult. One idea is
:autocmd CursorHold * call feedkeys(":noh\<CR>")
(One needs to use feedkeys() because :nohlsearch is ineffective in functions and autocmds.) This clears the highlighting whenever you pause the cursor for some seconds. You can add other triggers like InsertEnter or CursorHoldI.
What does not work is CursorMoved, because the searches and n / N jump as well. You would need to overload those commands, store the cursor position after the jump, and modify the autocmd to only clear the highlighting when the position is different.
What I do: I have Enter mapped to :nohlsearch; it's quick and easy to reach.
you can turn it on or off with:
:set hls
or
:set nohls
I have F7 mapped to set hls!:
noremap <F7> :set hls!<CR>

Resources