views:

2086

answers:

7

I recently started using vim 7 (previously vim 6) and the smartindent setting. For the most part, it works well, though I'm so used to typing a tab after an open brace that it is almost counter-productive.

However, there is one piece of maniacal behaviour. When editing a shell script, I try to create a comment at the current indent level, but smartindent will have nothing to do with it. It insists that the comment must be at level 0 (no indent). What's worse, it breaks shift-right ('>>' and friends) so that they do not work. This is outright insubordination, and I'd like to know what's the best way to fix it?

(I'm also not keen on smartindent's ideas about indenting then after if.)

Preferred solutions will save me manual bashing - I'm being lazy. One option would be 'turn off smartindent when editing shell scripts (leave it on for the rest)'. Another option would be guidelines on how to find the control script for smartindent and what to edit to change the characteristics I don't like. The final option (which I don't need advice on how to do - just the hint that it is the best, or only, way to restore sanity) is to leave smartindent unset.

I saw the vaguely related question on "(PHP and) annoying vim unindent rules"; it doesn't provide me with the direct answer, though maybe the cindent and related items mentioned in there are in fact part of the answer.

+4  A: 

Find the indent file, (e.g. /usr/share/vim/vim71/indent/sh.vim on my system)

This line looks like the problem:

setlocal indentkeys-=:,0#

Perhaps you can fix this in your .vimrc or load a custom indent file manually.

edit: It looks more complicated than I thought, but maybe there is something specifically set in the indenting file that you would need to fix.

2nd edit: Looks like I was completely wrong, Check out:

Restoring indent after typing hash

or

howto-configure-vim-to-not-put-comments-at-the-beginning-of-lines-while-editing

Good pointers in the right direction. There's a README.txt file which also provides some pointers - notably to ':help indent-expression', which in turn points to 30.3 of the online manual. But that file is the one that I need to hack, butcher or otherwise modify, countermand or replace. Thanks!
Jonathan Leffler
Heh...found out that smartindent puts # at the start for C pre-processor directives. I'm probably going to cancel the shell rules altogether by creating ~/.vim/indent/sh.vim containing ':let b:did_indent = 1'. I'll chase the links you added with the second edit, too.
Jonathan Leffler
A: 

Well, after exploring some options, including using ':set cindent' instead of ':set smartindent', I've ended up reverting to just using ':set autoindent'. There probably are ways to make this stuff work exactly as I want it to, but it is messy enough and fiddly enough that I can't be bothered. I've worked fine with autoindent for the previous 20-odd years, and the benefits from the extra bells and whistles provided by smartindent are outweighed by the what I regard as its misbehaviour.

Thank you, Juan, for your assistance. Believe it or not, it did help - quite a lot.

I also discovered a couple of other neat commands, though, while following up on this:

>i}
>a}

These right-shift the block of code you are in. The 'i' version indents the body and not the closing braces (my preferred style), and the 'a' version indents the closing braces to (the version that is required at work).

Also, you can apply qualifiers to '%' in commands executed at the shell:

:make %:r.o

This would run make on the 'root' of the current file name (that's '%:r') followed by '.o'. Or, in other words, if I'm editing somefile.c, this executes make somefile.o.

Jonathan Leffler
Glad to help. Thanks for the tip about shifting blocks. I shift blocks all the time, but was visually selecting text and using the right shift (>>) operator.
I used to use '>%' on the line with the open or close brace to shift everything. I'd also use '>%<<%<<' to shift the body of a block right and then unindent the two braces. But those new commands seem to work in the middle of a block, which is nice.
Jonathan Leffler
A: 

I have the following lines in my .vimrc and I don't observe the problem.

set smartindent
inoremap # X^H#

I used to have set autoindent after these two lines but it seems that it has no effect.

PolyThinker
+1  A: 

Add the line below in your .vimrc

filetype indent on

(it will set the right indent mode depending on the filetype)

+1  A: 

Yes that is very annoying. smartindent is really only for C like languages. See how I enable the appropriate indenting based on language at: http://www.pixelbeat.org/settings/.vimrc

pixelbeat
+1  A: 

I had this same issue for a long time, until I realized that autoindent and smartindent are both unnecessary if "filetype indent on" is set in your vimrc - 'filetype indent on' uses the indent/sh.vim (or whatever language) file in your vim directory to figure out the indentation rules, and autoindent and smartindent both can interfere with it.

I haven't tested this with sh, but perl suddenly started behaving properly when I switched.

Sidenote: Juan's redirect, "Restoring indent after typing hash", is not a good solution - while it does correct the problem in one situation (typing code in), it doesn't change how the editor thinks it should be indented, so a re-indent (visual =, or normal ==) will shove it back to the left.

A: 

The previous answer suggesting:

:inoremap # X^H#

is excellent. It is the answer suggested by the VIM documentation at ":help smartindent". Note that ^H is entered using CTRL-V CTRL-H. The relevant section from the documentation is below.

    When typing '#' as the first character in a new line, the indent for
    that line is removed, the '#' is put in the first column.  The indent
    is restored for the next line.  If you don't want this, use this
    mapping: ":inoremap # X^H#", where ^H is entered with CTRL-V CTRL-H.
    When using the ">>" command, lines starting with '#' are not shifted
    right.
Russell Silva