Skip to content

SakolB/bcd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bcd - Better CD

A fuzzy directory navigator for your terminal. Search and jump to any directory with an interactive TUI.

Features

  • BFS Directory Discovery: Finds directories closest to your current location first
  • FZF v2 Fuzzy Matching: Intelligent scoring algorithm for accurate search results
  • Real-time Updates: Results appear as directories are discovered
  • Smooth Performance: Async architecture with batching and heap-based ranking
  • Interactive TUI: Full-screen terminal interface with real-time fuzzy search
  • Shell Integration: Seamlessly cd into selected directories

Built With

  • Bubble Tea - Terminal UI framework for building interactive applications
  • Bubbles - TUI components for Bubble Tea (text input, viewports, etc.)
  • Lipgloss - Style definitions for terminal rendering
  • FZF v2 Algorithm - Fuzzy matching scoring algorithm

Installation

Requirements

  • Go 1.21 or later (for building from source)
  • Unix-like system (Linux, macOS)

Dependencies like Bubble Tea are automatically downloaded during build - you don't need to install them manually.

Quick Install

./install.sh

This will:

  1. Check for Go installation
  2. Build the bcd-bin binary (automatically downloads dependencies)
  3. Install it to ~/.local/bin/ (or use --system flag for /usr/local/bin)
  4. Add ~/.local/bin to your PATH if needed
  5. Add shell integration function bcd() to your shell config
  6. Prompt you to reload your shell

Note: The binary is named bcd-bin, but you use the shell function bcd to invoke it.

After installation, run:

source ~/.bashrc  # or source ~/.zshrc for Zsh

System-wide Installation

./install.sh --system

Installs to /usr/local/bin (requires sudo).

Uninstallation

./uninstall.sh

This will:

  1. Remove the bcd-bin binary from ~/.local/bin or /usr/local/bin
  2. Remove shell integration from your shell config files
  3. Create backup files of all modified configs (.bcd_backup)

Use --force to skip the confirmation prompt:

./uninstall.sh --force

Manual Installation

  1. Build the binary:
go build -o bcd-bin ./cmd/bcd
  1. Move it somewhere in your PATH:
mkdir -p ~/.local/bin
mv bcd-bin ~/.local/bin/
  1. Add ~/.local/bin to your PATH (if not already):
export PATH="$HOME/.local/bin:$PATH"
  1. Add the shell function to your shell config:

Bash (~/.bashrc):

# bcd shell integration
bcd() {
  local selected_path

  selected_path="$(
    command bcd-bin "$@" 2>&1 1>/dev/tty \
      | tr -d '\r' \
      | sed -E 's/\x1b\[[0-9;?]*[ -/]*[@-~]//g' \
      | grep -oE 'BCD_SELECTED_PATH:[^[:cntrl:]]+' \
      | tail -n 1 \
      | sed 's/^BCD_SELECTED_PATH://'
  )"

  if [[ -n "$selected_path" ]]; then
    if [[ -d "$selected_path" ]]; then
      builtin cd -- "$selected_path" || return 1
    elif [[ -f "$selected_path" ]]; then
      builtin cd -- "$(dirname -- "$selected_path")" || return 1
    fi
  fi
}

Zsh (~/.zshrc):

# bcd shell integration
bcd() {
  local selected_path

  selected_path="$(
    command bcd-bin "$@" 2>&1 1>/dev/tty \
      | tr -d '\r' \
      | sed -E 's/\x1b\[[0-9;?]*[ -/]*[@-~]//g' \
      | grep -oE 'BCD_SELECTED_PATH:[^[:cntrl:]]+' \
      | tail -n 1 \
      | sed 's/^BCD_SELECTED_PATH://'
  )"

  if [[ -n "$selected_path" ]]; then
    if [[ -d "$selected_path" ]]; then
      builtin cd -- "$selected_path" || return 1
    elif [[ -f "$selected_path" ]]; then
      builtin cd -- "$(dirname -- "$selected_path")" || return 1
    fi
  fi
}

Fish (~/.config/fish/functions/bcd.fish):

# bcd shell integration
function bcd
    set selected_path (
        command bcd-bin $argv 2>&1 1>/dev/tty \
            | tr -d '\r' \
            | sed -E 's/\x1b\[[0-9;?]*[ -/]*[@-~]//g' \
            | grep -oE 'BCD_SELECTED_PATH:[^[:cntrl:]]+' \
            | tail -n 1 \
            | sed 's/^BCD_SELECTED_PATH://'
    )

    if test -n "$selected_path"
        if test -d "$selected_path"
            builtin cd -- $selected_path
        else if test -f "$selected_path"
            builtin cd -- (dirname -- $selected_path)
        end
    end
end
  1. Reload your shell:
source ~/.bashrc  # or source ~/.zshrc for Zsh

Usage

# Search from current directory
bcd

# Search from a specific directory
bcd /path/to/start

Note: You invoke bcd (the shell function), which internally calls bcd-bin (the binary).

Keyboard Shortcuts

  • ↑/↓ or Ctrl+p/n: Navigate results
  • Enter: Select directory and cd into it
  • Esc or Ctrl+c: Cancel
  • Type to search: Fuzzy match against directory names

How it Works

Directory Discovery and Ranking

  1. BFS Traversal: Discovers directories using breadth-first search, prioritizing closer paths
  2. Distance Calculation: Ranks results by path distance from starting location
  3. FZF v2 Scoring: Uses dynamic programming for optimal fuzzy matching
  4. Async Processing: Background worker processes entries without blocking the UI
  5. Batching: Groups directory discoveries (100 entries or 50ms intervals) for efficient processing
  6. Heap-Based Ranking: Maintains top results using a max-heap for O(log k) insertion

Shell Integration

The shell function bcd() wraps the bcd-bin binary and enables cd functionality through clever I/O redirection:

  1. Redirection order: 2>&1 1>/dev/tty - First redirects stderr to stdout (captured by command substitution), then redirects stdout to /dev/tty (terminal)
  2. TUI renders to terminal: stdout goes to /dev/tty so you can see and interact with the TUI
  3. Selection captured via stderr: The bcd-bin binary outputs BCD_SELECTED_PATH:/path/to/dir to stderr, which gets captured
  4. Shell extracts path: The captured output is piped through tr, sed, and grep to extract the clean path
  5. cd into directory: The shell function uses builtin cd to change directories

This approach allows the interactive TUI to display normally while the selected path is captured for shell use. The separation of the binary (bcd-bin) and shell function (bcd) prevents naming conflicts and makes the integration cleaner.

Project Structure

bcd/
├── cmd/bcd/           # Main application entry point
├── internal/          # Internal packages
│   ├── crawler/       # BFS directory traversal
│   ├── entry/         # Path entry data structures
│   ├── ranker/        # FZF v2 scoring and ranking
│   └── tui/           # Bubble Tea TUI interface
├── scripts/           # Shell integration scripts
│   ├── bcd.bash       # Bash integration
│   ├── bcd.zsh        # Zsh integration
│   └── bcd.fish       # Fish integration
├── install.sh         # Installation script
├── uninstall.sh       # Uninstallation script
├── LICENSE            # MIT License with FZF attribution
└── README.md

Troubleshooting

bcd: command not found

This means the shell function isn't loaded. Make sure you've:

  1. Added the shell integration to your shell config
  2. Reloaded your shell:
    source ~/.bashrc  # or source ~/.zshrc

If bcd-bin itself is missing, ensure ~/.local/bin is in your PATH:

# Add to your shell config if not present
export PATH="$HOME/.local/bin:$PATH"

# Reload your shell
source ~/.bashrc  # or source ~/.zshrc

Shell function not working

If the bcd command doesn't cd you to the selected directory:

  1. Verify the shell function is defined:

    type bcd  # Should show it's a shell function
  2. Make sure you've reloaded your shell config after installation

  3. For reinstallation, the install script will warn if integration already exists. Use the uninstall script first:

    ./uninstall.sh
    ./install.sh

TUI not displaying correctly

The TUI requires a terminal that supports ANSI escape codes. Most modern terminals (Terminal.app, iTerm2, Alacritty, etc.) work fine.

Development

Building from Source

go build -o bcd-bin ./cmd/bcd

Running Tests

go test ./internal/...

Architecture

  • cmd/bcd: Entry point, handles TUI initialization and output
  • internal/crawler: BFS directory discovery with concurrent traversal
  • internal/entry: Path entry data structures with distance calculation
  • internal/ranker: FZF v2 fuzzy matching with heap-based ranking
  • internal/tui: Bubble Tea TUI with async message handling

License

MIT License - See LICENSE file for details

This project uses the FZF v2 algorithm for fuzzy matching. See LICENSE for attribution.

About

A better cd tool that let you search for directories and files to cd into

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published