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).
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.
Whenever I append a : character in Vim in Python mode, it either:
indents the line
dedents the line
does nothing
What is it even trying to do, and how do I get rid of this behavior?
Certain keys, when pressed, will trigger Vim's indent feature, which will attempt to set the correct amount of indentation on the current line. (You can manually trigger this by typing == in normal mode.)
You can change which keys trigger this behavior, but first you need to know what indenting mode is being used.
First, execute :set indentexpr?. If it is nonempty (I would expect this for Python), then indentexpr mode is being used. In this case, executing :set indentkeys? gives you the list of trigger keys. To remove the colon, execute :setlocal indentkeys-=:.
If indentexpr is empty, then you are probably using cindent mode, and :set cindent? will tell you that cindent is set. In this case, do the same as before, but using cinkeys instead of indentkeys. (Note that indentexpr mode takes precedence over cindent mode.)
Nathan Grigg's answer set me on the right track. I had to make a few changes for my setup.
I had to use :setlocal indentkeys-=<:>, because in my case :set indentkeys? showed indentkeys=0{,0},!^F,o,O,e,<:>,=elif,=except.
Also, putting :setlocal indentkeys-=<:> in .vim/after/ftplugin/python.vim did not work to make the change permanent. I found that there is a built-in vim python indent file that runs AFTER this after-ftplugin file.
To diagnose, open a Python file for editing, and run :scriptnames. That will show you a list of all the vim scripts that have run, in order of precedence. The scripts at the bottom of that list have been applied most recently, and take precedence. See this question on SuperUser for more info.
When I did that, it showed me a built-in vim file at /my-install-path/vim/7.4.1830/share/vim/vim74/indent/python.vim. Sure enough, that was setting <:> as part of the indent keys.
To fix it, I set an autocommand in .vimrc, and that really gets the last word.
autocmd FileType python setlocal indentkeys-=<:>
Update
I had to add :setlocal indentkeys-=: after all. Here's what I have in my .vimrc now.
autocmd FileType python setlocal indentkeys-=<:>
autocmd FileType python setlocal indentkeys-=:
It is trying to be helpful. If you want to turn off all the auto-indenting for the current file,
:setlocal noautoindent
:setlocal nocindent
:setlocal nosmartindent
:setlocal indentexpr=
Or, you can add set in your vimrc file. You can do these per file type too. See here
TL;DR I disabled autoindentation by typing:
:set indentexpr=
then hitting the ENTER key.
It's a quick fix without needing to understand indentkeys ..
Thanks to Christian Long for the docs to indentkeys, where I noticed (my emphasis):
A list of keys that, when typed in Insert mode, cause reindenting of
the current line. Only happens if 'indentexpr' isn't empty.
Tip - you might want to save a copy of the existing value of indentexpr before you clear it out. To see that (and any other values that are set) just type:
:set
HTH
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'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.