This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
rdir is a terminal-based file manager inspired by macOS Finder, written in Go using the tcell library for terminal UI. It features a Redux-like architecture with centralized state management, fuzzy search capabilities, global search with gitignore support, built-in pager, and comprehensive test coverage.
- Language: Go 1.25.1
- Primary dependency: tcell/v2 (terminal UI)
- Architecture: Redux-like with pure reducers, centralized state, unidirectional data flow
- Code size: ~22,000 lines (excluding tests), ~19,000 lines of tests
- Test coverage: 518 tests across 55 test files, 100% pass rate
Use the PowerShell helper (cross-platform via pwsh) instead of invoking make directly:
./scripts/make.ps1 build # Build binary to build/rdir
./scripts/make.ps1 test # Run all tests
./scripts/make.ps1 test-coverage # Coverage report
./scripts/make.ps1 test-race # Race detector
./scripts/make.ps1 bench-fuzzy # Fuzzy matching benchmarks
./scripts/make.ps1 run # Build and run the application
./scripts/make.ps1 clean # Remove build artifacts
./scripts/make.ps1 fmt # go fmt ./...
./scripts/make.ps1 lint # golangci-lint run ./...
./scripts/make.ps1 help # Show available commandsgo build -o build/rdir ./cmd/rdir # Build binary
go test ./internal/... # Run all tests
go test ./internal/... -v -run Name # Run specific test
go test ./internal/... -cover # Coverage report
go test ./internal/... -race # Race detector
go test ./internal/search -bench . # Run benchmarksTerminal Events → InputHandler → Actions → StateReducer → AppState → Renderer → Screen
rdir/
├── cmd/rdir/ # Entry point (main.go)
├── internal/
│ ├── app/ # Application lifecycle, event loop
│ │ ├── application.go # App struct and initialization
│ │ ├── loop.go # Main event loop (696 lines)
│ │ ├── actions.go # App-level actions
│ │ └── platform.go # Platform-specific code
│ ├── fs/ # Filesystem utilities
│ │ ├── text.go # Text detection heuristics
│ │ ├── entry.go # FileEntry type
│ │ └── hidden_*.go # Platform-specific hidden file detection
│ ├── search/ # Search functionality
│ │ ├── fuzzy.go # Fuzzy matching engine (1,227 lines)
│ │ ├── fuzzy_dp_ascii32.go # SIMD-optimized matching
│ │ ├── global_search*.go # Recursive indexed search
│ │ ├── gitignore.go # Gitignore parsing and matching
│ │ └── ignore_provider.go # Ignore file handling
│ ├── state/ # State management
│ │ ├── state.go # AppState struct
│ │ ├── reducer.go # Main reducer (2,226 lines)
│ │ ├── actions.go # Action definitions
│ │ ├── state_*.go # State helpers (navigation, display, filter, etc.)
│ │ ├── preview_*.go # Preview generation and formatting
│ │ └── markdown_*.go # Markdown parsing and rendering
│ ├── ui/
│ │ ├── input/handler.go # Event → Action conversion
│ │ ├── render/ # UI rendering
│ │ │ ├── renderer.go # Main renderer (1,047 lines)
│ │ │ ├── preview.go # Preview panel rendering
│ │ │ └── layout.go # Layout calculations
│ │ └── pager/ # Built-in pager
│ │ ├── pager.go # Pager implementation (3,672 lines)
│ │ └── search.go # Pager search functionality
│ ├── shellsetup/ # Shell integration (--setup flag)
│ └── textutil/ # Text utilities (sanitize, tabs)
├── docs/ # Documentation
└── build/ # Compiled binaries
| Package | Purpose | Key Files |
|---|---|---|
app |
Event loop, application lifecycle | loop.go, application.go |
state |
State management, reducers | reducer.go, state.go |
search |
Fuzzy matching, global search | fuzzy.go, global_search*.go, gitignore.go |
ui/render |
Terminal rendering | renderer.go, preview.go |
ui/pager |
Built-in file viewer | pager.go, search.go |
ui/input |
Input handling | handler.go |
fs |
Filesystem operations | text.go, entry.go |
- ↑/↓: Navigate file list
- Enter: Enter directory
- →: Open file in built-in pager or enter directory
- ←/Backspace: Go to parent directory
- [/]: Navigate back/forward in history (with cursor restoration)
- Page Up/Down: Scroll viewport
- /: Enter fuzzy filter mode (filters current directory)
- Type characters: Case-insensitive pattern matching
- Results sorted by match quality
- Esc: Clear filter and exit filter mode
- Ctrl+P: Enter global search mode (searches recursively)
- Searches across entire directory tree
- Respects
.gitignorepatterns - Indexed for performance
- Esc: Exit global search
- →: Open selected file in pager (text files only)
- / in pager: Search within file
- n/N: Next/previous search result
- q: Exit pager
- Supports large files, UTF-16, syntax highlighting for markdown
Displays file content preview:
- Text: First 64 KB with syntax highlighting (Markdown, JSON)
- Binary: Hex dump with ASCII gutter (up to 1 KB)
- Directories: Lists first 10 items
- Metadata: Size, modified time, permissions
- q: Exit rdir and output current directory to stdout
rdir --setup: Print shell function for cd-on-exit (bash/zsh/fish/pwsh)
Tests are organized by feature area:
Reducer tests (internal/state/):
reducer_navigation_test.go- Navigation actionsreducer_filter_test.go- Local fuzzy filterreducer_global_search_test.go- Global search functionalityreducer_hidden_files_test.go- Hidden file handlingreducer_filter_hidden_test.go- Filter + hidden interactionsreducer_state_test.go- State helpersreducer_history_simple_test.go- History navigationreducer_io_test.go- Filesystem integrationreducer_symlink_test.go- Symlink handlingreducer_preview_test.go- Preview generationreducer_refresh_test.go- Directory refresh
Search tests (internal/search/):
fuzzy_test.go- Fuzzy matching algorithmfuzzy_benchmark_test.go- Performance benchmarksglobal_search_*_test.go- Global search testsglobal_search_ignore_test.go- Gitignore integration
UI tests (internal/ui/):
input/handler_test.go- Input handlingrender/renderer_test.go- Renderingpager/pager_test.go- Pager functionality
Integration tests:
fuzzy_integration_test.go- End-to-end filter teststest_esc_logic_test.go- Esc key behaviortest_filter_cursor_restoration_test.go- Cursor restoration
# All tests
go test ./internal/...
# Specific package
go test ./internal/state -v
go test ./internal/search -v
go test ./internal/ui/pager -v
# Pattern matching
go test ./internal/... -v -run Navigate
go test ./internal/... -v -run Filter
go test ./internal/... -v -run GlobalSearch
go test ./internal/... -v -run Pager
# Benchmarks
go test ./internal/search -bench . -benchmemAll mutable data lives in AppState struct. UI reads state, never modifies directly.
Reduce(state, action) functions have no side effects. Same input → same output.
selectionHistory map[string]int tracks cursor position per directory for seamless navigation.
internal/search/gitignore.go implements full gitignore pattern matching for global search.
Extensible formatter system in internal/state/preview_formatter_*.go:
- Text, Markdown, JSON, Binary formats
- Markdown AST parsing and styled rendering
- Define in
internal/state/actions.goorinternal/app/actions.go - Handle in
reducer.goorloop.go - Add key binding in
internal/ui/input/handler.go - Write tests
- Create
internal/state/preview_formatter_<format>.go - Register in
preview_formatter.go - Add tests in
preview_formatter_<format>_test.go
- Core logic in
internal/search/global_search*.go - State integration in
internal/state/state_global_search.go - Tests in
internal/search/global_search_*_test.go
Fuzzy matching is highly optimized:
- SIMD acceleration on ARM64 (
fuzzy_simd_arm64.go) - ASCII32 DP optimization (
fuzzy_dp_ascii32.go) - Benchmarks available in
fuzzy_benchmark_test.go
All documentation is in docs/:
- IMPLEMENTATION.md - Architecture and feature details
- TEST_GUIDE.md - Testing philosophy
- FUZZY_SEARCH.md - Fuzzy algorithm explanation
- OPTIMIZATIONS.md - Performance optimization notes
- ASCII_DP32_REPORT.md - SIMD optimization report
- FUZZY_OPT_PROGRESS.md - Optimization progress
- SCORING_SCENARIOS.md - Scoring test scenarios
- All state logic testable without UI
- Use
t.Logf()in tests to inspect state Reduce()is pure - deterministic behavior- Use
-raceflag for concurrency issues - Pager has extensive test coverage for edge cases