andk / cpanpm

CPAN.pm
87 stars 79 forks source link

[feature] Shell completion #173

Open Freed-Wu opened 1 year ago

Freed-Wu commented 1 year ago

Is it possible that cpan has tab completion in shell (bash/zsh/fish/etc)? TIA!

briandfoy commented 9 months ago

This is something I'm open to adding. The only thing I can think to complete is namespaces, and there are a lot of those. I don't know how I'd accomplish that; maybe an out of band process to make the complete file?

Note that tab completion is something almost entirely outside of the command itself, so cpan doesn't have to really do anything for you to be able to complete. The cpan command, however, can know how to create that file for you.

briandfoy commented 9 months ago

I played around with namespace autocompletion in bash, and it's so slow as to be unusable. Also, the : is a special character in complete, which uses it as a word separator. Even when I limited it to the top namespace in a distribution it was pretty slow, and missed things that you would expect, such as Test::Foo being in the Foo distro.

I think this means that the command-line version of this has no where to go. If there were a web skin on cpan, you could hook in MetaCPAN's API and update as you type into a box.

Freed-Wu commented 9 months ago

it's so slow as to be unusable.

What is your completion script? I want to try it in my machine to see its effect :smile:

briandfoy commented 9 months ago

I used this to make a basic bash complete command line. This creates a smaller completion list than you actually need.

use File::Spec::Functions;

my $cpan_dir = catfile( $ENV{HOME}, qw(.cpan sources modules) );
my $packages = catfile( $cpan_dir, '02packages.details.txt.gz' );

open my $fh, '<:gzip', $packages or die "Could not open $packages: $!";

my $complete = qq(#/usr/bin/env bash\ncomplete -W ");

while( <$fh> ) {
    my( $namespace, $version, $path ) = split;
    next if $Seen{$path};
    $Seen{$path} = $namespace;
    $complete .= " $namespace";
    }

$complete .= qq(" cpan);

open my $complete_fh, '>:utf8', ".cpan_complete" or die "Could not open .cpan_complete: $!";
print {$complete_fh} $complete;
close $complete_fh;