Movement to the closing parenthesis from inside block - vim

I want a movement to get from point 1 to points 2 and 3:
FunctionCall(a, b, c, AnotherFunc(a, b))
^ <--- ^ ------------> ^
3 1 2
Ideally it would work with editing operations like d, y etc
Now I count closing parentheses visually and use <n>f), but it's very annoying.
Vim does have facilities to know about blocks, i.e. i(, a(, but I want 'a half' of such a command.
How can I achieve this?

What I usually do is using a suitable commands from various-motions.
For example, for your particular case ]) followed by % will help.
They can be combined with operations like d, y and c.
More details using :help various-motions

You are right that the text objects have knowledge about both sides of the block. If you briefly go into visual mode, your cursor will end up on the end of the range (va(<Esc>) or the beginning (va(o<Esc>) when using the v_o command to switch to the "other" side of the selection.
Unfortunately, because this involves multiple steps, it only works for navigation, but not as an atomic {motion} to be used with d, y, etc. You could write a custom motion for those, though. For example:
onoremap ,) :normal! va(<C-v><Esc><CR>
onoremap ,( :normal! va(o<C-v><Esc><CR>
These then work like motions, e.g. gU,) uppercases the text from the cursor to the closing parenthesis.

The normal mode command % will take you to the next opening paren (and while there, toggling between the opening and closing parentheses). So sadly it would jump to the innermost opening paren instead of place 2 or 3.
Couple that with a F( and you've got something remotely neat that doesn't involve counting. So in place 1, F(% would take you to place 3 and a subsequent % would jump you to place 2.

You can do the following:
nnoremap <silent> ,) :normal! va(<c-v><esc><cr>
nnoremap <silent> ,( :normal! va(o<c-v><esc><cr>
onoremap ,) :<c-u>normal! mava(o`a<cr>
onoremap ,( :<c-u>normal! mava(`a<cr>
Note that for the motion version (onoremap), it consumes the a mark, which can be a problem; so it could be improved.

Related

Vim: how to remap a "general" key

One thing I really like in Vim is it's hability to have multiple clipboards available. However I hate to write "ay to yank and "ap to paste, I'd rather have something closer to the classical Ctrl-c, Ctrl-v, like ←a (←: AltGr + y) and þa (þ: AltGr + p).
I could make a remap like nnoremap ←a "ay in this case, but then I would only have the buffer "a" available to use this way. So the question is: could I make a remap such as nnoremap ←{key} "{key}y in vim, that would replace the {key} with whatever I typed, so that I could use any character as a register with only one remap? (←q becomes "qy, ←w becomes "wy, etc...)
Btw: yes, AltGr keys like "←" and "þ" works just like any other letter for commands.
The left-hand side of a mapping can't be dynamic.
The easiest way to deal with that limitation is simply to loop through a list:
for reg in 'abcdefghijklmnopqrstuvwxyz'
execute 'nnoremap ←' .. reg .. ' "' .. reg .. 'y'
execute 'nnoremap þ' .. reg .. ' "' .. reg .. 'p'
endfor
See :help :for, :help :execute, :help expr-...
Note that y is an operator and an operator is supposed to "operate" on a motion. This means that all those "{char}y normal mode mappings are useless. For this to actually be useful, you would need to:
make visual mode mappings for y,
make a custom operator for use in normal mode, see :help :map-operator.

Vim: record macro entering insert mode via mapping

I'm trying to have remap i/c/o/a and friends to always record a macro. But the keypress that actually brings me into insert mode is not recorded (explained below).
For example, if we have:
nnoremap i qzi
inoremap <esc> <esc>q
Ideally, this means that when I enter insert mode (i), I also start recording to register z. And when I leave (<esc>), we stop recording. So register z should have the entire sequence needed to repeat what I did in insert mode.
But then if I try to type in insert mode (e.g., ihelloworld<esc>) and then check :registers a, I get
---Registers---
"z helloworld^[
Notice how the i command is not included -- only what i typed in insert mode is.
Why is this happening? What can I do to get around it?
I also noticed that if I just typed qzihelloworld<esc> normally, the z register DOES contain ihelloworld<esc> (with the i).
For those interested, I'm doing trying to do this because certain operations break 'repeat last command (the period key .)'. For example, if you use <c-o> or move around while insert-mode, . will only repeat the last segment of your insert mode. In particular, I'm trying to find a workaround for an autoclosing plugin
As #Carpetsmoker explains why it doesn't get recorded:
From :help q
The 'q' command is disabled while executing a register, and it doesn't work inside a mapping and :normal.
So that explains why it doesn't work ...
A solution:
As the command (e.g., i) in the mapping is not recorded, a solution is to prepend it to the recorded buffer when leaving insert mode.
To distinguish between i, a, o, etc, you can store the command in a variable, and then prepend that to the recorded macro:
nnoremap i :let b:mode="i"<cr>qzi
nnoremap a :let b:mode="a"<cr>qza
nnoremap o :let b:mode="o"<cr>qzo
inoremap <Esc> <Esc>q :let #z=":normal! ".b:mode.#z<CR>
Simply prepending i (etc.) to the macro doesn't work (for me) since it triggers the mapping for i. Calling it with normal! fixes that.
Another option is to modify the macro to enter insert using startinsert (combined with suitable movements to emulate i, a, o, etc.) by prepending the macro like this
:let #z=":startinsert^M".#z
caveat: Your rationale for wanting this:
For example, if you use <c-o> or move around while insert-mode, . will only repeat the last segment of your insert mode.
(my emphasis) needs the warning that "moving around" (with arrow keys) does not work (at least in my quick tests) without additional hacking, as the arrow keys send an <esc> ... sequence, triggering the end of the recording mapping for <esc>. c-o will work though, so you can move around (slowly) with e.g. <c-o> h (for moving left).
Another problem is that replaying it as a macro does not work (with this solution at least, perhaps due to the use of normal!) if you have newlines, etc., in the recorded macro. A solution to that is to execute the buffer instead of replaying it as a macro. That is, :exe #z instead of #z for instance with the mapping
nnoremap <space>z :execute #z<cr>

VimTutor arrow keys v/s hjkl

VimTutor says in its first lesson:
NOTE: The cursor keys should also work. But using hjkl you will be
able to
move around much faster, once you get used to it. Really!
However, I find no difference at all between them. Is there really a difference between using hjkl v/s the arrow keys?
You don't have to move your hand from the touch type position to use hjkl, whereas you do if you use the arrow keys.
The thing is that you start out using the "hjkl" key just as a slightly better way to move your cursor, but the truth is that they are actually motions.
h motions one character left
j motions one line down
k motions one line up
l motions one character right
So for example, with the delete operator d: dl deletes the current character, dh deletes the previous character, dj deletes the current line and a line below it, and dk deletes the current line and a line above it. The same is of course true for the y, c, V, gU and any operator.
Another example are split windows. You can create a couple of windows using Control-w+s and Control-w+v, then use your trusty hjkl to move around between your windows, Control-w+h moves a window left, Control-w+j moves a window down, etcetera.
So it's not just that they are an improvement over the arrow keys. As your understanding of Vim grows, you'll learn that the hjkl keys can be combined with other commands in many ways, and you will be happy you can use them.
In fact, using h j k l keys makes a good practice to avoid to much of right hand movimentation on your keyboard when you have to reach the arrow keys but, there are more efficient ways to navigate through a text file using vim:
f <char> : Go to the next occurrence of a character<char> on the current line. Cursor is placed above the character;
t <char> : Go to the next occurrence of a character<char> on the current line. Cursor is placed right before the character;
T and F: Backward your character search on this line, however T will put the cursor right after the character(or before if you think backwards ;) ), and F will put it above of it.
/ <char> <Enter>: Go the next occurrence of a character independent of line. After you do this one time, pressing n or N goes to the next and previous occurrence.
? <char> <Enter>: Go to the next occurrence of a character independent of line, backwards. n will search next occurrence(backwards) and N will go to the previous.
{ and } : Navigate on paragraphs. Paragraphs are basically blocks divided by an empty line. See :help paragraph for further details.
( and ) : Navigate back and forward on Sentences(:help sentence). A sentence is a group of words ended by . ! or ? followed by a space, tab or endline.
e : next word, place the cursor at the end of the word
w : next word, place the cursor at the start of the word
b : back 1 word, place the cursor at the start of the word
ge : back 1 word, place the cursor at the end of the word
E W B and gE : Same as e w b ge, but with WORD. See :help word for further details.
If you want to start by getting the first good habits of using h j k l or other movements and avoid the arrow keys, pleace the following lines on your .vimrc file inside your home to disable them:
noremap <Up> <NOP>
noremap <Down> <NOP>
noremap <Left> <NOP>
noremap <Right> <NOP>

vim line operations (e.g., dd) on wrapped text

I'm using wrap in vim, but I want vim to otherwise behave as though the lines have actual breaks in them (rather than "soft breaks" for screen rendering).
I've mapped j to gj and k to gk for navigation. However, line operations (such as dd) still act upon the whole line, rather than the "screen line". Is there any way to alter this behavior such that 'dd' is limited to the screen line?
You can create a key mapping:
:nnoremap dd g0dg$
I would rather create a new operator, for example x in operator-pending mode:
onoremap x :norm! g0vg$<cr>
xnoremap x g$og0o
With the first mapping, dx will delete a screen line, yx will yank a screen line (beware, it will not be pasted linewise, but characterwise), cx will delete a screen line and start insert mode, and so on.
With the 2nd mapping, x in visual mode will extend to screen lines the visual selection.
I wouldn't advise remapping dd, because this might break plugins (if they use :normal instead of :normal! or if they use :×××map instead of :×××noremap.

Map 'f' to PageUp in vi

I can map 'jj' to
imap jj <Esc>
and I can even map letters to tab navigation
map tj :tabprevious<CR>
map tk :tabnext<CR>
But I can't map g to page up (even though spacebar acts as page down)
map <Space> <PageDown>
map g <PageUp>
According to this "When you try to map multiple key sequences, you won't be able to start them with lower or upper case letters ("Too dangerous to map that"), but the punctuation and control characters are fair game." Can anyone confirm this?
If so, how does one assign a function to an unmapped key like 'g'
This isn't answering your question, but I thought it may be helpful to the problem you are having with your RSI. It maps the spacebar to toggle between fast and slow move modes. Normally pressing j or k will scroll down one line. Pressing space will turn on fast move mode, where pressing j or k will scroll down/up 10 lines. Press space again to go back to normal. This will only work in vim, not just plain vi (most "vi" programs are just symlinks to vim anyway though).
It works in both normal and visual edit modes.
To use it, put this code somewhere in your ~/.vimrc file:
map <Space> :call ToggleFastMoveMode()<CR>
vmap <Space> :call ToggleFastMoveMode()<CR>gv
let g:fastMoveMode = 0
function! ToggleFastMoveMode()
let g:fastMoveMode = 1 - g:fastMoveMode
if (g:fastMoveMode == 0)
noremap j j
vnoremap j j
noremap k k
vnoremap k k
else
noremap j 10j
vnoremap j 10j
noremap k 10k
vnoremap k 10k
endif
endfunction
(Edit - original answer suggested native Ctrl-f and Ctrl-b, but answer was updated as the goal here is to avoid using Ctrl and Shift)
A few points to add
Leaving the issue of choosing the right character to you, assuming we chose X for now.
I can think of two reasons why map X <PageUp> isn't working for you.
Your version of vi may not support PageUp/PageDown. If this is the issue then try instead to map to vi's page jumping (B for back, accompanied by for forward) eg. map X <C-b>.
Another other option is that it doesn't work 'as expected'. In vi PageUp/PageDown act on the 'viewport' not the cursor. So if you'r looking at the top of the file, but the cursor is not at the top or won't do anything. PageDown won't 'work' if your cursor is two lines from the bottom either.
To address this you could combine the 'move viewport up' <C-b> and the 'move cursor to the top of viewport' H eg. map X <C-b>H (The opposite being map X <C-f>L). Or specifying the number of lines to jump yourself map X 30k (Op. map X 30j).
Then the issue of choosing the right character to overwrite. Vi has a lot of native commands, so many in fact that only a handful of characters don't do something natively.
So if your goal is to avoid RSI, then of course overwrite something. But make sure to overwrite something that isn't too useful for you personally.
Natively:
f searches for a given symbol on the line you are currnetly on (can be very useful, but not critical I guess)
g on it's own does nothing, but gg moves cursor to top of file. Choosing g may cause issus as vim (not the original vi) will interpret two quick keypresses as go to top of file instead of do two PageUp's.

Resources