App-shcompgen
view release on metacpan or search on metacpan
lib/App/shcompgen.pm view on Meta::CPAN
"func.completer_command" => $prog,
"func.completee" => $completee,
"func.note"=>"hint(completer)",
%extrametas,
}];
}
if ($is_perl_script) {
for my $line (@lines) {
if ($line =~ /^\s*\# PERICMD_INLINE_SCRIPT: /) {
# pericmd-inline script cannot complete themselves, but they
# usually come with a separate completer script
return [200, "OK", 0, {
"func.reason" => "Perinci::CmdLine::Inline script",
}];
}
}
for my $line (@lines) {
if ($line =~ /^\s*((?:use|require)\s+
(
Getopt::Std|
Getopt::Long(?:::Complete|::Less|::EvenLess|::Subcommand|::More|::Descriptive)?|
CLI::MetaUtil::Getopt::Long(?::Complete)?|
Perinci::CmdLine(?:::Any|::Lite|::Classic)
))\b/x) {
return [200, "OK", 1, {
"func.completer_command"=> $prog, # later will be set
"func.completer_type"=> $2,
"func.note"=>"perl use/require statement: $1",
}];
}
}
}
}
[200, "OK", 0];
}
sub _generate_or_remove {
my $which0 = shift;
my %args = @_;
my $setdef_res = _set_args_defaults(\%args);
return $setdef_res unless $setdef_res->[0] == 200;
# to avoid writing a file and then removing the file again in the same run
my %written_files;
my %removed_files;
my $envres = envresmulti();
PROG:
for my $prog0 (@{ $args{prog} }) {
my ($prog, $progpath);
log_debug("Processing program %s ...", $prog0);
if ($prog0 =~ m!/!) {
($prog = $prog0) =~ s!.+/!!;
$progpath = $prog0;
unless (-f $progpath) {
log_error("No such file %s, skipped", $progpath);
$envres->add_result(404, "No such file", {item_id=>$prog0});
next PROG;
}
} else {
require File::Which;
$prog = $prog0;
$progpath = File::Which::which($prog0);
unless ($progpath) {
log_error("'%s' not found in PATH, skipped", $prog0);
$envres->add_result(404, "Not in PATH", {item_id=>$prog0});
next PROG;
}
}
my $which = $which0;
if ($which eq 'generate') {
my $detres = _detect_prog(prog=>$prog, progpath=>$progpath, shell=>$args{shell});
if ($detres->[0] != 200) {
log_error("Can't detect '%s': %s", $prog, $detres->[1]);
$envres->add_result($detres->[0], $detres->[1],
{item_id=>$prog0});
next PROG;
}
log_debug("Detection result for '%s': %s", $prog, $detres);
if (!$detres->[2]) {
if ($args{remove}) {
$which = 'remove';
goto REMOVE;
} else {
next PROG;
}
}
my ($script, @helper_scripts) = _gen_completion_script(
%args, prog => $prog, progpath => $progpath, detect_res => $detres);
my $comppath = _completion_script_path(
%args, prog => $prog, detect_res => $detres);
if ($args{stdout}) {
print $script;
next PROG;
}
if (-f $comppath) {
if (!$args{replace}) {
log_info("Not replacing completion script for $prog in '$comppath' (use --replace to replace)");
$envres->add_result(304, "Not replaced (already exists)", {item_id=>$prog0});
next PROG;
}
}
log_info("Writing completion script to %s ...", $comppath);
$written_files{$comppath}++;
eval { write_text($comppath, $script) };
if ($@) {
$envres->add_result(500, "Can't write to '$comppath': $@",
{item_id=>$prog0});
next PROG;
}
for my $hs (@helper_scripts) {
log_info("Writing helper script %s ...", $hs->{path});
$written_files{$hs->{path}}++;
eval {
write_text($hs->{path}, $hs->{content});
chmod 0755, $hs->{path};
};
if ($@) {
$envres->add_result(500, "Can't write helper script to '$hs->{path}': $@",
{item_id=>$prog0});
next PROG;
}
lib/App/shcompgen.pm view on Meta::CPAN
}
$removed_files{$hspath}++;
}
$envres->add_result(200, "OK", {item_id=>$prog0});
$removed_files{$comppath}++;
} # remove
} # for prog0
if (keys(%written_files) || keys(%removed_files)) {
if ($args{shell} eq 'tcsh') {
my $init_script_path = _tcsh_init_script_path(%args);
my $init_script = _gen_tcsh_init_script(%args);
log_debug("Re-writing init script %s ...", $init_script_path);
write_text($init_script_path, $init_script);
}
}
$envres->as_struct;
}
$SPEC{guess_shell} = {
v => 1.1,
summary => 'Guess running shell',
args => {
},
};
sub guess_shell {
my %args = @_;
my $setdef_res = _set_args_defaults(\%args);
return $setdef_res unless $setdef_res->[0] == 200;
[200, "OK", $args{shell}];
}
$SPEC{detect_prog} = {
v => 1.1,
summary => "Detect a program",
args => {
%shell_arg,
prog => {
schema => 'str*',
completion => $_complete_prog,
req => 1,
pos => 0,
},
},
'cmdline.default_format' => 'json',
};
sub detect_prog {
require File::Which;
my %args = @_;
_set_args_defaults(\%args);
my $progname = $args{prog};
my $progpath = File::Which::which($progname);
return [404, "No such program '$progname'"] unless $progpath;
$progname =~ s!.+/!!;
_detect_prog(
prog => $progname,
progpath => $progpath,
shell => $args{shell},
);
}
$SPEC{init} = {
v => 1.1,
summary => 'Initialize shcompgen',
description => <<'_',
This subcommand creates the completion directories and initialization shell
script, as well as run `generate`.
_
args => {
%common_args,
},
};
sub init {
my %args = @_;
my $setdef_res = _set_args_defaults(\%args);
return $setdef_res unless $setdef_res->[0] == 200;
my $shell = $args{shell};
my $global = $args{global};
my $instruction = '';
my $dirs;
my $init_location;
my $init_script;
my $init_script_path;
$dirs = _completion_scripts_dirs(%args);
if ($global) {
push @$dirs, $args{helper_global_dir};
} else {
push @$dirs, $args{helper_per_user_dir};
}
if ($shell eq 'bash') {
$init_location = $global ?
(-d "/etc/profile.d" ? "/etc/profile.d/shcompgen.sh" : "/etc/bash.bashrc") :
"~/.bashrc";
$init_script = <<_;
# generated by shcompgen version $App::shcompgen::VERSION
_
$init_script .= <<'_';
_shcompgen_loader()
{
# check if bash-completion is active by the existence of function
# '_completion_loader'.
local bc_active=0
if [[ "`type -t _completion_loader`" = "function" ]]; then bc_active=1; fi
( run in 2.454 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )