Wish: <range>

47 views
Skip to first unread message

Andy Wokula

unread,
Apr 9, 2011, 4:57:33 AM4/9/11
to vim...@googlegroups.com
I'd appreciate a <range> argument that can be used like
<line1>,<line2>
but which is empty when no range was given.

I'm talking about
:h :command-range

--
Andy

Tony Mechelynck

unread,
Apr 9, 2011, 7:22:29 AM4/9/11
to vim...@googlegroups.com, Andy Wokula

Could you give a use case which would not work just as well with either
-range or -range=% ? You'd have to use that range somewhere.

Maybe you could use :0command for your special case? That range is
allowed, but for some commands it is not meaningful.


Best regards,
Tony.
--
Really heard in court in the U.S.A.:
Q.: All your answers must be oral, all right? Which school did you attend?
A.: Oral.

ZyX

unread,
Apr 9, 2011, 7:29:30 AM4/9/11
to vim...@googlegroups.com
Reply to message «Re: Wish: <range>»,
sent 15:22:29 09 April 2011, Saturday
by Tony Mechelynck:

> Could you give a use case which would not work just as well with either
> -range or -range=% ? You'd have to use that range somewhere.
>
> Maybe you could use :0command for your special case? That range is
> allowed, but for some commands it is not meaningful.

If I understood him correctly, he wants to write `<range>' where now you write
`<line1>,<line2>', like this:
command -range Foo <range>call s:Foo()
instead of
command -range Foo <line1>,<line2>call s:Foo()
.

Original message:

signature.asc

Andy Wokula

unread,
Apr 9, 2011, 8:54:28 AM4/9/11
to vim...@googlegroups.com
Am 09.04.2011 13:29, schrieb ZyX:
> Reply to message �Re: Wish:<range>�,
> sent 15:22:29 09 April 2011, Saturday
> by Tony Mechelynck:
>
>> Could you give a use case which would not work just as well with either
>> -range or -range=% ? You'd have to use that range somewhere.
>>
>> Maybe you could use :0command for your special case? That range is
>> allowed, but for some commands it is not meaningful.
> If I understood him correctly, he wants to write `<range>' where now you write
> `<line1>,<line2>', like this:
> command -range Foo<range>call s:Foo()
> instead of
> command -range Foo<line1>,<line2>call s:Foo()
> .

Yep, that's what I meant.

For example, I have a command :InFunc . It's quite a trivial command,
it takes an argument Ex-command and executes it within a function.
Purpose is to automatically restore the highlighting state and the last
search pattern.
:h function-search-undo

Thus, mostly the Ex-command will be :global or :substitute .

Problem: :global has the default range "1,$" whereas :substitute has the
default range ".". For :InFunc, I'm urged to specify a default range
(e.g. either -range (current line) or -range=% (whole buffer)). I don't
want that, instead I want the default range of the argument command to
be in effect. But at the moment, it's not possible to check for an
empty range.


" What I use now:
:[range]InFunc {cmd} " execute :[range]{cmd}, for :subst
:[range]InFunc! {cmd} " execute :{cmd}, for :global

com! -bang -range -nargs=+ InFunc <line1>,<line2>call InFunc(<bang>0, <q-args>)

func! InFunc(bang, cmd) range
if a:bang
exec a:cmd
else
exec a:firstline.",".a:lastline. a:cmd
endif
endfunc


" I'd like to write the above this way:

com! -range=NoDefault -nargs=+ InFunc <range>call InFunc(<q-args>)

func! InFunc(cmd) range
exec a:range. a:cmd
endfunc


Oops, we would also need a new variable a:range !

Maybe, actually, <range> and a:range are not needed, I just want to be
able to check for an empty range:


com! -range -nargs=+ InFunc <line1>,<line2>call InFunc(<q-args>)

func! InFunc(cmd) range
if range_is_empty()
exec a:cmd
else
exec a:firstline.",".a:lastline. a:cmd
endif
endfunc


This would just a require a new function range_is_empty().

--
Andy

Ingo Karkat

unread,
Apr 9, 2011, 2:27:02 PM4/9/11
to vim...@googlegroups.com

Unless there are additional use cases where this could be useful, my first hunch
is that it's not worth the effort.

My first idea to implement your use case (with current Vim functionality) was a
cabbr <expr>, and then get the range via getcmdline(), extract and store it
somewhere, and then replace the InFunc cabbr with InFuncImpl, which would then
simply prepend the stored range to the passed command. The problem with this is
that for the cabbr to be expanded, there would need to be a whitespace before
it, so :2,4 InFunc instead of :2,4InFunc would need to be used. But the cabbr
could be replaced with a cmap, that wouldn't have that problem.

Reflecting on it some more, I think that the :InFunc is cumbersome (to type),
anyway. I would solve this via a :cmap <S-CR> which restores the previous
pattern from the search history. So instead of prepending InFunc to the Ex
command, I would just conclude the Ex command with <S-CR> instead of <CR>.

-- regards, ingo

Andy Wokula

unread,
Apr 13, 2011, 11:07:35 AM4/13/11
to vim...@googlegroups.com

It's more about consistency:

When you define a mapping, you can check if a count was given or not
(check v:count >= 1).

When you define a command with -range, you cannot check if a range was
given or not.


Here is another example:

DrChip's AsNeeded script comes with an ANX command:
:ANX {cmd}

ANX loads the script that defines the Ex-command {cmd} and immediately
executes {cmd}. It would be nice if :ANX could execute {cmd} with a
range. But this cannot be done at the moment, because it's unclear if
{cmd} accepts a range and what the default range of {cmd} will be.

Again, it would be nice if we could use <range> in place of <line1>,<line2>:

:com! -range -nargs=1 ANX call LoadCmd(<q-args>)| <range><args>


> My first idea to implement your use case (with current Vim
> functionality) was a cabbr<expr>, and then get the range via
> getcmdline(), extract and store it somewhere, and then replace the
> InFunc cabbr with InFuncImpl, which would then simply prepend the
> stored range to the passed command. The problem with this is that for
> the cabbr to be expanded, there would need to be a whitespace before
> it, so :2,4 InFunc instead of :2,4InFunc would need to be used. But
> the cabbr could be replaced with a cmap, that wouldn't have that
> problem.

For mappings I have a solution:

" remove trailing whitespace (except for the "-- " line in mails):
:no <Leader>ss :v/^-- $/s/\s\+$//e<C-B>InFunc! <C-E>

> Reflecting on it some more, I think that the :InFunc is cumbersome (to
> type), anyway. I would solve this via a :cmap<S-CR> which restores
> the previous pattern from the search history. So instead of prepending
> InFunc to the Ex command, I would just conclude the Ex command
> with<S-CR> instead of<CR>.

It's just that I want :InFunc to do this work. For example, another
thing we can't check for is the highlighting state of the last search
pattern, InFunc restores it automatically.

--
Andy

Andy Wokula

unread,
Apr 13, 2011, 11:09:28 AM4/13/11
to vim...@googlegroups.com
Am 09.04.2011 13:22, schrieb Tony Mechelynck:
> On 09/04/11 10:57, Andy Wokula wrote:
>> I'd appreciate a <range> argument that can be used like
>> <line1>,<line2>
>> but which is empty when no range was given.
>>
>> I'm talking about
>> :h :command-range
>>
>
> Could you give a use case which would not work just as well with
> either -range or -range=% ? You'd have to use that range somewhere.
>
> Maybe you could use :0command for your special case? That range is
> allowed, but for some commands it is not meaningful.

:com! -range TestZeroRange echo <line1> <line2>
:0TestZeroRange
1 1

Zero is converted to one.

Shouldn't that be regarded a bug?

--
Andy

ZyX

unread,
Apr 13, 2011, 11:43:15 AM4/13/11
to vim...@googlegroups.com
Reply to message «Re: Wish: <range>»,
sent 19:09:28 13 April 2011, Wednesday
by Andy Wokula:

> :com! -range TestZeroRange echo <line1> <line2>
> :0TestZeroRange
>
> 1 1
>
> Zero is converted to one.
>
> Shouldn't that be regarded a bug?

1. It is not a bug because first line has number `1', not `0'.
2. `:0read!echo "abc"' and `:1read!echo "abc"' are different, so you may want to
punish Bram for having yet another hack for built-in commands.

Original message:

signature.asc

Tony Mechelynck

unread,
Apr 13, 2011, 11:45:43 AM4/13/11
to vim...@googlegroups.com, Andy Wokula, Bram Moolenaar

I think it is. I have another command defined as follows:

command -nargs=0 -bar -bang -range -reg Put exe ((<q-bang> == '!') ?
<q-line1> : <q-line2>) . 'put' . <q-bang> <q-reg>

but

:0Put a

inserts register a _after_ line 1, and

:0Put /

returns

E488: Trailing characters

both of which I regard as bugs, since

:0put /

(without exclamation mark) inserts the search register before line 1
(which I regard as correct behaviour).


Best regards,
Tony.
--
Happiness is having a scratch for every itch.
-- Ogden Nash

Ingo Karkat

unread,
Apr 13, 2011, 11:59:09 AM4/13/11
to vim...@googlegroups.com
On 13-Apr-2011 17:07, Andy Wokula wrote:

> It's more about consistency:
>
> When you define a mapping, you can check if a count was given or not
> (check v:count >= 1).
>
> When you define a command with -range, you cannot check if a range was
> given or not.

A purist would argue that this information is not necessary, because the
defaults (-range and -range=%) handle that for you, and you could only use this
information to make the command behave in unexpected ways. But then, as a
Vimscripter, I love more power!

> Here is another example:
>
> DrChip's AsNeeded script comes with an ANX command:
> :ANX {cmd}

Uh, hasn't AsNeeded been obsoleted by Vim 7's autoload functionality? Anyway, it
probably could be worked around with dedicated :ANXRangeLine and :ANXRangeAll
commands, but I agree, for this particular case, using <range> would be far more
elegant. I still doubt that there are many more use cases, though.

-- regards, ingo

Charles Campbell

unread,
Apr 13, 2011, 12:30:27 PM4/13/11
to vim...@googlegroups.com
Ingo Karkat wrote:
>> Here is another example:
>>
>> DrChip's AsNeeded script comes with an ANX command:
>> :ANX {cmd}
>>
> Uh, hasn't AsNeeded been obsoleted by Vim 7's autoload functionality? Anyway, it
> probably could be worked around with dedicated :ANXRangeLine and :ANXRangeAll
> commands, but I agree, for this particular case, using<range> would be far more
> elegant. I still doubt that there are many more use cases, though.
>

No, AsNeeded hasn't been made obsolete. The autoload capability to
which I'm guessing that you're referring requires plugin writers to
re-write their code to take advantage of it; AsNeeded doesn't.

Regards,
Chip Campbell

Bram Moolenaar

unread,
Apr 13, 2011, 2:45:14 PM4/13/11
to ZyX, vim...@googlegroups.com

ZyX wrote:

> > :com! -range TestZeroRange echo <line1> <line2>
> > :0TestZeroRange
> >
> > 1 1
> >
> > Zero is converted to one.
> >
> > Shouldn't that be regarded a bug?
> 1. It is not a bug because first line has number `1', not `0'.
> 2. `:0read!echo "abc"' and `:1read!echo "abc"' are different, so you
> may want to
> punish Bram for having yet another hack for built-in commands.

You can use -range=1 to allow for a zero line number.

--
hundred-and-one symptoms of being an internet addict:
3. Your bookmark takes 15 minutes to scroll from top to bottom.

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

ZyX

unread,
Apr 13, 2011, 2:56:26 PM4/13/11
to vim...@googlegroups.com
Reply to message «Re: Wish: <range>»,
sent 22:45:14 13 April 2011, Wednesday
by Bram Moolenaar:

> You can use -range=1 to allow for a zero line number.

I must apologize: I overlooked this possibility. It still does not allow to test
for empty range.

Original message:

signature.asc

Tony Mechelynck

unread,
Apr 13, 2011, 3:00:12 PM4/13/11
to vim...@googlegroups.com, Bram Moolenaar, ZyX
On 13/04/11 20:45, Bram Moolenaar wrote:
>
> ZyX wrote:
>
>>> :com! -range TestZeroRange echo<line1> <line2>
>>> :0TestZeroRange
>>>
>>> 1 1
>>>
>>> Zero is converted to one.
>>>
>>> Shouldn't that be regarded a bug?
>> 1. It is not a bug because first line has number `1', not `0'.
>> 2. `:0read!echo "abc"' and `:1read!echo "abc"' are different, so you
>> may want to
>> punish Bram for having yet another hack for built-in commands.
>
> You can use -range=1 to allow for a zero line number.
>

Oh, oh. I don't see that documented at ":help :command-range". Is it a
new attribute?

Best regards,
Tony.
--
So Richard and I decided to try to catch [the small shark].
With a great deal of strategy and effort and shouting, we managed to
maneuver the shark, over the course of about a half-hour, to a sort of
corner of the lagoon, so that it had no way to escape other than to
flop up onto the land and evolve. Richard and I were inching toward
it, sort of crouched over, when all of a sudden it turned around and --
I can still remember the sensation I felt at that moment, primarily in
the armpit area -- headed right straight toward us.
Many people would have panicked at this point. But Richard and
I were not "many people." We were experienced waders, and we kept our
heads. We did exactly what the textbook says you should do when you're
unarmed and a shark that is nearly two feet long turns on you in water
up to your lower calves: We sprinted I would say 600 yards in the
opposite direction, using a sprinting style such that the bottoms of
our feet never once went below the surface of the water. We ran all
the way to the far shore, and if we had been in a Warner Brothers
cartoon we would have run right INTO the beach, and you would have seen
these two mounds of sand racing across the island until they bonked
into trees and coconuts fell onto their heads.
-- Dave Barry, "The Wonders of Sharks on TV"

Tony Mechelynck

unread,
Apr 13, 2011, 3:10:25 PM4/13/11
to vim...@googlegroups.com, Bram Moolenaar, ZyX
On 13/04/11 21:00, Tony Mechelynck wrote:
> On 13/04/11 20:45, Bram Moolenaar wrote:
>>
>> ZyX wrote:
>>
>>>> :com! -range TestZeroRange echo<line1> <line2>
>>>> :0TestZeroRange
>>>>
>>>> 1 1
>>>>
>>>> Zero is converted to one.
>>>>
>>>> Shouldn't that be regarded a bug?
>>> 1. It is not a bug because first line has number `1', not `0'.
>>> 2. `:0read!echo "abc"' and `:1read!echo "abc"' are different, so you
>>> may want to
>>> punish Bram for having yet another hack for built-in commands.
>>
>> You can use -range=1 to allow for a zero line number.
>>
>
> Oh, oh. I don't see that documented at ":help :command-range". Is it a
> new attribute?
>
> Best regards,
> Tony.

Ah, oops, there is -range=N but then N is the default. What if I want to
do like the :put and :read commands: allow a range defaulting to the
current line, but also allow line zero?

Best regards,
Tony.
--
ERROR 047: Keyboard not found. Press RETURN to continue.

Andy Wokula

unread,
Apr 13, 2011, 4:55:42 PM4/13/11
to vim...@googlegroups.com
Am 13.04.2011 20:45, schrieb Bram Moolenaar:
>
> ZyX wrote:
>
>>> :com! -range TestZeroRange echo<line1> <line2>
>>> :0TestZeroRange
>>>
>>> 1 1
>>>
>>> Zero is converted to one.
>>>
>>> Shouldn't that be regarded a bug?
>> 1. It is not a bug because first line has number `1', not `0'.
>> 2. `:0read!echo "abc"' and `:1read!echo "abc"' are different, so you
>> may want to
>> punish Bram for having yet another hack for built-in commands.
>
> You can use -range=1 to allow for a zero line number.

OK.

But a:firstline and a:lastline never become zero.

" -range=1 allows for zero range!

echo "A <line1> <line2> <count>"

com! -range=1 TestZeroRangeA echo <line1> <line2> <count>

0 TestZeroRangeA
" 0 0 0

TestZeroRangeA
" 12 1 1

3,5 TestZeroRangeA
" 3 5 5


echo "B a:firstline a:lastline"

com! -range=1 TestZeroRangeB <line1>,<line2>call TestZeroRangeB()

func! TestZeroRangeB() range
echo a:firstline a:lastline
endfunc

0 TestZeroRangeB
" 1 1


echo "C line1 line2"

com! -range=1 TestZeroRangeC call TestZeroRangeC(<line1>, <line2>)

func! TestZeroRangeC(line1, line2)
echo a:line1 a:line1
endfunc

0 TestZeroRangeC
" 0 0

--
Andy

Andy Wokula

unread,
Mar 23, 2018, 12:29:07 PM3/23/18
to vim...@googlegroups.com
TIL it is indeed possible to check if a range was given or not:

:com! -range Crwg :echo (<count>==-1 ? 'No range was given' : 'The given range is <line1>,<line2>')

Works with Vim 7.0 onwards.

Ingo Karkat

unread,
Mar 23, 2018, 2:16:24 PM3/23/18
to 'Andy Wokula' via vim_dev
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
How did you dig up that old thread?! (But thanks for following up!) I've found out about that, too:

To distinguish between no given range (then defaulting to something like the
last modified range) and a range, use -range=-1 and check <count>:
:command! -range=-1 Test echomsg <count> == -1 ? "'[,']" : <line1> . ',' . <line2>
This emulates -range=% but allows :0Test (passed via first argument boolean
flag), too:
:command! -range=-1 Test call Test((<count> == 0), (<count> == -1 && <line2> == 1 ? '1,' . line('$') : '<line1>,<line2>'))

- -- regards, ingo
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJatURcAAoJEA7ziXlAzQ/vsH4H/3mMbpNKoZJbgYEUmlIJAvv+
7zUphcl6TnyslZwrtz3BSDP4vcQpkFBvsMxwkjRd5z/i3+CtHC8w2v4AfgQr/SdH
fSdMipYM7JeqddWnaD37GlWyIm+gFoaPpuOuPdybnkXGYLs9A6YFZXX1+59OYXR8
QEuahc8/3M4ye9I6PVzqW/IHtMDYRSMPrxRQegZkn29F/mLjftmRh7u2W8c85zJ0
0QlaYpGvO3JqOxzMZSNOtvDWRGelscZPclE4wBuwdjtrCogtZy790ET6JJyUjFYw
Lj7/U2ydwa6UEr6RQRBSG0xmUbBiqLoQZYTLk6d9q/Ipvt9kplj3FqZlVJ9zoXc=
=e/Dn
-----END PGP SIGNATURE-----

Andy Wokula

unread,
Mar 28, 2018, 11:00:01 AM3/28/18
to vim...@googlegroups.com
Oops that old? Feels like yesterday.

> I've found out about that, too:
>
> To distinguish between no given range (then defaulting to something like the
> last modified range) and a range, use -range=-1 and check <count>:
> :command! -range=-1 Test echomsg <count> == -1 ? "'[,']" : <line1> . ',' . <line2>
> This emulates -range=% but allows :0Test (passed via first argument boolean
> flag), too:
> :command! -range=-1 Test call Test((<count> == 0), (<count> == -1 && <line2> == 1 ? '1,' . line('$') : '<line1>,<line2>'))

Amazing.

Right, it bothered me at the same time why a range "0" is always
turned into "1".

Best thing: I tried with gVim 5.7, it works there too.
A really old feature this is!

> - -- regards, ingo
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v2
>
> iQEcBAEBCAAGBQJatURcAAoJEA7ziXlAzQ/vsH4H/3mMbpNKoZJbgYEUmlIJAvv+
> 7zUphcl6TnyslZwrtz3BSDP4vcQpkFBvsMxwkjRd5z/i3+CtHC8w2v4AfgQr/SdH
> fSdMipYM7JeqddWnaD37GlWyIm+gFoaPpuOuPdybnkXGYLs9A6YFZXX1+59OYXR8
> QEuahc8/3M4ye9I6PVzqW/IHtMDYRSMPrxRQegZkn29F/mLjftmRh7u2W8c85zJ0
> 0QlaYpGvO3JqOxzMZSNOtvDWRGelscZPclE4wBuwdjtrCogtZy790ET6JJyUjFYw
> Lj7/U2ydwa6UEr6RQRBSG0xmUbBiqLoQZYTLk6d9q/Ipvt9kplj3FqZlVJ9zoXc=
> =e/Dn
> -----END PGP SIGNATURE-----

--
Andy
Reply all
Reply to author
Forward
0 new messages