Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[VIM]: bug report, curious glitch found in normal mode in global

2 views
Skip to first unread message

Loki Harfagr

unread,
Dec 19, 2009, 11:43:04 AM12/19/09
to
Hello,

a few days ago a colleague asked me how to to a little
file cleansing in vi, he wanted to, when found a line matching
a regexp, delete the matched line *and* the immediately following line.
I then did show him a quick recipe using 'normal mode' in
glogal search, I tested it and it was neat:
:g/regexp/normal n2dd

But then he used it in vim (I use elvis) and the file went havoc.

Here's a quick reduced sample bench for you to test and find out
what's to repair in the normal mode for vim:

making of a test file, 600 iterations of a line to keep
a line with the regexp to match and a ine following it :
>toto && for l in {1..600}; do printf "keepme\ndispose\nflush\n" >> toto; done

then open that file 'toto' in vi and type:
:g/dispose/normal n2dd

the result *should* be 1200 lines deleted and 600 lines
remaining (all these 'keepme' lines), *but* in
all the versions of vim7 on all distros I've tried it gave funny
and unpredicatable results, mainly deleting some 600 lines and
not others (and in one case my vim is simply not useable at all
even if I delete the vimrc and even if I uninstall/reinstall
the package!)

It is not a very bad bug (except for that vim on that server
where now it is dead Jim) as it's in a supposedly seldom used
trickery (normal people would use awk or sed to do this ;-)
but I still reported it here just in case that'd be a symptom
of an ill declared counter or pointer or acc some place in
the code.

Good luck.

Gary Johnson

unread,
Dec 19, 2009, 2:22:19 PM12/19/09
to

I don't know exactly what vim is doing in all the failure cases, but I
can understand why your command doesn't work.

The :g/regexp/ command first traverses the entire buffer (file) and tags
each matching line. Then it starts with the first tag in the buffer and
executes the "normal n2dd" command for each tagged line. The first
normal-mode command is "n", which jumps to the next match. Then "2dd"
deletes that line and the following line. Now vim attempts to execute
that normal command on the next tagged line, but that line was just
deleted. So it doesn't surprise me that vim gets confused and does odd
things to the buffer. It also seems reasonable that such undefined
behavior might vary from one version of vim to the next.

The solution is: don't use that "n". Just execute

:g/regexp/normal 2dd

Elvis apparently behaves differently. The original vi did not have a
:normal command, so that much is not a vi-compatibility issue. I don't
know whether the original vi tagged all matching lines first, then
executed the command on each tagged line as vim does, or whether it
executed the command on each matching line as it found the match, which
would avoid the problem.

The only way I can think of that this could have "broken" vim would be
if some file that retains vim's state became corrupted. The only file
like that I know of is your ~/.viminfo. Delete that file and vim should
work fine.

--
Gary Johnson

Gary Johnson

unread,
Dec 19, 2009, 2:59:52 PM12/19/09
to
Gary Johnson <gary...@eskimo.com> wrote:
> Loki Harfagr <l0...@thedarkdesign.free.fr.invalid> wrote:
> > Hello,
> >
> > a few days ago a colleague asked me how to to a little
> > file cleansing in vi, he wanted to, when found a line matching
> > a regexp, delete the matched line *and* the immediately following line.
> > I then did show him a quick recipe using 'normal mode' in
> > glogal search, I tested it and it was neat:
> > :g/regexp/normal n2dd
> >
> > But then he used it in vim (I use elvis) and the file went havoc.

[...]

> > ... (and in one case my vim is simply not useable at all


> > even if I delete the vimrc and even if I uninstall/reinstall
> > the package!)
> >
> > It is not a very bad bug (except for that vim on that server
> > where now it is dead Jim) as it's in a supposedly seldom used
> > trickery (normal people would use awk or sed to do this ;-)
> > but I still reported it here just in case that'd be a symptom
> > of an ill declared counter or pointer or acc some place in
> > the code.
>
> I don't know exactly what vim is doing in all the failure cases, but I
> can understand why your command doesn't work.

[...]

I should add that even if your command contained an error, it should not
have caused vim to become unusable. If you can repeat those results and
let me know the distribution, the vim package name and the vim version
that you used, I'll forward the information to the vim_dev list. Thanks
for reporting the problem.

--
Gary Johnson

Kaz Kylheku

unread,
Dec 19, 2009, 3:41:37 PM12/19/09
to
On 2009-12-19, Loki Harfagr <l0...@thedarkdesign.free.fr.INVALID> wrote:
> then open that file 'toto' in vi and type:
>:g/dispose/normal n2dd

In Vim, each line procssed by g becomes the current line; when
a normal mode command is processed, it is relative to that line.
So you don't have to do this search: you are already there.
Just 2dd, not n2dd.

Although, there is no specification for this command, we could argue
that Elvis is buggy by not binding the current position to each matching
location prior to executing the command.

Even though :normal is not in standard Vi, there is a precedent for the
idea that the current location iterates over the matches. Namely, in the
standard ex commands the location "." refers to current.

So for instance you can find all lines that contain "foo" and move
two lines at each location to the end of the buffer like this:

:g/foo/,.+1t$

The /foo/,.+1 is an address range, where the dot (.) means ``current
location'' and so .+1 means ``current
location plus one''.

This depends very much on the meaning of the ``current location'' being
set to each line that matches /foo/.

I could make the consistency argument that when the :normal command
is executed under :g, it too should have the same current position as
the . address.

Which tangentially brings us to this: using ex commands, you can avoid
the :normal 2dd kludge. Deleting each line that contains foo,
as well as the following line can be done like this:

:g/foo/.,+1d

This is not only more portable, but ironically /shorter/ than

:g/foo/normal 2dd

Please try everything with Elvis and Vim and report. :)

Loki Harfagr

unread,
Dec 20, 2009, 5:44:10 AM12/20/09
to
Sat, 19 Dec 2009 19:59:52 +0000, Gary Johnson did cat :

> Gary Johnson <gary...@eskimo.com> wrote:
>> Loki Harfagr <l0...@thedarkdesign.free.fr.invalid> wrote:
>> > Hello,
>> >
>> > a few days ago a colleague asked me how to to a little file cleansing
>> > in vi, he wanted to, when found a line matching a regexp, delete the
>> > matched line *and* the immediately following line. I then did show
>> > him a quick recipe using 'normal mode' in glogal search, I tested it
>> > and it was neat: :g/regexp/normal n2dd
>> >
>> > But then he used it in vim (I use elvis) and the file went havoc.
>
> [...]
>
>> > ... (and in one case my vim is simply not useable at all even if I
>> > delete the vimrc and even if I uninstall/reinstall the package!)
>> >
>> > It is not a very bad bug (except for that vim on that server
>> > where now it is dead Jim) as it's in a supposedly seldom used
>> > trickery (normal people would use awk or sed to do this ;-) but I
>> > still reported it here just in case that'd be a symptom of an ill
>> > declared counter or pointer or acc some place in the code.
>>
>> I don't know exactly what vim is doing in all the failure cases, but I
>> can understand why your command doesn't work.

Yes, and so do I, I don't usually use the 'normal' mode, it was
just that when my colleague asked for my help I've recently been
reading some articles that mentionned some funny uses of it so it
naturally (and inadvertendly ;-) happened that I jumped on the
occasion to try the ride.
Note that I didn't really think that it was a bug as it
was triggered while doing clumsy stuff in a dark corner but
that it *could* be some real bug hidden and by chance triggered
on this occasion.
As I said "normal" people would use other ways, btw thanks Kaz Kylheku
for mentioning the 'here,+quantity' tool, which is one I "usually" use
(or with warkers) and was at the moment just passed behind the impulse to
try the recently seen 'normal' and I knew the problem was mainly on
my side and my fault :-)

>
> [...]
>
> I should add that even if your command contained an error, it should not
> have caused vim to become unusable. If you can repeat those results and
> let me know the distribution, the vim package name and the vim version
> that you used, I'll forward the information to the vim_dev list. Thanks
> for reporting the problem.

I can't at the moment as this machine is at work but I'll try and reproduce
the problem as soon as I'l have a few spare time at work and, maybe harder,
as soon as I'll find again which of the files I tested the command on
was the one which triggered the freeze (as it was a long LDAP dump I'm
not sure I've kept a copy) and if not I'll try and build some equivalent case,
just be a bit patient as on this time of year the teams at work are far to
be fully present :-)

Cheers!

0 new messages