VIM move in Insert mode - vim

Why I ask:
I use to enter code for example if(condition){}, in following step:
if(){
}
move cursor back into () to complete condition
move cursor into {} to add task
I have read Traversing text in Insert mode, and I add follow code into my $HOME/.vimrc
" key mapping
inoremap <A-h> <C-o>h
inoremap <A-j> <C-o>j
inoremap <A-k> <C-o>k
inoremap <A-l> <C-o>l
now I can use Alt+h and Alt+l, but the rest of two new map had no effect, then I test: Ctrl+oj and Ctrl+ok, both of them work.
Is there any mistake when I do the key mapping?
How to check if my new mapping is conflicted with other or not?
UPDATE: 2nd/Nov/2016
I buy a new keyboard with cursor key...
Install auto pair
However, I found one interesting thing, when I in Linux, there is ok for all above mapping just except Alt+h, because it conflicted with the ubuntu current open window help menu. I only meet my problem when I use ssh via MobaXerm application.

I have read Traversing text in Insert mode, and I add follow code into
my $HOME/.vimrc
You should carefully read the accepted answer for that answer, specially this part:
The right way is to press Esc, go where you want to do a
small correction, fix it, go back and keep editing. It is effective
because Vim has much more movements than usual character
forward/backward/up/down. After you learn more of them, this will
happen to be more productive.
The answer where you borrowed the mappings also mentions this:
Notwithstanding what Pavel Shved said - that it is probably more
advisable to get used to Escaping Insert mode - here is an example set
of mappings for quick navigation within Insert mode: (...)
Anyway, if you want to understand the problem with the Alt+j and Alt+k, you should first ensure that the mapping is still defined in Vim (they could have been erased or overwritten). You can use :imap to list them; try these:
:imap <A-j>
:imap <A-k>
If your mappings are correctly defined each one will list its target (e.g.: * <C-O>j). In this case you should check if Vim is receiving these combinations correctly; try inserting then in the text (insert mode) by using Ctrl+V (or Ctrl+Q if you mapped that to paste from clipboard) and the Alt combinations. You can get more details at the Vim FAQ "I am not able to create a mapping for the key. What is wrong?".
Edit:
If your issue is mainly related with closing parenthesis, then there are several other options, which I believe that are more practical. I quick internet search returned the following:
SO - Automatic closing brackets for Vim
Vim wiki - Making Parenthesis And Brackets Handling Easier
plugin - Auto Pairs

I also think that you misuse Vim.
I know that the question was about something else but here is my idea of how you should move around in vim.
You have 3 steps:
1. Insert some empty loop / condition
2. Insert a condition
3. Insert a body of the loop / condition
This should represent 3 changes, each separated by leaving the insert mode.
To do it properly you can perform step 1 and then leave insert mode by using either Esc or Ctrl+[ (with the second one- which is also vim default- you do not have to reach for escape key).
Then you should navigate to the place where you want to insert your change using h,j,k or l and follow it by starting insert mode.
There are several ways to start insert mode:
I - start insert mode at the beginning of the line (omitting whitespaces at the beginning)
i - start insert mode before the cursor
a - start insert mode after the cursor
A - start insert mode at the end of the line
s - change the sign under the cursor (can be combined with visual mode)
c - change text from under the cursor until place you have specified with the movement (e.g. ce - change until the end of the word, cl - the same as "s")
C - change everything from cursor until the end of the line
S - replace the whole line
o - start insert mode in the new line below
O - start insert mode in the new line above

Related

Doing an insert remapping for commenter

I am trying to do a remapping when I'm in insert mode to insert a comment but am having a tough time figuring out what all the keys map to. What I am trying to do is:
:inoremap leadercspace ==> escleadercspacei
Basically, if I'm in insert mode I want to get out of insert mode to insert the comment (leader+c+space) and then go back into insert mode.
What would the correct :inoremap mapping for this be? What I have right now is:
:inoremap <leader>c<space> <Esc><Leader>c<space>i
But this doesn't seem to work (at least the latter half of it -- it does seem to be executing the mapping command). Note: the plugin I'm trying to remap is:
https://github.com/preservim/nerdcommenter
[count]<leader>c<space> |NERDCommenterToggle|
Toggles the comment state of the selected line(s). If the topmost selected line is commented, all selected lines are uncommented and vice versa.
From vim doc (:help nore):
Disallow mapping of {rhs}, to avoid nested and recursive mappings
In other words, the nore part forbids mapping to be applied to the rhs (right hand side).
So in your case, the <Esc><Leader>c<space>i doesn't trigger the VimCommenter mapping for that reason.
To allow recursion, you can take off the nore:
:imap <leader>c<space> <Esc><Leader>c<space>i
My recommendation is that, instead of creating an insert-mode mapping for this purpose, just use the native Ctrl+O mapping to run a single Normal mode command from Insert mode.
Assuming your leader key is set to the default \, you can use:
Ctrl+O, \, c, Space
You'll be left in Insert mode at the end of this sequence.
The advantages of this approach over an insert mode mapping are:
You don't need any extra configuration, since Ctrl+O is a native Vim command.
This works for any Normal mode command, so you don't need to add extra mappings for other commands you might want to be able to access from Insert mode.
Adding a multi-character mapping in Insert mode starting with <Leader> means Vim will always pause and hold if you insert the leader character. In this case, it will also pause when you insert <Leader> and c. I find that avoiding this kind of mappings of otherwise printable characters is usually best.

Add new line after current line in insert mode vim

I am new at Vim, and the transition from Sublime to Vim is being really hard. I want to know if there's a shortcut to add a new line above or behind the current line while I'm in insert mode without leaving it. In sublime I used
cmd + Enter
cmd + Shift + Enter
to do but I didn't find a similar way to do it on vim.
I found the way to do it in normal mode using 'o' and 'O' and also configuring this amazing way http://vim.wikia.com/wiki/Insert_newline_without_entering_insert_mode
but none of them reach what I need.
Thanks !
Defining a shortcut for adding line below is easy, just type the following on the Vim command-line (after typing : in normal mode) or add it to your vimrc file:
imap <C-Enter> <Esc>o
That adds an insert-mode mapping (imap) so that Ctrl-Enter will leave insert mode, then use o to add a new line after the current line (leaving you back in insert mode where you started). (<C-xxx> is how Vim represents the special key sequence Ctrl+xxx, and <Esc> is the Escape key).
That's very similar to the "amazing way" you link to, but just using the appropriate key sequence to go from insert mode to normal mode and then add the line. The way to create shortcuts in Vim is to build them up from smaller pieces. If you know about O and o then all you need to do is create a mapping to get into normal mode first then use them.
From that, it should be obvious how to do the other mapping too:
imap <C-S-Enter> <Esc>O
(<C-S-xxx> means Ctrl+Shift+xxx)
Those mappings work fine for me in gvim GUI but may not work in the terminal-based vim, as the key sequences might not get passed correctly from the terminal to vim. Use some other mappings such as Ctrl+o if necessary.

How to efficiently add parentheses or a string in vim?

In traditional text editors, whenever I needed to open a string or parentheses and type something between it I used to do:
Type () or ""
Press left
Type in what I need
Press right
But in vim (that is if I followed the vim way) the process becomes quite tedious as I have to enter the normal mode to move a whole bunch of times:
Type () or ""
Press <ESC>
Press i
Type what I need
Press <ESC>
Press l
Press a
If it is not a good practice to use the arrow keys at any time, is there a more efficient way of doing this kind of task in vim?
It is actually quite easy to automatically append those closing characters in a mapping, and put your cursor where you want it. The trick is to do that, without also messing up the undo/redo/repeat actions. The problem is that cursor movement commands in insert mode will break the "undo sequence" so that any change you make after moving the cursor is undone separately from changes made before moving the cursor.
Warning: the following information may become dated
There are plenty of plugins available to automatically append these characters (see the partial list at the Vim wiki page for appending closing characters), and prior to Vim 7.4, some of them even had complicated workarounds for keeping the undo sequence intact. Unfortunately, they all relied on a bug in Vim that got fixed in version 7.4 for this.
A patch is available to add a cursor movement that does not break undo, so if you want to compile Vim yourself, you can grab that patch and use mappings like the following (no plugin required!) to do what you want:
inoremap ( ()<C-G>U<Left>
inoremap <expr> ) strpart(getline('.'), col('.')-1, 1) == ")" ? "\<C-G>U\<Right>" : ")"
These mappings will insert "()" when you type an opening (, placing the cursor in between the parentheses. When you type ')' and there is already a closing ')' after the cursor, Vim will skip over the parenthesis instead of inserting a new one. Cursor movement is preceded by <C-G>U which is the feature the aforementioned patch adds, allowing the following cursor movement to not break the undo sequence (as long as the movement is all in a single line).
As of Vim 7.4.663, this patch has still not been officially included.
No. Doing it in Vim is exactly the same as in your "traditional" editor:
Type () or ""
Press left
Type in what you need
Press right
But… why don't you type the opening character, what you want inside the pair and then the closing character?
Type ( or "
Type what you need
Type ) or "
Too simple?
I think using arrow keys to move around is bad practice in normal mode but in your case; moving one space while in insert mode, I would hazard to say using the arrow keys is probably best practice.
That being said if you are dead set on avoiding them you could use <i_ctrl-o>.
:help i_ctrl_o
CTRL-O execute one command, return to Insert mode *i_CTRL-O*
So, while in insert mode, you could type: ()<ctrl-o>h<xxx><ctrl-o>l, where <xxx> is whatever you want in the brackets.
Unfortunately that doesn't work if you cursor is on the last character of the line, which if you are typing it most likely is.
To solve that problem do :set virtualedit+=onemore or add it to your ~/.vimrc file.
Note that this solution is more keystrokes than simply using the arrow keys but you don't need to move your hands away from the home row so it may be faster anyway.

Opposite of newline in vim

In vim, is there a command to delete the newline, and all empty space behind the cursor?
Say I stand in the middle of a text in insert mode and press Enter, what command would the reverse what I just did?
A) An example:
"some code{ in here }"
B) After pressing Enter:
"some code{
in here }"
Now pressing backspace will delete one space of the indentation. I would rather have it delete all indentation, and jump back to A.
Can this be done in a command or by doing some remapping to the backspace key?
It's tragic how unknown the J command is. It joins lines in normal mode.
In insert mode, you can press <C-U> twice; first, it'll delete the indent before the cursor, then it'll join with the previous line. Note that this requires
:set backspace=indent,eol,start
did you try J (uppercase) ? it will give exactly what you want.
"some code{ cursor on this line, pressJ
in here }"
You can do ᴇꜱᴄ, K, Shift+J.
K jumps up to the previous line and Shift+J joins the two lines.
However, with properly configured indentation and syntax, a backspace doesn’t just delete a space, it deletes the full previous indentation block.
One easy way is up one line, to end of that line and just delete. As long as you still are in insert mode it will do the same thing as J when deleting at the last position - like most other editors. For me that is the quickest alternative because I'm used to it from other editors.
That is: ↑, End, Delete (when still in insert mode)
One quick alternative (the VIM-way) is (when still in insert mode):
↑, Ctrl+o, J (when still in insert mode)
(Ctrl+o is used in insert mode to enter one normal mode command.)
It's also possible to use a remapping of the backspace key:
inoremap <expr> <bs> getline('.')[:col('.')-2]=~'^\s\+$' ? "<c-u><c-u>" : "<bs>"
Note that this mapping completely overrides the normal behavior the backspace key. This will only be useful when you don't intend to use its normal behavior. This is not recommended if you can easily access the other options (c-u or J)
However, (as far as I know) there's no way to distinguish between manually added leading white spaces and auto indent. If you use noexpandtab, you can edit the regex to only match tabs.
This also does not work in some modes of auto-indent (for example, in block comment in C, vim automatically start a new line starts with *)

Pasting from the clipboard and automatically toggling ":set paste"

When I paste things from the clipboard, they're normally (always) multilined, and in those cases (and those cases only), I'd like :set paste to be triggered, since otherwise the tabbing will increase with each line (you've all seen it!).
Though the problem with :set paste is that it doesn't behave well with set smartindent, causing the cursor to jump to the beginning of a new line instead of at the correct indent. So I'd like to enable it for this instance only.
I'm using Mac, sshing to a Debian machine with Vim, and thus pasting in Insert mode using cmd + v.
I don't use a mac, but I believe I have the prefix right here: <D-v> should mean cmd-v. For insert mode:
:imap <D-v> ^O:set paste<Enter>^R+^O:set nopaste<Enter>
or really, just do this:
:imap <D-V> ^O"+p
The ^O and ^R are literal control-O and control-R, which you can type with ^V^O (control-v control-o) and ^V^R (control-v control-r). Control-O in insert mode allows you to execute one command then return to insert mode; here you can use it to put from the clipboard register.
This worked for me when I tested them mapped to a different key, so you should be all set.
There's no need to map anything when not in insert mode; you can just use "+p.
I have the following in my .vimrc:
inoremap <S-Insert> <ESC>:setl paste<CR>gi<C-R>+<ESC>:setl nopaste<CR>gi
gi is to start insert mode in the same position as where insert mode was stopped last time in the current buffer.
Update:
Jefromi posted a better solution. I have tinkered it a bit
inoremap <S-Insert> <ESC>"+p`]a
It inserts clipboard text and places the cursor right after it.
You're right in that you should only enable 'paste' when you need it. It does more than just affect indenting. You can read everything that it affects in its documentation. A related option that is very useful to ease the use of 'paste' is 'pastetoggle'.
If you were using X-forwarding and a terminal that can properly communicate mouse actions, you could also take advantage of the 'mouse' option. With :set mouse=a, Vim is made aware of what the mouse is doing and therefore won't perform automatic indentation when it receives a multi-line paste via a middle-button mouse click.
Even without the mouse capability, X-forwarding could help because Vim will do the same thing when manually pasting from the clipboard or selection registers ("+ and "* respectively).
This ought to be solvable with a Vim script. (I hate Vim scripting, so it would have to be a much more serious infliction to cause me to solve it myself.) Even with iTerm2's "paste slowly" mode, the default is to break the data to be pasted into 16 byte chunks and send one every 0.125 seconds. Therefore, you should be able to programmatically detect a 16 byte chunk of "keystrokes" and do something about it.
In pseudocode that would look like:
if too_fast_too_be_human():
set('pastemode', True)
else
set('pastemode', False)
# where either
def too_fast_too_be_human
char_threshold = 16
return len(input_buffer) > char_threshold
# or
def too_fast_too_be_human
static byte_times = []
char_threshold = 16
time_threshold = 0.125
byte_times.append(now())
while(len(byte_times) > char_threshold):
byte_times.unshift()
return (byte_times[-1] - byte_times[0]) < time_threshold
There are weaknesses to that, but it would work for most cases.
We can paste (insert mode) without messing up indentation using
Ctrl-r Ctrl-o Register
Ctrl-r Ctrl-o +
Ctrl-r Ctrl-o *
Ctrl-r Ctrl-o 0
CTRL-R CTRL-O {0-9a-z"%#*+/:.-=} *i_CTRL-R_CTRL-O*
Insert the contents of a register literally and don't
auto-indent. Does the same as pasting with the mouse
"MiddleMouse". When the register is linewise this will
insert the text above the current line, like with `P`.
Does not replace characters!
The '.' register (last inserted text) is still inserted as
typed.

Resources