Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert spaces to tabs in Vim or Linux?

I've looked over several questions on Stack Overflow for how to convert spaces to tabs without finding what I need. There seem to be more questions about how to convert tabs to spaces, but I'm trying to do the opposite.

In Vim I've tried :retab and :retab! without luck, but I believe those are actually for going from tabs to spaces anyways.

I tried both expand and unexpand at the command prompt without any luck.

Here is the file in question:

http://gdata-python-client.googlecode.com/hg-history/a9ed9edefd61a0ba0e18c43e448472051821003a/samples/docs/docs_v3_example.py

How can I convert leading spaces to tabs using either Vim or the shell?

like image 854
cwd Avatar asked Feb 01 '12 23:02

cwd


People also ask

Which command will translate all the whitespace to tabs in Linux?

The tr command in UNIX is a command line utility for translating or deleting characters.

How do I set tab to 4 spaces in Linux?

As for tabs, there are two settings. Within Vim, type a colon and then "set tabstop=4" which will set the tabs to display as four spaces. Hit colon again and type "set expandtab" which will insert spaces for tabs.

How do I show tabs in Vim?

A quick way to visualize whether there is a Tab character is by searching for it using Vim's search-commands : In NORMAL mode, type /\t and hit <Enter> . It will search for the Tab character ( \t ) and highlight the results.


6 Answers

Using Vim to expand all leading spaces (wider than 'tabstop'), you were right to use retab but first ensure 'expandtab' is reset (:verbose set ts? et? is your friend). retab takes a range, so I usually specify % to mean "the whole file".

:set tabstop=2      " To match the sample file
:set noexpandtab    " Use tabs, not spaces
:%retab!            " Retabulate the whole file

Before doing anything like this (particularly with Python files!), I usually set 'list', so that I can see the whitespace and change.

I have the following mapping in my .vimrc for this:

nnoremap    <F2> :<C-U>setlocal lcs=tab:>-,trail:-,eol:$ list! list? <CR>
like image 155
Johnsyweb Avatar answered Oct 05 '22 06:10

Johnsyweb


1 - If you have spaces and want tabs.

First, you need to decide how many spaces will have a single tab. That said, suppose you have lines with leading 4 spaces, or 8... Than you realize you probably want a tab to be 4 spaces. Now with that info, you do:

:set ts=4
:set noet
:%retab!

There is a problem here! This sequence of commands will look for all your text, not only spaces in the begin of the line. That mean a string like: "Hey,␣this␣␣␣␣is␣4␣spaces" will become "Hey,␣this⇥is␣4␣spaces", but its not! its a tab!.

To settle this little problem I recomend a search, instead of retab.

:%s/^\(^I*\)␣␣␣␣/\1^I/g

This search will look in the whole file for any lines starting with whatever number of tabs, followed by 4 spaces, and substitute it for whatever number of tabs it found plus one.

This, unfortunately, will not run at once!

At first, the file will have lines starting with spaces. The search will then convert only the first 4 spaces to a tab, and let the following...

You need to repeat the command. How many times? Until you get a pattern not found. I cannot think of a way to automatize the process yet. But if you do:

`10@:`

You are probably done. This command repeats the last search/replace for 10 times. Its not likely your program will have so many indents. If it has, just repeat again @@.

Now, just to complete the answer. I know you asked for the opposite, but you never know when you need to undo things.

2 - You have tabs and want spaces.

First, decide how many spaces you want your tabs to be converted to. Lets say you want each tab to be 2 spaces. You then do:

:set ts=2
:set et
:%retab!

This would have the same problem with strings. But as its better programming style to not use hard tabs inside strings, you actually are doing a good thing here. If you really need a tab inside a string, use \t.

like image 37
DrBeco Avatar answered Oct 05 '22 05:10

DrBeco


:%s/\(^\s*\)\@<=    /\t/g

Translation: Search for every instance of 4 consecutive spaces (after the = character), but only if the entire line up to that point is whitespace (this uses the zero-width look-behind assertion, \@<=). Replace each found instance with a tab character.

like image 40
Simon Zuckerbraun Avatar answered Oct 05 '22 07:10

Simon Zuckerbraun


Changes all spaces to tab :%s/\s/\t/g

like image 40
murat budak Avatar answered Oct 05 '22 07:10

murat budak


Linux: with unexpand (and expand)

Here is a very good solution: https://stackoverflow.com/a/11094620/1115187, mostly because it uses *nix-utilities:

  1. unexpand — spaces -> tabs
  2. expand — tabs -> spaces

Linux: custom script

My original answer

Bash snippet for replacing 4-spaces indentation (there are two {4} in script) with tabs in all .py files in the ./app folder (recursively):

find ./app -iname '*.py' -type f \
    -exec awk -i inplace \
    '{ match($0, /^(( {4})*)(.*?)$/, arr); gsub(/ {4}/, "\t", arr[1]) }; { print arr[1] arr[3] }' {} \; 

It doesn't modify 4-spaces in the middle or at the end.

Was tested under Ubuntu 16.0x and Linux Mint 18

like image 40
maxkoryukov Avatar answered Oct 05 '22 06:10

maxkoryukov


In my case, I had multiple spaces(fields were separated by one or more space) that I wanted to replace with a tab. The following did it:

:% s/\s\+/\t/g
like image 44
z atef Avatar answered Oct 05 '22 05:10

z atef