use
5.010001;
our
$AUTHORITY
=
'cpan:PERLANCAR'
;
our
$DATE
=
'2023-07-08'
;
our
$DIST
=
'App-ShellCompleter-cpanm'
;
our
$VERSION
=
'0.212'
;
my
$noop
=
sub
{};
my
$comp_installed_mods
=
sub
{
my
%args
=
@_
;
log_trace(
"[_cpanm] Adding completion: installed modules"
);
Complete::Module::complete_module(
word
=>
$args
{word},
path_sep
=>
'::'
,
);
};
my
$comp_installable
=
sub
{
my
%args
=
@_
;
my
$word
=
$args
{word} //
''
;
{
last
unless
$ENV
{SCRIPT_MODE};
last
unless
$word
eq
''
||
$word
=~ /\A\w[\w-]*\z/;
my
$dbh
= _connect_lcpan() or
last
;
my
$sth
;
$sth
=
$dbh
->prepare(
"SELECT name FROM script WHERE name LIKE '$word%' ORDER BY name"
);
$sth
->execute;
my
@scripts
;
my
%seen
;
while
(
my
@row
=
$sth
->fetchrow_array) {
my
$script
=
$row
[0];
push
@scripts
,
$script
unless
$seen
{
$script
}++;
}
return
\
@scripts
if
@scripts
;
}
{
log_trace(
"[_cpanm] Trying completion: tarballs & dirs"
);
local
$Complete::Common::OPT_FUZZY
= 0;
local
$Complete::Common::OPT_WORD_MODE
= 0;
local
$Complete::Common::OPT_CHAR_MODE
= 0;
my
$answer
= complete_file(
filter
=>
sub
{ log_trace(
" $_"
); /\.(zip|tar\.gz|tar\.bz2)$/i || (-d
$_
) },
word
=>
$word
,
);
}
{
last
unless
$word
eq
''
||
$word
=~ /\A(\w+)(::\w+)*(::)?\z/;
my
$dbh
= _connect_lcpan() or
last
;
my
$sth
;
my
$mod_prefix
=
$args
{mod_prefix} //
''
;
my
$prefixed_word
=
"$mod_prefix$word"
;
my
$num_sep
= 0;
while
(
$prefixed_word
=~ /::/g) {
$num_sep
++ }
if
(
$prefixed_word
eq
''
) {
$sth
=
$dbh
->prepare(
"SELECT name,has_child FROM namespace WHERE name='' AND num_sep=0 ORDER BY name"
);
}
else
{
$sth
=
$dbh
->prepare(
"SELECT name,has_child FROM namespace WHERE name LIKE '$prefixed_word%' AND num_sep=$num_sep ORDER BY name"
);
}
$sth
->execute;
my
@mods
;
while
(
my
@row
=
$sth
->fetchrow_array) {
my
$mod
=
$row
[0];
$mod
=~ s/\A\Q
$mod_prefix
\E//;
push
@mods
,
$mod
unless
grep
{
$_
eq
$mod
}
@mods
;
if
(
$row
[1]) {
$mod
.=
'::'
;
push
@mods
,
$mod
unless
grep
{
$_
eq
$mod
}
@mods
;
}
};
return
\
@mods
if
@mods
;
}
[];
};
sub
_connect_lcpan {
no
warnings
'once'
;
eval
"use App::lcpan 0.32"
;
if
($@) {
log_trace(
"[_cpanm] App::lcpan not available, skipped "
.
"trying to complete from CPAN module names"
);
return
;
}
my
%lcpanargs
;
my
$res
= Perinci::CmdLine::Util::Config::read_config(
program_name
=>
"lcpan"
,
);
unless
(
$res
->[0] == 200) {
log_trace(
"[_cpanm] Can't get config for lcpan: %s"
,
$res
);
last
;
}
my
$config
=
$res
->[2];
$res
= Perinci::CmdLine::Util::Config::get_args_from_config(
config
=>
$config
,
args
=> \
%lcpanargs
,
meta
=>
$App::lcpan::SPEC
{update},
);
unless
(
$res
->[0] == 200) {
log_trace(
"[_cpanm] Can't get args from config: %s"
,
$res
);
return
;
}
App::lcpan::_set_args_default(\
%lcpanargs
);
my
$dbh
= App::lcpan::_connect_db(
'ro'
,
$lcpanargs
{cpan},
$lcpanargs
{index_name});
}
sub
run_completer {
my
%cargs
=
@_
;
die
"This script is for shell completion only\n"
unless
$ENV
{GETOPT_LONG_DUMP} ||
$ENV
{COMP_LINE} ||
$ENV
{COMMAND_LINE};
GetOptionsWithCompletion(
sub
{
my
%args
=
@_
;
my
$type
=
$args
{type};
my
$word
=
$args
{word};
if
(
$type
eq
'arg'
) {
log_trace(
"[_cpanm] Completing arg"
);
my
$seen_opts
=
$args
{seen_opts};
if
(
$seen_opts
->{
'--uninstall'
} ||
$seen_opts
->{
'--reinstall'
}) {
return
$comp_installed_mods
->(
word
=>
$word
);
}
else
{
return
$comp_installable
->(
mod_prefix
=>
$cargs
{mod_prefix},
word
=>
$word
,
mirror
=>
$seen_opts
->{
'--mirror'
});
}
}
elsif
(
$type
eq
'optval'
) {
my
$ospec
=
$args
{ospec};
my
$opt
=
$args
{opt};
log_trace(
"[_cpanm] Completing optval (opt=$opt)"
);
if
(
$ospec
eq
'l|local-lib=s'
||
$ospec
eq
'L|local-lib-contained=s'
) {
return
complete_file(
filter
=>
'd'
,
word
=>
$word
);
}
elsif
(
$ospec
eq
'format=s'
) {
return
complete_array_elem(
array
=>[
qw/tree json yaml dists/
],
word
=>
$word
);
}
elsif
(
$ospec
eq
'cpanfile=s'
) {
return
complete_file(
word
=>
$word
);
}
}
return
[];
},
'f|force'
=>
$noop
,
'n|notest!'
=>
$noop
,
'test-only'
=>
$noop
,
'S|sudo!'
=>
$noop
,
'v|verbose'
=>
$noop
,
'verify!'
=>
$noop
,
'q|quiet!'
=>
$noop
,
'h|help'
=>
$noop
,
'V|version'
=>
$noop
,
'perl=s'
=>
$noop
,
'l|local-lib=s'
=>
$noop
,
'L|local-lib-contained=s'
=>
$noop
,
'self-contained!'
=>
$noop
,
'exclude-vendor!'
=>
$noop
,
'mirror=s@'
=>
$noop
,
'mirror-only!'
=>
$noop
,
'mirror-index=s'
=>
$noop
,
'M|from=s'
=>
$noop
,
'cpanmetadb=s'
=>
$noop
,
'cascade-search!'
=>
$noop
,
'prompt!'
=>
$noop
,
'installdeps'
=>
$noop
,
'skip-installed!'
=>
$noop
,
'skip-satisfied!'
=>
$noop
,
'reinstall'
=>
$noop
,
'interactive!'
=>
$noop
,
'i|install'
=>
$noop
,
'info'
=>
$noop
,
'look'
=>
$noop
,
'U|uninstall'
=>
$noop
,
'self-upgrade'
=>
$noop
,
'uninst-shadows!'
=>
$noop
,
'lwp!'
=>
$noop
,
'wget!'
=>
$noop
,
'curl!'
=>
$noop
,
'auto-cleanup=s'
=>
$noop
,
'man-pages!'
=>
$noop
,
'scandeps'
=>
$noop
,
'showdeps'
=>
$noop
,
'format=s'
=>
$noop
,
'save-dists=s'
=>
$noop
,
'skip-configure!'
=>
$noop
,
'static-install!'
=>
$noop
,
'dev!'
=>
$noop
,
'metacpan!'
=>
$noop
,
'report-perl-version!'
=>
$noop
,
'configure-timeout=i'
=>
$noop
,
'build-timeout=i'
=>
$noop
,
'test-timeout=i'
=>
$noop
,
'with-develop'
=>
$noop
,
'without-develop'
=>
$noop
,
'with-configure'
=>
$noop
,
'without-configure'
=>
$noop
,
'with-feature=s'
=>
$noop
,
'without-feature=s'
=>
$noop
,
'with-all-features'
=>
$noop
,
'pp|pureperl!'
=>
$noop
,
"cpanfile=s"
=>
$noop
,
);
}
1;