App-Greple
view release on metacpan or search on metacpan
RIPGREP-STUDY.md view on Meta::CPAN
宿¸¬ã§ãå¤§è¦æ¨¡ããªã¼æ¤ç´¢ã§ 5 å以ä¸ï¼ããªã¼ã大ããããããçãªã»ã©æ¡å¤§ï¼ã®æ¹åã確èªããã
## 2. ç¾ç¶åæ: greple ã®ã¢ã¼ããã¯ãã£
ãµãã¨ã¼ã¸ã§ã³ãã«ããã³ã¼ã調æ»çµæã®è¦ç¹ï¼file:line ã¯ç¾ master åºæºï¼ã
### 2.1 å¦çã¢ãã«
- **slurp æ¹å¼**: ãã¡ã¤ã«å
¨ä½ã 1 ã¹ã«ã©æååã¨ãã¦èªãï¼`script/greple:989-1023`ï¼ã
è¡åä½ã¹ããªã¼ãã³ã°ã§ã¯ãªãã
- **æååä½ãªãã»ãã**: å
¥å㯠`binmode STDIN, ":encoding($file_code)"`ï¼`script/greple:1226`ï¼ã§
èªã¿è¾¼ã¿æã«ãã³ã¼ãããã以å¾ã®æ¤ç´¢ã»é åæ¼ç®ã¯ãã¹ã¦ **Perl å
鍿ååä¸ã®æåãªãã»ãã**ã§è¡ãããã
`Regions.pm` ã® `match_regions`ï¼`lib/App/Greple/Regions.pm:97-117`ï¼ã¯
`pos() - length(${^MATCH})` ã§ `[from, to]` ãç®åºããã
- **é å代æ°**: `--inside/--outside/--include/--exclude`ããããã¯æ§ç¯ãmust/need/allow å¤å®ã¯
ãã¹ã¦ `[from, to]` ãã¢é
åã«å¯¾ããéåæ¼ç®ï¼`Regions.pm`, `Grep.pm`ï¼ã
- **Perl æ£è¦è¡¨ç¾ã¸ã®ä¾å**: `/p` + `${^MATCH}`ã`pos()`ã`\G` + `\X`ï¼`Pattern.pm:134`ï¼ã
å¯å¤é·å¾èªã¿ãã¦ã¼ã¶ã¼ãã¿ã¼ã³ã® Perl æ¹è¨å
¨è¬ã
- **ã¢ã¸ã¥ã¼ã«çµåç¹**: `--inside '&func'` çã®é¢æ°ãã¿ã¼ã³ã¯ `$_` ã«ãã¡ã¤ã«å
容ãå
¥ã£ãç¶æ
ã§
å¼ã°ãã`[from, to]` ã®é åãªã¹ããè¿ãï¼`Grep.pm:444-457`ï¼ã`--begin/--end/--postgrep/--print`
ãåæ§ã« Perl ã³ã¼ããæ¤ç´¢ãã¤ãã©ã¤ã³ã¸ç´æ¥ä»å
¥ããã
RIPGREP-STUDY.md view on Meta::CPAN
### 2.3 ããã«ããã¯ã®åè§£
ä¸ã®æ°å¤ãã greple ã® 1 å®è¡ãããã®ã³ã¹ãå
訳ãåè§£ã§ããã
| ãã§ã¼ãº | 宿¸¬å¤ | åè |
|---|---|---|
| èµ·åï¼ã¢ã¸ã¥ã¼ã«ãã¼ãã»ãªãã·ã§ã³å¦çï¼ | 44ms | Getopt::EX çãã©ã®æ¹å¼ã§ãæ®ãä¸é |
| ãã³ã¼ã + æ£è¦è¡¨ç¾ã¹ãã£ã³ | ç´ 80ms / 26MB | ããã 0 ä»¶æ 0.124s â èµ·å 44ms |
| **ãããå¾å¦ç**ï¼Match/Block æ§ç¯ã»é åæ¼ç®ã»ã«ã¦ã³ãï¼ | **ç´ 7µs / ããã** | 10 ä¸ãããã§ 0.7ã0.9sã**æ¯é
çã³ã¹ã** |
| ãã¡ã¤ã«ãã¨ã®ãªã¼ãã¼ããã | ç´ 0.25ms / ãã¡ã¤ã« | openã»binmodeã»slurp ç |
**嫿**: rg ã 26MB ã 10ms ã§èµ°æ»ããã®ã«å¯¾ã greple ã®ã¹ãã£ã³ãã§ã¼ãºã¯ 80ms â 差㯠8 åã ã
絶対å¤ã¯å°ãããããããå¤ãå ´åã® 0.8ã1.0s ã®å¤§åã¯ã¹ãã£ã³ã§ã¯ãªã
**ãããå¾ã® Perl å´å¦ç**ã§ãããããã¯åæãããåæãå¤é¨åãã¦ãæ¶ããªãã
ã¤ã¾ããrg ã«ä½ç½®ãåºããããæ¹å¼ã®çè«ä¸ã®æ¹åä¸éã¯ããã®ã¯ã¼ã¯ãã¼ãã§ã¯ 1 å²ç¨åº¦ãããªãã
## 3. ripgrep å´ã®äºå®ç¢ºèª
### 3.1 `--json` åºåï¼å®æ¸¬ç¢ºèªæ¸ã¿ï¼
lib/App/Greple/Grep.pm view on Meta::CPAN
for my $i (@chunk) {
my $pat = $patlist->[$i];
pipe(my $r, my $w) or last;
my $pid = fork;
if (not defined $pid) { # fall back to sequential
close $r; close $w;
last;
}
if ($pid == 0) {
close $r;
binmode $w;
my @p = match_regions(pattern => $pat->regex,
group => $self->{group_index},
index => $self->{group_index} >= 2);
my $data = pack 'J*',
map { ($_->[0], $_->[1], $_->[2] // NO_INDEX) } @p;
syswrite $w, $data if length $data;
close $w;
POSIX::_exit(0);
}
close $w;
binmode $r;
push @child, [ $i, $pid, $r ];
}
for (@child) {
my($i, $pid, $r) = @$_;
my $data = do { local $/; <$r> };
close $r;
waitpid $pid, 0;
next if $? != 0; # fall back to sequential
my @v = unpack 'J*', $data // '';
my @p;
lib/App/Greple/Grep.pm view on Meta::CPAN
my $threshold = $ENV{GREPLE_PARALLEL_THRESHOLD} // $default_threshold;
return if length() < $threshold;
pipe(my $r, my $w) or return;
my $pid = fork;
if (not defined $pid) { # fall back to sequential
close $r; close $w;
return;
}
if ($pid == 0) {
close $r;
binmode $w;
my $data = pack 'J*', match_borders $self->{border};
syswrite $w, $data if length $data;
close $w;
POSIX::_exit(0);
}
close $w;
binmode $r;
$self->{BORDERS_CHILD} = [ $pid, $r ];
warn "started borders child process\n" if $debug{m};
}
sub read_borders {
my $self = shift;
my($pid, $r) = @{delete $self->{BORDERS_CHILD}};
my $data = do { local $/; <$r> };
close $r;
waitpid $pid, 0;
script/greple view on Meta::CPAN
pairs @param;
};
my $file_code;
my $default_icode = 'utf8'; # default input encoding
my @default_icode_list = qw(euc-jp 7bit-jis);
my $output_code;
my $default_ocode = 'utf8'; # default output encoding
$output_code = $opt_ocode || $default_ocode;
binmode STDOUT, ":encoding($output_code)";
## show unused option characters
if ($opt_d{u}) {
my $s = join('','0'..'9',"\n",'a'..'z',"\n",'A'..'Z',"\n");
map { /\|([0-9a-zA-Z])\b/ && $s =~ s/$1/./ } @optargs;
die $s;
}
## show man pages
if ($opt_man or $opt_show or $opt_path) {
script/greple view on Meta::CPAN
open SAVESTDIN, '<&', \*STDIN or die "open: $!";
open SAVESTDOUT, '>&', \*STDOUT or die "open: $!";
open SAVESTDERR, '>&', \*STDERR or die "open: $!";
sub recover_stdin {
open STDIN, '<&', \*SAVESTDIN or die "open: $!";
}
sub recover_stderr {
open STDERR, '>&', \*SAVESTDERR or die "open: $!";
binmode STDERR, ':encoding(utf8)';
}
sub recover_stdout {
close STDOUT;
open STDOUT, '>&', \*SAVESTDOUT or die "open: $!";
}
sub close_stdout {
close SAVESTDOUT;
close STDOUT;
}
script/greple view on Meta::CPAN
if (not defined $content) {
if ($opt_error eq 'fatal') {
die "ABORT on $current_file\n";
}
if ($opt_error ne 'retry') {
warn "SKIP $current_file\n" if $opt_warn{skip};
next FILE;
}
# Try again
binmode STDIN, ':raw';
seek STDIN, 0, 0 or do {
warn "SKIP $current_file (not seekable)\n"
if $opt_warn{skip};
next FILE;
};
$content = $slurp->();
if (not defined $content) {
warn "SKIP* $current_file\n" if $opt_warn{skip};
next FILE;
}
warn "RETRY $current_file\n" if $opt_warn{retry};
$stat{read_retry}++;
binmode STDOUT, ':raw';
}
my $matched = grep_data(\$content);
$stat{match_effective} += $matched;
$stat{file_searched}++;
$stat{length} += length $content;
} continue {
close STDIN; # wait; # wait for 4.019 or earlier?
# recover STDIN for opening '-' and some weird command which needs
# STDIN opened (like unzip)
recover_stdin;
binmode STDOUT, ":encoding($output_code)";
}
}
sub usage {
pod2usage(-verbose => 0, -exitval => "NOEXIT");
my $quote = qr/[\\(){}\|\*?]/;
for my $bucket ($rcloader->buckets) {
my $module = $bucket->module;
print " $module options:\n";
script/greple view on Meta::CPAN
warn "$file: $!\n" unless -l $file;
next;
};
}
if (my @filters = $filter_d->get_filters($file)) {
push_input_filter({ &FILELABEL => $file }, @filters);
}
if ($file_code eq 'binary') {
binmode STDIN, ":raw";
} else {
binmode STDIN, ":encoding($file_code)";
}
return $file;
}
undef;
}
######################################################################
sub grep_data {
t/runner/Runner.pm view on Meta::CPAN
use IO::File;
sub run {
my $obj = shift;
use IO::File;
my $pid = (my $fh = new IO::File)->open('-|') // die "open: $@\n";
if ($pid == 0) {
if (my $stdin = $obj->{STDIN}) {
open STDIN, "<&=", $stdin->fileno or die "open: $!\n";
$stdin->fcntl(F_SETFD, 0) or die "fcntl F_SETFD: $!\n";
binmode STDIN, ':encoding(utf8)';
}
open STDERR, ">&STDOUT";
$obj->execute;
exit 1;
}
$obj->{STDIN} = undef;
binmode $fh, ':encoding(utf8)';
$obj->{stdout} = do { local $/; <$fh> };
my $child = wait;
$child != $pid and die "child = $child, pid = $pid";
$obj->{pid} = $pid;
$obj->{result} = $?;
$obj;
}
sub status {
my $obj = shift;
t/runner/Runner.pm view on Meta::CPAN
}
*result = \&stdout; # for backward compatibility
sub setstdin {
my $obj = shift;
my $data = shift;
my $stdin = $obj->{STDIN} //= do {
my $fh = new_tmpfile IO::File or die "new_tmpfile: $!\n";
$fh->fcntl(F_SETFD, 0) or die "fcntl F_SETFD: $!\n";
binmode $fh, ':encoding(utf8)';
$fh;
};
$stdin->seek(0, 0) or die "seek: $!\n";
$stdin->truncate(0) or die "truncate: $!\n";
$stdin->print($data);
$stdin->seek(0, 0) or die "seek: $!\n";
$obj;
}
##
( run in 0.623 second using v1.01-cache-2.11-cpan-9581c071862 )