I'm deciding to switch from tabs to spaces in my python code. Previously, if I wanted to indent/unindent a block of code in vim, I would use the >> or << commands.
I'm using the vimrc setup for python by adding it to my ~/.vimrc:
source ~/.vimrc-python
Currently, it appears it is setting new tabs to be 8 spaces wide, and when I block indent/un-indent it moves everything by four spaces.
How might I get everything so that it is consistent?
Try these:
set shiftwidth=4
set tabstop=4
set expandtab
shiftwidth indicates how far to indent with the operations (<< and >>) you are using.
tabstop indicates how far to indent with the tab key.
expandtab converts tabs into spaces.
As [http://stackoverflow.com/users/2241874/bradd-szonye](Bradd Szonye) points out, you can also alternatively do
set shiftwidth=4
set softtabstop=4
set tabstop=8
set expandtab
which means that if there is an actual tab character, it will show as 8 columns, but hitting the tab key gives 4 spaces.
Related
This is my current .vimrc:
cat ~/.vimrc
set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936
set termencoding=utf-8
set encoding=utf-8
set tabstop=4
set softtabstop=4
set shiftwidth=4
set noexpandtab
set nu
set autoindent
set cindent
set encoding=utf-8
set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936
set termencoding=utf-8
I am debugging others' code and when I inserted a new line, it seems automatically indented with the next line. However, when I execute the python program, it complaints. For example, I added a print statement to the following:
for i, third in enumerate(third_list):
j = i % 4
third_group4[j] = third
print('i, j', i, j)
if j == 3:
....
The print seems aligns well with other lines, but it complains:
python test.py
File "test.py", line 156
if j == 3:
^
IndentationError: unexpected indent
The next line got the complaints about the indent. I manually checked and found that instead of the original 8 leading spaces in front of 'if', the first 4 spaces are a tab, which is also 4 spaces long. The 1-tab+4 spaces are the same length as the 8 spaces, but that's why it complains.
I tested a few other print statements and it seems it always affected the following line when I inserted a print statemnt.
How can I void this? I don't want to manually fixe the indent whenever I made a little change to the code. I am on Centos 7.
First, let's remove the redundant lines from your vimrc:
set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936
set termencoding=utf-8
set encoding=utf-8
set tabstop=4
set softtabstop=4
set shiftwidth=4
set noexpandtab
set nu
set autoindent
set cindent
Second, let's fix the encoding part:
set encoding=utf-8
set fileencodings+=gb18030,gbk,gb2312,cp936
:help 'termencoding' gets its value from :help 'encoding' so you only "need" set encoding=utf-8 if you want both options to have the same value.
Note that Vim gets its default value for 'encoding' from your environment so it might be a good idea to set it up properly instead of hacking individual programs to work the way you want.
The default value of :help 'fileencodingd' if 'encoding' is utf-8 is fine and covers a lot of ground already. Adding your local encodings makes more sense than redefining the whole thing.
and normalise option names:
set number
Now we can turn our attention to the rest…
set cindent is specifically made for C so it is useless if you are working on Python code and thus can safely be removed.
set noexpandtab explicitly tells Vim to use hard tabs. There are two problems with this line:
:help 'expandtab' is disabled by default so there is no point doing it manually.
You actually want spaces, not tabs, so the right value would be set expandtab.
Here is how your vimrc should look at this stage:
set encoding=utf-8
set fileencodings+=gb18030,gbk,gb2312,cp936
set tabstop=4
set softtabstop=4
set shiftwidth=4
set expandtab
set autoindent
set number
which doesn't seem to mess with the formatting of your sample code.
Note that Vim comes with a built-in filetype detection mechanism that, among other things, sets the standard indentation rules for Python. Just add the following line to your vimrc to benefit from it:
filetype plugin indent on
See :help :filetype.
I know it is possible to set the indent for a specific filetype by
set softtabstop=4
But the problem I am facing is, I have different python script files, some of them are indented with 2 spaces, while some of them are indented with 4 spaces. Is it possible to let vim determine the indent spaces to use (2 or 4) automatically based on the file opened?
Any help will be appreciated.
It looks like this vim plugin will do what you want: https://github.com/requalix/detect-indentation.
There are several plugins that can detect the used indent settings. Some, like my IndentConsistencyCop plugin also warn you about inconsistent indents. The following list is taken from my plugin's documentation:
My own IndentConsistencyCop plugin; automatic triggering is enabled by the companion IndentConsistencyCopAutoCmds plugin.
Indent Finder (vimscript #513) is a Python script and Vim plugin that scans
any loaded buffer and configures the appropriate indent settings
yaifa.vim (vimscript #3096) is a port to vimscript of the above
detectindent.vim (https://github.com/ciaranm/detectindent) by Ciaran
McCreesh tries to auto-detect the indentation settings
GuessIndent (vimscript #4251) is based on detectindent.vim
indentdetect.vim
(https://github.com/ervandew/vimfiles/blob/master/vim/plugin/indentdetect.vim)
by Eric Van Dewoestine performs a simple detection and can set defaults
based on the filespec
matchindent.vim (vimscript #4066) detects tabs, 2 and 4-space indents and
adapts the indent settings accordingly
sleuth.vim (vimscript #4375) by Tim Pope automatically adjusts 'shiftwidth'
and 'tabstop' heuristically (via a simplistic sampling that does not check
for bad or inconsistent indents) or by looking at other files of the same
type
filestyle (vimscript #5065) highlights tabs when 'expandtab' is set,
trailing spaces, and lines longer than 'textwidth', but doesn't actually
check conformance to indent
ShowSpaces (vimscript #5148) highlights spaces inside indentation, per
buffer / filetype.
Indent Detector (vimscript #5195) run when a file is opened or written, has
warnings about mixed tab / space indent, and can adapt Vim's corresponding
options automatically.
With the following option set:
setlocal formatprg=autopep8\ -aa\ -
When I select a single line in Visual Mode and press gq, the autopep8 makes its modification to the line but it also alters the indentation of the line: it defaults to an indent of 4 spaces, no matter the current indentation level of the line(s). I want it to assume that the lines are indented correctly and so to leave them alone.
Similarly, if I set the --indent-size 8 switch for autopep8 it will push the lines to an indent level of 8 spaces. Note that if the visual selection is large enough to encompass the top-level indentation (i.e. where there's no indentation), everything is indented correctly. But I tend to Visual Select smaller blocks before making commits.
You need to give --indent-size 0. So my .vimrc has this line:
" Use gq to clean up code
" Indent to 0 because otherwise it pushes selected lines to the given
" indent-size, no matter the current indent level of the line.
au FileType python setlocal formatprg=autopep8\ -aa\ --indent-size\ 0\ -
When I add a # in insert mode on an empty line in Vim while editing python files, vim moves the # to the beginning of the line, but I would like the # to be inserted at the tab level where I entered it.
For example, when writing this in vim
for i in range(10):
#
the # does not stay there where I entered it.
It is moved like so, by vim.
for i in range(10):
#
Does anyone know of a configuration item in vim that would change this?
If it helps, I am using Ubuntu 8.10.
I found an answer here http://vim.wikia.com/wiki/Restoring_indent_after_typing_hash
It seems that the vim smartindent option is the cause of the problem.
The referenced page above describes work-a-rounds but after reading the help in smartindent in vim itself (:help smartindent), I decided to try cindent instead of smartindent.
I replaced
set smartindent
with
set cindent
in my .vimrc file
and so far it is working perfectly.
This changed also fixed the behavior of '<<' and '>>' for indenting visual blocks that include python comments.
There are more configuration options for and information on indentation in the vim help for smartindent and cindent (:help smartindent and :help cindent).
#PolyThinker Though I see that response a lot to this question, in my opinion it's not a good solution. The editor still thinks it should be indented all the way to left - check this by pushing == on a line that starts with a hash, or pushing = while a block of code with comments in it is highlighted to reindent.
I would strongly recommend filetype indent on, and remove the set smartindent and set autoindent (or set cindent) lines from your vimrc. Someone else (appparently David Bustos) was kind enough to write a full indentation parser for us; it's located at $VIMDIRECTORY/indent/python.vim.
(Paul's cindent solution probably works for python, but filetype indent on is much more generally useful.)
I have the following lines in my .vimrc, seems to be installed by default with my Ubuntu 8.10
set smartindent
inoremap # X^H#
set autoindent
And I don't observe the problem. Maybe you can try this. (Note that ^H should be entered by Ctrl-V Ctrl-H)
My solution to the unindenting of #:
If you use cindent, recognize that it is designed for C and C++ coding. Here, a # means you are creating a #DEFINE or #MACRO(), so the behavior is correct. But for other languages where # is a comment, it is irritating.
The following worked for me:
" cindent enable specific indenting for C code
" set cin nocin
set cin
" cinkeys The default cinkeys causes leading # to unindent to column 0.
" To prevent this, remove the 0# from the definition.
" set cinkeys=0{,0},0),:,0#,!^F,o,O,e - default
set cinkeys=0{,0},0),:,!^F,o,O,e
It's caused by the 'smartindent' feature. If you have :set smartindent in your .vimrc you need to remove it.
Some of the other answers were useful, but none were enough to prevent Vim from reindenting a line when '#' is the first character. PolyThinker's answer didn't work for me, but it gave a clue that '#' could be remapped to "insert a character, then #, then delete the extra character and put the cursor where it should be". This is the mapping that does that:
inoremap # X#<left><backspace><right>
This is needed because vim's syntax packages seem to treat '#' as a special character, no matter how the options are set. I want a line started with '#' to be the same as a line begun with any other character. The most reliable solution I've found is the above mapping, which actually does change the line's first character.
Note: I've found this mapping causes problems after running I#<esc> then pressing "." to redo the previous insertion. I haven't found a solution yet.
My Vim configuration doesn't do that. You might try the python.vim script available from this link: http://www.vim.org/scripts/script.php?script_id=790
I removed set smartindent from ~/.vimrc but it still didn't disable smartindent. When I opened a .py file and ran :set smartindent? it displayed smartindent.
Turns out that further down in the ~/.vimrc was this line:
autocmd BufRead *.py set smartindent cinwords=if,elif,else,for,while,try,except,finally,def,class
^^^^^^^^^^^
Once I deleted "smartindent" from that line, then smartindent was finally disabled and my comments were indented properly again.
I use the tab key to indent my python code in Vim, but whenever I copy and paste a block Vim replaces every tab with 4 spaces, which raises an IndentationError
I tried setting :set paste as suggested in related questions but it makes no difference
Other sites suggest pasting 'tabless' code and using the visual editor to re-indent, but this is asking for trouble when it comes to large blocks
Are there any settings I can apply to vim to maintain tabs on copy/paste?
Thanks for any help with this :)
edit:
I am copying and pasting within vim using the standard gnome-terminal techniques (ctrl+shift+c / mouse etc.)
my .vimrc is:
syntax on
set ts=4
if has("terminfo")
let &t_Co=8
let &t_Sf="\e[3%p1%dm"
let &t_Sb="\e[4%p1%dm"
else
let &t_Co=8
let &t_Sf="\e[3%dm"
let &t_Sb="\e[4%dm"
endif
I looked up that ts -> Sets tab stops to n for text input, but don't know what value would maintain a tab character
See :h tabstop for all the options and how they interact with each other.
These are good settings if you prefer tabs:
set tabstop=4
set shiftwidth=4
set noexpandtab
With these settings, you hit <Tab> and you get <Tab>.
These are good settings if you prefer spaces:
set tabstop=4
set shiftwidth=4
set expandtab
With these settings, you hit <Tab> and you get <Space><Space><Space><Space>.
Whatever you choose, you should not use your terminal key bindings for copying/pasting. Inside Vim, you should "yank" with y and "put" with p or P; optionally using a specific register like "ay/"ap to yank/put to/from the content of #a or "+y/"+p to yank/paste to/from the system clipboard (if your Vim is built with clipboard support).
As a side note, you should use the long form names of your settings as they are more readable than their short counterpart. Your future self will thank you.
I was middle-click-pasting into a terminal vim instance. I have this in my vimrc:
set tabstop=2 " (ts)
set softtabstop=2 " (sts) Turned off with 0
set shiftwidth=2 " (sw) Used for autoindent, and << and >>
set expandtab " (et) Expand tabs to spaces
I ran
:set paste
:set noexpandtab
and vim preserved the tabs that were in the source text. Without overriding my expandtab setting, vim was auto-expanding the tabs in the source text.
What romainl said. Also, there are a few other settings that I find useful. Here is an excerpt from my .vimrc:
set autoindent " always set autoindenting on"
set smartindent " use smart indent if there is no indent file"
set tabstop=4 " <tab> inserts 4 spaces"
set softtabstop=4 " <BS> over an autoindent deletes 4 spaces."
set smarttab " Handle tabs more intelligently"
set expandtab " Use spaces, not tabs, for autoindent/tab key."
set shiftwidth=4 " an indent level is 4 spaces wide."
set shiftround " rounds indent to a multiple of shiftwidth"
In vim, enter :h <setting> for each of these settings to learn more about what they do,
First, make sure your indent settings represent your preferred style, as romainl has shown in his answer.
If you must paste code from outside Vim (e.g. a selection from another terminal), the :retab! command can fix up the spaces to Tabs; for the pasted text the full command with the proper range would be
:'[,']retab!
Alternatively, you could try pasting with the "*]p command, which automatically adapts the indent to the cursor position (see :help ]p).