Skip to content

ivomac/zsh-fzf-nav

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FZF Nav Plugin

A zsh plugin that defines an interactive file/directory navigator using fzf. Offers multiple navigation modes, git integration, and customizable actions.

Usage

Examples

  1. Basic file navigation:
  • Search for a file/directory.
  • Press Enter to cd to the directory/file's parent and open it with $FZF_NAV_OPEN.

search

  1. Quick edits with custom open script:
  • Create a custom mode in your .zshrc:
    function nav-edit() {
      printf 'nvim $1 +$2' > '/tmp/edit.sh'
      chmod +x /tmp/edit.sh
      FZF_NAV_USER_OPEN='/tmp/edit.sh' _fzf-nav
    }
    
  • Run nav-edit
  • Press Ctrl+R to switch to grep mode.
  • Type your search term.
  • Press Ctrl+U to open a file in the editor at the highlighted line.
  • Exiting the editor will return you to the fzf-nav menu so you can edit another search result.

nav-edit

  1. Git repository management:
  • Press Ctrl+G to switch to git mode.
  • Press Ctrl+G again to see repositories with modifications.
  • Press Ctrl+U on a repository to open lazygit (with config above).

git-mode

  1. Bookmark navigation:
  • Press Ctrl+T to show yazi bookmarks (with config above).
  • Press Enter on a bookmark to cd to it and open yazi.

Navigation Modes

The plugin supports several modes that you can switch between:

  • Search Mode (default): Shows all files and directories.
  • Files Mode: Shows only files.
  • Directories Mode: Shows only directories.
  • Grep Mode: Search within file contents.
  • Git Mode: List git repositories.
  • Status Mode: List git repositories with unclean status.
  • Fetch Mode: List git repositories with unclean status after fetch (slow).
  • User Mode: User-defined mode.

Key Bindings

Mode Switching:

  • Ctrl+F: Cycle through Search → Directories → Files.
  • Ctrl+R: Switch to Grep mode.
  • Ctrl+G: Cycle through Git → Status → Fetch modes.
  • Ctrl+T: Switch to User mode (fzf-nav-mode-user).

Actions:

  • Enter: Change to directory and open selections. Exits fzf.
  • Ctrl+O: Open selection without changing directory and exiting.
  • Ctrl+U: Open selection with user-defined command without exiting.
  • Ctrl+D: Open selection in a detached terminal.

Installation

Prerequisites

  • Needed:
  • Recommended:
    • Nerd-fonts compatible font.
    • bat - code highlighter
    • eza - better ls
  • Optional:

Loading

# Download plugin
folder="$ZDOTDIR/plugins/zsh-fzf-nav" 
if [[ ! -d "$folder" ]]; then
  git clone --recurse-submodules --depth 1 "https://github.com/ivomac/zsh-fzf-nav" "$folder"
fi

# Load plugin
source "$folder/zsh-fzf-nav.plugin.zsh"

Binding

The plugin defines a single entry point _fzf-nav to launch the menu. Bind it as you wish.

Super-tab

Open the menu with <Tab> when command line is empty, regular tab otherwise:

function fzf-nav() {
  if [[ -z "$BUFFER" ]]; then
    zle _fzf-nav
  else
    # if using fzf-tab plugin
    zle fzf-tab-complete
    # regular tab
    # zle expand-or-complete
  fi
}
zle -N fzf-nav

bindkey '^I' fzf-nav # Tab

Configuration

Some functions and variables need to be defined for the plugin to function. I recommend you paste and modify the configs below in your .zshrc.

Environment Variables

# general
export FZF_DEFAULT_OPTS=...              # Used by the plugin when calling fzf

# plugin-specific
export FZF_NAV_OPEN="nnn"                # Command to open selected items (needed)
export FZF_NAV_TERMCMD="foot"            # Terminal for detached operations (needed)
export FZF_NAV_SEPARATOR=◇               # Separator in file${sep}line grep results. (default: ◇)

# FD options array. Runs at start and on ctrl-f modes.
# No default.
export FZF_NAV_FD_OPTS=(
    "--color=always"
    "--hidden"
    "--no-ignore"
    "--exclude='**/.git/**'"
    "--exclude='**/.cargo/**'"
    "--exclude='**/.npm/**'"
    ...
)

# Search function in grep/ctrl-r mode.
# No default.
export FZF_NAV_RG_OPTS=(
    "--line-number"                  # Show line numbers (needed).
    "--with-filename"                # Include filename in output (needed).
    "--color=always"
    "--hidden"
    "--no-ignore"
    "--smart-case"
    "--glob=!'**/.git/**'"
    "--glob=!'**/.parallel/**'"
    "--glob=!'**/.cargo/**'"
    "--glob=!'**/.npm/**'"
    "--glob=!'**/.pki/**'"
    "--glob=!'**/.venv**/**'"
    "--glob=!'**/__pycache__/**'"
    "--glob=!'**/.ipython/**'"
    "--glob=!'**/cache/**'"
    "--glob=!'**/.cache/**'"
    "--glob=!'**/.nvim/**'"
    "--glob=!'**/nvim/undo/**'"
    "--glob=!'**/.android/**'"
    "--glob=!'**/.mozilla/firefox/*/**'"
    "--glob=!'**/.stfolder/**'"
    "--glob=!'**/.steam/**'"
    "--glob=!'**/.aider*/**'"
    "--glob=!'**/.local/share/*/**'"
    "--glob=!'**/yazi/packages/**'"
)

# Secondary opener script. No default.
export FZF_NAV_USER_OPEN="lg-open"
# Example:
example-user-open {
  # Git modes work well with a git TUI like lazygit.
  if [[ -d "$1" ]]; then
    # If directory, cd and launch
    (cd "$1" && lazygit)
  else
    # If file, cd to parent and launch
    (cd "$(dirname "$1")" && lazygit)
  fi
}

# User-defined selection mode script. No default.
export FZF_NAV_USER_MODE="bookmarks"
# Example: Extract bookmarks from yazi.
example-user-mode {
  head -n1 "$XDG_STATE_HOME/yazi/.dds" \
  | cut -d, -f4- \
  | jq -r '.[] | "\(.path)$FZF_NAV_SEPARATOR\(.desc)"'
}

# Preview script. Has default.
export FZF_NAV_PREVIEW="preview"
# Default:
default-preview {
  # preview files and directories with bat and eza.
  file="$1"
  line="$2"

  ftype=$(file -b --mime "$file")
  flags=""
  if [[ -L "$file" ]]; then
    echo "Symlink -> $(readlink -f "$file")\n"
    flags+="--links"
  fi

  if [[ -d "$file" ]]; then
    eza -Al --color=always $flags "$file"
  elif [[ -f "$file" ]]; then
    if [[ "$ftype" == text/* ]]; then
      if [[ $line =~ ^[0-9]+$ ]]; then
        start=$(($line - 10))
        if [[ $start -le 0 ]]; then
          start=1
        fi
        bat --line-range="$start:" --highlight-line "$line" "$file"
      else
        bat "$file"
      fi
    else
      echo "Binary file"
    fi
  elif [[ -n "$file" ]]; then
    bat "$file"
  fi
}

Look

The menu does not set any look and theme options and will use those in FZF_DEFAULT_OPTS. For the gifs above I used:

export FZF_DEFAULT_OPTS="\ 
--ansi \
--height=100% \
--input-border=bottom \
--header-border=bottom \
--pointer='█' \
--marker='█' \
--input-label-pos='0:top' \
--info=inline-right \
--preview-window='right:50%:border-left:wrap:<60(down:60%:border-top:wrap)' \
--tiebreak='begin,length' \
--tabstop=2 \
--reverse \
--bind='change:top' \
--bind='tab:toggle-out' \
--bind='ctrl-t:toggle-all' \
--bind='ctrl-s:jump' \
--bind='ctrl-y:execute-silent:wl-copy {}' \
--bind='ctrl-\\:toggle-preview' \
"

About

A zsh plugin with an fzf filesystem navigation menu

Topics

Resources

License

Stars

Watchers

Forks

Languages