├── LICENSE ├── README.md ├── assets ├── demo.png └── demo2.gif └── fzfm /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Ashish Kumar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fzfm 2 | 3 | **fzfm** is a **minimal and fast terminal-based file manager** powered by `fzf`, 4 | written in **Bash**. It showcases how **powerful** `fzf` can be, demonstrating 5 | its potential beyond simple fuzzy finding. It allows you to **navigate 6 | directories**, **preview files and directories**, and **open them** using your 7 | preferred applications directly from the **command line**. 8 | 9 | ![demo](assets/demo2.gif) 10 | 11 | ## Features 12 | 13 | - **Navigate directories** seamlessly using only your keyboard 14 | - **Blazing-fast fuzzy search** powered by `fzf` 15 | - **File preview** using `bat` (fallback to `cat`) 16 | - **Directory preview** using `eza` (fallback to `ls`) 17 | - **Customizable multimedia file opener** (`wslview`, `xdg-open`, etc.) 18 | - **Fully configurable** via environment variables 19 | 20 | ## Dependencies 21 | 22 | Ensure you have the following installed: 23 | 24 | - [`fzf`](https://github.com/junegunn/fzf) - Core dependency, the entire file 25 | manager is built around it 26 | - [`eza`](https://github.com/eza-community/eza) - For enhanced directory listing 27 | (fallback to `ls`) 28 | - [`bat`](https://github.com/sharkdp/bat) - For file previewing (fallback to 29 | `cat`) 30 | - [`nvim`](https://github.com/neovim/neovim) - For text editing (fallback to 31 | `nano`) 32 | - A media opener like `wslview`, `xdg-open`, or `open` 33 | - [Nerd Fonts](https://www.nerdfonts.com/) - For proper icon rendering in the 34 | terminal 35 | 36 | ## Installation 37 | 38 | 1. Clone the repository: 39 | ```bash 40 | git clone https://github.com/ashish0kumar/fzfm.git 41 | cd fzfm 42 | ``` 43 | 44 | 2. Optionally, move it to a directory in your `$PATH`: 45 | ```bash 46 | mv fzfm ~/.local/bin/fzfm 47 | ``` 48 | 49 | ## Usage 50 | 51 | Run the script: 52 | 53 | ```bash 54 | ./fzfm # or just `fzfm` if added to PATH 55 | ``` 56 | 57 | ### Key Bindings 58 | 59 | | **Key** | **Action** | 60 | | --------------------- | ---------------------- | 61 | | `Up/Down Arrow` | Move selection up/down | 62 | | `Enter / Right Arrow` | Open file/folder | 63 | | `Shift + Up/Down` | Scroll preview | 64 | | `Ctrl + R` | Refresh file list | 65 | 66 | ### Environment Variables 67 | 68 | Customize behavior according to your system by setting the following: 69 | 70 | ```bash 71 | export FZFM_MEDIA_OPENER="xdg-open" # Set preferred media opener 72 | export FZFM_TEXT_EDITOR="nvim" # Set preferred text editor 73 | export FZFM_LIST_COMMAND="eza" # Set directory listing command 74 | export FZFM_PREVIEW_COMMAND="bat" # Set preview command 75 | ``` 76 | 77 | ## License 78 | 79 | This project is open-source and licensed under the MIT License. 80 | 81 | ## Contributions 82 | 83 | Feel free to fork the repository, submit issues, or contribute improvements! 84 | -------------------------------------------------------------------------------- /assets/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashish0kumar/fzfm/93daec4ac806507d11f615f91566b715cc7aee35/assets/demo.png -------------------------------------------------------------------------------- /assets/demo2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashish0kumar/fzfm/93daec4ac806507d11f615f91566b715cc7aee35/assets/demo2.gif -------------------------------------------------------------------------------- /fzfm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Configuration variables with defaults 4 | MEDIA_OPENER="wslview" 5 | TEXT_EDITOR="nvim" 6 | LIST_COMMAND="eza" 7 | PREVIEW_COMMAND="batcat" 8 | 9 | # Function to check if a command exists 10 | command_exists() { 11 | command -v "$1" &> /dev/null 12 | } 13 | 14 | # Check and set up dependencies 15 | setup_dependencies() { 16 | # Check for fzf as it's required 17 | if ! command_exists "fzf"; then 18 | echo "Error: fzf is required but not installed" 19 | exit 1 20 | fi 21 | 22 | # Check and set list command (eza or ls) 23 | if ! command_exists "$LIST_COMMAND"; then 24 | echo "Warning: $LIST_COMMAND not found, falling back to ls" 25 | LIST_COMMAND="ls" 26 | LIST_ARGS="-1A --color=always" # ls arguments 27 | else 28 | LIST_ARGS="-1a --icons --color=always" # eza arguments 29 | fi 30 | 31 | # Check and set preview command 32 | if ! command_exists "$PREVIEW_COMMAND"; then 33 | echo "Warning: $PREVIEW_COMMAND not found, falling back to cat" 34 | PREVIEW_COMMAND="cat" 35 | fi 36 | 37 | # Check and set text editor 38 | if ! command_exists "$TEXT_EDITOR"; then 39 | echo "Warning: $TEXT_EDITOR not found, falling back to nano" 40 | command_exists "nano" && TEXT_EDITOR="nano" || { 41 | echo "Error: No suitable text editor found" 42 | exit 1 43 | } 44 | fi 45 | 46 | # Check and set media opener 47 | if ! command_exists "$MEDIA_OPENER"; then 48 | if command_exists "xdg-open"; then 49 | echo "Warning: $MEDIA_OPENER not found, falling back to xdg-open" 50 | MEDIA_OPENER="xdg-open" 51 | elif command_exists "open"; then 52 | echo "Warning: $MEDIA_OPENER not found, falling back to open" 53 | MEDIA_OPENER="open" 54 | else 55 | echo "Warning: No suitable media opener found, multimedia files won't be opened" 56 | MEDIA_OPENER="" 57 | fi 58 | fi 59 | } 60 | 61 | # Check and open file based on mime type 62 | open_file() { 63 | local file="$1" 64 | local mime_type=$(file --mime-type -b "$file") 65 | 66 | case "$mime_type" in 67 | text/*|application/json|application/xml|application/javascript|application/x-shellscript) 68 | $TEXT_EDITOR "$file" 69 | clear 70 | ;; 71 | image/*|video/*|audio/*|application/pdf) 72 | if [[ -n "$MEDIA_OPENER" ]]; then 73 | $MEDIA_OPENER "$file" &>/dev/null & 74 | else 75 | echo "No media opener available. Cannot open $file" 76 | read -n 1 -s -r -p "Press any key to continue..." 77 | clear 78 | fi 79 | ;; 80 | *) 81 | if [ -B "$file" ]; then 82 | $TEXT_EDITOR "$file" 83 | clear 84 | else 85 | if [[ -n "$MEDIA_OPENER" ]]; then 86 | $MEDIA_OPENER "$file" &>/dev/null || { 87 | $TEXT_EDITOR "$file" 88 | clear 89 | } 90 | else 91 | $TEXT_EDITOR "$file" 92 | clear 93 | fi 94 | fi 95 | ;; 96 | esac 97 | } 98 | 99 | # Main function 100 | fzfm() { 101 | setup_dependencies 102 | 103 | local list_command="$LIST_COMMAND $LIST_ARGS" 104 | 105 | while true; do 106 | selection=$( (echo ".."; eval "$list_command") | fzf \ 107 | --ansi \ 108 | --reverse \ 109 | --height 100% \ 110 | --info right \ 111 | --prompt "󰥨 Search: " \ 112 | --pointer ">" \ 113 | --marker "󰄲" \ 114 | --border "rounded" \ 115 | --border-label=" 󱉭 $(pwd)/ " \ 116 | --border-label-pos center \ 117 | --color 'fg:#cdd6f4,fg+:#cdd6f4,bg+:#313244,border:#a5aac3,pointer:#cba6f7,label:#cdd6f4' \ 118 | --bind "right:accept" \ 119 | --bind "enter:accept" \ 120 | --bind "shift-up:preview-up" \ 121 | --bind "shift-down:preview-down" \ 122 | --bind "ctrl-r:reload($list_command)" \ 123 | --preview-window="right:65%" \ 124 | --preview " 125 | file={} 126 | if [[ \"\$file\" == \"..\" ]]; then 127 | echo \"󱧰 Move up to parent directory\" 128 | elif [[ -d \"\$file\" ]]; then 129 | echo \"󰉋 Folder: \$file\" 130 | echo \"\" 131 | $list_command \"\$file\" 2>/dev/null 132 | elif [[ -f \"\$file\" ]]; then 133 | echo \"󰈙 File: \$file\" 134 | echo \"\" 135 | $PREVIEW_COMMAND --style=numbers --color=always --line-range :500 \"\$file\" 2>/dev/null || cat \"\$file\" 136 | else 137 | echo \"Invalid selection: \$file\" 138 | fi 139 | ") 140 | 141 | [[ -z "$selection" ]] && break 142 | 143 | if [[ "$selection" == ".." ]]; then 144 | cd .. || break 145 | elif [[ -d "$selection" ]]; then 146 | cd "$selection" || break 147 | elif [[ -f "$selection" ]]; then 148 | open_file "$selection" 149 | else 150 | break 151 | fi 152 | done 153 | } 154 | 155 | # Allow configuration through environment variables 156 | [[ -n "$FZFM_MEDIA_OPENER" ]] && MEDIA_OPENER="$FZFM_MEDIA_OPENER" 157 | [[ -n "$FZFM_TEXT_EDITOR" ]] && TEXT_EDITOR="$FZFM_TEXT_EDITOR" 158 | [[ -n "$FZFM_LIST_COMMAND" ]] && LIST_COMMAND="$FZFM_LIST_COMMAND" 159 | [[ -n "$FZFM_PREVIEW_COMMAND" ]] && PREVIEW_COMMAND="$FZFM_PREVIEW_COMMAND" 160 | 161 | clear 162 | fzfm --------------------------------------------------------------------------------