Tabs-to-spaces

classic Classic list List threaded Threaded
16 messages Options
Reply | Threaded
Open this post in threaded view
|

Tabs-to-spaces

Paul-433
I have colleagues who are way over the top anal about how code is formatted,
and it is the end of the world if there is a rogue space character anywhere in
the file, but rogue spaces are not why I'm here.

I have another colleague who likes to use spaces to indent code. I would like
to give him some vim commands that would let him live peacefully alongside the
others who insist on using tabs. I understand that vim can insert spaces when a
tab is pressed, using expandtab, but what I seek is the opposite: when my
colleague enters x number of spaces, vim writes a tab.

I could write a BufWritePost for him which basically does :%s/    /^I/g, but as
soon as he writes the file, when he navigates over his indentation, the cursor
will jump because they are now tabs. I guess I could make it happen when he
does :wq instead of just :w.

What's the best way of allowing someone to work by using spaces as indentation,
but having his files save with tabs instead?

He is really on thin ice, because if he sets it up to change four spaces into a
tab, but accidentally uses three or five spaces at any time, when the others
see an indent of three spaces, or an indent of a tab and a space, well that
means that armageddon has started.

--

.
Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

Tim Chase-2
> What's the best way of allowing someone to work by using
> spaces as indentation, but having his files save with tabs
> instead?

You're on the right path with an autocmd before writing.  If you
don't want to lose your position in the file, you should be able
to use

        :retab!

This relies on your settings, of

        :set noexpandtab ts=4

The "!" tells it to change spaces to tabs.  NOTE!  This does
change literal tabs within string contents (as cautioned in the
help for "retab") so you should use "\t" in your strings.  Not a
big deal to most folks, but could be a strange gotcha.

As a matter of fact, scrolling past the help on "retab", you'll find

        :help retab-example

which describes exactly what you wanted to do :)

-tim





Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

John (Eljay) Love-Jensen
In reply to this post by Paul-433
Hi Vigil,

In addition to what Tim posted, take a look at this for your buddy:

:help virtualedit

Doesn't solve the issue you posted, but is sort of related tangentially.

People that dislike tabs and prefer spaces, when editing a file with tabs,
may like the virtualedit behavior.

--Eljay


Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

Georg Dahn
In reply to this post by Tim Chase-2
Hi!

The Problem with this solution is, that there would be tabs afterwards
which shuldn't. Thus I suggest to map the following to a key:

:set noexpandtab | retab! | w | set expandtab | retab!

If the tabstop should differ from the default value (8):

:set noexpandtab tabstop=4 | retab! | w | set expandtab | retab!

Best regards,
Georg

Tim Chase wrote:

>> What's the best way of allowing someone to work by using
>> spaces as indentation, but having his files save with tabs
>> instead?
>
>
> You're on the right path with an autocmd before writing.  If you
> don't want to lose your position in the file, you should be able
> to use
>
>     :retab!
>
> This relies on your settings, of
>
>     :set noexpandtab ts=4
>
> The "!" tells it to change spaces to tabs.  NOTE!  This does
> change literal tabs within string contents (as cautioned in the
> help for "retab") so you should use "\t" in your strings.  Not a
> big deal to most folks, but could be a strange gotcha.
>
> As a matter of fact, scrolling past the help on "retab", you'll find
>
>     :help retab-example
>
> which describes exactly what you wanted to do :)
>
> -tim
>
>
>
>
>
>

               
___________________________________________________________
To help you stay safe and secure online, we've developed the all new Yahoo! Security Centre. http://uk.security.yahoo.com
Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

Paul-433
Thanks guys, I think I have a workable solution now.

In ~/.vimrc:

tabstop=4
autocmd BufReadPost *.php set expandtab | retab!

That will replace all tabs with spaces to keep my colleague happy.

In ~/.vim/ftplugin/php.vim:

autocmd BufWritePost *.php set noexpandtab | retab! | w | set expandtab |
retab!

That will replace his groups of four spaces with tabs, to keep my other
colleagues happy.

I just have to tell him to make sure he uses exactly four spaces.

I am wondering if, in a new version, there could be an option to retab which
would only replace leading tabs and spaces and not those buried inside code? I
tried to come up with a regex like :%s/^\(    \)/^I but it's too early in the
morning to figure out how to substitute the same number of tabs as there are
matches of (    ).

Incidentally, I discovered that putting a BufReadPost in a ~/.ftplugin/ script
is fruitless :)

--

.
Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

James Vega-3
On Fri, Sep 09, 2005 at 12:46:54AM +0100, Vigil wrote:
> I am wondering if, in a new version, there could be an option to retab which
> would only replace leading tabs and spaces and not those buried inside code? I
> tried to come up with a regex like :%s/^\(    \)/^I but it's too early in the
> morning to figure out how to substitute the same number of tabs as there are
> matches of (    ).

Like this?

function! RetabLeadingWhitespace(TabOrSpace) range
    let l:space = ''
    let l:count = 1
    " Use 'tabstop' to determine how wide a block of spaces should be
    while l:count <= &ts
        let l:space = l:space . ' '
        let l:count = l:count + 1
    endwhile
    " Convert leading tabs to spaces
    if a:TabOrSpace =~? "space"
        let l:pattern = '^\t'
        let l:replace = l:space
    " Convert leading spaces to tabs
    elseif a:TabOrSpace =~? "tab"
        let l:pattern = '^' . l:space
        " A single tab character
        let l:replace = ' '
    else
        echo 'Argument must be either "tab" or "space".'
        return
    endif
    let l:linenr = a:firstline
    while l:linenr <= a:lastline
        let l:newhead = ''
        let l:curline = getline(l:linenr)
        while match(l:curline, l:pattern) != -1
            let l:newhead = l:newhead . l:replace
            let l:curline = substitute(l:curline, l:pattern, '', '')
        endwhile
        call setline(l:linenr, l:newhead . l:curline)
        let l:linenr = l:linenr + 1
    endwhile
endfunction

James
--
GPG Key: 1024D/61326D40 2003-09-02 James Vega <[hidden email]>

attachment0 (204 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

Tim Chase-2
In reply to this post by Paul-433
> I am wondering if, in a new version, there could be an option
> to retab which would only replace leading tabs and spaces and
> not those buried inside code? I tried to come up with a regex
> like :%s/^\(    \)/^I but it's too early in the morning to
> figure out how to substitute the same number of tabs as there
> are matches of (    ).

The following seems to do the trick for me, assuming you have
your 'ts' set to 4.

%s/^\(    \|\t\)*/\=substitute(substitute(submatch(0),
"\t", "    ", "g"), "    ", "\t", "g")

(all on one line, broken to ensure that my mailer doesn't bung it
in some inconvenient place, as in this example, spaces actually
do matter)

If your 'tabstop' setting is something other than 4, change it in
all three places (in the search expression, as the replacement
in the inner substitute(), and within the search regexp of the
outer substitute() expression.

It should work, preserving any trailing leading spaces ("modulo"
if you will...if you've got a non-zero modulo when you divide out
the spaces into groups of 'ts'), and only effecting items at the
beginning of the line.

It does have a peculiarity in that if you have the following
(using <sp> for space and <tab> for tabs)

<sp><sp><tab><sp><sp><tab>printf("foo!");

In the screen, it will show up as two 'ts' widths, but will
expand to three 'ts' widths.

HTH,

-tim




Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

Gary Johnson
In reply to this post by Paul-433
On 2005-09-09, Vigil <[hidden email]> wrote:

> I just have to tell him to make sure he uses exactly four spaces.

To avoid the fallout from using an incorrect number of spaces, you
could execute this command when a file is opened

    match ErrorMsg '^\( \{4}\)*\zs \{1,3}\ze\S'

which would highlight any leading spaces beyond a multiple of four.
 
> I am wondering if, in a new version, there could be an option to retab
> which would only replace leading tabs and spaces and not those buried
> inside code? I tried to come up with a regex like :%s/^\(    \)/^I but it's
> too early in the morning to figure out how to substitute the same number of
> tabs as there are matches of (    ).

If you're using Unix, you could filter the buffer through the
unexpand command instead of using retab before writing it, which
would convert only leading spaces to tabs.

HTH,
Gary

--
Gary Johnson                 | Agilent Technologies
[hidden email]     | Wireless Division
                             | Spokane, Washington, USA
Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

Paul-433
In reply to this post by James Vega-3
On Fri, 9 Sep 2005, James Vega wrote:

> Like this?
>
> function! RetabLeadingWhitespace(TabOrSpace) range

I put that function in my ~/.vimrc before my autocmds, and replaced "retab!" in
my autocmds with "RetabLeadingWhitespace" (with then without the exclamation
mark), but when I open a *.php I get:

Error detected while processing BufRead Auto commands for "*.php":
E492: Not an editor command:  RetabLeadingWhitespace

--

.
Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

Paul-433
In reply to this post by Tim Chase-2
On Fri, 9 Sep 2005, Tim Chase wrote:

> The following seems to do the trick for me, assuming you have
> your 'ts' set to 4.
>
> %s/^\(    \|\t\)*/\=substitute(substitute(submatch(0),
> "\t", "    ", "g"), "    ", "\t", "g")

I bunged that into my autocmds but it gave the wrong results. It did a search
for leading tabs and replaced them with tabs!

--

.
Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

Paul-433
In reply to this post by Gary Johnson
On Fri, 9 Sep 2005, Gary Johnson wrote:

> If you're using Unix, you could filter the buffer through the
> unexpand command instead of using retab before writing it, which
> would convert only leading spaces to tabs.

I'm trying not to use external commands in case they're not on a particular
system.

--

.
Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

Tim Chase-2
In reply to this post by Paul-433
>> The following seems to do the trick for me, assuming you have
>> your 'ts' set to 4.
>>
>> %s/^\(    \|\t\)*/\=substitute(substitute(submatch(0),
>> "\t", "    ", "g"), "    ", "\t", "g")
>
> I bunged that into my autocmds but it gave the wrong results.
> It did a search for leading tabs and replaced them with tabs!

Whoops...I must have misinterpreted the dirction you wanted to
go.  The above command actually normalizes any existing
combination of tabs * spaces to just spaces, and then lops off
groups of four spaces and converts them to tabs.

To go the other way, you should be able to strip off the outer
substitute command (which was doing that lopping process):

%s/^\(    \|\t\)*/\=substitute(submatch(0), "\t", "    ", "g")

It still doesn't gracefully handle situations like I mentioned:

        <sp><sp><tab><sp><sp><tab>

as that starts out at two tabstops, but ends up at three tabstops.

However, as long as you are using even multiples of leading
spaces or tabs, the above should work.

-tim




Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

James Vega-3
In reply to this post by Paul-433
On Sat, Sep 10, 2005 at 05:51:56PM +0100, Vigil wrote:

> On Fri, 9 Sep 2005, James Vega wrote:
>
> >Like this?
> >function! RetabLeadingWhitespace(TabOrSpace) range
>
> I put that function in my ~/.vimrc before my autocmds, and replaced "retab!" in my autocmds with
> "RetabLeadingWhitespace" (with then without the exclamation mark), but when I open a *.php I get:
>
> Error detected while processing BufRead Auto commands for "*.php":
> E492: Not an editor command:  RetabLeadingWhitespace
What was the auto command line in your .vimrc?

James
--
GPG Key: 1024D/61326D40 2003-09-02 James Vega <[hidden email]>

attachment0 (204 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

Paul-433
On Sun, 11 Sep 2005, James Vega wrote:

>> Error detected while processing BufRead Auto commands for "*.php":
>> E492: Not an editor command:  RetabLeadingWhitespace
>
> What was the auto command line in your .vimrc?

autocmd BufReadPost  *.php set expandtab | RetabLeadingWhitespace(TabOrSpace)

I guess the syntax is wrong...

--

.
Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

A.J.Mechelynck
----- Original Message -----
From: "Vigil" <[hidden email]>
To: "Vim Mailing List" <[hidden email]>
Sent: Wednesday, September 14, 2005 9:02 PM
Subject: Re: Tabs-to-spaces


> On Sun, 11 Sep 2005, James Vega wrote:
>
>>> Error detected while processing BufRead Auto commands for "*.php":
>>> E492: Not an editor command:  RetabLeadingWhitespace
>>
>> What was the auto command line in your .vimrc?
>
> autocmd BufReadPost  *.php set expandtab |
> RetabLeadingWhitespace(TabOrSpace)
>
> I guess the syntax is wrong...

The syntax should be

    autocmd BufReadPost *.php set expandtab | call
RetabLeadingWhitespace(TabOrSpace)

After a ":set" command and a bar, Vim expects another ex-command, i.e.,
something that could follow the colon on the command-line.
RetabLeadingWhitespace() is not an ex-command, it's a function. To invoke
it, either use its return value in an expression, or use it as the argument
of the ":call" ex-command.


Best regards,
Tony.


Reply | Threaded
Open this post in threaded view
|

Re: Tabs-to-spaces

James Vega-3
In reply to this post by Paul-433
On Wed, Sep 14, 2005 at 08:02:12PM +0100, Vigil wrote:

> On Sun, 11 Sep 2005, James Vega wrote:
>
> >>Error detected while processing BufRead Auto commands for "*.php":
> >>E492: Not an editor command:  RetabLeadingWhitespace
> >
> >What was the auto command line in your .vimrc?
>
> autocmd BufReadPost  *.php set expandtab | RetabLeadingWhitespace(TabOrSpace)
>
> I guess the syntax is wrong...
Yup, that should be "... | call Retab..." and hopefully you've let
TabOrSpace somewhere before that call or it's not going to work.  That's
an argument to the function that needs to be either the string 'tab' or
'space'.

James
--
GPG Key: 1024D/61326D40 2003-09-02 James Vega <[hidden email]>

attachment0 (204 bytes) Download Attachment