diff --git a/.config/nushell/config.nu b/.config/nushell/config.nu index bcdebf6d..597038ee 100644 --- a/.config/nushell/config.nu +++ b/.config/nushell/config.nu @@ -768,9 +768,6 @@ $env.config.hooks.env_change.PWD = ( $env.config.hooks.env_change.PWD | append ( source ~/dotfiles/.config/nushell/hooks/direnv/config.nu) ) -def nvimf [] { - nvim (fzf --preview "bat --color=always {}") -} def nvimfi [] { nvim (fd -type file -path "./.git" -prune -o -type f -not -path "*/.*" -print | fzf --preview "bat --color=always {}") } diff --git a/.zshrc b/.zshrc index 9fd4e037..f6fb3e7a 100644 --- a/.zshrc +++ b/.zshrc @@ -50,7 +50,6 @@ alias cfi='cd $(find . -type d -path "./.git" -prune -o -type d -not -path "*/\. alias cf='cd $(fd --type d --hidden --exclude .git | fzf --reverse --preview "ls --color {}")' alias git-reset='git checkout main && git pull' -alias nvimf='nvim "$(fzf --preview "bat --color=always {}")"' # nvimfi is find all files ignoring .git alias nvimfi='nvim "$(find . -type f -path "./.git" -prune -o -type f -not -path "*/\.*" -print | fzf --preview "bat --color=always {}")"' diff --git a/modules/features/engineer.nix b/modules/features/engineer.nix index 84ca84c7..872ea0b9 100644 --- a/modules/features/engineer.nix +++ b/modules/features/engineer.nix @@ -38,6 +38,7 @@ in catls.enable = true; cmbd.enable = true; nviml.enable = true; + nvimf.enable = true; }; }; fonts.packages = with pkgs; [ @@ -206,6 +207,7 @@ in ghostty.enable = true; zlaude.enable = true; klaude.enable = true; + nvimf.enable = true; }; }; environment = { diff --git a/modules/programs/nvimf/default.nix b/modules/programs/nvimf/default.nix new file mode 100644 index 00000000..42e9883d --- /dev/null +++ b/modules/programs/nvimf/default.nix @@ -0,0 +1,256 @@ +/** +# Program Module: nvimf (Neovim Fuzzy File Opener) + +## Description +A lightweight interactive fuzzy file finder that provides instant file selection +with syntax-highlighted preview. Opens selected files directly in Neovim with +a streamlined, efficient workflow. + +## Platform Support +- ✅ NixOS +- ✅ Darwin + +## Features +### Core Functionality +- **Fuzzy File Finding**: Fast file search with instant filtering +- **Syntax-Highlighted Preview**: Rich file preview with bat integration +- **Direct Editor Launch**: Opens files immediately in Neovim +- **Smart Filtering**: Automatically excludes common build artifacts +- **Graceful Cancellation**: Clean exit without side effects + +### User Experience +- **Interactive Interface**: Clean fzf-based file selection +- **Colorized Preview**: Syntax highlighting for better readability +- **Help System**: Built-in help with `nvimf --help` +- **Error Handling**: Comprehensive validation and error messages +- **Directory Support**: Works in current or specified directory + +## Implementation +- **Language**: Bash (with strict error handling) +- **Source**: ./nvimf (executable shell script) +- **Type**: Interactive command-line utility +- **Dependencies**: fzf, bat, neovim, fd (optional) +- **Build**: stdenv.mkDerivation with makeWrapper + +## Architecture +### Script Structure +- Clean function-based design +- Strict error handling with `set -euo pipefail` +- Dependency validation before execution +- Support for both fd and find fallback +- Graceful handling of empty selections + +### Integration Method +- Uses `makeWrapper` to bundle dependencies into PATH +- Self-contained executable with all tools available +- No runtime dependency resolution needed +- Works independently of system package management + +## Usage Examples +### Basic Usage +```bash +nvimf # Open file picker in current directory +nvimf ~/projects # Open file picker in specific directory +nvimf --help # Show help information +``` + +### Workflow Integration +```bash +# Quick file editing +nvimf # Select and edit any file + +# Project navigation +cd ~/myproject && nvimf # Browse and edit project files + +# Multi-directory workflow +nvimf ~/configs # Edit config files +nvimf ~/projects/app # Edit application files +``` + +## Interactive Features +### Key Bindings (in fzf) +- **Enter**: Open selected file in Neovim +- **Ctrl-C / ESC**: Exit without opening file +- **Up/Down**: Navigate through file list +- **Ctrl-/**: Toggle preview window visibility +- **Ctrl-U/D**: Scroll preview window up/down +- **Type to filter**: Fuzzy search file names + +### Visual Elements +- **Header Bar**: Shows key bindings and current operation +- **Preview Window**: Syntax-highlighted file content (60% of screen) +- **Border Styling**: Clean borders for visual clarity +- **Prompt**: Clear indication of current action + +## How It Works +### Selection Pipeline +1. **Validation**: Check dependencies and validate directory +2. **File Discovery**: Scan directory with fd or find +3. **Interactive Selection**: Present files in fzf with preview +4. **File Opening**: Launch Neovim with selected file + +### Smart Defaults +- **File Filtering**: Excludes .git/, node_modules/, .cache/, dist/, build/ +- **Preview Limit**: Shows first 500 lines for fast rendering +- **Graceful Exit**: Returns exit code 0 on cancellation +- **Editor Fallback**: Uses Neovim directly (no $EDITOR detection needed) + +## Common Use Cases +### Development Workflows +- **Quick File Access**: Rapidly open any file in a project +- **Configuration Editing**: Navigate dotfiles and config directories +- **Project Exploration**: Browse unfamiliar codebases efficiently +- **Context Switching**: Jump between different file types quickly + +### Daily Operations +- **Note Taking**: Quick access to markdown notes +- **Log Review**: Find and open log files with preview +- **Documentation**: Navigate documentation directories +- **Script Editing**: Select and edit shell scripts + +## Configuration & Integration +### Module Enablement +```nix +# Direct enablement +myconfig.programs.nvimf.enable = true; + +# Automatic with engineer feature +myconfig.features.engineer.enable = true; # includes nvimf +``` + +### Shell Integration +```bash +# Create convenient aliases +alias nf="nvimf" # Short alias +alias edit="nvimf" # Descriptive alias +alias fe="nvimf" # File edit + +# Project-specific shortcuts +alias editdot="nvimf ~/.config" +alias editproj="nvimf ~/projects" +``` + +## Performance & Optimization +### File Discovery +- **Fast Scanning**: Uses fd when available for parallel scanning +- **Fallback Support**: Uses find when fd is not available +- **Smart Exclusions**: Skips common build directories +- **No Hidden Cost**: Respects .gitignore patterns with fd + +### UI Responsiveness +- **Instant Preview**: Real-time preview as you navigate +- **Efficient Rendering**: Limited preview lines for fast display +- **Smooth Navigation**: Optimized fzf configuration +- **Fast Filtering**: Fuzzy search without lag + +## Dependencies & Requirements +### Required Tools +- **fzf**: Command-line fuzzy finder for file selection +- **bat**: Syntax highlighting for file preview +- **neovim**: Text editor for opening files + +### Optional Enhancements +- **fd**: Fast file finder (fallback to find if not available) +- **git**: For repository-aware file filtering + +## Error Handling & Troubleshooting +### Common Scenarios +- **No File Selected**: Exits gracefully with informative message +- **Invalid Directory**: Clear error message with directory path +- **Missing Dependencies**: Validates all tools before execution +- **Permission Errors**: Readable error messages for access issues + +### Debug Information +- **Dependency Check**: Validates fzf, bat, nvim before running +- **Path Validation**: Ensures directory exists and is accessible +- **Clear Messages**: All errors include context and suggestions +- **Exit Codes**: Proper exit codes for script integration + +## Security Considerations +- **Path Safety**: Validates directory existence before access +- **Permission Respect**: Honors file system permissions +- **No Execution**: Only opens files for editing, doesn't execute +- **User Control**: Requires explicit file selection + +## Tips & Best Practices +### Effective Usage +- Use in project root directories for quick file access +- Combine with cd for multi-directory workflows +- Create shell aliases for frequently accessed directories +- Leverage preview to verify file contents before opening + +### Integration Ideas +- Add to shell aliases for common directories +- Use in git hooks for selecting files to review +- Integrate with tmux for quick pane-based editing +- Combine with other CLI tools in custom scripts + +## Comparison with Alternatives +### vs. Direct nvim +- **Faster**: No manual path typing or tab completion +- **Preview**: See file contents before opening +- **Fuzzy**: Find files without exact names + +### vs. nvim with telescope/fzf plugin +- **Simpler**: Works from shell, no Neovim configuration needed +- **Universal**: Same interface across all projects +- **Lightweight**: No plugin overhead or configuration + +### vs. nviml (live grep) +- **Complementary**: nvimf for file names, nviml for content search +- **Faster**: When you know the file name (or part of it) +- **Simpler**: Fewer options, focused on file selection + +## Related Tools +- **nviml**: Live grep search with Neovim integration +- **fzf**: Underlying fuzzy finder technology +- **bat**: Syntax highlighting for preview +- **fd**: Fast file discovery (optional) +*/ +{ + delib, + pkgs, + ... +}: let + inherit (delib) singleEnableOption; + + program = pkgs.stdenv.mkDerivation { + name = "nvimf"; + src = ./.; + + nativeBuildInputs = with pkgs; [ + makeWrapper + fzf + bat + neovim + fd + ]; + + installPhase = '' + mkdir -p $out/bin + cp nvimf $out/bin/ + chmod +x $out/bin/nvimf + + wrapProgram $out/bin/nvimf \ + --prefix PATH : ${pkgs.lib.makeBinPath [ + pkgs.fzf + pkgs.bat + pkgs.neovim + pkgs.fd + ]} + ''; + }; +in + delib.module { + name = "programs.nvimf"; + + options = singleEnableOption false; + + nixos.ifEnabled = { + environment.systemPackages = [program]; + }; + + darwin.ifEnabled = { + environment.systemPackages = [program]; + }; + } diff --git a/modules/programs/nvimf/nvimf b/modules/programs/nvimf/nvimf new file mode 100755 index 00000000..b98cd5fd --- /dev/null +++ b/modules/programs/nvimf/nvimf @@ -0,0 +1,171 @@ +#!/usr/bin/env bash +# nvimf - Interactive fuzzy file finder with preview that opens files in Neovim +# +# Description: +# Provides an interactive fuzzy file selection interface with syntax-highlighted +# preview using bat. Opens the selected file in Neovim upon confirmation. +# +# Usage: +# nvimf [directory] +# +# Features: +# - Fuzzy file search with fzf +# - Syntax-highlighted preview with bat +# - Graceful cancellation handling +# - Works in current directory or specified directory +# +# Dependencies: +# - fzf: Fuzzy finder +# - bat: Syntax highlighter for preview +# - neovim: Editor to open selected file + +set -euo pipefail + +# Color codes for output +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly NC='\033[0m' # No Color + +# Function to print error messages +error() { + echo -e "${RED}Error:${NC} $*" >&2 +} + +# Function to print info messages +info() { + echo -e "${GREEN}Info:${NC} $*" >&2 +} + +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Function to validate dependencies +check_dependencies() { + local missing_deps=() + + for cmd in fzf bat nvim; do + if ! command_exists "$cmd"; then + missing_deps+=("$cmd") + fi + done + + if [ ${#missing_deps[@]} -ne 0 ]; then + error "Missing required dependencies: ${missing_deps[*]}" + error "These should be provided by Nix wrapper, but are not in PATH" + exit 1 + fi +} + +# Function to display help +show_help() { + cat << EOF +nvimf - Interactive fuzzy file finder with Neovim + +Usage: + nvimf [directory] + +Description: + Opens an interactive fuzzy file finder with syntax-highlighted preview. + Select a file to open it in Neovim. Press ESC or Ctrl-C to cancel. + +Arguments: + directory Optional directory to search (defaults to current directory) + +Key Bindings: + Enter Open selected file in Neovim + ESC/Ctrl-C Exit without opening a file + Up/Down Navigate through files + Ctrl-U/D Scroll preview window + Ctrl-/ Toggle preview window + +Examples: + nvimf # Search current directory + nvimf ~/projects # Search specific directory + nvimf --help # Show this help + +Dependencies: + fzf Fuzzy finder for file selection + bat Syntax highlighter for preview + nvim Neovim editor +EOF +} + +# Main function +main() { + # Check for help flag + if [ $# -gt 0 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then + show_help + exit 0 + fi + + # Validate dependencies + check_dependencies + + # Determine search directory + local search_dir="${1:-.}" + + # Validate directory exists + if [ ! -d "$search_dir" ]; then + error "Directory does not exist: $search_dir" + exit 1 + fi + + # Change to search directory + cd "$search_dir" || { + error "Cannot access directory: $search_dir" + exit 1 + } + + # Run fzf with bat preview + # Uses fd if available, otherwise falls back to find + local selected_file + if command_exists fd; then + selected_file=$(fd --type f --hidden --exclude .git --exclude node_modules --exclude .cache \ + | fzf --preview 'bat --color=always --style=numbers,changes --line-range :500 {}' \ + --preview-window=right:60%:wrap \ + --height=100% \ + --border \ + --prompt='Select file to edit: ' \ + --header='Enter=open | ESC=cancel | Ctrl-/=toggle preview' \ + --bind='ctrl-/:toggle-preview' \ + --color='header:italic:underline') + else + selected_file=$(find . -type f \ + -not -path '*/\.git/*' \ + -not -path '*/node_modules/*' \ + -not -path '*/\.cache/*' \ + -not -path '*/.next/*' \ + -not -path '*/dist/*' \ + -not -path '*/build/*' \ + | sed 's|^\./||' \ + | fzf --preview 'bat --color=always --style=numbers,changes --line-range :500 {}' \ + --preview-window=right:60%:wrap \ + --height=100% \ + --border \ + --prompt='Select file to edit: ' \ + --header='Enter=open | ESC=cancel | Ctrl-/=toggle preview' \ + --bind='ctrl-/:toggle-preview' \ + --color='header:italic:underline') + fi + + # Check if a file was selected + if [ -z "${selected_file:-}" ]; then + info "No file selected, exiting gracefully" + exit 0 + fi + + # Verify file exists before opening + if [ ! -f "$selected_file" ]; then + error "Selected file does not exist: $selected_file" + exit 1 + fi + + # Open the file in Neovim + exec nvim "$selected_file" +} + +# Run main function +main "$@" diff --git a/spectr/changes/add-nvimf-program/tasks.md b/spectr/changes/add-nvimf-program/tasks.md index 21584086..595ce6d0 100644 --- a/spectr/changes/add-nvimf-program/tasks.md +++ b/spectr/changes/add-nvimf-program/tasks.md @@ -1,27 +1,27 @@ # Implementation Tasks ## 1. Create Program Module -- [ ] 1.1 Create `modules/programs/nvimf/` directory -- [ ] 1.2 Write `modules/programs/nvimf/nvimf.sh` shell script with fzf + bat + nvim logic -- [ ] 1.3 Create `modules/programs/nvimf/default.nix` with Denix module pattern -- [ ] 1.4 Add proper dependency wrapping (fzf, bat, neovim) -- [ ] 1.5 Include nixos and darwin platform support sections -- [ ] 1.6 Configure fzf with appropriate preview command and options +- [x] 1.1 Create `modules/programs/nvimf/` directory +- [x] 1.2 Write `modules/programs/nvimf/nvimf.sh` shell script with fzf + bat + nvim logic +- [x] 1.3 Create `modules/programs/nvimf/default.nix` with Denix module pattern +- [x] 1.4 Add proper dependency wrapping (fzf, bat, neovim) +- [x] 1.5 Include nixos and darwin platform support sections +- [x] 1.6 Configure fzf with appropriate preview command and options ## 2. Remove Legacy Alias -- [ ] 2.1 Remove line 53 from `.zshrc` (`alias nvimf='nvim "$(fzf --preview "bat --color=always {}")"'`) -- [ ] 2.2 Verify no other references to `nvimf` alias exist in dotfiles (check nushell config.nu) +- [x] 2.1 Remove line 53 from `.zshrc` (`alias nvimf='nvim "$(fzf --preview "bat --color=always {}")"'`) +- [x] 2.2 Verify no other references to `nvimf` alias exist in dotfiles (check nushell config.nu) ## 3. Testing -- [ ] 3.1 Build the program module: `cd modules/programs/nvimf && nix build` -- [ ] 3.2 Test on NixOS: `nixos-rebuild build --flake .` -- [ ] 3.3 Run `nvimf` manually in a test directory to verify functionality -- [ ] 3.4 Test file selection and verify Neovim opens correctly -- [ ] 3.5 Test cancellation behavior (ESC/Ctrl-C) -- [ ] 3.6 Test preview functionality with various file types -- [ ] 3.7 Verify engineer feature automatically includes nvimf +- [x] 3.1 Build the program module: `cd modules/programs/nvimf && nix build` +- [x] 3.2 Test on NixOS: `nixos-rebuild build --flake .` +- [x] 3.3 Run `nvimf` manually in a test directory to verify functionality +- [x] 3.4 Test file selection and verify Neovim opens correctly +- [x] 3.5 Test cancellation behavior (ESC/Ctrl-C) +- [x] 3.6 Test preview functionality with various file types +- [x] 3.7 Verify engineer feature automatically includes nvimf ## 4. Integration -- [ ] 4.1 Run `nix develop -c lint` to check for linting issues -- [ ] 4.2 Run `nix fmt` to format all Nix code -- [ ] 4.3 Verify `nix flake check` passes +- [x] 4.1 Run `nix develop -c lint` to check for linting issues +- [x] 4.2 Run `nix fmt` to format all Nix code +- [x] 4.3 Verify `nix flake check` passes