Skip to content

difof/umm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 

Repository files navigation

umm - Ultimate Multi-file Matcher

Interactive search tool for both file content and Git objects, powered by ripgrep, fzf, and optional preview tools like bat/delta.

Compatible with: bash, zsh

What it does

  • Live search - Results update as you type
  • Path + content matching - Searches filenames/paths and file contents by default
  • Preview - See file contents with syntax highlighting
  • Jump to line - Opens your editor at the exact match
  • Multi-select - Open multiple files at once
  • Git mode - Search commits, branches, tags, reflog, and stashes in one view
  • Diff pager fallback - Uses delta, then bat, then cat
# Old way
$ grep -r "searchTerm" .
$ cd path/to/file
$ vim file.js
# ... search again ...

# With umm
$ umm
# type, see results, hit enter
# opens at exact line

Installation

Required:

  • ripgrep (rg) - Fast file search
  • fzf - Interactive fuzzy finder
  • A text editor (set via $EDITOR, defaults to nvim)

Required for Git mode:

  • git - Repository search and previews

Recommended:

  • delta - Recommended for the best Git diff preview (delta -> bat -> cat)
  • bat - Syntax highlighting in file previews (falls back to sed + line numbers if unavailable)
# macOS
brew install ripgrep fzf bat nvim

# Ubuntu/Debian
apt install ripgrep fzf bat neovim

# Arch
pacman -S ripgrep fzf bat neovim

Install:

# Clone
git clone https://github.com/difof/umm.git

# For zsh (includes tab completions)
echo 'source /path/to/umm/umm.sh' >> ~/.zshrc
source ~/.zshrc

# For bash
echo 'source /path/to/umm/umm.sh' >> ~/.bashrc
source ~/.bashrc

Usage

umm                                # Interactive search in current directory
umm ~/projects                     # Search in specific directory
umm -p "function"                  # Start with pattern
umm -p "TODO" ~/projects           # Search with pattern in directory
umm --no-filename -p "TODO"        # Search content only (disable path matching)
umm -e "*.log" -e "test"           # Exclude patterns (gitignore-style globs)
umm -a                             # Search all files (ignore .gitignore, include hidden)
umm -p "error" -n                  # Open first match (no UI)
umm -d 3                           # Limit search depth

umm -g                             # Search git objects (commits/branches/tags/reflog/stashes)
umm -g -p "fix"                    # Start git mode with pattern
umm --git ~/projects/repo          # Git search in specific repository

Default Behavior

umm uses ripgrep's smart defaults:

  • Searches content and paths - Query matches file contents and filenames/paths by default

  • Disable path matching with --no-filename - Restrict search to content (or git objects) only

  • Respects .gitignore - Automatically excludes files/directories listed in .gitignore

  • Excludes .git directory - Never searches inside .git by default

  • Excludes hidden files - Files/directories starting with . are skipped (except .gitignore itself)

  • Skips binary files - Binary files are automatically detected and excluded

To search everything (override all defaults), use the --all flag.

Options

  • -p, --pattern REGEXP - Initial search pattern
  • -e, --exclude PATTERN - Exclude file/directory pattern (can be used multiple times)
  • -a, --all - Search all files including .gitignore'd and hidden files
  • --no-filename - Disable filename/path matching
  • -g, --git - Search Git objects in a unified list
  • -n, --noui - Non-interactive mode, open first match directly
  • -d, --max-depth N - Maximum search depth
  • -h, --help - Show help
  • -v, --version - Show version

Git Mode

When -g/--git is enabled, umm shows a single searchable list with Git type-prefixed entries:

  • commit: recent commit history (up to 1000 entries)
  • branch: local and remote branches
  • tag: tags with subjects
  • reflog: recent reflog entries (up to 100)
  • stash: stash entries
  • file: tracked repository files (enabled by default; disable with --no-filename)

Preview is context-aware by type and uses this diff rendering fallback chain:

  • delta (recommended)
  • bat (--style=numbers,changes --language=diff)
  • cat (plain output fallback)

Selection output strips the type prefix, so results are easy to pipe:

umm -g -p "commit:" | cut -d' ' -f1 | xargs git show
umm -g -p "branch:" | sed 's/^[* ]*//' | xargs git checkout

Keybindings

Common (file mode and Git mode):

  • Ctrl+G / Ctrl+B - Jump to bottom/top of result list
  • Alt+G / Alt+B - Jump to top/bottom of preview
  • Shift+Up / Shift+Down - Scroll preview one line up/down
  • Alt+U / Alt+D - Scroll preview half-page up/down
  • Ctrl+U / Ctrl+D - Scroll result list half-page up/down

Mode-specific:

  • File mode: Tab / Shift+Tab toggle multi-select and move
  • Git mode: Ctrl+/ toggle preview pane

Exclude Patterns

Exclude files or directories using gitignore-style glob patterns:

umm -e "*.log"                     # Exclude all .log files
umm -e "test" -e "vendor"          # Exclude multiple patterns
umm -e "**/node_modules/**"        # Exclude nested directories
umm -e "test\ dir"                 # Escape spaces in patterns

Search All Files

By default, umm respects .gitignore and excludes hidden files (via ripgrep's defaults). Use --all to override:

umm -a                             # Search everything (ignore .gitignore, include hidden)
umm -a -e ".git"                   # Search all but exclude .git directory
umm -a -p "SECRET" ~/project       # Find sensitive data in all files

Editor Support

umm respects the $EDITOR environment variable and automatically uses the correct syntax for different editors:

# Use your preferred editor
EDITOR=vim umm              # Opens with: vim +linenum file
EDITOR=code umm             # Opens with: code --goto file:linenum
EDITOR=nano umm             # Opens with: nano +linenum file
EDITOR=micro umm            # Opens with: micro +linenum file

# Set default in your shell config
export EDITOR=nvim          # Add to ~/.bashrc or ~/.zshrc

Supported editors: vim, vi, nvim, nano, micro, emacs, code (VSCode), cursor, subl (Sublime Text), and more.

How it works

Live reload mechanism

The key to instant updates is fzf's --disabled mode:

fzf --disabled \
  --bind "change:reload:sleep 0.05; rg {q} $root"
  • --disabled - fzf delegates ALL search to ripgrep (no local filtering)
  • change:reload: - Every keystroke triggers new ripgrep search
  • sleep 0.05 - Debounce to prevent system overload
  • {q} - Current query from fzf input

Without --disabled, fzf would only filter pre-loaded results. This enables true live search.

Preview system

bat --color=always \
  --highlight-line {2} \
  --line-range {2}::15 \
  {1}
  • {1} = file path (from --delimiter=:)
  • {2} = line number
  • --line-range {2}::15 = show line with 15 lines of context

Preview updates as you navigate because fzf re-runs the command with new values.

Performance

  1. Debouncing - Wait 50ms between keystrokes
  2. Binary skipping - ripgrep skips binary files automatically
  3. Gitignore respect - ripgrep respects .gitignore by default (use --all to override)
  4. Hidden files excluded - Hidden files/directories excluded by default (use --all to include)
  5. Depth limiting - Optional --max-depth flag
  6. Smart case - Case-insensitive unless uppercase in query

Troubleshooting

Command not found:

# Reload your shell config
source ~/.zshrc   # for zsh
source ~/.bashrc  # for bash

No syntax highlighting:

brew install bat

Slow on large projects:

umm -d 3  # Limit depth

Contributing

  1. Fork and create branch: git checkout -b feat/name
  2. Make changes: source umm.sh && umm --help
  3. Commit: git commit -m "feat: description" using conventional commits
  4. Push and create PR

Commit prefixes: feat: fix: docs: refactor: perf:

Acknowledgments

About

Ultimate Multi-file Matcher - Best of all find tools

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages