NAME

Langertha::Raider::SearchTools - Internal search tools of raider: glob (files by name) and grep (files by content)

VERSION

version 0.504

SYNOPSIS

my $search = Langertha::Raider::SearchTools->new( root => '/some/project' );
my $server = $search->server;     # MCP::Server with the tools glob and grep

say $search->glob({ pattern => 'lib/**/*.pm' });
say $search->grep({ pattern => 'sub \w+', output_mode => 'count' });

DESCRIPTION

Internal module. Its interface may change without notice.

The two search tools of raider, named and shaped after Claude Code's Glob and Grep (Langertha::Raider::ToolNames), confined to one directory the way Langertha::Raider::FileTools is: every path argument is resolved with realpath and must stay inside "root" (unless "confine" is off). Paths in the results are relative to "root", so they go straight into read_file.

Both tools see the same files. They walk the tree without following symbolic links, skip the version control directories (.git, .hg, .svn), look into hidden files and do not apply .gitignore: what is searched does not depend on which engine runs the search. Narrow a search with path and glob instead. Files over 10 MB and binary files (a NUL byte near the start) are skipped.

glob matches a pattern against the path below the search directory (* and ? stay within one path segment, ** crosses segments, [abc] and {a,b} as in a shell) and lists the matches, newest modification time first.

grep searches file contents with a regular expression, with the modes and options of Claude Code's tool. It runs ripgrep when there is one ("rg") and plain Perl otherwise; the output is the same. A type together with a glob is always searched by the Perl code, as ripgrep cannot take both filters at once. The pattern is a Perl regular expression in the Perl code and a Rust one in ripgrep -- stay with the common syntax (no look-around, no back-references).

root

Required. The directory the tools are confined to and the relative paths of the results are taken from. It must exist.

rg

Path of the ripgrep executable grep uses. Default: rg off PATH. Pass 0 to always use the Perl code (a test does, to be independent of the host), or a path to name the executable.

default_limit

How many results a call returns unless head_limit says otherwise (glob: files; grep: lines of content, files or counts). Default 250.

extra_roots

More directories a path may name besides "root" (the additional directories of ADR 0021). Results inside them are shown as absolute paths. One that does not exist is left out. A CodeRef returning the list (or an ArrayRef) is called on every call, so the roots can change while the tools are mounted (/reload).

confine

True by default: a path must stay inside "root" and the "extra_roots". False (or a CodeRef answering false, asked on every call) lets a search start anywhere -- the application does so in the Claude layout, where the permission gate asks before a search outside the root and the additional directories (ADR 0023). Results outside "root" are absolute paths; the walk still follows no symbolic link.

hider

Called without arguments at the start of every call. Returns undef, or code that is called with the real absolute path of each file a call would list or search and returns true for a file to leave out -- the application hides the files a permission rule refuses or asks about reading (ADR 0021). The result then ends with (N paths hidden by permission rules). While a hider is in force grep runs the Perl code, which applies it file by file.

server

The MCP::Server with the tools glob and grep, built once.

engine

my $engine = $search->engine;     # 'ripgrep' or 'perl'

Which one "grep" runs for an ordinary search.

types

The names grep accepts as type, sorted.

glob

my $text = $search->glob({ pattern => '**/*.pm', path => 'lib' });

The files below path (default: "root") whose path below path matches pattern, one per line, newest modification time first, as paths relative to "root". At most "default_limit" are listed; the text says so when there are more. Croaks on a missing pattern, a pattern that leaves the search directory, and a path that does not exist, is not a directory or leaves the root (and the "extra_roots"). Files the "hider" hides are not listed; the text then ends with how many.

grep

my $text = $search->grep({
  pattern     => 'TODO',
  path        => 'lib',              # directory or file; default: the root
  glob        => '*.pm',             # only files matching it (any depth)
  type        => 'perl',             # only files of this type
  output_mode => 'content',          # files_with_matches (default), content, count
  '-i'        => 1,                  # ignore case
  '-n'        => 1,                  # line numbers in content mode (default on)
  '-B' => 1, '-A' => 2, '-C' => 3,   # context lines; context is an alias of -C
  multiline   => 1,                  # the pattern may span lines, . matches a newline
  head_limit  => 50, offset => 0,    # slice of the output
});

The files of path whose content matches pattern. files_with_matches lists the files, newest first; count gives path:N lines, the number of matching lines; content gives the matching lines as path:line:text and context lines as path-line-text, groups of lines apart from each other separated by --. head_limit (default "default_limit", 0 for no limit) and offset cut the lines of the output, and the text says when it was cut. Lines over 2000 characters are shortened. Croaks on an invalid option or pattern and a path that does not exist or leaves the root; a search without a match returns No matches found. Files the "hider" hides are not searched; the text then ends with how many.

SEE ALSO

SUPPORT

Issues

Please report bugs and feature requests at https://github.com/Getty/langertha-raider/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

https://raudssus.de/