#!perl use 5.010; use strict; use warnings; use Log::ger; BEGIN { $ENV{TRACE} = 1 } use File::Which qw(which); use Getopt::Long; use Log::ger::Level::FromEnv; use Log::ger::Output Screen => (colorize_tags=>1); our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY our $DATE = '2022-01-16'; # DATE our $DIST = 'App-CompleteUtils'; # DIST our $VERSION = '0.180'; # VERSION sub _shell_quote_arg { require String::ShellQuote; # pass some strings unquoted: foo=bar is quoted into 'foo=bar' by # String::ShellQuote; skip quoting it #say "D:<$_[0]>"; if ($_[0] =~ /\A[A-Za-z0-9_=^-]+\z/) { return $_[0]; } else { return String::ShellQuote::shell_quote($_[0]); } } my %Opts = ( shell => undef, ); my @inc; Getopt::Long::Configure( 'no_ignore_case', 'bundling', 'no_permute', 'pass_through', 'auto_help', 'auto_version'); GetOptions( 'include|I=s' => sub { unshift @inc, $_[1]; }, 'shell|s=s' => \$Opts{shell}, 'bash' => sub { $Opts{shell} = 'bash' }, 'tcsh' => sub { $Opts{shell} = 'tcsh' }, 'fish' => sub { $Opts{shell} = 'fish' }, 'zsh' => sub { $Opts{shell} = 'zsh' }, ); @ARGV or die "testcomp: Please specify script to run as first argument\n"; my $script = shift @ARGV; if (!(-f $script) && $script !~ m!/!) { my $script_p = which($script) or die "testcomp: Script '$script' not found in PATH\n"; $script = $script_p; } unless ($Opts{shell}) { require Shell::Guess; my $shell = Shell::Guess->running_shell; $shell = "tcsh" if $shell eq 'c'; $shell = "zsh" if $shell eq 'z'; $Opts{shell} = $shell; } my $comp_line = "$script "; if (@ARGV == 1 && $ARGV[0] =~ /\s/) { # user types: scriptname 'arg1 arg2 ...'. we should split the quoted args $comp_line .= join(" ", @ARGV); } else { # user types: scriptname 'arg1' 'arg two'. we should re-quote to avoid the # space inside arg value to split args. $comp_line .= join(" ", map {_shell_quote_arg($_)} @ARGV); } my $comp_point; if ($comp_line =~ /\^/) { $comp_point = index($comp_line, '^'); $comp_line =~ s/\^//; } else { $comp_point = length($comp_line); } my @cmd = ($^X, (map {"-I$_"} @inc), "-MLog::ger::Level::FromEnv", "-MLog::ger::Output=Screen,colorize_tags,1", $script); if ($Opts{shell} eq 'tcsh') { log_trace("[testcomp] COMMAND_LINE=<%s>", $comp_line); $ENV{COMMAND_LINE} = $comp_line; } else { log_trace("[testcomp] COMP_LINE=<%s>, COMP_POINT=%d", $comp_line, $comp_point); $ENV{COMP_LINE} = $comp_line; $ENV{COMP_POINT} = $comp_point; } log_trace("[testcomp] exec(): %s", \@cmd); exec @cmd; # ABSTRACT: Test your tab completion # PODNAME: testcomp __END__ =pod =encoding UTF-8 =head1 NAME testcomp - Test your tab completion =head1 VERSION This document describes version 0.180 of testcomp (from Perl distribution App-CompleteUtils), released on 2022-01-16. =head1 SYNOPSIS Usage (place caret sign (C<^>) somewhere to place cursor): % testcomp [testcomp-options] -- <your-script> [your-script-options]^ ... % testcomp [testcomp-options] -- <your-script> '[your-script-options]^ ...' Examples: % testcomp -- yourscript --opt1 val --opt2 % testcomp -Ilib -- 'yourscript --opt1^ --opt2 val' =head1 DESCRIPTION This utility will run your script (finding it in C<PATH> if not found in current directory) while setting C<COMP_LINE> and C<COMP_POINT> to test how your script will perform shell completion. In addition to that, it will also load L<Log::ger::Output::Screen> and set C<TRACE=1> to let you see trace log messages. You can place caret sign (C<^>) somewhere in the argument to place cursor (set C<COMP_POINT>)>. If no caret sign is present, C<COMP_POINT> is put at the end of C<COMP_LINE>. =head1 OPTIONS =head2 --include=dir, -I Like Perl's C<-I>. =head2 --shell=SHELL, -s Set shell. Currently this has a single effect: if shell is set to C<tcsh>, then C<COMMAND_LINE> will be set for the program instead of C<COMP_LINE> and C<COMP_POINT>. If unspecified, will be detected using C<< Shell::Guess->running_shell >>. =head2 --bash Shortcut for C<--shell=bash>. =head2 --fish Shortcut for C<--shell=fish>. =head2 --tcsh Shortcut for C<--shell=tcsh>. =head2 --zsh Shortcut for C<--shell=zsh>. =head1 HOMEPAGE Please visit the project's homepage at L<https://metacpan.org/release/App-CompleteUtils>. =head1 SOURCE Source repository is at L<https://github.com/perlancar/perl-App-CompleteUtils>. =head1 SEE ALSO L<App::CompleteUtils> You can use this utility to test scripts using these frameworks: L<Perinci::CmdLine>, L<Getopt::Long::Complete>, L<Getopt::Long::Subcommand>. But actually all scripts which can complete itself by detecting C<COMP_LINE> and C<COMP_POINT> can be tested. =head1 AUTHOR perlancar <perlancar@cpan.org> =head1 CONTRIBUTING To contribute, you can send patches by email/via RT, or send pull requests on GitHub. Most of the time, you don't need to build the distribution yourself. You can simply modify the code, then test via: % prove -l If you want to build the distribution (e.g. to try to install it locally on your system), you can install L<Dist::Zilla>, L<Dist::Zilla::PluginBundle::Author::PERLANCAR>, and sometimes one or two other Dist::Zilla plugin and/or Pod::Weaver::Plugin. Any additional steps required beyond that are considered a bug and can be reported to me. =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2022, 2020, 2018, 2017, 2016, 2015, 2014 by perlancar <perlancar@cpan.org>. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 BUGS Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=App-CompleteUtils> When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. =cut