treegrep is a regex pattern matcher that displays results in a tree structure with an interface to jump to matched text.
examples, editor integrations, and help.
crates.io | GitHub | AUR | NetBSD
- cargo:
cargo install treegrep - releases: Download from releases
- manual:
git clone https://github.com/4imothy/treegrep cd treegrep cargo build --release
neovim
- sample installation using lazy.nvim
return {
'4imothy/treegrep',
build = function()
require('treegrep').build_tgrep()
end,
config = function()
require('treegrep').setup({
selection_file = '/tmp/tgrep-select',
repeat_file = '/tmp/tgrep-repeat',
})
vim.keymap.set('n', '<leader>tt', function() require('treegrep').tgrep_with('--menu') end)
vim.keymap.set('n', '<leader>tr', function() require('treegrep').tgrep_with('--repeat --select') end)
vim.keymap.set('n', '<leader>tm', function() require('treegrep').tgrep_with('--menu --repeat') end)
vim.keymap.set('n', '<leader>tf', function() require('treegrep').tgrep_with('--files --select') end)
end,
}helix
- sample keybind to run treegrep and open selection
C-t = [
':sh rm -f /tmp/tgrep-select',
':insert-output tgrep --menu --selection-file=/tmp/tgrep-select --repeat-file=/tmp/tgrep-repeat > /dev/tty',
':open %sh{ f=$(sed -n 1p /tmp/tgrep-select); l=$(sed -n 2p /tmp/tgrep-select); [ -n "$l" ] && echo "$f:$l" || echo "$f"; }',
':redraw',
':set mouse false',
':set mouse true',
]vim
- sample installation using vim-plug
Plug '4imothy/treegrep', {'do': {-> TgrepBuild()}}
let g:tgrep_selection_file = '/tmp/tgrep-select'
let g:tgrep_repeat_file = '/tmp/tgrep-repeat'
nnoremap <leader>tt :call TgrepWith('--menu')<cr>
nnoremap <leader>tr :call TgrepWith('--repeat --select')<cr>
nnoremap <leader>tm :call TgrepWith('--menu --repeat')<cr>
nnoremap <leader>tf :call TgrepWith('--files --select')<cr>tgrep --regexp \bstruct\s+\w+ --regexp \bimpl\s+\w+ --path src --line-number --context=1 --count
src: 10
βββterm.rs: 1
β βββ-1:
β βββ15: pub struct Term<'a> {
β β°ββ+1: pub height: u16,
βββmatcher.rs: 3
β βββ-1:
β βββ20: struct Matcher {
β βββ+1: combined: RegexMatcher,
β βββ-1:
β βββ25: impl Matcher {
β βββ+1: fn new(patterns: &[String]) -> Result<Self, Message> {
β βββ-1:
β βββ44: struct MatchSink<'a> {
β β°ββ+1: lines: Vec<Line>,
βββargs_menu.rs: 1
β βββ-1:
β βββ21: pub struct ArgsMenu<'a, 'b> {
β β°ββ+1: term: &'a mut term::Term<'b>,
βββerrors.rs: 4
β βββ-1:
β βββ14: pub struct Message {
β βββ+1: pub mes: String,
β βββ-1: }
β βββ17: impl Error for Message {}
β βββ+1:
β βββ-1:
β βββ34: impl fmt::Debug for Message {
β βββ+1: fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
β βββ-1:
β βββ40: impl fmt::Display for Message {
β β°ββ+1: fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
βββstyle.rs: 1
β βββ-1:
β βββ31: pub struct DisplayRepeater<T>(T, usize);
β β°ββ+1: impl<T: Display> Display for DisplayRepeater<T> {
βββmatch_system.rs: 8
β βββ-1:
β βββ23: pub struct Directory {
β βββ+1: pub path: PathBuf,
β βββ-1:
β βββ30: impl Directory {
β βββ+1: pub fn new(path: &Path) -> Result<Self, Message> {
β βββ-1:
β βββ41: pub struct File {
β βββ+1: pub path: PathBuf,
β βββ-1:
β βββ47: impl File {
β βββ+1: pub fn from_pathbuf(path: PathBuf) -> Result<Self, Message> {
β βββ-1: #[cfg_attr(test, derive(PartialEq, Debug))]
β βββ72: pub struct Match {
β βββ+1: pub regexp_id: usize,
β βββ-1:
β βββ78: impl Match {
β βββ+1: pub fn new(regexp_id: usize, start: usize, end: usize) -> Self {
β βββ-1:
β βββ103: pub struct Line {
β βββ+1: pub content: String,
β βββ-1:
β βββ110: impl Line {
β β°ββ+1: pub fn new(content: String, mut matches: Vec<Match>, line_num: usize) -> Self {
βββselect_menu.rs: 5
β βββ-1:
β βββ81: impl OpenStrategy {
β βββ+1: fn from(editor: &str) -> Self {
β βββ-1:
β βββ93: pub struct SelectMenu<'a, 'b> {
β βββ+1: jump: JumpLocation,
β βββ-1:
β βββ110: struct Window {
β βββ+1: first: isize,
β βββ-1:
β βββ115: impl Window {
β βββ+1: pub fn shift_up(&mut self) {
β βββ-1:
β βββ136: impl JumpLocation {
β β°ββ+1: fn default() -> Self {
βββconfig.rs: 6
β βββ-1:
β βββ15: pub struct KeyBindings {
β βββ+1: pub down: Vec<KeyCode>,
β βββ-1:
β βββ35: pub struct Characters {
β βββ+1: pub bl: char,
β βββ-1:
β βββ51: pub struct Colors {
β βββ+1: pub file: Color,
β βββ-1:
β βββ62: impl args::Color {
β βββ+1: fn get(&self) -> Color {
β βββ-1:
β βββ80: pub struct Config {
β βββ+1: pub path: PathBuf,
β βββ-1:
β βββ186: impl Config {
β β°ββ+1: pub fn get_styling(matches: &ArgMatches) -> (bool, bool) {
βββargs.rs: 7
β βββ-1:
β βββ19: pub struct ArgInfo {
β βββ+1: pub id: &'static str,
β βββ-1:
β βββ25: impl ArgInfo {
β βββ+1: const fn new(id: &'static str, h: &'static str, s: Option<char>) -> Self {
β βββ-1:
β βββ40: impl ValueEnum for OpenStrategy {
β βββ+1: fn value_variants<'a>() -> &'a [Self] {
β βββ-1: #[derive(Clone)]
β βββ85: struct ColorParser;
β βββ+1:
β βββ87: impl clap::builder::TypedValueParser for ColorParser {
β βββ+1: type Value = Color;
β βββ-1: #[derive(Clone)]
β βββ173: struct KeyCodeParser;
β βββ+1:
β βββ175: impl clap::builder::TypedValueParser for KeyCodeParser {
β β°ββ+1: type Value = KeyCode;
β°ββwriter.rs: 9
βββ-1:
βββ26: pub struct OpenInfo<'a> {
βββ+1: pub path: &'a Path,
βββ-1:
βββ37: struct PathDisplay<'a> {
βββ+1: prefix: Option<Vec<PrefixComponent>>,
βββ-1:
βββ150: struct LineDisplay<'a> {
βββ+1: prefix: Vec<PrefixComponent>,
βββ-1:
βββ279: struct LongBranchDisplay<'a> {
βββ+1: prefix: Vec<PrefixComponent>,
βββ-1:
βββ320: struct OverviewDisplay {
βββ+1: dirs: usize,
βββ-1:
βββ328: impl Entry for OverviewDisplay {
βββ+1: fn open_info(&self) -> Result<OpenInfo<'_>, Message> {
βββ-1:
βββ340: impl Display for OverviewDisplay {
βββ+1: fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
βββ-1:
βββ388: impl Directory {
βββ+1: fn to_lines<'a>(
βββ-1:
βββ473: impl File {
β°ββ+1: fn to_lines<'a>(
tgrep Print src/select_menu.rs --trim --line-number --char-vertical=| --char-horizontal=- --char-top-left=+ --char-top-right=+ --char-bottom-left=+ --char-bottom-right=+ --char-tee=+ --char-ellipsis=|
select_menu.rs
+--15: style::{Print, SetBackgroundColor},
+--214: queue!(self.term, Print(&self.lines[orig]))?;
+--216: queue!(self.term, Print(config().chars.ellipsis))?;
+--711: Print(style::style_with(config().chars.selected_indicator.as_str(), c)),
+--715: queue!(self.term, Print(config().chars.selected_indicator.as_str()),)?;
+--725: Print(config().chars.selected_indicator_clear.as_str()),
+--741: Print(format!(
+--753: Print(format!(
+--766: Print(format!(
tgrep --files --hidden --glob=!.git
treegrep
βββsrc
β βββmatch_system.rs
β βββargs.rs
β βββwriter.rs
β βββmain.rs
β βββerrors.rs
β βββselect_menu.rs
β βββstyle.rs
β βββlog.rs
β βββconfig.rs
β βββmatcher.rs
β βββterm.rs
β β°ββargs_menu.rs
βββdoc
β βββtreegrep.vim9.txt
β β°ββtreegrep.nvim.txt
βββ.github
β β°ββworkflows
β βββupdate_readme
β βββtest.yml
β βββupdate_readme.yml
β β°ββcr.yml
βββbenchmarks
β βββrunner
β β°ββtimes
βββlua
β β°ββtreegrep.lua
βββplugin
β β°ββtreegrep.vim
βββtests
β βββpool
β β β°ββalice_adventures_in_wonderland_by_lewis_carroll.txt
β βββtargets
β β βββfiles_1
β β βββwide_2
β β βββlinks_4
β β βββlinks_3
β β βββlinks_2
β β βββfiles_long_branch_expr_2
β β βββglob_exclusion
β β βββno_matches
β β βββfiles_long_branch_1
β β βββcontext_b1
β β βββcontext_a1
β β βββfiles_long_branch_expr_count_2
β β βββoverview_dir
β β βββwide_1
β β βββfiles_2
β β βββline_number
β β βββdeep
β β βββcontext_c1
β β βββlinks_1
β β βββcount
β β βββcolon
β β βββoverview_file
β β βββfiles_long_branch_expr_1
β β βββoverlapping
β β βββfile
β β βββmax_depth
β β βββfiles_long_branch_2
β β βββglob_inclusion
β β βββfiles_long_branch_expr_count_1
β β β°ββfiles_with_expr
β βββutils.rs
β βββtests.rs
β β°ββfile_system.rs
βββ.gitignore
βββREADME.md
βββCargo.lock
βββrustfmt.toml
βββCargo.toml
β°ββLICENSE
tgrep --files --long-branch --hidden --glob=!.git
treegrep
βββsrc
β βββmatch_system.rs, args.rs, writer.rs, main.rs, errors.rs
β βββselect_menu.rs, style.rs, log.rs, config.rs, matcher.rs
β β°ββterm.rs, args_menu.rs
βββdoc
β β°ββtreegrep.vim9.txt, treegrep.nvim.txt
βββ.github
β β°ββworkflows
β β°ββupdate_readme, test.yml, update_readme.yml, cr.yml
βββbenchmarks
β β°ββrunner, times
βββlua
β β°ββtreegrep.lua
βββplugin
β β°ββtreegrep.vim
βββtests
β βββpool
β β β°ββalice_adventures_in_wonderland_by_lewis_carroll.txt
β βββtargets
β β βββmax_depth, files_long_branch_2, glob_inclusion, files_long_branch_expr_count_1, overview_file
β β βββfiles_with_expr, files_long_branch_expr_1, overlapping, file, links_1
β β βββcolon, count, context_c1, deep, line_number
β β βββfiles_2, wide_1, overview_dir, files_long_branch_expr_count_2, files_long_branch_1
β β βββcontext_b1, context_a1, glob_exclusion, no_matches, files_long_branch_expr_2
β β β°ββfiles_1, wide_2, links_4, links_3, links_2
β β°ββutils.rs, tests.rs, file_system.rs
βββ.gitignore, README.md, Cargo.lock, LICENSE, rustfmt.toml
β°ββCargo.toml
treegrep 1.3.0
by Timothy Cronin
home page: https://github.com/4imothy/treegrep
regex pattern matcher that displays results in a tree structure with an interface to jump to matched text
tgrep [OPTIONS] [positional regexp] [positional target]
arguments:
[positional regexp]
a regex expression to search for
[positional target]
the path to search, if not provided, search the current directory
options:
-e, --regexp <>
a regex expression to search for
-p, --path <>
the path to search, if not provided, search the current directory
-s, --select
results are shown in a selection interface for opening
-f, --files
if an expression is given, hide matched content, otherwise, show the files that would be searched
-., --hidden
search hidden files
-n, --line-number
show line number of match
-c, --count
display number of files matched in directory and number of lines matched in a file
-g, --glob <>
rules match .gitignore globs, but ! has inverted meaning, overrides other ignore logic
-l, --links
search linked paths
-o, --overview
conclude results with an overview
-d, --max-depth <>
the max depth to search
-C, --context <>
number of lines to show before and after each match
-B, --before-context <>
number of lines to show before each match
-A, --after-context <>
number of lines to show after each match
--max-length <>
set the max length for a matched line
--menu
provide arguments and select results through an interface
--no-ignore
don't use ignore files
--trim
trim whitespace at the beginning of lines
--threads <>
set the appropriate number of threads to use
--long-branch
multiple files from the same directory are shown on the same branch
--editor <>
command used to open selections
--open-like <>
command line syntax for opening a file at a line
[possible values: vi, hx, code, jed, default]
--completions <>
generate completions for given shell
[possible values: bash, elvish, fish, powershell, zsh]
--selection-file <>
file to write selection to (first line: file path, second line: line number if applicable)
--repeat-file <>
file where arguments are saved
--repeat
repeats the last saved search
--no-color
don't use colors
--no-bold
don't bold anything
--file-color <>
black, white, red, green, yellow, blue, magenta, cyan, grey, rgb(_._._), ansi(_)
--dir-color <>
black, white, red, green, yellow, blue, magenta, cyan, grey, rgb(_._._), ansi(_)
--text-color <>
black, white, red, green, yellow, blue, magenta, cyan, grey, rgb(_._._), ansi(_)
--line-number-color <>
black, white, red, green, yellow, blue, magenta, cyan, grey, rgb(_._._), ansi(_)
--branch-color <>
black, white, red, green, yellow, blue, magenta, cyan, grey, rgb(_._._), ansi(_)
--match-colors <>
black, white, red, green, yellow, blue, magenta, cyan, grey, rgb(_._._), ansi(_)
--selected-indicator-color <>
black, white, red, green, yellow, blue, magenta, cyan, grey, rgb(_._._), ansi(_)
--selected-bg-color <>
black, white, red, green, yellow, blue, magenta, cyan, grey, rgb(_._._), ansi(_)
--search-highlight-color <>
black, white, red, green, yellow, blue, magenta, cyan, grey, rgb(_._._), ansi(_)
--prefix-len <>
number of characters to show before a match
[default: 3]
--long-branch-each <>
number of files to print on each branch
[default: 5]
--char-vertical <>
vertical branch character
--char-horizontal <>
horizontal branch character
--char-top-left <>
top-left corner character
--char-top-right <>
top-right corner character
--char-bottom-left <>
bottom-left corner character
--char-bottom-right <>
bottom-right corner character
--char-tee <>
tee branch character
--char-ellipsis <>
folding indicator character
--selected-indicator <>
selected indicator characters
[default: "ββ± "]
--key-down <>
move down
[default: down j n]
--key-up <>
move up
[default: up k p]
--key-big-down <>
big jump down
[default: J N]
--key-big-up <>
big jump up
[default: K P]
--key-down-path <>
next path
[default: } ]]
--key-up-path <>
previous path
[default: { []
--key-down-same-depth <>
next path at same depth
[default: ) d]
--key-up-same-depth <>
previous path at same depth
[default: ( u]
--key-top <>
go to top
[default: home g <]
--key-bottom <>
go to bottom
[default: end G >]
--key-page-down <>
page down
[default: pagedown f]
--key-page-up <>
page up
[default: pageup b]
--key-center <>
center cursor
[default: z l]
--key-help <>
show help
[default: h]
--key-quit <>
quit
[default: q]
--key-open <>
open selection
[default: enter]
--key-fold <>
fold/unfold path
[default: tab]
--key-search <>
search within results
[default: / s]
-h, --help
print help
-V, --version
print version
arguments are prefixed with the contents of the TREEGREP_DEFAULT_OPTS environment variable