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

P::RD for tab-completion

1 view
Skip to first unread message

Ted Zlatanov

unread,
Mar 30, 2010, 2:44:46 PM3/30/10
to recde...@perl.org
I've got a working grammar that will parse, say

A a1 a2 a3
B b1 b2

into structures. A and B don't overlap so I know that any sequence
beginning with A must have a1, a2, and a3.

Now I'm interested in finding out how much of the A rule can be matched,
for tab-completion (so I can tell if a1, a2, or a3 should be
completed). I'm using Term::ReadLine::Gnu but that's not too
important. Basically I want, given "A a1", to say "oh you want all the
possible values for a2 and a1 is already given."

I'm currently doing this by making a1..3 optional and then assembling
them back in order, but was wondering if there's a better way to fail
the match but tell me how far the parser got before it failed.

Thanks
Ted

Ted Zlatanov

unread,
Mar 30, 2010, 4:46:20 PM3/30/10
to recde...@perl.org
On Tue, 30 Mar 2010 13:44:46 -0500 Ted Zlatanov <t...@lifelogs.com> wrote:

TZ> I've got a working grammar that will parse, say
TZ> A a1 a2 a3
TZ> B b1 b2

TZ> into structures. A and B don't overlap so I know that any sequence
TZ> beginning with A must have a1, a2, and a3.

TZ> Now I'm interested in finding out how much of the A rule can be matched,
TZ> for tab-completion (so I can tell if a1, a2, or a3 should be
TZ> completed). I'm using Term::ReadLine::Gnu but that's not too
TZ> important. Basically I want, given "A a1", to say "oh you want all the
TZ> possible values for a2 and a1 is already given."

TZ> I'm currently doing this by making a1..3 optional and then assembling
TZ> them back in order, but was wondering if there's a better way to fail
TZ> the match but tell me how far the parser got before it failed.

Here's an example of a rule:

get: 'get' family(?) keys(?) getparams(?)
{ $return = [ [ family => $item[2], keys => $item[3], getparams => $item[4] ],
\&::internalPRD_get, \&::dump_hash, $item[2], $item[3], $item[4] ]; }

(I could have used IxHash for the first parameter instead of an array)

So then my code looks at the first item returned, that's my structure.
It figures out that e.g. "family" is filled but "keys" is not and does
completion on the keys parameter. There's a little more logic to
distinguish between a partially-filled key vs. an empty one but that's
about it.

Ted

Damian Conway

unread,
Mar 31, 2010, 2:35:47 AM3/31/10
to recde...@perl.org
Hi Ted,

If I were building a completion checker, I'd probably do something like the
following.

Hope this helps,

Damian

-----cut----------cut----------cut----------cut----------cut-----

use Parse::RecDescent;

my @trial_inputs = (
'',
'm',
'mv',
'mv ',
'mv f',
'mv file',
'mv file ',
'mv file t',
'mv file to',
'mv file to ',
'mv file to f',
'mv file to file',
'mv file to file ',
);

my $grammar = q{
partial_cmd: <rulevar: local $expecting = ''>
| cmd { 'nothing (cmd is complete)' }
| { $expecting }

cmd: <skip: ''>
{ $expecting = 'cmd_name' } cmd_name
{ $expecting = 'file1' } ws file ws
{ $expecting = 'to' } 'to'
{ $expecting = 'file2' } ws file ws

cmd_name: 'mv' | 'cp' | 'ln'

file: /\S+/

ws: /\s+/
};

my $parser = Parse::RecDescent->new($grammar);

for my $input (@trial_inputs) {
print "'$input' : complete on ", $parser->partial_cmd($input), "\n";
}

-----END----------END----------END----------END----------END-----

Ted Zlatanov

unread,
Mar 31, 2010, 12:29:11 PM3/31/10
to recde...@perl.org
Thanks for the help. I used it for a tab-completing CLI I developed to
talk to the Cassandra database; see Net::Cassandra::Easy 0.07 or later
on CPAN (cassidy.pl is the CLI).

I'm not happy with the verbosity of the resulting grammar but it works
well. Maybe P::RD could have better built-in completion support,
similar to the way <autotree> works: something you can access when a
rule fails that tells you how far it got and what was successfully
parsed. Basically the $expecting variable you suggested but set
automatically.

Ted

0 new messages