- Is it possible to have variable width tabs within a single line?

I'd like to replace a "Tab marker" in a line with a variable number of

spaces depending on the column, specifically I want to have tabstops at

the 28, 88, 105 and 115 columns.

Effectively, it would be something like :

if column < 28

then insert spaces to column 28

else

if column < 88

then insert spaces to column 88

etc, etc, etc

TIA

--

Tony Veale Transportation Systems Dept.

veale@... Software Engineering Laboratory

tel : (508)490-2072 Raytheon

fax : (508)490-2007 Marlborough, MA 01752-3789 - Tony Veale wrote:
>

I thought this was an interesting problem, so I wrote a map and a function:

> Is it possible to have variable width tabs within a single line?

>

> I'd like to replace a "Tab marker" in a line with a variable number of

> spaces depending on the column, specifically I want to have tabstops at

> the 28, 88, 105 and 115 columns.

>

> Effectively, it would be something like :

>

> if column < 28

> then insert spaces to column 28

> else

> if column < 88

> then insert spaces to column 88

>

> etc, etc, etc

>

> TIA

imap <Tab> <C-R>=VarTab(virtcol("."), 28, 88, 105, 115)<CR>

fun! VarTab(c, ...)

let i = 1

while i <= a:0

execute "let num_sp = -a:c + a:" . i

if num_sp > 0

break

endif

let i = i+1

endwhile

if i > a:0

return ""

endif

let spaces = " "

let len = 1

while len < num_sp

let spaces = spaces . spaces

let len = len + len

endwhile

return strpart(spaces, 0, num_sp)

endfun

You did not say what should happen if the cursor is already at or beyond

the last tabstop, so I decided to do nothing. To understand how the map

calls the function, see

:help i_ctrl-r

:help virtcol()

HTH --Benji Fisher - It appeared that Benji Fisher wrote:
>

Thanks Benji - that was agreat help!

> Tony Veale wrote:

> >

> > Is it possible to have variable width tabs within a single line?

> >

> > I'd like to replace a "Tab marker" in a line with a variable number of

> > spaces depending on the column, specifically I want to have tabstops at

> > the 28, 88, 105 and 115 columns.

> >

> > Effectively, it would be something like :

> >

> > if column < 28

> > then insert spaces to column 28

> > else

> > if column < 88

> > then insert spaces to column 88

> >

> > etc, etc, etc

> >

> > TIA

>

> I thought this was an interesting problem, so I wrote a map and a function:

>

> imap <Tab> <C-R>=VarTab(virtcol("."), 28, 88, 105, 115)<CR>

>

> fun! VarTab(c, ...)

> let i = 1

> while i <= a:0

> execute "let num_sp = -a:c + a:" . i

> if num_sp > 0

> break

> endif

> let i = i+1

> endwhile

> if i > a:0

> return ""

> endif

> let spaces = " "

> let len = 1

> while len < num_sp

> let spaces = spaces . spaces

> let len = len + len

> endwhile

> return strpart(spaces, 0, num_sp)

> endfun

>

> You did not say what should happen if the cursor is already at or beyond

> the last tabstop, so I decided to do nothing. To understand how the map

> calls the function, see

>

> :help i_ctrl-r

> :help virtcol()

>

> HTH --Benji Fisher

Unfortunately, I have since discovered that the tabstop widths are not

fixed, but need to be extracted from an embedded code of the format:

<ST.n.n.n.n.n.n>

where n is each tabstop width and there may be between 1 and 9 of these

"n"'s.

So what I need is to extract the tabstop values and pass them by

variable into the VarTab function, but I can't seem to be able to write

a regexp to describe a variable length format and use the

sub-expressions are arguments to VarTab.

Any help as to how to do this would be appreciated!

--

Tony Veale Transportation Systems Dept.

veale@... Software Engineering Laboratory

tel : (508)490-2072 Raytheon

fax : (508)490-2007 Marlborough, MA 01752-3789 - Tony Veale，您好！

在 2001-03-01 17:28:00 您写道：>It appeared that Benji Fisher wrote:

So, if column==28? I think you'd like let it go.

>>

>> Tony Veale wrote:

>> >

>> > Is it possible to have variable width tabs within a single line?

>> >

>> > I'd like to replace a "Tab marker" in a line with a variable number of

>> > spaces depending on the column, specifically I want to have tabstops at

>> > the 28, 88, 105 and 115 columns.

>> >

>> > Effectively, it would be something like :

>> >

>> > if column < 28

>> > then insert spaces to column 28

>> > else

>> > if column < 88

>> > then insert spaces to column 88

Let's separate the task into more simples:

expand line which length less than 28 up to 28 with spaces;

fu! ExpSpace1(lineLimit)

if strlen(getline("."))<a:lineLimit

exe "normal ".(a:lineLimit-strlen(getline(".")))."A ^C"

endif

endf

Usage:

:1,$call ExpSpace1(28)

replace 28 with your favorite number.

Now it's time to deal with serval column vaulues:

fun! ExpSpace(...)

if a:0<1

return

endif

let i=1

while i<a:0

exe "let lineLimit=a:".i

if strlen(getline("."))<lineLimit

return ExpSpace1(lineLimit)

elseif strlen(getline("."))==lineLimit

break | "do nothing

else

let i=i+1 | "use larger lineLimit

endif

endwhile

endf

usage:

:1,$call ExpSpace(28,88,105,115)

One thing you must follow is the arg num must be increment sequence, which depend upon the function ExpSpace, because make ExpSpace(88,28,115,105) work as you expected will make the function more complex.

The basic logic is:

if(column<28)

expand to 28 with spaces

else if(column==28)

let it go.

else if(column<88)

expand to 88 with spaces

else if(column==88)

let it go.

else if(column<105)

expand to 105 with spaces

else if(column==105)

let it go.

else if(column<115)

expand to 115 with spaces

else

let it go.

Is it what you expected.

BTW, I think you can't use different tabstop value in one sigle line, in fact, you can't use varies ts value in one file(buffer), :set ts=N, N is global to the current buffer.

>> >

致

>> > etc, etc, etc

>> >

>> > TIA

>>

>> I thought this was an interesting problem, so I wrote a map and a function:

>>

>> imap <Tab> <C-R>=VarTab(virtcol("."), 28, 88, 105, 115)<CR>

>>

>> fun! VarTab(c, ...)

>> let i = 1

>> while i <= a:0

>> execute "let num_sp = -a:c + a:" . i

>> if num_sp > 0

>> break

>> endif

>> let i = i+1

>> endwhile

>> if i > a:0

>> return ""

>> endif

>> let spaces = " "

>> let len = 1

>> while len < num_sp

>> let spaces = spaces . spaces

>> let len = len + len

>> endwhile

>> return strpart(spaces, 0, num_sp)

>> endfun

>>

>> You did not say what should happen if the cursor is already at or beyond

>> the last tabstop, so I decided to do nothing. To understand how the map

>> calls the function, see

>>

>> :help i_ctrl-r

>> :help virtcol()

>>

>> HTH --Benji Fisher

>

>Thanks Benji - that was agreat help!

>

>Tony Veale Transportation Systems Dept.

>veale@... Software Engineering Laboratory

>tel : (508)490-2072 Raytheon

>fax : (508)490-2007 Marlborough, MA 01752-3789

礼！

赵如飞

vimer@... - Tony Veale wrote:
>

[snip]

> It appeared that Benji Fisher wrote:

> >

> > Tony Veale wrote:

> > >

> > > Is it possible to have variable width tabs within a single line?

> > >

> > > I'd like to replace a "Tab marker" in a line with a variable number of

> > > spaces depending on the column, specifically I want to have tabstops at

> > > the 28, 88, 105 and 115 columns.

> >

Well, if you want to convert "<ST.28.88.105.115>" to

> > I thought this was an interesting problem, so I wrote a map and a function:

> >

> > imap <Tab> <C-R>=VarTab(virtcol("."), 28, 88, 105, 115)<CR>

> >

> > fun! VarTab(c, ...)

> > let i = 1

> > while i <= a:0

> > execute "let num_sp = -a:c + a:" . i

> > if num_sp > 0

> > break

> > endif

> > let i = i+1

> > endwhile

> > if i > a:0

> > return ""

> > endif

> > let spaces = " "

> > let len = 1

> > while len < num_sp

> > let spaces = spaces . spaces

> > let len = len + len

> > endwhile

> > return strpart(spaces, 0, num_sp)

> > endfun

> >

> > You did not say what should happen if the cursor is already at or beyond

> > the last tabstop, so I decided to do nothing. To understand how the map

> > calls the function, see

> >

> > :help i_ctrl-r

> > :help virtcol()

> >

> > HTH --Benji Fisher

>

> Thanks Benji - that was agreat help!

>

> Unfortunately, I have since discovered that the tabstop widths are not

> fixed, but need to be extracted from an embedded code of the format:

>

> <ST.n.n.n.n.n.n>

>

> where n is each tabstop width and there may be between 1 and 9 of these

> "n"'s.

>

> So what I need is to extract the tabstop values and pass them by

> variable into the VarTab function, but I can't seem to be able to write

> a regexp to describe a variable length format and use the

> sub-expressions are arguments to VarTab.

>

> Any help as to how to do this would be appreciated!

",28,105,115" then you would do

:s/<ST//

:s/>//

:s/\./,/g

In a script, it is easier to use the substitute() function:

:let params = substitute(getline("."), '.*<ST\([.[:digit:]]*\)>.*', '\1',

'')

:let params = substitute(params, '\.', ',', 'g')

or, if that regexp makes you go cross-eyed, perhaps

:let params = matchstr(getline("."), '<ST.*>')

:let params = substitute(params, '<ST', '', '')

:let params = substitute(params, '>', '', '')

:let params = substitute(params, '\.', ',', 'g')

Then, build a string that defines the :map command and :execute it.

:execute ':map <Tab> <C-R>=VarTab(virtcol(".")' . params . ')'

Now, wrap these commands in a function, and decide whether you want to

invoke it manually (maybe with a command or menu item) or automatically,

with an autocommand. If you want to search for the embedded code, use the

regexp in the first substitute() line (without the .* at the beginning and

end).

HTH --Benji Fisher