Issue with smartindent in Vim - vim

In vim with smartindent on:
Press Enter after say an if-statement
Type in {
Press Enter twice
Type in }
If you hit ↑ and go to the previous line, indentation is removed from the blank line.
Even the vim documentation says that:
If you do not type anything on the new line except <BS> or CTRL-D and then type <Esc>, CTRL-O or <CR>, the indent is deleted again.
Is there any way to keep this indentation and not have it deleted?

Use Shift+S to start editing on a blank line (from command mode, obviously). This will start your cursor off with the expected level of indentation.
Another doesn't-answer-the-question-as-asked-but-is-a-better-solution-overall:
When typing an opening brace in insert mode, this will insert a matching set of braces
and leave the cursor on a new line in the middle.
:imap { {<CR>}<Esc>O
Similarly, this will auto-insert matching parens and square brackets.
:imap ( ()<Left>
:imap [ []<Left>
(Strip off the leading : when adding to vimrc.)
As I commented on Victor's answer, changing Vim's indentation behavior will leave "empty" lines containing extraneous spaces throughout your files. IMO, this is completely intolerable.

When this happens to me, I sometimes use ddko (or ddO) to delete the line without enough spaces and open a new line with the correct indent. Or, I'll just press A and then Tab enough times to get to the correct indent.

the article here talks about you're very same problem, and what to put in vimrc to fix it.
inoremap <CR> <CR><Space><BS>
nnoremap o o<Space><BS>
nnoremap O O<Space><BS>
I havn't exactly tested this tho.
also the same article links to a shorter alternate solution.

My preferred method is {<CR>}<esc>shift+o as it outpaces {<CR><CR>}<esc>k shift+s by several strokes. I get in a rut with it, though, and end up just using o or O to grab new, properly-indented lines off an empty when I should be using S.
That is, set up your bracing structure and open line-above:
if (true) {
}//cursor here, press shift-o
And you get the indenting you expect.
The open-above trick isn't any fewer keypresses than <up><end><cr>, but with escape remapped and shift being chorded, you can throw it in quite fast.
Also, don't forget your manual indent reset and block-movement. If you're inside a mangled curly brace block, simply use ={ (or =i{ if you're on top of one of the braces). I use that when I have a Good Idea that needs to see text asap, and I don't worry about any formatting frippery until I take a breather.

Related

extra space added when going into insert mode in an abbreviation

I'm trying to create an abbreviation which replace typed text by what I want but also move the cursor and enters insert mode.
the ab is as following:
:abbreviate MSG `MSG(("")); <Esc>F"i
everything works fine except when entering insert mode, I have to extra spaces before the cursor.
I've tried then to add <BS><BS> but it's leading to delete the first quote. Same thing if I'm putting only one <BS> (which is really strange, it seems the second <BS> has no effect at all...)
I guess I'm missing something but I can't figure out what...
Thanks for your help !
A citation from Vim help system (:help abbreviations):
An abbreviation is only recognized when you type a non-keyword
character. This can also be the <Esc> that ends insert mode or the
<CR> that ends a command. The non-keyword character which ends the
abbreviation is inserted after the expanded abbreviation. An
exception to this is the character <C-]>, which is used to expand an
abbreviation without inserting any extra characters.
Example:
:ab hh hello
"hh<Space>" is expanded to "hello<Space>"
"hh<C-]>" is expanded to "hello"
So if you press <Space> after entering MSG a space is inserted after expanding your abbreviation.
To avoid adding a needless space you can invoke the abbreviation with pressing <C-]> after entering MSG or you can try elaborate a mapping like this:
:inoremap MSG `MSG(("")); <C-O>F"
But IMHO such a mapping is very inconvenient.
Another option may be to use use one of the many abbreviation plugins like this (first shown by Google).

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.

vim ident: don't remove tabs indent when closing }

When I have the following in vim with cindent or vim-javascript turned on:
if(bla){
#
(# shows cursor)
I type a new line:
if(bla){
#
and then close the }
if(bla){
}
The problem is, now I go back up to the previous line and
if(bla){
#
}
There's no more indent after #! Now you might think this isn't annoying, but when I am working in files with multiple levels of tab indenting it destroys my productivity because of the way I code. Is there any way to make closing a } NOT destroy the tab indent before the lines?
The tab is not deleted because you closed the {}, it's deleted because you didn't enter any text on that line.
I've had many variants of the following mappings in my ~/.vimrc to "fix" that issue (waiting for a cleaner solution) for a couple of years:
inoremap {<CR> {<CR>}<C-o>==<C-o>O
inoremap {; {<CR>};<C-o>==<C-o>O
Both do the same thing: they close the {} and put the cursor where it belongs. There are a bunch of autoclosing plugins that offer that feature but I've found them too annoying in the long run.
What are you using to move up to the blank line? The arrow keys (a bad habit, according to some)? Maybe you don't need to put in the closing brace until you've written the stuff above it? You could also just not leave the blank line, hit the closing brace, then type <esc>O to open above. Or if you like to leave the blank line for some reason just use S to reset the indent.

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 *)

How do I insert a linebreak where the cursor is without entering into insert mode in Vim?

Is possible to insert a line break where the cursor is in Vim without entering into insert mode? Here's an example ([x] means cursor is on x):
if (some_condition) {[ ]return; }
Occasionally, I might want to enter some more code. So I'd press i to get into insert mode, press Enter to insert the line break and then delete the extra space. Next, I'd enter normal mode and position the cursor before the closing brace and then do the same thing to get it on its own line.
I've been doing this a while, but there's surely a better way to do it?
For the example you've given, you could use rEnter to replace a single character (the space) with Enter. Then, fspace. to move forward to the next space and repeat the last command.
Depending on your autoindent settings, the above may or may not indent the return statement properly. If not, then use sEnterTabEsc instead to replace the space with a newline, indent the line, and exit insert mode. You would have to replace the second space with a different command so you couldn't use '.' in this case.
A simple mapping to break the line at the cursor by pressing Ctrl+Enter:
:nmap <c-cr> i<cr><Esc>
essentially enters 'insert' mode, inserts a line break and goes back to normal mode.
put it in your .vimrc file for future use.
Here's how to create a macro that inserts a newline at the cursor whenever you press 'g' while not in insert mode:
From within vim, type:
:map g i[Ctrl+V][Enter][Ctrl+V][Esc][Enter]
Where:
[Ctrl+V] means hold the Ctrl key and press 'v'
[Enter] means press the Enter key
[Esc] means press the Esc key
You'll see the following at the bottom of your vim window until you press the final Enter:
:map g i^M^[
Explanation:
[Ctrl+V] means "quote the following character" -- it allows you to embed the newline and escape characters in the command.
So you're mapping the 'g' key to the sequence: i [Enter] [Escape]
This is vim for insert a newline before the cursor, then exit insert mode.
Tweaks:
You can replace the 'g' with any character that's not already linked to a command you use.
Add more to the command, e.g. f}i^M^[O -- This will find the } and insert another newline, then escape from insert mode and Open an empty line for you to enter more code.
You can add the command to your .vimrc or .exrc file to make it permanent. Just omit the colon from the beginning, so the command starts with "map"
Enjoy!
If you're usually expanding a one line block to three lines, try substitution. Change the opening bracket into bracket/return, and the closing bracket into return/bracket.
The command for substituting bracket/return for bracket looks like this:
:s/{/{\r/
Since you want to use this often, you could map the full sequence to an unused keystroke like this:
:map <F7> :s/{/{\r/ ^M :s/}/\r}/ ^M
Where you see ^M in the sequence, type [Ctrl-V], then press enter.
Now with your cursor anywhere on your sample line, press the mapped key, and the carriage returns are added.
Check :help map-which-keys for advice on selecting unused keystrokes to map.
Assuming you're okay with mapping K to something else (choose a different key of your liking), and using marker ' as a temporary marker is okay why not do this?
:nmap K m'a<CR><Esc>`'
now pressing K in normal mode over the character after which you want the line break to occur will split the line and leave the cursor where it was.
Basically, when you split a line you either want to just insert a carriage return, or in the case that you're on a space, replace that with a carriage return. Well, why settle for one or the other? Here's my mapping for K:
"Have K split lines the way J joins lines
nnoremap <expr>K getline('.')[col('.')-1]==' ' ? "r<CR>" : "i<CR><Esc>"
I use the ternary operator to condense the two actions into one key map. Breaking it down, <expr> means the key map's output can dynamic and in this case hinges on the condition getline('.')[col('.')-1]==' ' which is the long winded way to ask vim if the character under the cursor is a space. Finally, the familiar ternary operator ? : either replaces the space with linebreak (r<CR>) or inserts a new one (i<CR><Esc>)
Now you have a lovely sister key map to the J command.
Vim will automatically kill any whitespace to the right of the cursor if you break a line in two while autoindent (or any other indentation aid) is enabled.
If you do not want to use any of those settings, use s instead of i in order to substitute your new text for the blank rather than just inserting. (If there are multiple blanks, put the cursor on the leftmost and use cw instead.)
In fact you need the following combined operations:
Press v to enter Visual Mode
Select the line you want to split
Press : to enter in Command Mode
s/\s/\r/g
Done
If you have the input:
aaa bbb ccc ddd
and want to output
aaa
bbb
ccc
ddd
You can use the command
f r<ENTER>;.;.
o ESC command will do it for you.
Set this key mapping in your vimrc
:map <C-m> i<CR><Esc>h
Then press Ctrl+m if you want to use it in your vim.
IMHO, the built-in mapping gs is not a useful mapping (put vim to sleep), one could use this for splitting:
nmap gs i<CR><ESC>
In Vrapper you can use gql which will split a line without entering insert mode, but may not always maintain indentation.
I found this to be the most faithful implementation of what I'd expect the opposite behaviour to J
nnoremap S i<cr><esc>^mwgk:silent! s/\v +$//<cr>:noh<cr>`w
It does the simplistic new line at cursor, takes care of any trailing whitespace on the previous line if there are any present and then returns the cursor to the correct position.
i <cr> <esc> - this is one of the most common solutions suggested, it doesn't delete non-whitespace characters under your cursor but it also leaves you with trailing whitespace
^mw - goto start of new line and create a mark under w
gk - go up one line
:silent! s/\v +$//<cr> - regex replace any whitespace at the end of the line
:noh<cr> - Clear any search highlighting that the regex might have turned on
`w - return the the mark under w
Essentially combines the best of both r<esc><cr> and i<cr><esc>
Note: I have this bound to S which potentially overwrites a useful key but it is a synonym for cc and since I don't use it as often as I do splits I am okay with overwriting it.
This mapping will break up any one-line function you have. Simply put your cursor on the line and hit 'g' in normal mode:
:map g ^f{malr<CR>`a%hr<CR>`a
This assumes that you have a space after the opening brace and a space before the closing brace. See if that works for you.

Resources