## Variable width tabstops

Expand Messages
• 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
Message 1 of 5 , Feb 28, 2001
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
• ... I thought this was an interesting problem, so I wrote a map and a function: imap =VarTab(virtcol( . ), 28, 88, 105, 115) fun! VarTab(c, ...)
Message 2 of 5 , Feb 28, 2001
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
• ... 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
Message 3 of 5 , Mar 1, 2001
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.
> >
> > 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

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!

--
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 ÄúÐ´µÀ£º ... So, if column==28? I think you d like let it go. Let s separate the task into more
Message 4 of 5 , Mar 1, 2001
Tony Veale，您好！

在 2001-03-01 17:28:00 您写道：
>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.
>> >
>> > 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
So, if column==28? I think you'd like let it go.
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@...
• ... [snip] ... Well, if you want to convert to ,28,105,115 then you would do ... ) ... or, if that regexp makes you go cross-eyed,
Message 5 of 5 , Mar 1, 2001
Tony Veale wrote:
>
> 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.
[snip]
> >
> > 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!

Well, if you want to convert "<ST.28.88.105.115>" to
",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
Your message has been successfully submitted and would be delivered to recipients shortly.