mirror of
https://github.com/pragma-/pbot.git
synced 2024-11-23 04:19:27 +01:00
Fix interactive-editing chained commands
This commit is contained in:
parent
43f08b4cbc
commit
7638bb031b
@ -155,7 +155,7 @@ sub show_output {
|
||||
my $self = shift;
|
||||
my $output = $self->{output};
|
||||
|
||||
unless($self->{got_run} and $self->{copy_code}) {
|
||||
unless ($self->{got_run} and $self->{copy_code}) {
|
||||
open FILE, ">> log.txt";
|
||||
print FILE "------------------------------------------------------------------------\n";
|
||||
print FILE localtime() . "\n";
|
||||
@ -164,7 +164,7 @@ sub show_output {
|
||||
close FILE;
|
||||
}
|
||||
|
||||
if(exists $self->{options}->{'-paste'} or (defined $self->{got_run} and $self->{got_run} eq "paste")) {
|
||||
if (exists $self->{options}->{'-paste'} or (defined $self->{got_run} and $self->{got_run} eq 'paste')) {
|
||||
my $cmdline = $self->{cmdline};
|
||||
|
||||
$cmdline =~ s/\$sourcefile/$self->{sourcefile}/g;
|
||||
@ -444,7 +444,7 @@ sub process_cmdline_options {
|
||||
sub process_interactive_edit {
|
||||
my $self = shift;
|
||||
my $code = $self->{code};
|
||||
my (@last_code, $save_last_code, $unshift_last_code);
|
||||
my (@last_code, $unshift_last_code);
|
||||
|
||||
print " code: [$code]\n" if $self->{debug};
|
||||
|
||||
@ -474,7 +474,6 @@ sub process_interactive_edit {
|
||||
$code = $copy_code;
|
||||
$self->{only_show} = 1;
|
||||
$self->{copy_code} = 1;
|
||||
$save_last_code = 1;
|
||||
}
|
||||
|
||||
if($subcode =~ m/^\s*(?:and\s+)?(?:diff|show)\s+(\S+)\s*$/) {
|
||||
@ -500,425 +499,406 @@ sub process_interactive_edit {
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if($subcode =~ m/^\s*(?:and\s+)?diff(?:\s+\S+)?\s*$/i) {
|
||||
if($#last_code < 1) {
|
||||
print "$self->{nick}: Not enough recent code to diff.\n"
|
||||
} else {
|
||||
use Text::WordDiff;
|
||||
my $diff = word_diff(\$last_code[1], \$last_code[0], { STYLE => 'Diff' });
|
||||
if($diff !~ /(?:<del>|<ins>)/) {
|
||||
$diff = "No difference.";
|
||||
} else {
|
||||
$diff =~ s/<del>(.*?)(\s+)<\/del>/<del>$1<\/del>$2/g;
|
||||
$diff =~ s/<ins>(.*?)(\s+)<\/ins>/<ins>$1<\/ins>$2/g;
|
||||
$diff =~ s/<del>((?:(?!<del>).)*)<\/del>\s*<ins>((?:(?!<ins>).)*)<\/ins>/`replaced $1 with $2`/g;
|
||||
$diff =~ s/<del>(.*?)<\/del>/`removed $1`/g;
|
||||
$diff =~ s/<ins>(.*?)<\/ins>/`inserted $1`/g;
|
||||
}
|
||||
my $prevchange = $last_code[0];
|
||||
my @replacements;
|
||||
my $got_changes = 0;
|
||||
my $got_sub = 0;
|
||||
my $got_diff = 0;
|
||||
my $got_undo = 0;
|
||||
my $last_keyword;
|
||||
|
||||
print "$self->{nick}: $diff\n";
|
||||
while($subcode =~ s/^\s*(and)?\s*undo//) {
|
||||
splice @last_code, 0, 1;
|
||||
if(not defined $last_code[0]) {
|
||||
print "$self->{nick}: No more undos remaining.\n";
|
||||
exit 0;
|
||||
} else {
|
||||
$code = $last_code[0];
|
||||
$got_undo = 1;
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if($subcode =~ m/^\s*(?:and\s+)?(run|paste)\s*$/i) {
|
||||
$self->{got_run} = lc $1;
|
||||
if(defined $last_code[0]) {
|
||||
$code = $last_code[0];
|
||||
$self->{only_show} = 0;
|
||||
} else {
|
||||
print "$self->{nick}: No recent code to $self->{got_run}.\n";
|
||||
exit 0;
|
||||
}
|
||||
} else {
|
||||
my $got_undo = 0;
|
||||
my $got_sub = 0;
|
||||
while(1) {
|
||||
$got_sub = 0;
|
||||
|
||||
while($subcode =~ s/^\s*(and)?\s*undo//) {
|
||||
splice @last_code, 0, 1;
|
||||
if(not defined $last_code[0]) {
|
||||
print "$self->{nick}: No more undos remaining.\n";
|
||||
exit 0;
|
||||
} else {
|
||||
$code = $last_code[0];
|
||||
$got_undo = 1;
|
||||
}
|
||||
}
|
||||
|
||||
my @replacements;
|
||||
my $prevchange = $last_code[0];
|
||||
my $got_changes = 0;
|
||||
my $last_keyword;
|
||||
|
||||
while(1) {
|
||||
$got_sub = 0;
|
||||
#$got_changes = 0;
|
||||
|
||||
$subcode =~ s/^\s*and\s+'/and $last_keyword '/ if defined $last_keyword;
|
||||
|
||||
if($subcode =~ m/^\s*(and)?\s*remove \s*([^']+)?\s*'/) {
|
||||
$last_keyword = 'remove';
|
||||
my $modifier = 'first';
|
||||
|
||||
$subcode =~ s/^\s*(and)?\s*//;
|
||||
$subcode =~ s/remove\s*([^']+)?\s*//i;
|
||||
$modifier = $1 if defined $1;
|
||||
$modifier =~ s/\s+$//;
|
||||
|
||||
my ($e, $r) = extract_delimited($subcode, "'");
|
||||
|
||||
my $text;
|
||||
|
||||
if(defined $e) {
|
||||
$text = $e;
|
||||
$text =~ s/^'//;
|
||||
$text =~ s/'$//;
|
||||
$subcode = "replace $modifier '$text' with ''$r";
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced single quotes. Usage: cc remove [all, first, .., tenth, last] 'text' [and ...]\n";
|
||||
exit 0;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
if($subcode =~ s/^\s*(and)?\s*prepend '//) {
|
||||
$last_keyword = 'prepend';
|
||||
$subcode = "'$subcode";
|
||||
|
||||
my ($e, $r) = extract_delimited($subcode, "'");
|
||||
|
||||
my $text;
|
||||
|
||||
if(defined $e) {
|
||||
$text = $e;
|
||||
$text =~ s/^'//;
|
||||
$text =~ s/'$//;
|
||||
$subcode = $r;
|
||||
|
||||
$got_sub = 1;
|
||||
$got_changes = 1;
|
||||
|
||||
if(not defined $prevchange) {
|
||||
print "$self->{nick}: No recent code to prepend to.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
$code = $prevchange;
|
||||
$code =~ s/^/$text /;
|
||||
$prevchange = $code;
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced single quotes. Usage: cc prepend 'text' [and ...]\n";
|
||||
exit 0;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
if($subcode =~ s/^\s*(and)?\s*append '//) {
|
||||
$last_keyword = 'append';
|
||||
$subcode = "'$subcode";
|
||||
|
||||
my ($e, $r) = extract_delimited($subcode, "'");
|
||||
|
||||
my $text;
|
||||
|
||||
if(defined $e) {
|
||||
$text = $e;
|
||||
$text =~ s/^'//;
|
||||
$text =~ s/'$//;
|
||||
$subcode = $r;
|
||||
|
||||
$got_sub = 1;
|
||||
$got_changes = 1;
|
||||
|
||||
if(not defined $prevchange) {
|
||||
print "$self->{nick}: No recent code to append to.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
$code = $prevchange;
|
||||
$code =~ s/$/ $text/;
|
||||
$prevchange = $code;
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced single quotes. Usage: cc append 'text' [and ...]\n";
|
||||
exit 0;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
if($subcode =~ m/^\s*(and)?\s*replace\s*([^']+)?\s*'.*'\s*with\s*'.*?'/i) {
|
||||
$last_keyword = 'replace';
|
||||
$got_sub = 1;
|
||||
my $modifier = 'first';
|
||||
|
||||
$subcode =~ s/^\s*(and)?\s*//;
|
||||
$subcode =~ s/replace\s*([^']+)?\s*//i;
|
||||
$modifier = $1 if defined $1;
|
||||
$modifier =~ s/\s+$//;
|
||||
|
||||
my ($from, $to);
|
||||
my ($e, $r) = extract_delimited($subcode, "'");
|
||||
|
||||
if(defined $e) {
|
||||
$from = $e;
|
||||
$from =~ s/^'//;
|
||||
$from =~ s/'$//;
|
||||
$from = quotemeta $from;
|
||||
$from =~ s/\\ / /g;
|
||||
$subcode = $r;
|
||||
$subcode =~ s/\s*with\s*//i;
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced single quotes. Usage: cc replace 'from' with 'to' [and ...]\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
($e, $r) = extract_delimited($subcode, "'");
|
||||
|
||||
if(defined $e) {
|
||||
$to = $e;
|
||||
$to =~ s/^'//;
|
||||
$to =~ s/'$//;
|
||||
$subcode = $r;
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced single quotes. Usage: cc replace 'from' with 'to' [and replace ... with ... [and ...]]\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
given($modifier) {
|
||||
when($_ eq 'all' ) {}
|
||||
when($_ eq 'last' ) {}
|
||||
when($_ eq 'first' ) { $modifier = 1; }
|
||||
when($_ eq 'second' ) { $modifier = 2; }
|
||||
when($_ eq 'third' ) { $modifier = 3; }
|
||||
when($_ eq 'fourth' ) { $modifier = 4; }
|
||||
when($_ eq 'fifth' ) { $modifier = 5; }
|
||||
when($_ eq 'sixth' ) { $modifier = 6; }
|
||||
when($_ eq 'seventh') { $modifier = 7; }
|
||||
when($_ eq 'eighth' ) { $modifier = 8; }
|
||||
when($_ eq 'nineth' ) { $modifier = 9; }
|
||||
when($_ eq 'tenth' ) { $modifier = 10; }
|
||||
default { print "$self->{nick}: Bad replacement modifier '$modifier'; valid modifiers are 'all', 'first', 'second', ..., 'tenth', 'last'\n"; exit 0; }
|
||||
}
|
||||
|
||||
my $replacement = {};
|
||||
$replacement->{'from'} = $from;
|
||||
$replacement->{'to'} = $to;
|
||||
$replacement->{'modifier'} = $modifier;
|
||||
|
||||
push @replacements, $replacement;
|
||||
next;
|
||||
}
|
||||
|
||||
if($subcode =~ m/^\s*(and)?\s*s\/.*\//) {
|
||||
$last_keyword = undef;
|
||||
$got_sub = 1;
|
||||
$subcode =~ s/^\s*(and)?\s*s//;
|
||||
|
||||
my ($regex, $to);
|
||||
my ($e, $r) = extract_delimited($subcode, '/');
|
||||
|
||||
if(defined $e) {
|
||||
$regex = $e;
|
||||
$regex =~ s/^\///;
|
||||
$regex =~ s/\/$//;
|
||||
$subcode = "/$r";
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced slashes. Usage: cc s/regex/substitution/[gi] [and s/.../.../ [and ...]]\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
($e, $r) = extract_delimited($subcode, '/');
|
||||
|
||||
if(defined $e) {
|
||||
$to = $e;
|
||||
$to =~ s/^\///;
|
||||
$to =~ s/\/$//;
|
||||
$subcode = $r;
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced slashes. Usage: cc s/regex/substitution/[gi] [and s/.../.../ [and ...]]\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $suffix;
|
||||
$suffix = $1 if $subcode =~ s/^([^ ]+)//;
|
||||
|
||||
if(length $suffix and $suffix =~ m/[^gi]/) {
|
||||
print "$self->{nick}: Bad regex modifier '$suffix'. Only 'i' and 'g' are allowed.\n";
|
||||
exit 0;
|
||||
}
|
||||
if(defined $prevchange) {
|
||||
$code = $prevchange;
|
||||
} else {
|
||||
print "$self->{nick}: No recent code to change.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $ret = eval {
|
||||
my ($ret, $a, $b, $c, $d, $e, $f, $g, $h, $i, $before, $after);
|
||||
|
||||
if(not length $suffix) {
|
||||
$ret = $code =~ s|$regex|$to|;
|
||||
($a, $b, $c, $d, $e, $f, $g, $h, $i) = ($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
$before = $`;
|
||||
$after = $';
|
||||
} elsif($suffix =~ /^i$/) {
|
||||
$ret = $code =~ s|$regex|$to|i;
|
||||
($a, $b, $c, $d, $e, $f, $g, $h, $i) = ($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
$before = $`;
|
||||
$after = $';
|
||||
} elsif($suffix =~ /^g$/) {
|
||||
$ret = $code =~ s|$regex|$to|g;
|
||||
($a, $b, $c, $d, $e, $f, $g, $h, $i) = ($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
$before = $`;
|
||||
$after = $';
|
||||
} elsif($suffix =~ /^ig$/ or $suffix =~ /^gi$/) {
|
||||
$ret = $code =~ s|$regex|$to|gi;
|
||||
($a, $b, $c, $d, $e, $f, $g, $h, $i) = ($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
$before = $`;
|
||||
$after = $';
|
||||
}
|
||||
|
||||
if($ret) {
|
||||
$code =~ s/\$1/$a/g;
|
||||
$code =~ s/\$2/$b/g;
|
||||
$code =~ s/\$3/$c/g;
|
||||
$code =~ s/\$4/$d/g;
|
||||
$code =~ s/\$5/$e/g;
|
||||
$code =~ s/\$6/$f/g;
|
||||
$code =~ s/\$7/$g/g;
|
||||
$code =~ s/\$8/$h/g;
|
||||
$code =~ s/\$9/$i/g;
|
||||
$code =~ s/\$`/$before/g;
|
||||
$code =~ s/\$'/$after/g;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
};
|
||||
|
||||
if($@) {
|
||||
my $error = $@;
|
||||
$error =~ s/ at .* line \d+\.\s*$//;
|
||||
print "$self->{nick}: $error\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if($ret) {
|
||||
$got_changes = 1;
|
||||
}
|
||||
|
||||
$prevchange = $code;
|
||||
}
|
||||
|
||||
if($got_sub and not $got_changes) {
|
||||
print "$self->{nick}: No substitutions made.\n";
|
||||
exit 0;
|
||||
} elsif($got_sub and $got_changes) {
|
||||
next;
|
||||
}
|
||||
$subcode =~ s/^\s*and\s+'/and $last_keyword '/ if defined $last_keyword;
|
||||
|
||||
if($subcode =~ m/^\s*(?:and\s+)?diff\b/i) {
|
||||
$got_diff = 1;
|
||||
last;
|
||||
}
|
||||
|
||||
if($#replacements > -1) {
|
||||
use re::engine::RE2 -strict => 1;
|
||||
@replacements = sort { $a->{'from'} cmp $b->{'from'} or $a->{'modifier'} <=> $b->{'modifier'} } @replacements;
|
||||
|
||||
my ($previous_from, $previous_modifier);
|
||||
|
||||
foreach my $replacement (@replacements) {
|
||||
my $from = $replacement->{'from'};
|
||||
my $to = $replacement->{'to'};
|
||||
my $modifier = $replacement->{'modifier'};
|
||||
|
||||
if(defined $previous_from) {
|
||||
if($previous_from eq $from and $previous_modifier =~ /^\d+$/) {
|
||||
$modifier -= $modifier - $previous_modifier;
|
||||
}
|
||||
}
|
||||
|
||||
if(defined $prevchange) {
|
||||
$code = $prevchange;
|
||||
} else {
|
||||
print "$self->{nick}: No recent code to change.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $ret = eval {
|
||||
my $got_change;
|
||||
|
||||
my ($first_char, $last_char, $first_bound, $last_bound);
|
||||
$first_char = $1 if $from =~ m/^(.)/;
|
||||
$last_char = $1 if $from =~ m/(.)$/;
|
||||
|
||||
if($first_char =~ /\W/) {
|
||||
$first_bound = '.?';
|
||||
} else {
|
||||
$first_bound = '\b';
|
||||
}
|
||||
|
||||
if($last_char =~ /\W/) {
|
||||
$last_bound = '.?';
|
||||
} else {
|
||||
$last_bound = '\b';
|
||||
}
|
||||
|
||||
if($modifier eq 'all') {
|
||||
if($code =~ s/($first_bound)$from($last_bound)/$1$to$2/g) {
|
||||
$got_change = 1;
|
||||
}
|
||||
} elsif($modifier eq 'last') {
|
||||
if($code =~ s/(.*)($first_bound)$from($last_bound)/$1$2$to$3/) {
|
||||
$got_change = 1;
|
||||
}
|
||||
} else {
|
||||
my $count = 0;
|
||||
my $unescaped = $from;
|
||||
$unescaped =~ s/\\//g;
|
||||
if($code =~ s/($first_bound)$from($last_bound)/if(++$count == $modifier) { "$1$to$2"; } else { "$1$unescaped$2"; }/ge) {
|
||||
$got_change = 1;
|
||||
}
|
||||
}
|
||||
return $got_change;
|
||||
};
|
||||
|
||||
if($@) {
|
||||
my $error = $@;
|
||||
$error =~ s/ at .* line \d+\.\s*$//;
|
||||
print "$self->{nick}: $error\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if($ret) {
|
||||
$got_sub = 1;
|
||||
$got_changes = 1;
|
||||
}
|
||||
|
||||
$prevchange = $code;
|
||||
$previous_from = $from;
|
||||
$previous_modifier = $modifier;
|
||||
}
|
||||
|
||||
if(not $got_changes) {
|
||||
print "$self->{nick}: No replacements made.\n";
|
||||
if($subcode =~ m/^\s*(?:and\s+)?(run|paste)\b/i) {
|
||||
$self->{got_run} = lc $1;
|
||||
$self->{only_show} = 0;
|
||||
if ($prevchange) {
|
||||
$code = $prevchange;
|
||||
} else {
|
||||
print "$self->{nick}: No recent code to $self->{got_run}.\n";
|
||||
exit 0;
|
||||
}
|
||||
}
|
||||
|
||||
$save_last_code = 1;
|
||||
if($subcode =~ m/^\s*(and)?\s*remove \s*([^']+)?\s*'/) {
|
||||
$last_keyword = 'remove';
|
||||
my $modifier = 'first';
|
||||
|
||||
unless($got_undo and not $got_changes) {
|
||||
$unshift_last_code = 1 unless $copy_code and not $got_changes;
|
||||
$subcode =~ s/^\s*(and)?\s*//;
|
||||
$subcode =~ s/remove\s*([^']+)?\s*//i;
|
||||
$modifier = $1 if defined $1;
|
||||
$modifier =~ s/\s+$//;
|
||||
|
||||
my ($e, $r) = extract_delimited($subcode, "'");
|
||||
|
||||
my $text;
|
||||
|
||||
if(defined $e) {
|
||||
$text = $e;
|
||||
$text =~ s/^'//;
|
||||
$text =~ s/'$//;
|
||||
$subcode = "replace $modifier '$text' with ''$r";
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced single quotes. Usage: cc remove [all, first, .., tenth, last] 'text' [and ...]\n";
|
||||
exit 0;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
if($copy_code and $got_changes) {
|
||||
$self->{only_show} = 0;
|
||||
if($subcode =~ s/^\s*(and)?\s*prepend '//) {
|
||||
$last_keyword = 'prepend';
|
||||
$subcode = "'$subcode";
|
||||
|
||||
my ($e, $r) = extract_delimited($subcode, "'");
|
||||
|
||||
my $text;
|
||||
|
||||
if(defined $e) {
|
||||
$text = $e;
|
||||
$text =~ s/^'//;
|
||||
$text =~ s/'$//;
|
||||
$subcode = $r;
|
||||
|
||||
$got_sub = 1;
|
||||
$got_changes = 1;
|
||||
|
||||
if(not defined $prevchange) {
|
||||
print "$self->{nick}: No recent code to prepend to.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
$code = $prevchange;
|
||||
$code =~ s/^/$text /;
|
||||
$prevchange = $code;
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced single quotes. Usage: cc prepend 'text' [and ...]\n";
|
||||
exit 0;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
if($got_undo and not $got_changes) {
|
||||
$self->{only_show} = 1;
|
||||
if($subcode =~ s/^\s*(and)?\s*append '//) {
|
||||
$last_keyword = 'append';
|
||||
$subcode = "'$subcode";
|
||||
|
||||
my ($e, $r) = extract_delimited($subcode, "'");
|
||||
|
||||
my $text;
|
||||
|
||||
if(defined $e) {
|
||||
$text = $e;
|
||||
$text =~ s/^'//;
|
||||
$text =~ s/'$//;
|
||||
$subcode = $r;
|
||||
|
||||
$got_sub = 1;
|
||||
$got_changes = 1;
|
||||
|
||||
if(not defined $prevchange) {
|
||||
print "$self->{nick}: No recent code to append to.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
$code = $prevchange;
|
||||
$code =~ s/$/ $text/;
|
||||
$prevchange = $code;
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced single quotes. Usage: cc append 'text' [and ...]\n";
|
||||
exit 0;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
if($subcode =~ m/^\s*(and)?\s*replace\s*([^']+)?\s*'.*'\s*with\s*'.*?'/i) {
|
||||
$last_keyword = 'replace';
|
||||
$got_sub = 1;
|
||||
my $modifier = 'first';
|
||||
|
||||
$subcode =~ s/^\s*(and)?\s*//;
|
||||
$subcode =~ s/replace\s*([^']+)?\s*//i;
|
||||
$modifier = $1 if defined $1;
|
||||
$modifier =~ s/\s+$//;
|
||||
|
||||
my ($from, $to);
|
||||
my ($e, $r) = extract_delimited($subcode, "'");
|
||||
|
||||
if(defined $e) {
|
||||
$from = $e;
|
||||
$from =~ s/^'//;
|
||||
$from =~ s/'$//;
|
||||
$from = quotemeta $from;
|
||||
$from =~ s/\\ / /g;
|
||||
$subcode = $r;
|
||||
$subcode =~ s/\s*with\s*//i;
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced single quotes. Usage: cc replace 'from' with 'to' [and ...]\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
($e, $r) = extract_delimited($subcode, "'");
|
||||
|
||||
if(defined $e) {
|
||||
$to = $e;
|
||||
$to =~ s/^'//;
|
||||
$to =~ s/'$//;
|
||||
$subcode = $r;
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced single quotes. Usage: cc replace 'from' with 'to' [and replace ... with ... [and ...]]\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
given($modifier) {
|
||||
when($_ eq 'all' ) {}
|
||||
when($_ eq 'last' ) {}
|
||||
when($_ eq 'first' ) { $modifier = 1; }
|
||||
when($_ eq 'second' ) { $modifier = 2; }
|
||||
when($_ eq 'third' ) { $modifier = 3; }
|
||||
when($_ eq 'fourth' ) { $modifier = 4; }
|
||||
when($_ eq 'fifth' ) { $modifier = 5; }
|
||||
when($_ eq 'sixth' ) { $modifier = 6; }
|
||||
when($_ eq 'seventh') { $modifier = 7; }
|
||||
when($_ eq 'eighth' ) { $modifier = 8; }
|
||||
when($_ eq 'nineth' ) { $modifier = 9; }
|
||||
when($_ eq 'tenth' ) { $modifier = 10; }
|
||||
default { print "$self->{nick}: Bad replacement modifier '$modifier'; valid modifiers are 'all', 'first', 'second', ..., 'tenth', 'last'\n"; exit 0; }
|
||||
}
|
||||
|
||||
my $replacement = {};
|
||||
$replacement->{'from'} = $from;
|
||||
$replacement->{'to'} = $to;
|
||||
$replacement->{'modifier'} = $modifier;
|
||||
|
||||
push @replacements, $replacement;
|
||||
next;
|
||||
}
|
||||
|
||||
if($subcode =~ m/^\s*(and)?\s*s\/.*\//) {
|
||||
$last_keyword = undef;
|
||||
$got_sub = 1;
|
||||
$subcode =~ s/^\s*(and)?\s*s//;
|
||||
|
||||
my ($regex, $to);
|
||||
my ($e, $r) = extract_delimited($subcode, '/');
|
||||
|
||||
if(defined $e) {
|
||||
$regex = $e;
|
||||
$regex =~ s/^\///;
|
||||
$regex =~ s/\/$//;
|
||||
$subcode = "/$r";
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced slashes. Usage: cc s/regex/substitution/[gi] [and s/.../.../ [and ...]]\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
($e, $r) = extract_delimited($subcode, '/');
|
||||
|
||||
if(defined $e) {
|
||||
$to = $e;
|
||||
$to =~ s/^\///;
|
||||
$to =~ s/\/$//;
|
||||
$subcode = $r;
|
||||
} else {
|
||||
print "$self->{nick}: Unbalanced slashes. Usage: cc s/regex/substitution/[gi] [and s/.../.../ [and ...]]\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $suffix;
|
||||
$suffix = $1 if $subcode =~ s/^([^ ]+)//;
|
||||
|
||||
if(length $suffix and $suffix =~ m/[^gi]/) {
|
||||
print "$self->{nick}: Bad regex modifier '$suffix'. Only 'i' and 'g' are allowed.\n";
|
||||
exit 0;
|
||||
}
|
||||
if(defined $prevchange) {
|
||||
$code = $prevchange;
|
||||
} else {
|
||||
print "$self->{nick}: No recent code to change.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $ret = eval {
|
||||
my ($ret, $a, $b, $c, $d, $e, $f, $g, $h, $i, $before, $after);
|
||||
|
||||
if(not length $suffix) {
|
||||
$ret = $code =~ s|$regex|$to|;
|
||||
($a, $b, $c, $d, $e, $f, $g, $h, $i) = ($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
$before = $`;
|
||||
$after = $';
|
||||
} elsif($suffix =~ /^i$/) {
|
||||
$ret = $code =~ s|$regex|$to|i;
|
||||
($a, $b, $c, $d, $e, $f, $g, $h, $i) = ($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
$before = $`;
|
||||
$after = $';
|
||||
} elsif($suffix =~ /^g$/) {
|
||||
$ret = $code =~ s|$regex|$to|g;
|
||||
($a, $b, $c, $d, $e, $f, $g, $h, $i) = ($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
$before = $`;
|
||||
$after = $';
|
||||
} elsif($suffix =~ /^ig$/ or $suffix =~ /^gi$/) {
|
||||
$ret = $code =~ s|$regex|$to|gi;
|
||||
($a, $b, $c, $d, $e, $f, $g, $h, $i) = ($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
$before = $`;
|
||||
$after = $';
|
||||
}
|
||||
|
||||
if($ret) {
|
||||
$code =~ s/\$1/$a/g;
|
||||
$code =~ s/\$2/$b/g;
|
||||
$code =~ s/\$3/$c/g;
|
||||
$code =~ s/\$4/$d/g;
|
||||
$code =~ s/\$5/$e/g;
|
||||
$code =~ s/\$6/$f/g;
|
||||
$code =~ s/\$7/$g/g;
|
||||
$code =~ s/\$8/$h/g;
|
||||
$code =~ s/\$9/$i/g;
|
||||
$code =~ s/\$`/$before/g;
|
||||
$code =~ s/\$'/$after/g;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
};
|
||||
|
||||
if($@) {
|
||||
my $error = $@;
|
||||
$error =~ s/ at .* line \d+\.\s*$//;
|
||||
print "$self->{nick}: $error\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if ($ret) {
|
||||
$got_changes = 1;
|
||||
}
|
||||
|
||||
$prevchange = $code;
|
||||
}
|
||||
|
||||
if ($got_sub and not $got_changes) {
|
||||
print "$self->{nick}: No substitutions made.\n";
|
||||
exit 0;
|
||||
} elsif ($got_sub and $got_changes) {
|
||||
next;
|
||||
}
|
||||
|
||||
last;
|
||||
}
|
||||
|
||||
if (@replacements) {
|
||||
use re::engine::RE2 -strict => 1;
|
||||
@replacements = sort { $a->{'from'} cmp $b->{'from'} or $a->{'modifier'} <=> $b->{'modifier'} } @replacements;
|
||||
|
||||
my ($previous_from, $previous_modifier);
|
||||
|
||||
foreach my $replacement (@replacements) {
|
||||
my $from = $replacement->{'from'};
|
||||
my $to = $replacement->{'to'};
|
||||
my $modifier = $replacement->{'modifier'};
|
||||
|
||||
if(defined $previous_from) {
|
||||
if($previous_from eq $from and $previous_modifier =~ /^\d+$/) {
|
||||
$modifier -= $modifier - $previous_modifier;
|
||||
}
|
||||
}
|
||||
|
||||
if(defined $prevchange) {
|
||||
$code = $prevchange;
|
||||
} else {
|
||||
print "$self->{nick}: No recent code to change.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $ret = eval {
|
||||
my $got_change;
|
||||
|
||||
my ($first_char, $last_char, $first_bound, $last_bound);
|
||||
$first_char = $1 if $from =~ m/^(.)/;
|
||||
$last_char = $1 if $from =~ m/(.)$/;
|
||||
|
||||
if($first_char =~ /\W/) {
|
||||
$first_bound = '.?';
|
||||
} else {
|
||||
$first_bound = '\b';
|
||||
}
|
||||
|
||||
if($last_char =~ /\W/) {
|
||||
$last_bound = '.?';
|
||||
} else {
|
||||
$last_bound = '\b';
|
||||
}
|
||||
|
||||
if($modifier eq 'all') {
|
||||
if($code =~ s/($first_bound)$from($last_bound)/$1$to$2/g) {
|
||||
$got_change = 1;
|
||||
}
|
||||
} elsif($modifier eq 'last') {
|
||||
if($code =~ s/(.*)($first_bound)$from($last_bound)/$1$2$to$3/) {
|
||||
$got_change = 1;
|
||||
}
|
||||
} else {
|
||||
my $count = 0;
|
||||
my $unescaped = $from;
|
||||
$unescaped =~ s/\\//g;
|
||||
if($code =~ s/($first_bound)$from($last_bound)/if(++$count == $modifier) { "$1$to$2"; } else { "$1$unescaped$2"; }/ge) {
|
||||
$got_change = 1;
|
||||
}
|
||||
}
|
||||
return $got_change;
|
||||
};
|
||||
|
||||
if($@) {
|
||||
my $error = $@;
|
||||
$error =~ s/ at .* line \d+\.\s*$//;
|
||||
print "$self->{nick}: $error\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if($ret) {
|
||||
$got_sub = 1;
|
||||
$got_changes = 1;
|
||||
}
|
||||
|
||||
$prevchange = $code;
|
||||
$previous_from = $from;
|
||||
$previous_modifier = $modifier;
|
||||
}
|
||||
|
||||
if(not $got_changes) {
|
||||
print "$self->{nick}: No replacements made.\n";
|
||||
exit 0;
|
||||
}
|
||||
}
|
||||
|
||||
if($save_last_code) {
|
||||
unless($got_undo and not $got_changes) {
|
||||
$unshift_last_code = 1 unless $copy_code and not $got_changes;
|
||||
}
|
||||
|
||||
if ($copy_code and $got_changes) {
|
||||
$self->{only_show} = 0;
|
||||
}
|
||||
|
||||
if ($got_undo and not $got_changes) {
|
||||
$self->{only_show} = 1;
|
||||
}
|
||||
|
||||
unless (($self->{got_run} or $got_diff) and not $got_changes) {
|
||||
if($unshift_last_code) {
|
||||
unshift @last_code, $code;
|
||||
}
|
||||
@ -934,6 +914,28 @@ sub process_interactive_edit {
|
||||
close FILE;
|
||||
}
|
||||
|
||||
if ($got_diff) {
|
||||
if($#last_code < 1) {
|
||||
print "$self->{nick}: Not enough recent code to diff.\n"
|
||||
} else {
|
||||
use Text::WordDiff;
|
||||
my $diff = word_diff(\$last_code[1], \$last_code[0], { STYLE => 'Diff' });
|
||||
|
||||
if($diff !~ /(?:<del>|<ins>)/) {
|
||||
$diff = "No difference.";
|
||||
} else {
|
||||
$diff =~ s/<del>(.*?)(\s+)<\/del>/<del>$1<\/del>$2/g;
|
||||
$diff =~ s/<ins>(.*?)(\s+)<\/ins>/<ins>$1<\/ins>$2/g;
|
||||
$diff =~ s/<del>((?:(?!<del>).)*)<\/del>\s*<ins>((?:(?!<ins>).)*)<\/ins>/`replaced $1 with $2`/g;
|
||||
$diff =~ s/<del>(.*?)<\/del>/`removed $1`/g;
|
||||
$diff =~ s/<ins>(.*?)<\/ins>/`inserted $1`/g;
|
||||
}
|
||||
|
||||
print "$self->{nick}: $diff\n";
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
|
||||
$self->{code} = $code;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user