Vim -- detecting ex mode in vimrc - vim

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.

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

Set cursor shape on suspending vim

I'm using iTerm2 and Vim 7.4 on top of OS X 10.9.
In my bash shell, my cursor is a blinking line. I've installed Vitality (https://github.com/sjl/vitality.vim/) in order to get the Vim cursor to be a block in normal mode and a line in insert mode. Then, in order to get my cursor to revert to a line on exiting vim, I've added the following autocmd to my .vimrc (sourced from this stack overflow question):
autocmd VimLeave * let &t_me="\<Esc>]50;CursorShape=1\x7"
This is all working great; the one problem is that when I suspend Vim via Ctrl-Z (which I do frequently), my cursor remains a block. Is there some way to detect that Vim is being suspended (maybe via an autocmd) and set the cursor to a line? Also, presumably I would then have to reset the cursor to a block on resuming Vim.
There's no :autocmd event for suspending, but you can solve this part by hooking into the <C-z> command:
:nnoremap <silent> <C-z> :let &t_me=...<CR><C-z>
Restoring the cursor on restore is more difficult. It looks like the Vitality plugin already uses autocmd events to change the shape, so one mode change (into / out of insert mode) would be required to correct things.
If that's not enough, you'd have to install a separate fire-once autocmd (e.g. on CursorMoved,CursorHold) in the above mapping. Or you could try sending the :let command via feedkeys(), in the hope that it would only be executed after Vim awakes (not tested that).
I use Ingo's suggestion along with what I found here:
Update Vim after it suspended?
... To toggle a different terminal setting (called "Bracketed Paste Mode") when
I suspend Vim. You can tweak this for any other escape sequence pairs you
need, as the general concept is not BPM specific. This trick solves the 'fg'
problem. Here it is:
" (Re)Set Bracketed Paste Mode
function SetBPM(mode)
execute "silent !echo -ne '\033[?2004" . a:mode . "'"
endfunction
" toggle BPM when suspending (hook ctrl-z)...
nnoremap <silent> <C-z> :call SetBPM("l")<CR>:suspend<bar>:call SetBPM("h")<CR>

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>

What are ways to reduce mode errors while learning 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

Resources