Sepia
view release on metacpan or search on metacpan
lib/Sepia.pm view on Meta::CPAN
};
map { s/^:://; $_ } _completions('::', split //, shift);
}
sub apropos_re
{
my ($icase, $re) = @_;
$re =~ s/_/[^_]*_/g;
$icase ? qr/^$re.*$/i : qr/^$re.*$/;
}
sub all_completions
{
my $icase = $_[0] !~ /[A-Z]/;
my @parts = split /:+/, shift, -1;
my $re = apropos_re $icase, pop @parts;
use vars '&_completions';
local *_completions = sub {
no strict;
my $stash = shift;
if (@_ == 0) {
map { "$stash$_" } grep /$re/, keys %{$stash};
} else {
my $re2 = $icase ? qr/^$_[0].*::$/i : qr/^$_[0].*::$/;
my @pkgs = grep /$re2/, keys %{$stash};
map { _completions "$stash$_", @_[1..$#_] } @pkgs
}
};
map { s/^:://; $_ } _completions('::', @parts);
}
=item C<@res = filter_exact_prefix @names>
Filter exact matches so that e.g. "A::x" completes to "A::xx" when
both "Ay::xx" and "A::xx" exist.
=cut
sub filter_exact_prefix
{
my @parts = split /:+/, shift, -1;
my @res = @_;
my @tmp;
my $pre = shift @parts;
while (@parts && (@tmp = grep /^\Q$pre\E(?:::|$)/, @res)) {
@res = @tmp;
$pre .= '::'.shift @parts;
}
@res;
}
=item C<@res = lexical_completions $type, $str, $sub>
Find lexicals of C<$sub> (or a parent lexical environment) of type
C<$type> matching C<$str>.
=cut
sub lexical_completions
{
eval q{ use PadWalker 'peek_sub' };
# "internal" function, so don't warn on failure
return if $@;
*lexical_completions = sub {
my ($type, $str, $sub) = @_;
$sub = "$PACKAGE\::$sub" unless $sub =~ /::/;
# warn "Completing $str of type $type in $sub\n";
no strict;
return unless defined *{$sub}{CODE};
my $pad = peek_sub(\&$sub);
if ($type) {
map { s/^[\$\@&\%]//;$_ } grep /^\Q$type$str\E/, keys %$pad;
} else {
map { s/^[\$\@&\%]//;$_ } grep /^.\Q$str\E/, keys %$pad;
}
};
goto &lexical_completions;
}
=item C<@compls = completions($string [, $type [, $sub ] ])>
Find a list of completions for C<$string> with glob type C<$type>,
which may be "SCALAR", "HASH", "ARRAY", "CODE", "IO", or the special
value "VARIABLE", which means either scalar, hash, or array.
Completion operates on word subparts separated by [:_], so
e.g. "S:m_w" completes to "Sepia::my_walksymtable". If C<$sub> is
given, also consider its lexical variables.
=item C<@compls = method_completions($expr, $string [,$eval])>
Complete among methods on the object returned by C<$expr>. The
C<$eval> argument, if present, is a function used to do the
evaluation; the default is C<eval>, but for example the Sepia REPL
uses C<Sepia::repl_eval>. B<Warning>: Since it has to evaluate
C<$expr>, method completion can be extremely problematic. Use with
care.
=cut
sub completions
{
my ($type, $str, $sub) = @_;
my $t;
my %h = qw(@ ARRAY % HASH & CODE * IO $ SCALAR);
my %rh;
@rh{values %h} = keys %h;
$type ||= '';
$t = $type ? $rh{$type} : '';
my @ret;
if ($sub && $type ne '') {
@ret = lexical_completions $t, $str, $sub;
}
if (!@ret) {
@ret = grep {
$type ? filter_typed $type : filter_untyped
} all_completions $str;
}
if (!@ret && $str !~ /:/) {
@ret = grep {
$type ? filter_typed $type : filter_untyped
} all_abbrev_completions $str;
lib/Sepia.pm view on Meta::CPAN
=cut
sub define_shortcuts
{
define_shortcut 'help', \&Sepia::repl_help,
'help [CMD]',
'Display help on all commands, or just CMD.';
define_shortcut 'cd', \&Sepia::repl_chdir,
'cd DIR', 'Change directory to DIR';
define_shortcut 'pwd', \&Sepia::repl_pwd,
'Show current working directory';
define_shortcut 'methods', \&Sepia::repl_methods,
'methods X [RE]',
'List methods for reference or package X, matching optional pattern RE';
define_shortcut 'package', \&Sepia::repl_package,
'package PKG', 'Set evaluation package to PKG';
define_shortcut 'who', \&Sepia::repl_who,
'who PKG [RE]',
'List variables and subs in PKG matching optional pattern RE.';
define_shortcut 'wantarray', \&Sepia::repl_wantarray,
'wantarray [0|1]', 'Set or toggle evaluation context';
define_shortcut 'format', \&Sepia::repl_format,
'format [TYPE]', "Set output formatter to TYPE (one of 'dumper', 'dump', 'yaml', 'plain'; default: 'dumper'), or show current type.";
define_shortcut 'strict', \&Sepia::repl_strict,
'strict [0|1]', 'Turn \'use strict\' mode on or off';
define_shortcut 'quit', \&Sepia::repl_quit,
'Quit the REPL';
alias_shortcut 'exit', 'quit';
define_shortcut 'restart', \&Sepia::repl_restart,
'Reload Sepia.pm and relaunch the REPL.';
define_shortcut 'shell', \&Sepia::repl_shell,
'shell CMD ...', 'Run CMD in the shell';
define_shortcut 'eval', \&Sepia::repl_eval,
'eval EXP', '(internal)';
define_shortcut 'size', \&Sepia::repl_size,
'size PKG [RE]',
'List total sizes of objects in PKG matching optional pattern RE.';
define_shortcut define => \&Sepia::repl_define,
'define NAME [\'DOC\'] BODY',
'Define NAME as a shortcut executing BODY';
define_shortcut undef => \&Sepia::repl_undef,
'undef NAME', 'Undefine shortcut NAME';
define_shortcut test => \&Sepia::repl_test,
'test FILE...', 'Run tests interactively.';
define_shortcut load => \&Sepia::repl_load,
'load [FILE]', 'Load state from FILE.';
define_shortcut save => \&Sepia::repl_save,
'save [PATTERN [FILE]]', 'Save variables matching PATTERN to FILE.';
define_shortcut reload => \&Sepia::repl_reload,
'reload [MODULE | /RE/]', 'Reload MODULE, or all modules matching RE.';
define_shortcut freload => \&Sepia::repl_full_reload,
'freload MODULE', 'Reload MODULE and all its dependencies.';
define_shortcut time => \&Sepia::repl_time,
'time [0|1]', 'Print timing information for each command.';
define_shortcut lsmod => \&Sepia::repl_lsmod,
'lsmod [PATTERN]', 'List loaded modules matching PATTERN.';
}
=item C<repl_strict([$value])>
Toggle strict mode. Requires L<PadWalker> and L<Devel::LexAlias>.
=cut
sub repl_strict
{
eval q{ use PadWalker qw(peek_sub set_closed_over);
use Devel::LexAlias 'lexalias';
};
if ($@) {
print "Strict mode requires PadWalker and Devel::LexAlias.\n";
} else {
*repl_strict = sub {
my $x = as_boolean(shift, $STRICT);
if ($x && !$STRICT) {
$STRICT = {};
} elsif (!$x) {
undef $STRICT;
}
};
goto &repl_strict;
}
}
sub repl_size
{
eval q{ require Devel::Size };
if ($@) {
print "Size requires Devel::Size.\n";
} else {
*Sepia::repl_size = sub {
my ($pkg, $re) = split ' ', shift, 2;
if ($re) {
$re =~ s!^/|/$!!g;
} elsif (!$re && $pkg =~ /^\/(.*?)\/?$/) {
$re = $1;
undef $pkg;
} elsif (!$pkg) {
$re = '.';
}
my (@who, %res);
if ($STRICT && !$pkg) {
@who = grep /$re/, keys %$STRICT;
for (@who) {
$res{$_} = Devel::Size::total_size($Sepia::STRICT->{$_});
}
} else {
no strict 'refs';
$pkg ||= 'main';
@who = who($pkg, $re);
for (@who) {
next unless /^[\$\@\%\&]/; # skip subs.
next if $_ eq '%SIG';
$res{$_} = eval "no strict; package $pkg; Devel::Size::total_size \\$_;";
}
}
my $len = max(3, map { length } @who) + 4;
my $fmt = '%-'.$len."s%10d\n";
# print "$pkg\::/$re/\n";
print 'Var', ' ' x ($len + 2), "Bytes\n";
print '-' x ($len-4), ' ' x 9, '-' x 5, "\n";
for (sort { $res{$b} <=> $res{$a} } keys %res) {
printf $fmt, $_, $res{$_};
}
};
goto &repl_size;
}
}
=item C<repl_time([$value])>
( run in 2.355 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )