VIM: Set a key mapping to replace ampersand (&) at a set column - vim

I would like to set up a key mapping so that when I type this key (specifically the F7 key in my example), it replaces whatever character is in column 6 with an ampersand (&).
I am trying
:nnoremap <F7> 6| R &<ESC>
Yet that doesn't seem to be doing the trick and I cannot seem to grasp why.
Why is what I'm trying wrong?

Yet that doesn't seem to be doing the trick and I cannot seem to grasp why.
So… what does it do instead of what you expect?
Anyway, there are a number of problems with your mapping:
You can't use a literal pipe character in a mapping. You must escape it (\|) or use <bar> instead, which gives us the following:
nnoremap <F7> 6\| R &<Esc>
nnoremap <F7> 6<Bar> R &<Esc>
See :help map-bar.
In your macro, the <Space> character () is interpreted as the <Space> command and thus moves the cursor one character to the right. If you don't mean <Space> (the command) don't use <Space> (the character):
nnoremap <F7> 6\|R&<Esc>
R puts you in replace mode. This is useless because you are only replacing one character and it forces you to <Esc> to normal mode. Use r instead:
nnoremap <F7> 6\|r&
See :help R and :help r.

Alternatively, it may also be useful to move the cursor back to its original position (i.e. the location before the replacement). To do this use:
nnoremap <F7> :let a=getpos(".")<cr>6\|r&:call cursor(a[1],a[2])<cr>
this map is broken up like this:
:let a=getpos(".")<cr> saves the cursor position on variable a
6\|r& is explained in an earlier answer
:call cursor(a[1],a[2])<cr> returns the cursor to its original position

Here you go:
:map <F7> 05lr&
No escape. Just type that and hit enter. The is really typing out those characters -- less than sign, capital F, the number 7, etc..

Related

Vim keymapping for moving as many characters as the value contained in `textwidth` internal variable

Vim features an internal variable textwidth, which determines how many characters will be printed on screen before adding an <EOL> character to wrap the text to a next line.
I would like to create a mapping, let's say <c-j>, for which I would like the cursor to move a number of characters to the right equal to the value stored in textwidth. This would simulate "going down a line" when the text is wrapped.
I assume that a simple approach would be along the lines of:
nnoremap <c-j> {textwidth}l
However, I have not found a way of evaluating the value of textwidth so that it cant be used as a count for the command l.
Any help is welcome!
There are two ways: One is the interpolation of &textwidth (the & sigil turns the option name into a variable that contains its value; cp. :help :let-option), as in #RuslanOsmanov's answer:
nnoremap <silent> <C-j> :execute "normal!" &textwidth . 'l'<CR>
Another is :help :map-expression, which automatically evaluates the mapping's right-hand side as a Vimscript expression. I would prefer this one, as it's shorter:
nnoremap <expr> <C-j> &textwidth . 'l'
Further improvements
You probably should consider what to do if 'textwidth' is unset, i.e. zero. Unhandled, this would result in a 0l motion, i.e. going to the second character in the line. You can use a conditional to turn this into a no-op, for example. (Or make it beep by returning '<Esc>' instead of '').
nnoremap <expr> <C-j> (&textwidth == 0 ? '<Esc>' : &textwidth . 'l')
Really needed?
Vim has a :help gj command (and variants for the other directions) built-in, that does something similar to what you're trying to implement. Unless you're attempting to solve a special case (e.g. disregarding options like 'showbreak' that further reduce the amount of characters actually shown), it would be advisable to just use (and maybe remap) the built-ins.
You can refer to an option value by prefixing its name with an ampersand, e.g. &textwidth.
Moving &textwidth characters to the right can be run as follows:
:execute "normal!" &textwidth 'l'
where the arguments ("normal!", &textwidth, and 'l') are concatenated with a space and executed as an Ex command.
So your mapping might look something like this:
:nnoremap <silent> <c-j> :execute "normal!" &textwidth 'l'<cr>

Vim mapping to surround word with a character

In my vimrc file I have the following entry to surround a word with '+':
:nnoremap <silent> q+ wbi+<ESC>ea+<Esc>
I would like to change this to surround a word with any other symbol, for example a quote, but I would not like to use another plugin or to insert one more map. I would like something like this in my vimrc:
:nnoremap <silent> qX wbiX<ESC>eaX<Esc>
where X would be the character to put around the word.
How can this be done in VIM?
Thanks
The general idea:
:nnoremap q :let c=nr2char(getchar())\|:exec "normal wbi".c."\eea".c."\e"<CR>
But I don't think that q is a good choice, especially for your example with quotes, because q starts the extremely handy recording feature from vim. The normal q command also does expect a second character (the recording target register) and it actually can be ". This will be quite confusing for you when you're on another computer or if someone else is using your vim. You should preprend a leader for q. With a leader:
:nnoremap <leader>q :let c=nr2char(getchar())\|:exec "normal wbi".c."\eea".c."\e"<CR>
The default leader value is \, but this can be changed. Note that it had to be changed before defining the mapping. You can see the currently configured leader with let mapleader (which prints an error message if there's no leader configured). With these statements,
:let mapleader=','
:nnoremap <leader>q :let c=nr2char(getchar())\|:exec "normal wbi".c."\eea".c."\e"<CR>
you can type ,q+ to surround your word with + and ,q" in order to surround your word with ".
By the way: Your mapping doesn't work if your cursor is on the last character on line. Change the mapping to:
:nnoremap <leader>q :let c=nr2char(getchar())\|:exec "normal viwo\ei".c."\eea".c."\e"<CR>
Use Tim Pope's surround.vim plugin!
To surround a word with + signs:
ysiw+

Setting mouse=a and mapping <esc> to :noh breaks mouse working on vim? [duplicate]

I am a happy VIM user, although I admit I'm quite far from being fluent. I found this nice post:
Vim clear last search highlighting and I thought I'd become a better person if I didn't have to hammer away a random character sequence every time I did a search. Now, I'm also using the vimrc config from here:
http://amix.dk/vim/vimrc.html
and the problem I have is that when I add the line nnoremap <esc> :noh<return><esc> to it (it doesn't seem to make a difference where I put it) I get awkward behaviour when I use arrows in command mode, namely letters from A to D appear in a newline and I get switched to insert mode.
There has to be some mapping conflict but for the life of me I can't figure out where it is.
EDIT: As it follows from the answers it turns out the Ultimate vimrc part is not relevant, the mentioned nnoremap command will cause altered arrow behaviour even if it's the only vimrc entry. Changing title to a more informative one.
PS. I know I shouldn't use arrows, hopefully I'll get there one day.
The mapping
nnoremap <esc> :noh<return><esc>
will conflict with so called "grey keys" and I believe that it should be used either in GVim only or in terminal Vim by someone who does not use special keys like arrows.
From what I know (and guess) how Vim processes keys, I would say that it's impossible to do anything with this. For Vim to recognize special key all its components should go in a row, so when you press Arrow Left Vim gets the following sequence of codes:
<esc> [ D
But after your mapping Arrow Left becomes:
: n o h l <cr> <esc>
[ D
Vim sees two separate sequences and treats <esc> as a single press of Escape key, thus next two codes of Left Arrow key lose their special meaning.
So I suggest you to map :noh to some other key sequence (e.g. to one starting with <leader>, see :help mapleader; I don't recommend you to use F-keys, using them is as bad as using of arrow keys).
The cause had been explained well, but solution was not mentioned. However there is a straight one.
If you’ll tell to Vim explicitly that there are key sequences starting from <esc>[
:nnoremap <silent><esc> :noh<CR>
:nnoremap <esc>[ <esc>[
than when single <esc> will be pressed Vim will wait for a second (or different time, see :h 'timeoutlen') or for a next key (second <esc> for example) and only then replace it with :noh<CR>.
This solution preserves the ESC mapping to :nohlsearch.
The comment on this answer explaining why this is happening tells us that the root cause is the TermResponse behavior of vim. This can be compensated for by wrapping the mapping in an autocommand for the TermResponse event.
This ensures that the binding doesn't happen until after the term response is set, which prevents Esc from also sending a string like ]>1;3201;0c to vim.
Change your line in vimrc to this:
augroup no_highlight
autocmd TermResponse * nnoremap <esc> :noh<return><esc>
augroup END
The augroup commands are not strictly necessary, but they prevent multiple mappings when you reload your vimrc without quitting vim.
EDIT: If you also use a graphical vim like Gvim or Macvim, the TermResponse event will not fire. Assuming you use a single vimrc, you'll need some additional code like
if has('gui_running')
nnoremap <silent> <esc> :nohlsearch<return><esc>
else
" code from above
augroup no_highlight
autocmd TermResponse * nnoremap <esc> :noh<return><esc>
augroup END
end
Problem is that when you press an arrow terminal emits something like <Esc>OA. Vim part that supports terminal seems to use the same mapping mechanism to do the job as you are using: while nmap <Esc>OA will tell you nothing, call feedkeys("\eOA") will move one line up and call feedkeys("\eOA", 'n') will add letter A beyond current line. With your mapping being noremappable you forbid vim to use <Esc> as a part of the key. The problem is that you need remappable mapping here, but can have remappable mapping without it being recursive as well only if it starts with {lhs}, but <Esc>:noh<CR>OA is not going to work. I thought the following code will (it uses <expr> and function with side effect to make <Esc> be the first character of the actual {rhs} and still launch :noh), but in fact it does not:
function s:NoHlSearch()
nohlsearch
return "\e"
endfunction
nmap <expr> <Esc> <SID>NoHlSearch()
. I have no other idea how to solve the problem of having non-recursive remappable mapping which includes {lhs} but not at the start.
I have had good luck with this
if $TERM =~ 'xterm'
set noek
endif
nnoremap <silent> <esc> <esc>:noh<cr>
The disadvantage is that function keys can not be used in insert mode.
:h ek

How can I map the '<' key in vim?

I would like to create the map
:map <F2> :map <F12> etcetcmy_map
which would have the result of: when I hit <F2>, the string map <F12> etcetcmy_map is typed into my console. but I'm having problems mapping the < key/char. Most pointedly, this is not being done; the string isn't being typed into my console. What happens instead is the the char under the cursor is case fliped (from upper to lower and vice versa) and then the cursor is moved forward by 1 char.
I've tried reading the documentation and have tried the Ctrl-V method, but I'm not getting it right. Does anyone how to do this, or if it is possible?
In your mapping's right-hand side, the <F12> is executed as a key press of the F12 key (with the unexpected side effects you've described), but you want a literal insertion of the string <F12>. For that, escape the < char as <lt>:
:map <F2> :map <lt>F12> etcetcmy_map
Also, you should use :noremap; it makes the mapping immune to remapping and recursion.
If you want to map F12 to etcetcmy_map when you press F2, you can:
:map <F2> :map <F12> etcetcmy_map<cr>

Mapping <esc> in vimrc causes bizarre arrow behaviour

I am a happy VIM user, although I admit I'm quite far from being fluent. I found this nice post:
Vim clear last search highlighting and I thought I'd become a better person if I didn't have to hammer away a random character sequence every time I did a search. Now, I'm also using the vimrc config from here:
http://amix.dk/vim/vimrc.html
and the problem I have is that when I add the line nnoremap <esc> :noh<return><esc> to it (it doesn't seem to make a difference where I put it) I get awkward behaviour when I use arrows in command mode, namely letters from A to D appear in a newline and I get switched to insert mode.
There has to be some mapping conflict but for the life of me I can't figure out where it is.
EDIT: As it follows from the answers it turns out the Ultimate vimrc part is not relevant, the mentioned nnoremap command will cause altered arrow behaviour even if it's the only vimrc entry. Changing title to a more informative one.
PS. I know I shouldn't use arrows, hopefully I'll get there one day.
The mapping
nnoremap <esc> :noh<return><esc>
will conflict with so called "grey keys" and I believe that it should be used either in GVim only or in terminal Vim by someone who does not use special keys like arrows.
From what I know (and guess) how Vim processes keys, I would say that it's impossible to do anything with this. For Vim to recognize special key all its components should go in a row, so when you press Arrow Left Vim gets the following sequence of codes:
<esc> [ D
But after your mapping Arrow Left becomes:
: n o h l <cr> <esc>
[ D
Vim sees two separate sequences and treats <esc> as a single press of Escape key, thus next two codes of Left Arrow key lose their special meaning.
So I suggest you to map :noh to some other key sequence (e.g. to one starting with <leader>, see :help mapleader; I don't recommend you to use F-keys, using them is as bad as using of arrow keys).
The cause had been explained well, but solution was not mentioned. However there is a straight one.
If you’ll tell to Vim explicitly that there are key sequences starting from <esc>[
:nnoremap <silent><esc> :noh<CR>
:nnoremap <esc>[ <esc>[
than when single <esc> will be pressed Vim will wait for a second (or different time, see :h 'timeoutlen') or for a next key (second <esc> for example) and only then replace it with :noh<CR>.
This solution preserves the ESC mapping to :nohlsearch.
The comment on this answer explaining why this is happening tells us that the root cause is the TermResponse behavior of vim. This can be compensated for by wrapping the mapping in an autocommand for the TermResponse event.
This ensures that the binding doesn't happen until after the term response is set, which prevents Esc from also sending a string like ]>1;3201;0c to vim.
Change your line in vimrc to this:
augroup no_highlight
autocmd TermResponse * nnoremap <esc> :noh<return><esc>
augroup END
The augroup commands are not strictly necessary, but they prevent multiple mappings when you reload your vimrc without quitting vim.
EDIT: If you also use a graphical vim like Gvim or Macvim, the TermResponse event will not fire. Assuming you use a single vimrc, you'll need some additional code like
if has('gui_running')
nnoremap <silent> <esc> :nohlsearch<return><esc>
else
" code from above
augroup no_highlight
autocmd TermResponse * nnoremap <esc> :noh<return><esc>
augroup END
end
Problem is that when you press an arrow terminal emits something like <Esc>OA. Vim part that supports terminal seems to use the same mapping mechanism to do the job as you are using: while nmap <Esc>OA will tell you nothing, call feedkeys("\eOA") will move one line up and call feedkeys("\eOA", 'n') will add letter A beyond current line. With your mapping being noremappable you forbid vim to use <Esc> as a part of the key. The problem is that you need remappable mapping here, but can have remappable mapping without it being recursive as well only if it starts with {lhs}, but <Esc>:noh<CR>OA is not going to work. I thought the following code will (it uses <expr> and function with side effect to make <Esc> be the first character of the actual {rhs} and still launch :noh), but in fact it does not:
function s:NoHlSearch()
nohlsearch
return "\e"
endfunction
nmap <expr> <Esc> <SID>NoHlSearch()
. I have no other idea how to solve the problem of having non-recursive remappable mapping which includes {lhs} but not at the start.
I have had good luck with this
if $TERM =~ 'xterm'
set noek
endif
nnoremap <silent> <esc> <esc>:noh<cr>
The disadvantage is that function keys can not be used in insert mode.
:h ek

Resources