# Copyright (C) 2011-2012 Rocky Bernstein use warnings; no warnings 'redefine'; use rlib '../../../..'; use Devel::Trepan::DB::LineCache; use Devel::Trepan::DB::Sub; package Devel::Trepan::CmdProcessor::Command::Edit; use if !@ISA, Devel::Trepan::CmdProcessor::Command ; unless (@ISA) { eval <<"EOE"; use constant ALIASES => ('e'); use constant CATEGORY => 'files'; use constant SHORT_HELP => 'Invoke an editor on some source code'; use constant NEED_STACK => 0; use constant MIN_ARGS => 0; # Need at least this many use constant MAX_ARGS => 2; # Need at most this many - undef -> unlimited. EOE } use strict; our @ISA = @CMD_ISA; # value inherited from parent use vars @CMD_VARS; # value inherited from parent our $NAME = set_name(); our $HELP = <<"HELP"; =pod ${NAME} [[I] [I]] With no argument, edits file containing most recent line listed. The value of the environment variable I is used for the editor to run. If no I environment variable is set /bin/ex is used. The editor should support line and file positioning via editor-name +line file-name (Most editors do.) =head2 Examples: ${NAME} # Edit current location ${NAME} 7 # Edit current file at line 7 ${NAME} test.rb # Edit test.rb, line 1 ${NAME} test.rb 10 # Edit test.rb line 10 =cut HELP # FIXME: include line numbers. Should we include all files? # Combine with BREAK completion. sub complete($$) { my ($self, $prefix) = @_; my @completions = sort ('.', DB::LineCache::file_list()); Devel::Trepan::Complete::complete_token(\@completions, $prefix); } # This method runs the command sub run($$) { my ($self, $args) = @_; my $proc = $self->{proc}; my ($filename, $line_number); my $count = scalar @$args; if (1 == $count) { if ($proc->{terminated}) { $proc->msg_need_running("implicit edit file and line"); return; } $filename = $self->{proc}->filename; $line_number = $self->{proc}->line; } elsif (2 == $count) { $line_number = $self->{proc}->get_int_noerr($args->[1]); if (defined $line_number) { if ($proc->{terminated}) { $proc->msg_need_running("implicit edit file"); return; } $filename = $self->{proc}->filename; } else { $filename = $args->[1]; $line_number = 1; } } elsif (3 == $count) { ($line_number, $filename) = ($args->[2], $args->[1]); } else { $self->errmsg("edit needs at most 2 args."); return; } my $editor = $ENV{'EDITOR'} || '/bin/ex'; if ( -r $filename ) { use File::Basename; $filename = basename($filename) if $self->{proc}{settings}{basename}; my @edit_cmd = ($editor, "+$line_number", $filename); $self->{proc}->msg(sprintf "Running: %s...", join(' ', @edit_cmd)); system(@edit_cmd); $self->{proc}->msg("Warning: return code was $?") if $? != 0; } else { $self->errmsg("File \"${filename}\" is not readable."); } } unless (caller) { require Devel::Trepan::CmdProcessor; my $proc = Devel::Trepan::CmdProcessor->new(undef, 'bogus'); my $cmd = __PACKAGE__->new($proc); sub create_frame() { my ($pkg, $file, $line, $fn) = caller(0); return [ { file => $file, fn => $fn, line => $line, pkg => $pkg, }]; } my $frame_ary = create_frame(); $proc->frame_setup($frame_ary); $cmd->run([$NAME]); $cmd->run([$NAME, '7']); $cmd->run([$NAME, __FILE__, '10']); } 1;