line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package File::Searcher::Interactive;
|
2
|
1
|
|
|
1
|
|
2498
|
use File::Searcher;
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
use Term::Prompt;
|
4
|
|
|
|
|
|
|
use Term::ANSIColor qw/:constants/;
|
5
|
|
|
|
|
|
|
$Term::ANSIColor::AUTORESET = 1;
|
6
|
|
|
|
|
|
|
use strict;
|
7
|
|
|
|
|
|
|
use vars qw($VERSION @ISA);
|
8
|
|
|
|
|
|
|
@ISA = qw(File::Searcher);
|
9
|
|
|
|
|
|
|
$VERSION = '0.9';
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub interactive{
|
13
|
|
|
|
|
|
|
my $self = shift;
|
14
|
|
|
|
|
|
|
$self->{_interactive} = 1;
|
15
|
|
|
|
|
|
|
$self->start;
|
16
|
|
|
|
|
|
|
}
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub _process_file{
|
19
|
|
|
|
|
|
|
my $self = shift;
|
20
|
|
|
|
|
|
|
my ($file) = @_;
|
21
|
|
|
|
|
|
|
my @expressions = @{$self->{_expressions}};
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
my $contents='';
|
24
|
|
|
|
|
|
|
$self->_backup($file) if $self->do_backup;
|
25
|
|
|
|
|
|
|
$self->_archive($file) if $self->do_archive;
|
26
|
|
|
|
|
|
|
$self->{_search}->add_files_matched($file);
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
my $lock = new File::Flock $file;
|
29
|
|
|
|
|
|
|
open(FILE, $file) || die "Cannot read file $file\n";
|
30
|
|
|
|
|
|
|
my @contents = ;
|
31
|
|
|
|
|
|
|
$contents = join("", @contents);
|
32
|
|
|
|
|
|
|
foreach my $expression (@expressions)
|
33
|
|
|
|
|
|
|
{
|
34
|
|
|
|
|
|
|
next if $self->{_search}->expression($expression)->skip_expression;
|
35
|
|
|
|
|
|
|
my ($match_cnt,$replace_cnt,$skip_next,$do_file,$do_all,$new_match_cnt,$re_do) = (0)x7;
|
36
|
|
|
|
|
|
|
$self->{_search}->expression($expression)->add_files_matched($file);
|
37
|
|
|
|
|
|
|
$do_all = $self->expression($expression)->do_all;
|
38
|
|
|
|
|
|
|
my $preview = '';
|
39
|
|
|
|
|
|
|
my $more = 1;
|
40
|
|
|
|
|
|
|
my ($search, $replace, $options_search, $options_replace) = $self->_get_search($expression);
|
41
|
|
|
|
|
|
|
$search = "(?$options_search)$search";
|
42
|
|
|
|
|
|
|
while($contents =~ m/$search/g)
|
43
|
|
|
|
|
|
|
{
|
44
|
|
|
|
|
|
|
my $match = Match->new(match=>$&,pre=>$`,post=>$',last=>$+,start_offset=>@-,end_offset=>@+,contents=>$contents);
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
my $return_status = 0;
|
47
|
|
|
|
|
|
|
$return_status = $self->{_on_expression_match}->($match, $self->{_search}->expression($expression)) if $do_file != 1 && $do_all != 1 && $new_match_cnt < 1;
|
48
|
|
|
|
|
|
|
$contents = $return_status and next if $return_status !~ /\d+/ && $return_status ne '';
|
49
|
|
|
|
|
|
|
$self->expression($expression)->do_all(1) and $do_all = 1 if $return_status == 100;
|
50
|
|
|
|
|
|
|
$do_file = 1 if $return_status == 10;
|
51
|
|
|
|
|
|
|
$self->expression($expression)->skip_expression(1) and last if $return_status == -100;
|
52
|
|
|
|
|
|
|
last if $return_status == -10;
|
53
|
|
|
|
|
|
|
$skip_next = 1 if $return_status == -1;
|
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
$skip_next = 1 if $match->match eq $replace;
|
56
|
|
|
|
|
|
|
$skip_next = 1 if $new_match_cnt > 0;
|
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
my $short_pre = substr($match->pre, (-25*$more), (25*$more));
|
59
|
|
|
|
|
|
|
my $short_post = substr($match->post, 0, 25*$more);
|
60
|
|
|
|
|
|
|
my $message = $short_pre; $message .= $re_do ? BOLD $preview : BOLD $match->match; $message .= $short_post;
|
61
|
|
|
|
|
|
|
unless($do_file || $do_all || $skip_next)
|
62
|
|
|
|
|
|
|
{
|
63
|
|
|
|
|
|
|
my $out = BOLD $file ."\n"; $out.=$message; $out.="\n--------------\n"; $out .= BOLD $replace . "\n";
|
64
|
|
|
|
|
|
|
print $out;
|
65
|
|
|
|
|
|
|
}
|
66
|
|
|
|
|
|
|
my $prompt = BOLD "[Y]"; $prompt .= "Replace "; $prompt .= BOLD "[A]"; $prompt .= "All In File "; $prompt .= BOLD "[Z]"; $prompt .= "All Files\n "; $prompt .= BOLD "[P]"; $prompt .= "Preview "; $prompt .= BOLD "[M]"; $prompt .= "More\n";
|
67
|
|
|
|
|
|
|
my $result = '';
|
68
|
|
|
|
|
|
|
$result = "Y" if $do_file || $do_all;
|
69
|
|
|
|
|
|
|
$result = "Next" if $skip_next;
|
70
|
|
|
|
|
|
|
$result = &Term::Prompt::prompt("x", "$prompt", "", "Next") unless $result;
|
71
|
|
|
|
|
|
|
$more = 1 if $result !~ /M/i && $skip_next != 1;
|
72
|
|
|
|
|
|
|
$re_do = 0 unless $skip_next;
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
if($result =~ /A/i){
|
75
|
|
|
|
|
|
|
my $v_message = "Are you sure you want to replace "; $v_message .= BOLD "ALL "; $v_message .= "occurances of $search in "; $v_message .= BOLD "THIS "; $v_message .= "file";
|
76
|
|
|
|
|
|
|
my $verify = &prompt("y", "$v_message", "", "n");
|
77
|
|
|
|
|
|
|
$do_file = 1 if $verify == 1;
|
78
|
|
|
|
|
|
|
$contents = $match->pre . $match->match . $match->post if $verify != 1;
|
79
|
|
|
|
|
|
|
}
|
80
|
|
|
|
|
|
|
elsif($result =~ /Z/i){
|
81
|
|
|
|
|
|
|
my $v_message = "Are you sure you want to replace "; $v_message .= BOLD "ALL "; $v_message .= "occurances of $search in "; $v_message .= BOLD "ALL "; $v_message .= "remaining files";
|
82
|
|
|
|
|
|
|
my $verify = &prompt("y", "$v_message", "", "No");
|
83
|
|
|
|
|
|
|
$do_all = 1 if $verify == 1;
|
84
|
|
|
|
|
|
|
$self->expression($expression)->do_all(1) if $verify == 1;
|
85
|
|
|
|
|
|
|
$contents = $match->pre . $match->match . $match->post if $verify != 1;
|
86
|
|
|
|
|
|
|
}
|
87
|
|
|
|
|
|
|
elsif($result =~ /P/i){
|
88
|
|
|
|
|
|
|
$re_do = 1;
|
89
|
|
|
|
|
|
|
my $body = $match->match;
|
90
|
|
|
|
|
|
|
eval ("\$body =~ s/$search/$replace/$options_replace");
|
91
|
|
|
|
|
|
|
$contents = $match->pre . $match->match . $match->post;
|
92
|
|
|
|
|
|
|
$new_match_cnt = $match_cnt+1;
|
93
|
|
|
|
|
|
|
$preview = $body;
|
94
|
|
|
|
|
|
|
}
|
95
|
|
|
|
|
|
|
elsif($result =~ /m/i){
|
96
|
|
|
|
|
|
|
$re_do = 1;
|
97
|
|
|
|
|
|
|
$more = $more*2;
|
98
|
|
|
|
|
|
|
$contents = $match->pre . $match->match . $match->post;
|
99
|
|
|
|
|
|
|
$new_match_cnt = $match_cnt+1;
|
100
|
|
|
|
|
|
|
$preview = $match->match;
|
101
|
|
|
|
|
|
|
}
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
$match_cnt++ unless $skip_next == 1 || $re_do == 1;
|
104
|
|
|
|
|
|
|
if($result =~ /y/i || ($result =~ /Z/i && $do_all) || ($result =~ /A/i && $do_file))
|
105
|
|
|
|
|
|
|
{
|
106
|
|
|
|
|
|
|
my $body = $match->match;
|
107
|
|
|
|
|
|
|
eval ("\$body =~ s/$search/$replace/$options_replace");
|
108
|
|
|
|
|
|
|
$replace_cnt++;
|
109
|
|
|
|
|
|
|
$contents = $match->pre . $body . $match->post;
|
110
|
|
|
|
|
|
|
$new_match_cnt = $match_cnt+1;
|
111
|
|
|
|
|
|
|
}
|
112
|
|
|
|
|
|
|
$new_match_cnt--;
|
113
|
|
|
|
|
|
|
$skip_next = 0;
|
114
|
|
|
|
|
|
|
}
|
115
|
|
|
|
|
|
|
$self->{_search}->expression($expression)->add_files_replaced($file) if $replace_cnt > 0;
|
116
|
|
|
|
|
|
|
$self->{_search}->expression($expression)->replacements($file, $replace_cnt);
|
117
|
|
|
|
|
|
|
$self->{_search}->expression($expression)->matches($file, $match_cnt);
|
118
|
|
|
|
|
|
|
}
|
119
|
|
|
|
|
|
|
close(FILE);
|
120
|
|
|
|
|
|
|
if($self->{_search}->do_replace)
|
121
|
|
|
|
|
|
|
{
|
122
|
|
|
|
|
|
|
open(FILE, ">$file") || die "Cannot read file $file\n";
|
123
|
|
|
|
|
|
|
print FILE $contents;
|
124
|
|
|
|
|
|
|
close(FILE);
|
125
|
|
|
|
|
|
|
}
|
126
|
|
|
|
|
|
|
}
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
1;
|
130
|
|
|
|
|
|
|
__END__
|