From 0faf7168f28ce3a116ebe230af65c456c263348b Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Wed, 1 Nov 2023 19:27:39 +0000 Subject: [PATCH 01/46] Add `Open file with` command --- README.md | 5 ++++- fff | 50 ++++++++++++++++++++++++++++++++++++++++++-------- fff.1 | 3 ++- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a17e4a4..ce22c4f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # fff (*Fucking Fast File-Manager*) +## This forks adds an option to open a file with specified program. + img A simple file manager written in `bash`. @@ -120,8 +122,9 @@ k: scroll up h: go to parent dir l: go to child dir -enter: go to child dir +enter: go to child dir/open file backspace: go to parent dir +o: open file with -: Go to previous dir. diff --git a/fff b/fff index 16766e3..82fedcd 100755 --- a/fff +++ b/fff @@ -592,6 +592,13 @@ open() { redraw full elif [[ -f $1 ]]; then + # If 'fff' was opened as a file picker, save the opened + # file in a file called 'opened_file'. + ((file_picker == 1)) && { + printf '%s\n' "$1" > \ + "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/opened_file" + exit + } # Figure out what kind of file we're working with. get_mime_type "$1" @@ -599,14 +606,6 @@ open() { # Everything else goes through 'xdg-open'/'open'. case "$mime_type" in text/*|*x-empty*|*json*) - # If 'fff' was opened as a file picker, save the opened - # file in a file called 'opened_file'. - ((file_picker == 1)) && { - printf '%s\n' "$1" > \ - "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/opened_file" - exit - } - clear_screen reset_terminal "${VISUAL:-${EDITOR:-vi}}" "$1" @@ -625,6 +624,31 @@ open() { fi } +open_with() { + # Open directories and files. + if [[ -d $1/ ]]; then + search= + search_end_early= + cd "${1:-/}" ||: + redraw full + + elif [[ -f $1 ]]; then + # If 'fff' was opened as a file picker, save the opened + # file in a file called 'opened_file'. + ((file_picker == 1)) && { + printf '%s\n' "$1" > \ + "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/opened_file" + exit + } + + clear_screen + reset_terminal + "$2" "$1" + setup_terminal + redraw + fi +} + cmd_line() { # Write to the command_line (under status_line). cmd_reply= @@ -1024,6 +1048,16 @@ key() { open "$PWD" ;; + # Open file with. + ${FFF_KEY_OPEN_WITH:=o}) + [[ -e "${list[scroll]}" ]] && { + cmd_line "open with: " "cmd" + + [[ $cmd_reply ]] && + open_with "${list[scroll]}" "${cmd_reply}" + } + ;; + # Go to '$HOME'. ${FFF_KEY_GO_HOME:='~'}) open ~ diff --git a/fff.1 b/fff.1 index 7880c30..29e3364 100644 --- a/fff.1 +++ b/fff.1 @@ -16,8 +16,9 @@ k: scroll up h: go to parent dir l: go to child dir -enter: go to child dir +enter: go to child dir/open file backspace: go to parent dir +o: open file with \-: Go to previous dir\. From cb4b431e4aee4e0e4d05f013a663a42365c188f8 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Wed, 1 Nov 2023 19:51:44 +0000 Subject: [PATCH 02/46] Add `Open file with (detached)` option --- README.md | 1 + fff | 11 +++++++++++ fff.1 | 1 + 3 files changed, 13 insertions(+) diff --git a/README.md b/README.md index ce22c4f..2f699fe 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ l: go to child dir enter: go to child dir/open file backspace: go to parent dir o: open file with +O: open file with GUI program detached from file manager -: Go to previous dir. diff --git a/fff b/fff index 82fedcd..cdfb041 100755 --- a/fff +++ b/fff @@ -1058,6 +1058,17 @@ key() { } ;; + # Open file with to run background. + ${FFF_KEY_OPEN_WITH_DETACHED:=O}) + [[ -e "${list[scroll]}" ]] && { + cmd_line "open with (detached): " "cmd" + + [[ $cmd_reply ]] && + nohup "${cmd_reply}" "${list[scroll]}" &>/dev/null & + disown + } + ;; + # Go to '$HOME'. ${FFF_KEY_GO_HOME:='~'}) open ~ diff --git a/fff.1 b/fff.1 index 29e3364..0bb192e 100644 --- a/fff.1 +++ b/fff.1 @@ -19,6 +19,7 @@ l: go to child dir enter: go to child dir/open file backspace: go to parent dir o: open file with +O: open file with GUI program detached from file manager \-: Go to previous dir\. From e851da1d35d3e3cd38fc97478373fd8faa6f45db Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Wed, 1 Nov 2023 21:11:54 +0000 Subject: [PATCH 03/46] Add support for Nerd Fonts devicons --- README.md | 9 +- fff | 352 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 359 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2f699fe..03c2514 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # fff (*Fucking Fast File-Manager*) -## This forks adds an option to open a file with specified program. +## This forks adds an option to open a file with specified program and Nerd Fonts devicons suport. img @@ -182,6 +182,10 @@ Ctrl+C: exit without 'cd'. # (Off by default) export FFF_HIDDEN=1 +# Show/Hide file icons on open +# (Off by default) +export FFF_FILE_ICON=1 + # Use LS_COLORS to color fff. # (On by default if available) # (Ignores FFF_COL1) @@ -339,6 +343,9 @@ export FFF_KEY_EXECUTABLE="X" # Toggle hidden files. export FFF_KEY_HIDDEN="." + +# Toggle file icons +export FFF_DISPLAY_ICON="I" ``` ### Disabling keybindings. diff --git a/fff b/fff index cdfb041..a2de3fc 100755 --- a/fff +++ b/fff @@ -154,6 +154,347 @@ get_mime_type() { mime_type=$(file "-${file_flags:-biL}" "$1" 2>/dev/null) } +get_icon() { + # $1 Absolute path to the file + # $2 name of the file/directory + # $3 the extracted extension from the file name + printf ' ' + + # Icons for directories + [[ -d "$1" ]] && { + case "$2" in + # English + '.git' ) printf -- ''; return ;; + 'Desktop' ) printf -- ''; return ;; + 'Documents' ) printf -- ''; return ;; + 'Downloads' ) printf -- ''; return ;; + 'Dotfiles' ) printf -- ''; return ;; + 'Dropbox' ) printf -- ''; return ;; + 'Music' ) printf -- ''; return ;; + 'Pictures' ) printf -- ''; return ;; + 'Public' ) printf -- ''; return ;; + 'Templates' ) printf -- ''; return ;; + 'Videos' ) printf -- ''; return ;; + + # Spanish + 'Escritorio' ) printf -- ''; return ;; + 'Documentos' ) printf -- ''; return ;; + 'Descargas' ) printf -- ''; return ;; + 'Música' ) printf -- ''; return ;; + 'Imágenes' ) printf -- ''; return ;; + 'Público' ) printf -- ''; return ;; + 'Plantillas' ) printf -- ''; return ;; + 'Vídeos' ) printf -- ''; return ;; + # French + 'Bureau' ) printf -- ''; return ;; + 'Images' ) printf -- ''; return ;; + 'Musique' ) printf -- ''; return ;; + 'Publique' ) printf -- ''; return ;; + 'Téléchargements' ) printf -- ''; return ;; + 'Vidéos' ) printf -- ''; return ;; + # Portuguese + 'Imagens' ) printf -- ''; return ;; + 'Modelos' ) printf -- ''; return ;; + 'Área de trabalho') printf -- ''; return ;; + # Italian + 'Documenti' ) printf -- ''; return ;; + 'Immagini' ) printf -- ''; return ;; + 'Modelli' ) printf -- ''; return ;; + 'Musica' ) printf -- ''; return ;; + 'Pubblici' ) printf -- ''; return ;; + 'Scaricati' ) printf -- ''; return ;; + 'Scrivania' ) printf -- ''; return ;; + 'Video' ) printf -- ''; return ;; + # German + 'Bilder' ) printf -- ''; return ;; + 'Dokumente' ) printf -- ''; return ;; + 'Musik' ) printf -- ''; return ;; + 'Schreibtisch' ) printf -- ''; return ;; + 'Vorlagen' ) printf -- ''; return ;; + 'Öffentlich' ) printf -- ''; return ;; + # Hungarian + 'Dokumentumok' ) printf -- ''; return ;; + 'Képek' ) printf -- ''; return ;; + 'Zene' ) printf -- ''; return ;; + 'Letöltések' ) printf -- ''; return ;; + 'Videók' ) printf -- ''; return ;; + 'Számítógép' ) printf -- ''; return ;; + + * ) printf -- ''; return ;; + esac + } + + # Icons for files with no extension + [[ "$2" == *"/$3" ]] && { + case "$2" in + '_gvimrc' | '_vimrc' |\ + 'bspwmrc' |'cmakelists.txt'|\ + 'config' | 'Makefile' |\ + 'makefile' | 'sxhkdrc' |\ + 'ini' ) printf -- ''; return ;; + + 'authorized_keys' |\ + 'known_hosts' |\ + 'license' |\ + 'LICENSE' ) printf -- ''; return ;; + + 'gemfile' |\ + 'Rakefile' |\ + 'rakefile' ) printf -- ''; return ;; + + 'a.out' |\ + 'configure' ) printf -- ''; return ;; + + 'dockerfile' ) printf -- ''; return ;; + 'Dockerfile' ) printf -- ''; return ;; + 'dropbox' ) printf -- ''; return ;; + 'exact-match-case-sensitive-2' ) printf -- 'X2'; return ;; + 'ledger' ) printf -- ''; return ;; + 'node_modules' ) printf -- ''; return ;; + 'playlists' ) printf -- ''; return ;; + 'procfile' ) printf -- ''; return ;; + 'README' ) printf -- ''; return ;; + '*' ) printf -- ''; return ;; + esac + } + + # Icon for files with the name starting with '.' + # without an extension + [[ "$2" == ".$3" ]] && { + case "$2" in + '.bash_aliases' |\ + '.bash_history' |\ + '.bash_logout' |\ + '.bash_profile' |\ + '.bashprofile' |\ + '.bashrc' |\ + '.dmrc' |\ + '.DS_Store' |\ + '.fasd' |\ + '.gitattributes' |\ + '.gitconfig' |\ + '.gitignore' |\ + '.inputrc' |\ + '.jack-settings' |\ + '.nvidia-settings-rc' |\ + '.pam_environment' |\ + '.profile' |\ + '.recently-used' |\ + '.selected_editor' |\ + '.Xauthority' |\ + '.Xdefaults' |\ + '.xinitrc' |\ + '.xinputrc' |\ + '.Xresources' |\ + '.zshrc' ) printf -- ''; return ;; + + '.vim' |\ + '.viminfo' |\ + '.vimrc' ) printf -- ''; return ;; + + '.fehbg' ) printf -- ''; return ;; + '.gvimrc' ) printf -- ''; return ;; + '.ncmpcpp' ) printf -- ''; return ;; + + '*' ) printf -- ''; return ;; + esac + } + + # Icon for files whose names have an extension + [[ "$2" == *"."* ]] && { + case "$2" in + 'cmakelists.txt' |\ + 'Makefile.ac' |\ + 'Makefile.in' |\ + 'mimeapps.list' |\ + 'user-dirs.dirs' ) printf -- ''; return ;; + + 'README.markdown' |\ + 'README.md' |\ + 'README.rst' |\ + 'README.txt' ) printf -- ''; return ;; + + 'config.ac' |\ + 'config.m4' |\ + 'config.mk' ) printf -- ''; return ;; + + 'gruntfile.coffee' |\ + 'gruntfile.js' |\ + 'gruntfile.ls' ) printf -- ''; return ;; + + 'package-lock.json' |\ + 'package.json' |\ + 'webpack.config.js' ) printf -- ''; return ;; + + 'gulpfile.coffee' |\ + 'gulpfile.js' |\ + 'gulpfile.ls' ) printf -- ''; return ;; + + 'LICENSE.txt' |\ + 'LICENSE.md' ) printf -- ''; return ;; + + + '.gitlab-ci.yml' ) printf -- ''; return ;; + 'config.ru' ) printf -- ''; return ;; + 'docker-compose.yml' ) printf -- ''; return ;; + 'exact-match-case-sensitive-1.txt' ) printf -- 'X1'; return ;; + 'favicon.ico' ) printf -- ''; return ;; + 'mix.lock' ) printf -- ''; return ;; + 'react.jsx' ) printf -- ''; return ;; + esac + + case "$3" in + '7z' | 'apk' |\ + 'bz2' | 'cab' |\ + 'cpio'| 'deb' |\ + 'gem' | 'gz' |\ + 'gzip'| 'lha' |\ + 'lzh' | 'lzma' |\ + 'rar' | 'rpm' |\ + 'tar' | 'tgz' |\ + 'xbps'| 'xz' |\ + 'zip' ) printf -- ''; return ;; + + 'bat' | 'conf' |\ + 'cvs' |\ + 'htaccess' |\ + 'htpasswd' |\ + 'ini' | 'rc' |\ + 'toml'| 'yaml' |\ + 'yml' ) printf -- ''; return ;; + + 'asp' | 'awk' |\ + 'bash'| 'csh' |\ + 'efi' | 'elf' |\ + 'fish'| 'ksh' |\ + 'ps1' | 'rom' |\ + 'zsh' ) printf -- ''; return ;; + + 'avi' | 'flv' |\ + 'm4v' | 'mkv' |\ + 'mov' | 'mp4' |\ + 'mpeg'| 'mpg' |\ + 'webm' ) printf -- ''; return ;; + + + 'bmp' | 'gif' |\ + 'ico' | 'jpeg' |\ + 'jpg' | 'png' |\ + 'ppt' | 'pptx' |\ + 'webp' ) printf -- ''; return ;; + + 'aup' | 'cue' |\ + 'flac'| 'm4a' |\ + 'mp3' | 'ogg' |\ + 'wav' ) printf -- ''; return ;; + + 'c' | 'c++' |\ + 'cc' | 'cp' |\ + 'cpp' | 'cxx' |\ + 'h' | 'hpp' ) printf -- ''; return ;; + + 'docx'| 'doc' |\ + 'epub'| 'pdf' |\ + 'rtf' | 'xls' |\ + 'xlsx' ) printf -- ''; return ;; + + 'ejs' | 'haml' |\ + 'htm' | 'html' |\ + 'slim'| 'xhtml'|\ + 'xml' ) printf -- ''; return ;; + + 'a' | 'cmake' |\ + 'jl' | 'o' |\ + 'so' ) printf -- ''; return ;; + + 'asm' | 'css' |\ + 'less'| 's' |\ + 'sh' ) printf -- ''; return ;; + + 'db' | 'dump' |\ + 'img' | 'iso' |\ + 'sql' ) printf -- ''; return ;; + + 'f#' | 'fs' |\ + 'fsi' | 'fsx' |\ + 'fsscript' ) printf -- ''; return ;; + + 'markdown' |\ + 'md' | 'mdx' |\ + 'rmd' ) printf -- ''; return ;; + + 'gemspec' |\ + 'rake'| 'rb' ) printf -- ''; return ;; + + 'dll' | 'exe' |\ + 'msi' ) printf -- ''; return ;; + + 'eex' | 'ex' |\ + 'exs' | 'leex' ) printf -- ''; return ;; + + 'class' |\ + 'jar' | 'java' ) printf -- ''; return ;; + + 'mustache' |\ + 'hbs' ) printf -- ''; return ;; + + 'json' |\ + 'webmanifest' ) printf -- ''; return ;; + + 'py' | 'pyc' |\ + 'pyd' | 'pyo' ) printf -- ''; return ;; + + 'cbr' | 'cbz' ) printf -- ''; return ;; + 'clj' | 'cljc' ) printf -- ''; return ;; + 'cljs'| 'edn' ) printf -- ''; return ;; + 'hrl' | 'erl' ) printf -- ''; return ;; + 'hh' | 'hxx' ) printf -- ''; return ;; + 'hs' | 'lhs' ) printf -- ''; return ;; + 'js' | 'mjs' ) printf -- ''; return ;; + 'jsx' | 'tsx' ) printf -- ''; return ;; + 'key' | 'pub' ) printf -- ''; return ;; + 'ml' | 'mli' ) printf -- 'λ'; return ;; + 'pl' | 'pm' ) printf -- ''; return ;; + 'vim' | 'vimrc' ) printf -- ''; return ;; + 'psb' | 'psd' ) printf -- ''; return ;; + 'rlib'| 'rs' ) printf -- ''; return ;; + 'sass'| 'scss' ) printf -- ''; return ;; + 'sln' | 'suo' ) printf -- ''; return ;; + + 'coffee' ) printf -- ''; return ;; + 'ai' ) printf -- ''; return ;; + 'cs' ) printf -- ''; return ;; + 'd' ) printf -- ''; return ;; + 'dart' ) printf -- ''; return ;; + 'diff' ) printf -- ''; return ;; + 'elm' ) printf -- ''; return ;; + 'fi' ) printf -- '|'; return ;; + 'go' ) printf -- ''; return ;; + 'log' ) printf -- ''; return ;; + 'lua' ) printf -- ''; return ;; + 'nix' ) printf -- ''; return ;; + 'php' ) printf -- ''; return ;; + 'pp' ) printf -- ''; return ;; + 'r' ) printf -- 'ﳒ'; return ;; + 'rproj' ) printf -- '鉶'; return ;; + 'rss' ) printf -- ''; return ;; + 'scala' ) printf -- ''; return ;; + 'styl' ) printf -- ''; return ;; + 'swift' ) printf -- ''; return ;; + 't' ) printf -- ''; return ;; + 'tex' ) printf -- 'ﭨ'; return ;; + 'ts' ) printf -- ''; return ;; + 'twig' ) printf -- ''; return ;; + 'vue' ) printf -- '﵂'; return ;; + 'xcplayground' ) printf -- ''; return ;; + 'xul' ) printf -- ''; return ;; + esac + } + + + printf -- ''; return +} + status_line() { # Status_line to print when files are marked for operation. local mark_ui="[${#marked_files[@]}] selected (${file_program[*]}) [p] ->" @@ -229,6 +570,7 @@ print_line() { local file_ext=${file_name##*.} local format local suffix + local icon # If the dir item doesn't exist, end here. if [[ -z ${list[$1]} ]]; then @@ -303,8 +645,11 @@ print_line() { # Remove all non-printable characters. file_name=${file_name//[^[:print:]]/^[} + (( ${FFF_FILE_ICON:=0} == 1 )) && \ + icon="$(get_icon "${list[$1]}" "$file_name" "$file_ext") " + printf '\r%b%s\e[m\r' \ - "${file_pre}${format}" \ + "${file_pre}${format}${icon}"\ "${file_name}${suffix}${file_post}" } @@ -1074,6 +1419,11 @@ key() { open ~ ;; + ${FFF_DISPLAY_ICON:='I'}) + FFF_FILE_ICON=$(( $((FFF_FILE_ICON + 1)) % 2 )) + redraw + ;; + # Go to trash. ${FFF_KEY_GO_TRASH:=t}) get_os From 937b3c85bdd1f3da95dfc5ab0f717f60c8ebc443 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Wed, 1 Nov 2023 23:29:35 +0000 Subject: [PATCH 04/46] Add help page and update README --- README.md | 24 +++----- fff | 158 +++++++++++++++++++++++++++++++++++++++++++++++++---- fff.1 | 2 + icon_value | 1 + 4 files changed, 158 insertions(+), 27 deletions(-) create mode 100644 icon_value diff --git a/README.md b/README.md index 03c2514..13d9475 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# fff (*Fucking Fast File-Manager*) +# fff (*Fucking Fine File-Manager*) -## This forks adds an option to open a file with specified program and Nerd Fonts devicons suport. +### This fork is meant to make fff a more feature-rich file manager, but at cost of raw speed. img @@ -10,16 +10,16 @@ A simple file manager written in `bash`. Packaging status -- It's Fucking Fast 🚀 +- It's Fucking Fine :) - Minimal (*only requires **bash** and coreutils*) - Smooth Scrolling (*using **vim** keybindings*) -- Works on **Linux**, **BSD**, **macOS**, **Haiku** etc. +- Works on **Linux** (and others?). +- Supports [Nerd Fonts devicons](https://www.nerdfonts.com/#home). - Supports `LS_COLORS`! - File Operations (*copy, paste, cut, **ranger style bulk rename**, etc*) img - Instant as you type search - Tab completion for all commands! - Automatic CD on exit (*see [setup](#cd-on-exit)*) -- Works as a **file picker** in `vim`/`neovim` ([**link**](https://github.com/dylanaraps/fff.vim))! - **Display images with w3m-img!** - Supports `$CDPATH`. @@ -67,20 +67,9 @@ A simple file manager written in `bash`. ## Installation -### Distros - -- KISS Linux (based): `kiss b fff` -- FreeBSD: `pkg install fff` -- Haiku: `pkgman install fff` -- macOS: `brew install fff` -- Nix: `nix-env -iA fff` -- Void Linux: `xbps-install -S fff` -- Arch Linux: `pacman -S fff` - ### Manual 1. Download `fff`. - - Release: https://github.com/dylanaraps/fff/releases/latest - Git: `git clone https://github.com/dylanaraps/fff` 2. Change working directory to `fff`. - `cd fff` @@ -89,6 +78,7 @@ A simple file manager written in `bash`. - **Haiku**: `make PREFIX="$(finddir B_USER_NONPACKAGED_DIRECTORY)" MANDIR='$(PREFIX)/documentation/man' DOCDIR='$(PREFIX)/documentation/fff' install` - **OpenIndiana**: `gmake install` - **MinGW/MSys**: `make -i install` + - **Others**: `make install` - **NOTE**: You may have to run this as root. **NOTE:** `fff` can be uninstalled easily using `make uninstall`. This removes all of files from your system. @@ -173,6 +163,8 @@ c: clear file selections q: exit with 'cd' (if enabled). Ctrl+C: exit without 'cd'. + +?: show help ``` ## Customization diff --git a/fff b/fff index a2de3fc..104fe89 100755 --- a/fff +++ b/fff @@ -90,6 +90,8 @@ setup_options() { # Find supported 'file' arguments. file -I &>/dev/null || : "${file_flags:=biL}" + + helping=0 } get_term_size() { @@ -286,6 +288,7 @@ get_icon() { '.xinitrc' |\ '.xinputrc' |\ '.Xresources' |\ + '.zsh_history' |\ '.zshrc' ) printf -- ''; return ;; '.vim' |\ @@ -374,7 +377,7 @@ get_icon() { 'm4v' | 'mkv' |\ 'mov' | 'mp4' |\ 'mpeg'| 'mpg' |\ - 'webm' ) printf -- ''; return ;; + 'webm' ) printf -- ''; return ;; 'bmp' | 'gif' |\ @@ -498,10 +501,18 @@ get_icon() { status_line() { # Status_line to print when files are marked for operation. local mark_ui="[${#marked_files[@]}] selected (${file_program[*]}) [p] ->" + mark_ui="${marked_files[*]:+"$mark_ui"}" # Escape the directory string. # Remove all non-printable characters. - PWD_escaped=${PWD//[^[:print:]]/^[} + if ((helping)); then + mark_ui= + PWD_escaped=help + else + # Escape the directory string. + # Remove all non-printable characters. + PWD_escaped=${PWD//[^[:print:]]/^[} + fi # '\e7': Save cursor position. # This is more widely supported than '\e[s'. @@ -521,7 +532,7 @@ status_line() { "${FFF_COL2:-1}" \ "$COLUMNS" "" \ "($((scroll+1))/$((list_total+1)))" \ - "${marked_files[*]:+${mark_ui}}" \ + "$mark_ui" \ "${1:-${PWD_escaped:-/}}" \ "$LINES" } @@ -572,8 +583,20 @@ print_line() { local suffix local icon + # Help line + if ((helping)); then + file_name=${list[$1]} + if [[ "$file_name" ]]; then + # Highlight the key(s), escaping any specials in overrides to a human-readable form + format+=\\e[${di:-1;3${FFF_COL1:-2}}m + local action="${file_name%: *}" + format+="$(cat -A <<<"$action" | head -c -2)\\e[${fi:-37}m: " + file_name="${file_name##*: }" + fi + format+=\\e[${fi:-37}m + # If the dir item doesn't exist, end here. - if [[ -z ${list[$1]} ]]; then + elif [[ -z ${list[$1]} ]]; then return # Directory. @@ -636,7 +659,7 @@ print_line() { format+="\\e[1;3${FFF_COL4:-6};7m" # If the list item is marked for operation. - [[ ${marked_files[$1]} == "${list[$1]:-null}" ]] && { + !((helping)) && [[ ${marked_files[$1]} == "${list[$1]:-null}" ]] && { format+=\\e[3${FFF_COL3:-1}m${mark_pre} suffix+=${mark_post} } @@ -795,15 +818,101 @@ redraw() { # Redraw the current window. # If 'full' is passed, re-fetch the directory list. [[ $1 == full ]] && { + ((helping)) && { + helping=0 + find_previous=1 + } read_dir scroll=0 } + # If 'help' is passed, list help text. + [[ $1 == help ]] && { + helping=1 + list_help + scroll=0 + } + clear_screen draw_dir status_line } +list_help() { + # Set window name. + printf '\e]2;fff: help\e'\\ + + # Turn off icons. + icon_value="$(printf '%s\n' "$FFF_FILE_ICON")" + FFF_FILE_ICON=0 + + list=( + "${FFF_KEY_SCROLL_DOWN1:-j}: scroll down" + "${FFF_KEY_SCROLL_UP1:-k}: scroll up" + "${FFF_KEY_PARENT1:-h}: go to parent dir" + "${FFF_KEY_CHILD1:-l}: go to child dir" + '' + 'enter: go to child dir/open file' + 'backspace: go to parent dir' + "${FFF_KEY_OPEN_WITH:=o}: open file with" + "${FFF_KEY_OPEN_WITH_DETACHED:=O}: open file with GUI program detached from file manager" + '' + "${FFF_KEY_PREVIOUS:--}: go to previous dir" + '' + "${FFF_KEY_TO_TOP:-g}: go to top" + "${FFF_KEY_TO_BOTTOM:-G}: go to bottom" + '' + "${FFF_KEY_GO_DIR:-:}: go to a directory by typing" + '' + "${FFF_KEY_HIDDEN:-.}: toggle hidden files" + "${FFF_KEY_SEARCH:-/}: search" + "${FFF_KEY_GO_TRASH:-t}: go to trash" + "${FFF_KEY_GO_HOME:-~}: go to home" + "${FFF_KEY_REFRESH:-e}: refresh current dir" + "${FFF_KEY_SHELL:-!}: open shell in current dir" + '' + "${FFF_KEY_ATTRIBUTES:-x}: view file/dir attributes" + "${FFF_KEY_IMAGE:-i}: display image with w3m-img" + '' + 'down: scroll down' + 'up: scroll up' + 'left: go to parent dir' + 'right: go to child dir' + '' + "${FFF_KEY_MKFILE:-f}: new file" + "${FFF_KEY_MKDIR:-n}: new dir" + "${FFF_KEY_RENAME:-r}: rename" + "${FFF_KEY_EXECUTABLE:-X}: toggle executable" + '' + "${FFF_KEY_YANK:-y}: mark copy" + "${FFF_KEY_MOVE:-m}: mark move" + "${FFF_KEY_TRASH:-d}: mark trash (~/.local/share/fff/trash/)" + "${FFF_KEY_LINK:-s}: mark symbolic link" + "${FFF_KEY_BULK_RENAME:-b}: mark bulk rename" + '' + "${FFF_KEY_YANK_ALL:-Y}: mark all for copy" + "${FFF_KEY_MOVE_ALL:-M}: mark all for move" + "${FFF_KEY_TRASH_ALL:-D}: mark all for trash (~/.local/share/fff/trash/)" + "${FFF_KEY_LINK_ALL:-S}: mark all for symbolic link" + "${FFF_KEY_BULK_RENAME_ALL:-B}: mark all for bulk rename" + '' + "${FFF_KEY_PASTE:-p}: paste/move/delete/bulk_rename" + "${FFF_KEY_CLEAR:-c}: clear file selections" + '' + '[1-9]: favourites/bookmarks (see customization in man page)' + '' + "q: exit with 'cd' (if enabled) or exit this help" + "Ctrl+C: exit without 'cd'" + '' + "${FFF_KEY_HELP:-?}: show this help" + ) + + ((list_total=${#list[@]}-1)) + + # Save the original list in a second list as a backup. + cur_list=("${list[@]}") +} + mark() { # Mark file for operation. # If an item is marked in a second directory, @@ -1017,6 +1126,8 @@ cmd_line() { # Tab. $'\t') + ((helping)) && return + comp_glob="$cmd_reply*" # Pass the argument dirs to limit completion to directories. @@ -1045,7 +1156,7 @@ cmd_line() { "") # If there's only one search result and its a directory, # enter it on one enter keypress. - [[ $2 == search && -d ${list[0]} ]] && ((list_total == 0)) && { + !((helping)) && [[ $2 == search && -d ${list[0]} ]] && ((list_total == 0)) && { # '\e[?25l': Hide the cursor. printf '\e[?25l' @@ -1086,7 +1197,15 @@ cmd_line() { printf '\e[?25l' # Use a greedy glob to search. - list=("$PWD"/*"$cmd_reply"*) + if ((helping)); then + local item + list=() + for item in "${cur_list[@]}"; do + [[ "$item" == *"$cmd_reply"* ]] && list+=("$item") + done + else + list=("$PWD"/*"$cmd_reply"*) + fi ((list_total=${#list[@]}-1)) # Draw the search results on screen. @@ -1121,6 +1240,10 @@ key() { } case ${special_key:-$1} in + "${FFF_KEY_HELP:=?}") + redraw help + ;; + # Open list item. # 'C' is what bash sees when the right arrow is pressed # ('\e[C' or '\eOC'). @@ -1129,6 +1252,8 @@ key() { ${FFF_KEY_CHILD2:=$'\e[C'}|\ ${FFF_KEY_CHILD3:=""}|\ ${FFF_KEY_CHILD4:=$'\eOC'}) + ((helping)) && return + open "${list[scroll]}" ;; @@ -1142,6 +1267,8 @@ key() { ${FFF_KEY_PARENT3:=$'\177'}|\ ${FFF_KEY_PARENT4:=$'\b'}|\ ${FFF_KEY_PARENT5:=$'\eOD'}) + ((helping)) && return + # If a search was done, clear the results and open the current dir. if ((search == 1 && search_end_early != 1)); then open "$PWD" @@ -1159,7 +1286,7 @@ key() { ${FFF_KEY_SCROLL_DOWN1:=j}|\ ${FFF_KEY_SCROLL_DOWN2:=$'\e[B'}|\ ${FFF_KEY_SCROLL_DOWN3:=$'\eOB'}) - ((scroll < list_total)) && { + while ((scroll < list_total)); do ((scroll++)) ((y < max_items)) && ((y++)) @@ -1167,7 +1294,9 @@ key() { printf '\n' print_line "$scroll" status_line - } + + [[ "${list[scroll]}" ]] && break + done ;; # Scroll up. @@ -1178,7 +1307,7 @@ key() { ${FFF_KEY_SCROLL_UP3:=$'\eOA'}) # '\e[1L': Insert a line above the cursor. # '\e[A': Move cursor up a line. - ((scroll > 0)) && { + while ((scroll > 0)); do ((scroll--)) print_line "$((scroll+1))" @@ -1192,7 +1321,9 @@ key() { print_line "$scroll" status_line - } + + [[ "${list[scroll]}" ]] && break + done ;; # Go to top. @@ -1453,6 +1584,11 @@ key() { # Don't allow user to redefine 'q' so a bad keybinding doesn't # remove the option to quit. q) + ((helping)) && { + FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. + redraw full + return + } : "${FFF_CD_FILE:=${XDG_CACHE_HOME:=${HOME}/.cache}/fff/.fff_d}" [[ -w $FFF_CD_FILE ]] && diff --git a/fff.1 b/fff.1 index 0bb192e..69a00c2 100644 --- a/fff.1 +++ b/fff.1 @@ -67,6 +67,8 @@ c: clear file selections q: exit with 'cd' (if enabled). Ctrl+C: exit without 'cd'. + +?: show help . .fi . diff --git a/icon_value b/icon_value new file mode 100644 index 0000000..863f422 --- /dev/null +++ b/icon_value @@ -0,0 +1 @@ +declare -x FFF_FILE_ICON="1" From cddb62ab317ce449dc01cd9eb5ed5beaf77916fe Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 2 Nov 2023 08:29:40 +0000 Subject: [PATCH 05/46] Add human-readable size --- README.md | 9 +++++++++ fff | 10 +++++++--- icon_value | 1 - 3 files changed, 16 insertions(+), 4 deletions(-) delete mode 100644 icon_value diff --git a/README.md b/README.md index 13d9475..76deab5 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,15 @@ A simple file manager written in `bash`. - Supports `$CDPATH`. +## Thanks + +Most of code in there is from people how made PRs to fff: + +- Roy Orbitson (help page) +- Sidd Dino (devicons) +- qwool (idea for human-readable size) + + ## Table of Contents diff --git a/fff b/fff index 104fe89..022bc78 100755 --- a/fff +++ b/fff @@ -1252,8 +1252,6 @@ key() { ${FFF_KEY_CHILD2:=$'\e[C'}|\ ${FFF_KEY_CHILD3:=""}|\ ${FFF_KEY_CHILD4:=$'\eOC'}) - ((helping)) && return - open "${list[scroll]}" ;; @@ -1267,7 +1265,6 @@ key() { ${FFF_KEY_PARENT3:=$'\177'}|\ ${FFF_KEY_PARENT4:=$'\b'}|\ ${FFF_KEY_PARENT5:=$'\eOD'}) - ((helping)) && return # If a search was done, clear the results and open the current dir. if ((search == 1 && search_end_early != 1)); then @@ -1489,6 +1486,13 @@ key() { clear_screen status_line "${list[scroll]}" "${FFF_STAT_CMD:-stat}" "${list[scroll]}" + + # Show human-readable size. + printf " Size (human-readable): " + size=$("${FFF_STAT_CMD:-stat}" -c "%s" "${list[scroll]}" | numfmt --to=iec) + printf "$size" + [[ $size =~ [0-9]$ ]] && printf "B" || printf "" # If size is in bytes. + read -ern 1 redraw } diff --git a/icon_value b/icon_value deleted file mode 100644 index 863f422..0000000 --- a/icon_value +++ /dev/null @@ -1 +0,0 @@ -declare -x FFF_FILE_ICON="1" From 1c66017cb19d249e4e72c2015a0c14a094238db5 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 2 Nov 2023 08:54:03 +0000 Subject: [PATCH 06/46] Add git branch to stats --- fff | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fff b/fff index 022bc78..dc5861d 100755 --- a/fff +++ b/fff @@ -1491,7 +1491,12 @@ key() { printf " Size (human-readable): " size=$("${FFF_STAT_CMD:-stat}" -c "%s" "${list[scroll]}" | numfmt --to=iec) printf "$size" - [[ $size =~ [0-9]$ ]] && printf "B" || printf "" # If size is in bytes. + [[ $size =~ [0-9]$ ]] && printf "B\n" || printf "\n" # If size is in bytes. + + # Display git branch. + git_brach=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/\1/p') + [ -n "$git_brach" ] && printf " Git branch: $git_brach" || printf "" + read -ern 1 redraw From 42402f3a0019758f8c6dcd675629e1b5a401fbc8 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 2 Nov 2023 09:07:33 +0000 Subject: [PATCH 07/46] Display git branch on status line --- fff | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fff b/fff index dc5861d..1303547 100755 --- a/fff +++ b/fff @@ -526,6 +526,7 @@ status_line() { # '\e[H\e[K': Clear line below status_line. # '\e8': Restore cursor position. # This is more widely supported than '\e[u'. + git_brach=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/[\1]/p') printf '\e7\e[%sH\e[3%s;4%sm%*s\r%s %s%s\e[m\e[%sH\e[K\e8' \ "$((LINES-1))" \ "${FFF_COL5:-0}" \ @@ -533,7 +534,7 @@ status_line() { "$COLUMNS" "" \ "($((scroll+1))/$((list_total+1)))" \ "$mark_ui" \ - "${1:-${PWD_escaped:-/}}" \ + "${1:-${PWD_escaped:-/} $git_brach}" \ "$LINES" } From d49d00b06687720e28df68ede53ea24142472969 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 2 Nov 2023 09:10:35 +0000 Subject: [PATCH 08/46] Update README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 76deab5..d6c09f2 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,14 @@ A simple file manager written in `bash`. - **Display images with w3m-img!** - Supports `$CDPATH`. +#### Changes to original + +- Devicons support +- Help page on `?` +- Open with commands +- Human-readable size in stats +- Git branch in stats +- Git branch on status line ## Thanks From 36d094d32a4037af567338c33b70013903bfe77d Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 2 Nov 2023 12:32:07 +0000 Subject: [PATCH 09/46] Add git signs --- README.md | 5 +++++ fff | 52 ++++++++++++++++++++++++++++++++++++++++++++++------ fff.1 | 8 ++++++++ 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d6c09f2..749b99f 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ A simple file manager written in `bash`. - Human-readable size in stats - Git branch in stats - Git branch on status line +- Recursive git signs for changed files ## Thanks @@ -195,6 +196,10 @@ export FFF_HIDDEN=1 # (Off by default) export FFF_FILE_ICON=1 +# Show/Hide file icons on open +# (Off by default) +export FFF_GIT_CHANGES=1 + # Use LS_COLORS to color fff. # (On by default if available) # (Ignores FFF_COL1) diff --git a/fff b/fff index 1303547..c29e6f5 100755 --- a/fff +++ b/fff @@ -498,6 +498,14 @@ get_icon() { printf -- ''; return } +git_changes() { + if [[ " ${changed[@]} " =~ " $1 " ]]; then + printf -- '+'; return + else + printf -- ' '; return + fi +} + status_line() { # Status_line to print when files are marked for operation. local mark_ui="[${#marked_files[@]}] selected (${file_program[*]}) [p] ->" @@ -526,7 +534,7 @@ status_line() { # '\e[H\e[K': Clear line below status_line. # '\e8': Restore cursor position. # This is more widely supported than '\e[u'. - git_brach=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/[\1]/p') + git_branch=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/[\1]/p') printf '\e7\e[%sH\e[3%s;4%sm%*s\r%s %s%s\e[m\e[%sH\e[K\e8' \ "$((LINES-1))" \ "${FFF_COL5:-0}" \ @@ -534,7 +542,7 @@ status_line() { "$COLUMNS" "" \ "($((scroll+1))/$((list_total+1)))" \ "$mark_ui" \ - "${1:-${PWD_escaped:-/} $git_brach}" \ + "${1:-${PWD_escaped:-/} $git_branch}" \ "$LINES" } @@ -583,6 +591,7 @@ print_line() { local format local suffix local icon + local git='' # Help line if ((helping)); then @@ -672,8 +681,15 @@ print_line() { (( ${FFF_FILE_ICON:=0} == 1 )) && \ icon="$(get_icon "${list[$1]}" "$file_name" "$file_ext") " + # Check if current dir is a git repo and has changes, then + # display git signs if is. + if [ " $git_branch" != " " ] && [ -n "$git_output" ]; then + (( ${FFF_GIT_CHANGES:=0} == 1 )) && \ + git="$(git_changes "$file_name")" + fi + printf '\r%b%s\e[m\r' \ - "${file_pre}${format}${icon}"\ + "${file_pre}${format}${git}${icon}"\ "${file_name}${suffix}${file_post}" } @@ -816,6 +832,19 @@ draw_img() { } redraw() { + changed=() + git_branch=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/\1/p') + # Check if git branch name is not empty, then get changed files. + if [ " $git_branch" != " " ]; then + git_output=$(git status -s -unormal) + while read -r line; do + # Get elements. + element="${line#* }" + element="${line%%/*}" + changed+=("$element") + done <<< "$git_output" + fi + # Redraw the current window. # If 'full' is passed, re-fetch the directory list. [[ $1 == full ]] && { @@ -1242,6 +1271,12 @@ key() { case ${special_key:-$1} in "${FFF_KEY_HELP:=?}") + ((helping)) && { + FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. + redraw full + return + } + redraw help ;; @@ -1495,9 +1530,7 @@ key() { [[ $size =~ [0-9]$ ]] && printf "B\n" || printf "\n" # If size is in bytes. # Display git branch. - git_brach=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/\1/p') - [ -n "$git_brach" ] && printf " Git branch: $git_brach" || printf "" - + [ -n "$git_branch" ] && printf " Git branch: $git_branch" read -ern 1 redraw @@ -1560,11 +1593,18 @@ key() { open ~ ;; + # Display icons. ${FFF_DISPLAY_ICON:='I'}) FFF_FILE_ICON=$(( $((FFF_FILE_ICON + 1)) % 2 )) redraw ;; + # Display git changes. + ${FFF_GIT_CHANGES:='I'}) + FFF_GIT_CHANGES=$(( $((FFF_GIT_CHANGES + 1)) % 2 )) + redraw + ;; + # Go to trash. ${FFF_KEY_GO_TRASH:=t}) get_os diff --git a/fff.1 b/fff.1 index 69a00c2..e24bc0d 100644 --- a/fff.1 +++ b/fff.1 @@ -85,6 +85,14 @@ export FFF_LS_COLORS=1 # (On by default) export FFF_HIDDEN=0 +# Show/Hide file icons on open +# (Off by default) +export FFF_FILE_ICON=1 + +# Show/Hide file icons on open +# (Off by default) +export FFF_GIT_CHANGES=1 + # Directory color [0\-9] export FFF_COL1=2 From 6382119187ba11635c8fe52f939c344bc8337827 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 2 Nov 2023 16:43:55 +0000 Subject: [PATCH 10/46] Add ncdu integration --- README.md | 7 +++++-- fff | 11 +++++++++++ fff.1 | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 749b99f..21d8f0f 100644 --- a/README.md +++ b/README.md @@ -32,14 +32,16 @@ A simple file manager written in `bash`. - Git branch in stats - Git branch on status line - Recursive git signs for changed files +- `ncdu` integration ## Thanks -Most of code in there is from people how made PRs to fff: +Most of code in there is from people who made PRs and posted issues to fff: - Roy Orbitson (help page) - Sidd Dino (devicons) - qwool (idea for human-readable size) +- Docbroke (ncdu integration) ## Table of Contents @@ -151,6 +153,7 @@ e: refresh current dir x: view file/dir attributes i: display image with w3m-img +u: run ncdu down: scroll down up: scroll up @@ -196,7 +199,7 @@ export FFF_HIDDEN=1 # (Off by default) export FFF_FILE_ICON=1 -# Show/Hide file icons on open +# Show/Hide git status signs on open # (Off by default) export FFF_GIT_CHANGES=1 diff --git a/fff b/fff index c29e6f5..7f3f860 100755 --- a/fff +++ b/fff @@ -1588,6 +1588,17 @@ key() { } ;; + # Run ncdu to get sizes. + ${FFF_NCDU:=u}) + [[ -e "${list[scroll]}" ]] && { + clear_screen + reset_terminal + ncdu "$PWD" + setup_terminal + redraw + } + ;; + # Go to '$HOME'. ${FFF_KEY_GO_HOME:='~'}) open ~ diff --git a/fff.1 b/fff.1 index e24bc0d..ea62996 100644 --- a/fff.1 +++ b/fff.1 @@ -37,6 +37,7 @@ e: refresh current dir x: view file/dir attributes i: display image with w3m-img +u: run ncdu down: scroll down up: scroll up From 2160ac6c8321adcd848bddd91d23eb9628dd4bc6 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 2 Nov 2023 17:02:19 +0000 Subject: [PATCH 11/46] Update README and update devicons code --- README.md | 7 +++++-- fff | 18 +++--------------- fff.1 | 5 +++++ 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 21d8f0f..451cb2c 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,9 @@ Most of code in there is from people who made PRs and posted issues to fff: - Program handling (*non-text*). - *Not needed on macos and Haiku.* - *Customizable (if not using `xdg-open`): `$FFF_OPENER`.* +- `ncdu` (*optional*) +- `Nerd Font` (*optional*) + - Icons **Dependencies for image display** @@ -361,8 +364,8 @@ export FFF_KEY_EXECUTABLE="X" # Toggle hidden files. export FFF_KEY_HIDDEN="." -# Toggle file icons -export FFF_DISPLAY_ICON="I" +# Open ncdu +export FFF_KEY_NCDU="u" ``` ### Disabling keybindings. diff --git a/fff b/fff index 7f3f860..4ceebcb 100755 --- a/fff +++ b/fff @@ -160,7 +160,6 @@ get_icon() { # $1 Absolute path to the file # $2 name of the file/directory # $3 the extracted extension from the file name - printf ' ' # Icons for directories [[ -d "$1" ]] && { @@ -689,7 +688,7 @@ print_line() { fi printf '\r%b%s\e[m\r' \ - "${file_pre}${format}${git}${icon}"\ + "${file_pre}${format}${git} ${icon}"\ "${file_name}${suffix}${file_post}" } @@ -903,6 +902,7 @@ list_help() { '' "${FFF_KEY_ATTRIBUTES:-x}: view file/dir attributes" "${FFF_KEY_IMAGE:-i}: display image with w3m-img" + "${FFF_KEY_NCDU:-u}: open ncdu" '' 'down: scroll down' 'up: scroll up' @@ -1589,7 +1589,7 @@ key() { ;; # Run ncdu to get sizes. - ${FFF_NCDU:=u}) + ${FFF_KEY_NCDU:=u}) [[ -e "${list[scroll]}" ]] && { clear_screen reset_terminal @@ -1604,18 +1604,6 @@ key() { open ~ ;; - # Display icons. - ${FFF_DISPLAY_ICON:='I'}) - FFF_FILE_ICON=$(( $((FFF_FILE_ICON + 1)) % 2 )) - redraw - ;; - - # Display git changes. - ${FFF_GIT_CHANGES:='I'}) - FFF_GIT_CHANGES=$(( $((FFF_GIT_CHANGES + 1)) % 2 )) - redraw - ;; - # Go to trash. ${FFF_KEY_GO_TRASH:=t}) get_os diff --git a/fff.1 b/fff.1 index ea62996..6812a72 100644 --- a/fff.1 +++ b/fff.1 @@ -245,6 +245,11 @@ export FFF_KEY_EXECUTABLE="X" # Toggle hidden files. export FFF_KEY_HIDDEN="." +# Toggle file icons +export FFF_DISPLAY_ICON="I" + +# Open ncdu +export FFF_KEY_NCDU="u" . .fi From 5024427436d0d1e116c0045f8a41e854bbe83b74 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 2 Nov 2023 17:54:57 +0000 Subject: [PATCH 12/46] Add modification date and time --- README.md | 5 +++++ fff | 20 ++++++++++++++++++-- fff.1 | 4 ++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 451cb2c..46714f4 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ A simple file manager written in `bash`. - Git branch on status line - Recursive git signs for changed files - `ncdu` integration +- Modification date and time ## Thanks @@ -206,6 +207,10 @@ export FFF_FILE_ICON=1 # (Off by default) export FFF_GIT_CHANGES=1 +# Show/Hide modification time of file on open +# (Off by default) +export FFF_DATE=1 + # Use LS_COLORS to color fff. # (On by default if available) # (Ignores FFF_COL1) diff --git a/fff b/fff index 4ceebcb..4077935 100755 --- a/fff +++ b/fff @@ -383,7 +383,8 @@ get_icon() { 'ico' | 'jpeg' |\ 'jpg' | 'png' |\ 'ppt' | 'pptx' |\ - 'webp' ) printf -- ''; return ;; + 'webp'| 'GIF' |\ + 'xcf' ) printf -- ''; return ;; 'aup' | 'cue' |\ 'flac'| 'm4a' |\ @@ -687,8 +688,23 @@ print_line() { git="$(git_changes "$file_name")" fi + # Display time and date. + local line='' + (( ${FFF_DATE:=0} == 1 )) && \ + date="$(date -r ${list[$1]} +"%Y-%m-%d" 2> /dev/null)" \ + time="$(date -r ${list[$1]} +"%H:%M" 2> /dev/null)" + + # If there is error, then just print spaces. + if [ "$?" -ne "0" ]; then + (( ${FFF_DATE:=0} == 1 )) && \ + line=' ' + else + date=" ${date} " + time=" ${time} " + fi + printf '\r%b%s\e[m\r' \ - "${file_pre}${format}${git} ${icon}"\ + "${file_pre}${format}${date}${time}${git}${line:${#git}} ${icon}"\ "${file_name}${suffix}${file_post}" } diff --git a/fff.1 b/fff.1 index 6812a72..d600f45 100644 --- a/fff.1 +++ b/fff.1 @@ -94,6 +94,10 @@ export FFF_FILE_ICON=1 # (Off by default) export FFF_GIT_CHANGES=1 +# Show/Hide modification time of file on open +# (Off by default) +export FFF_DATE=1 + # Directory color [0\-9] export FFF_COL1=2 From 585edbd19b8a780a4892a2dd72160d50ab01a7ff Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 2 Nov 2023 18:30:06 +0000 Subject: [PATCH 13/46] Add sorting option and keybind --- README.md | 43 ++++++++++++++++++------------------------- fff | 14 ++++++++++++++ fff.1 | 9 +++++++++ 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 46714f4..0fdc6fc 100644 --- a/README.md +++ b/README.md @@ -4,28 +4,9 @@ img -A simple file manager written in `bash`. - - - -Packaging status - -- It's Fucking Fine :) -- Minimal (*only requires **bash** and coreutils*) -- Smooth Scrolling (*using **vim** keybindings*) -- Works on **Linux** (and others?). -- Supports [Nerd Fonts devicons](https://www.nerdfonts.com/#home). -- Supports `LS_COLORS`! -- File Operations (*copy, paste, cut, **ranger style bulk rename**, etc*) img -- Instant as you type search -- Tab completion for all commands! -- Automatic CD on exit (*see [setup](#cd-on-exit)*) -- **Display images with w3m-img!** -- Supports `$CDPATH`. - -#### Changes to original - -- Devicons support +### Changes to original + +- [Nerd Fonts devicons](https://www.nerdfonts.com/#home) support - Help page on `?` - Open with commands - Human-readable size in stats @@ -34,15 +15,16 @@ A simple file manager written in `bash`. - Recursive git signs for changed files - `ncdu` integration - Modification date and time +- Sort files by modification time or alphabetically -## Thanks +### Thanks -Most of code in there is from people who made PRs and posted issues to fff: +A big part of code in there is from people who made PRs and posted issues to fff: - Roy Orbitson (help page) - Sidd Dino (devicons) - qwool (idea for human-readable size) -- Docbroke (ncdu integration) +- Docbroke (ncdu integration, sorting) ## Table of Contents @@ -138,6 +120,7 @@ l: go to child dir enter: go to child dir/open file backspace: go to parent dir + o: open file with O: open file with GUI program detached from file manager @@ -155,6 +138,7 @@ t: go to trash e: refresh current dir !: open shell in current dir +I: sort files x: view file/dir attributes i: display image with w3m-img u: run ncdu @@ -211,6 +195,12 @@ export FFF_GIT_CHANGES=1 # (Off by default) export FFF_DATE=1 +# Default method to sort files on open +# 0 - alphabetically +# 1 - modification time +# (0 by default) +export FFF_SORT_METHOD=1 + # Use LS_COLORS to color fff. # (On by default if available) # (Ignores FFF_COL1) @@ -360,6 +350,9 @@ export FFF_KEY_IMAGE="i" # display image with w3m-img ### Miscellaneous +# Sort files. +export FFF_KEY_SORT="I" + # Show file attributes. export FFF_KEY_ATTRIBUTES="x" diff --git a/fff b/fff index 4077935..e720fcf 100755 --- a/fff +++ b/fff @@ -92,6 +92,7 @@ setup_options() { file -I &>/dev/null || : "${file_flags:=biL}" helping=0 + sort=${FFF_SORT_METHOD:=0} } get_term_size() { @@ -572,6 +573,10 @@ read_dir() { fi done + [ $sort == 1 ] && \ + dirs=($(stat -c '%Y=%n' "${dirs[@]}" | sort -nr | cut -d '=' -f2)) \ + files=($(stat -c '%Y=%n' "${files[@]}" | sort -nr | cut -d '=' -f2)) + list=("${dirs[@]}" "${files[@]}") # Indicate that the directory is empty. @@ -899,6 +904,7 @@ list_help() { '' 'enter: go to child dir/open file' 'backspace: go to parent dir' + '' "${FFF_KEY_OPEN_WITH:=o}: open file with" "${FFF_KEY_OPEN_WITH_DETACHED:=O}: open file with GUI program detached from file manager" '' @@ -916,6 +922,7 @@ list_help() { "${FFF_KEY_REFRESH:-e}: refresh current dir" "${FFF_KEY_SHELL:-!}: open shell in current dir" '' + "${FFF_KEY_SORT:-I} sort files" "${FFF_KEY_ATTRIBUTES:-x}: view file/dir attributes" "${FFF_KEY_IMAGE:-i}: display image with w3m-img" "${FFF_KEY_NCDU:-u}: open ncdu" @@ -1626,6 +1633,13 @@ key() { open "$FFF_TRASH" ;; + # Sort by name (0) time (1). + ${FFF_KEY_SORT:=I}) + [ $sort == 0 ] && sort=1 || sort=0 + + open "$PWD" + ;; + # Go to previous dir. ${FFF_KEY_PREVIOUS:=-}) open "$OLDPWD" diff --git a/fff.1 b/fff.1 index d600f45..e157051 100644 --- a/fff.1 +++ b/fff.1 @@ -98,6 +98,12 @@ export FFF_GIT_CHANGES=1 # (Off by default) export FFF_DATE=1 +# Default method to sort files on open +# 0 - alphabetically +# 1 - modification time +# (0 by default) +export FFF_SORT_METHOD=1 + # Directory color [0\-9] export FFF_COL1=2 @@ -240,6 +246,9 @@ export FFF_KEY_MKFILE="f" ### Miscellaneous +# Sort files. +export FFF_KEY_SORT="I" + # Show file attributes. export FFF_KEY_ATTRIBUTES="x" From 865465c2797f1a27a51667d1e3b14c5e0e3007e0 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 2 Nov 2023 20:11:44 +0000 Subject: [PATCH 14/46] Add option to see file details --- README.md | 5 +++++ fff | 42 ++++++++++++++++++++++++++++++------------ fff.1 | 7 +++++++ 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 0fdc6fc..62fac4e 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ t: go to trash e: refresh current dir !: open shell in current dir +N: display file details I: sort files x: view file/dir attributes i: display image with w3m-img @@ -201,6 +202,10 @@ export FFF_DATE=1 # (0 by default) export FFF_SORT_METHOD=1 +# Show/Hide file details on open +# (Off by default) +export FFF_FILE_DETAILS=1 + # Use LS_COLORS to color fff. # (On by default if available) # (Ignores FFF_COL1) diff --git a/fff b/fff index e720fcf..26193dc 100755 --- a/fff +++ b/fff @@ -93,6 +93,7 @@ setup_options() { helping=0 sort=${FFF_SORT_METHOD:=0} + details=${FFF_FILE_DETAILS:=0} } get_term_size() { @@ -693,23 +694,32 @@ print_line() { git="$(git_changes "$file_name")" fi - # Display time and date. - local line='' - (( ${FFF_DATE:=0} == 1 )) && \ - date="$(date -r ${list[$1]} +"%Y-%m-%d" 2> /dev/null)" \ - time="$(date -r ${list[$1]} +"%H:%M" 2> /dev/null)" + # Display details (date, time and file size). + if (( details == 1 )); then + local line=' ' - # If there is error, then just print spaces. - if [ "$?" -ne "0" ]; then - (( ${FFF_DATE:=0} == 1 )) && \ - line=' ' + file_size=$("${FFF_STAT_CMD:-stat}" -c "%s" "${list[$1]}" | numfmt --to=iec) + date="$(date -r ${list[$1]} +"%Y-%m-%d %H:%M" 2> /dev/null)" + + # If there is error, then just print space to align file names. + if [ "$?" -ne "0" ]; then + date=" " + line=' ' + else + date=" ${date} " + file_size=" ${file_size}B " + fi else - date=" ${date} " - time=" ${time} " + file_size='' + date='' + line='' fi + # ${file_size}${line:${#file_size}} + # https://stackoverflow.com/a/4411098 + # This basically makes the file size and file name align. printf '\r%b%s\e[m\r' \ - "${file_pre}${format}${date}${time}${git}${line:${#git}} ${icon}"\ + "${file_pre}${format}${date}${file_size}${line:${#file_size}}${git} ${icon}"\ "${file_name}${suffix}${file_post}" } @@ -922,6 +932,7 @@ list_help() { "${FFF_KEY_REFRESH:-e}: refresh current dir" "${FFF_KEY_SHELL:-!}: open shell in current dir" '' + "${FFF_KEY_DETAILS:-N} display file details" "${FFF_KEY_SORT:-I} sort files" "${FFF_KEY_ATTRIBUTES:-x}: view file/dir attributes" "${FFF_KEY_IMAGE:-i}: display image with w3m-img" @@ -1640,6 +1651,13 @@ key() { open "$PWD" ;; + # Show file details (on/off). + ${FFF_KEY_DETAILS:=N}) + [ $details == 0 ] && details=1 || details=0 + + open "$PWD" + ;; + # Go to previous dir. ${FFF_KEY_PREVIOUS:=-}) open "$OLDPWD" diff --git a/fff.1 b/fff.1 index e157051..dc60425 100644 --- a/fff.1 +++ b/fff.1 @@ -104,6 +104,10 @@ export FFF_DATE=1 # (0 by default) export FFF_SORT_METHOD=1 +# Show/Hide file details on open +# (Off by default) +export FFF_FILE_DETAILS=1 + # Directory color [0\-9] export FFF_COL1=2 @@ -246,6 +250,9 @@ export FFF_KEY_MKFILE="f" ### Miscellaneous +# Display file details. +export FFF_KEY_DETAILS="N" + # Sort files. export FFF_KEY_SORT="I" From 5002ecf1fd10f55b85d5c95d81e9e221cac5b5e8 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 2 Nov 2023 20:20:28 +0000 Subject: [PATCH 15/46] Add sorting to status line --- README.md | 3 ++- fff | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 62fac4e..eed9836 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ - Git branch on status line - Recursive git signs for changed files - `ncdu` integration -- Modification date and time +- Display file modification date, time and size - Sort files by modification time or alphabetically ### Thanks @@ -25,6 +25,7 @@ A big part of code in there is from people who made PRs and posted issues to fff - Sidd Dino (devicons) - qwool (idea for human-readable size) - Docbroke (ncdu integration, sorting) +- yiselieren (file details) ## Table of Contents diff --git a/fff b/fff index 26193dc..14426b6 100755 --- a/fff +++ b/fff @@ -536,7 +536,16 @@ status_line() { # '\e[H\e[K': Clear line below status_line. # '\e8': Restore cursor position. # This is more widely supported than '\e[u'. + + # Display git branch and sorting. git_branch=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/[\1]/p') + + if [ $sort -eq 0 ]; then + sort_help="Sort: alpha" + else + sort_help="Sort: date" + fi + printf '\e7\e[%sH\e[3%s;4%sm%*s\r%s %s%s\e[m\e[%sH\e[K\e8' \ "$((LINES-1))" \ "${FFF_COL5:-0}" \ @@ -544,7 +553,7 @@ status_line() { "$COLUMNS" "" \ "($((scroll+1))/$((list_total+1)))" \ "$mark_ui" \ - "${1:-${PWD_escaped:-/} $git_branch}" \ + "${1:-${PWD_escaped:-/} $git_branch $sort_help}" \ "$LINES" } From a73bf5c08fa867199d7bd5bfdfc343cbad041c26 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Fri, 3 Nov 2023 10:38:39 +0000 Subject: [PATCH 16/46] Update README --- README.md | 17 ++++++++--------- fff.1 | 6 +----- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index eed9836..6230263 100644 --- a/README.md +++ b/README.md @@ -13,21 +13,21 @@ - Git branch in stats - Git branch on status line - Recursive git signs for changed files -- `ncdu` integration -- Display file modification date, time and size +- `ncdu` integration img +- Display file modification date, time and size (resource-heavy) - Sort files by modification time or alphabetically + ### Thanks A big part of code in there is from people who made PRs and posted issues to fff: -- Roy Orbitson (help page) +- Roy Orbitson (help page) img - Sidd Dino (devicons) - qwool (idea for human-readable size) - Docbroke (ncdu integration, sorting) - yiselieren (file details) - ## Table of Contents @@ -189,14 +189,10 @@ export FFF_HIDDEN=1 # (Off by default) export FFF_FILE_ICON=1 -# Show/Hide git status signs on open +# Show/Hide git status signs (+) on open # (Off by default) export FFF_GIT_CHANGES=1 -# Show/Hide modification time of file on open -# (Off by default) -export FFF_DATE=1 - # Default method to sort files on open # 0 - alphabetically # 1 - modification time @@ -356,6 +352,9 @@ export FFF_KEY_IMAGE="i" # display image with w3m-img ### Miscellaneous +# Display file details. +export FFF_KEY_DETAILS="N" + # Sort files. export FFF_KEY_SORT="I" diff --git a/fff.1 b/fff.1 index dc60425..06c3992 100644 --- a/fff.1 +++ b/fff.1 @@ -90,14 +90,10 @@ export FFF_HIDDEN=0 # (Off by default) export FFF_FILE_ICON=1 -# Show/Hide file icons on open +# Show/Hide git status signs (+) on open # (Off by default) export FFF_GIT_CHANGES=1 -# Show/Hide modification time of file on open -# (Off by default) -export FFF_DATE=1 - # Default method to sort files on open # 0 - alphabetically # 1 - modification time From 3b4a139c1efb490a0915ec07f918f5ebe81e5026 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 4 Nov 2023 10:07:35 +0000 Subject: [PATCH 17/46] Add trash path and bookmarks to help --- README.md | 5 ++--- fff | 12 ++++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6230263..fae6f8b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ - [Nerd Fonts devicons](https://www.nerdfonts.com/#home) support - Help page on `?` -- Open with commands +- `Open with` commands - Human-readable size in stats - Git branch in stats - Git branch on status line @@ -77,7 +77,7 @@ A big part of code in there is from people who made PRs and posted issues to fff ### Manual 1. Download `fff`. - - Git: `git clone https://github.com/dylanaraps/fff` + - Git: `git clone https://github.com/piotr-marendowski/fff` 2. Change working directory to `fff`. - `cd fff` 3. Run `make install` inside the script directory to install the script. @@ -85,7 +85,6 @@ A big part of code in there is from people who made PRs and posted issues to fff - **Haiku**: `make PREFIX="$(finddir B_USER_NONPACKAGED_DIRECTORY)" MANDIR='$(PREFIX)/documentation/man' DOCDIR='$(PREFIX)/documentation/fff' install` - **OpenIndiana**: `gmake install` - **MinGW/MSys**: `make -i install` - - **Others**: `make install` - **NOTE**: You may have to run this as root. **NOTE:** `fff` can be uninstalled easily using `make uninstall`. This removes all of files from your system. diff --git a/fff b/fff index 14426b6..57ce1ff 100755 --- a/fff +++ b/fff @@ -978,8 +978,20 @@ list_help() { "Ctrl+C: exit without 'cd'" '' "${FFF_KEY_HELP:-?}: show this help" + '' + "trash directory: ${FFF_TRASH:-${XDG_DATA_HOME}/fff/trash}" + 'Bookmarks: ' ) + # Add bookmarks to list. + for i in {1..9}; do + var="FFF_FAV$i" + path=${!var} + if [[ -n $path ]]; then + list+=("$i: $path") + fi + done + ((list_total=${#list[@]}-1)) # Save the original list in a second list as a backup. From ed4ddb941d9fc755689b3a515f97d9f6c2c9f489 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 4 Nov 2023 10:30:10 +0000 Subject: [PATCH 18/46] Update names for mkdir and mkfile --- fff | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fff b/fff index 57ce1ff..8af54bb 100755 --- a/fff +++ b/fff @@ -1539,7 +1539,7 @@ key() { # Create a directory. ${FFF_KEY_MKDIR:=n}) - cmd_line "mkdir: " "dirs" + cmd_line "Create directory: " "dirs" [[ $cmd_reply ]] && if [[ -e $cmd_reply ]]; then @@ -1556,7 +1556,7 @@ key() { # Create a file. ${FFF_KEY_MKFILE:=f}) - cmd_line "mkfile: " + cmd_line "Create file: " [[ $cmd_reply ]] && if [[ -e $cmd_reply ]]; then From eae3d8442bc9003e56901cf7139d2061bfa6e3c8 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 4 Nov 2023 12:02:52 +0000 Subject: [PATCH 19/46] Add ctrl + u/ctrl + d scroll options --- README.md | 6 ++++++ fff | 26 ++++++++++++++++++++++++++ fff.1 | 5 +++++ 3 files changed, 37 insertions(+) diff --git a/README.md b/README.md index fae6f8b..9eb1ecf 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ - `ncdu` integration img - Display file modification date, time and size (resource-heavy) - Sort files by modification time or alphabetically +- `ctrl + d`/`ctrl + u` scrolling ### Thanks @@ -278,6 +279,11 @@ export FFF_FILE_FORMAT="%f" # Format ('%f' is the current file): "str%fstr" # Example (Add a ' >' before files): FFF_MARK_FORMAT="> %f" export FFF_MARK_FORMAT=" %f*" + +# Scroll steps. +# (14 by default). +export FFF_SCROLL_UP=14 +export FFF_SCROLL_DOWN=14 ``` ## Customizing the keybindings. diff --git a/fff b/fff index 8af54bb..87a6c64 100755 --- a/fff +++ b/fff @@ -1313,6 +1313,32 @@ cmd_line() { } key() { + # Handle ctrl + u scroll up. + [[ $1 == $'\x15' ]] && { + ((scroll != 0)) && { + if ((scroll - ${FFF_SCROLL_UP:=14} < 0)); then + scroll=0 + redraw + else + scroll=$((scroll - ${FFF_SCROLL_UP:=14})) + redraw + fi + } + } + + # Handle ctrl + d for scroll down. + [[ $1 == $'\x04' ]] && { + ((scroll != list_total)) && { + if ((scroll + ${FFF_SCROLL_DOWN:=14} > list_total)); then + scroll=list_total + redraw + else + scroll=$((scroll + ${FFF_SCROLL_DOWN:=14})) + redraw + fi + } + } + # Handle special key presses. [[ $1 == $'\e' ]] && { read "${read_flags[@]}" -rsn 2 diff --git a/fff.1 b/fff.1 index 06c3992..8d01f21 100644 --- a/fff.1 +++ b/fff.1 @@ -175,6 +175,11 @@ export FFF_FILE_FORMAT="%f" # Format ('%f' is the current file): "str%fstr" # Example (Add a ' >' before files): FFF_MARK_FORMAT="> %f" export FFF_MARK_FORMAT=" %f*" + +# Scroll steps. +# (14 by default). +export FFF_SCROLL_UP=14 +export FFF_SCROLL_DOWN=14 . .fi . From eb50094804dad25b8d72370d0b8569c0a026629a Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 4 Nov 2023 22:00:37 +0000 Subject: [PATCH 20/46] Update devicons --- fff | 118 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 65 insertions(+), 53 deletions(-) diff --git a/fff b/fff index 87a6c64..0cf2e20 100755 --- a/fff +++ b/fff @@ -178,7 +178,6 @@ get_icon() { 'Public' ) printf -- ''; return ;; 'Templates' ) printf -- ''; return ;; 'Videos' ) printf -- ''; return ;; - # Spanish 'Escritorio' ) printf -- ''; return ;; 'Documentos' ) printf -- ''; return ;; @@ -228,13 +227,19 @@ get_icon() { } # Icons for files with no extension - [[ "$2" == *"/$3" ]] && { + [[ "$2" == "$3" ]] && { case "$2" in + 'lsb-release' | 'arch-release' |\ + 'gshadow' | 'group' |\ + 'hosts' | 'hostname' |\ + 'shadow' | 'sudoers' |\ + 'passwd' | 'os-release' |\ '_gvimrc' | '_vimrc' |\ 'bspwmrc' |'cmakelists.txt'|\ - 'config' | 'Makefile' |\ - 'makefile' | 'sxhkdrc' |\ - 'ini' ) printf -- ''; return ;; + 'config' | 'gradlew' |\ + 'ini' | 'sxhkdrc' ) printf -- ''; return ;; + + 'Makefile' | 'makefile' ) printf -- ''; return ;; 'authorized_keys' |\ 'known_hosts' |\ @@ -248,15 +253,17 @@ get_icon() { 'a.out' |\ 'configure' ) printf -- ''; return ;; - 'dockerfile' ) printf -- ''; return ;; - 'Dockerfile' ) printf -- ''; return ;; + 'dockerfile' |\ + 'Dockerfile' ) printf -- '󰡨'; return ;; + 'dropbox' ) printf -- ''; return ;; 'exact-match-case-sensitive-2' ) printf -- 'X2'; return ;; 'ledger' ) printf -- ''; return ;; - 'node_modules' ) printf -- ''; return ;; + 'node_modules' ) printf -- '󰎙'; return ;; 'playlists' ) printf -- ''; return ;; 'procfile' ) printf -- ''; return ;; 'README' ) printf -- ''; return ;; + 'PKGBUILD' ) printf -- '󰏖'; return ;; '*' ) printf -- ''; return ;; esac } @@ -265,32 +272,22 @@ get_icon() { # without an extension [[ "$2" == ".$3" ]] && { case "$2" in - '.bash_aliases' |\ - '.bash_history' |\ - '.bash_logout' |\ - '.bash_profile' |\ - '.bashprofile' |\ - '.bashrc' |\ - '.dmrc' |\ - '.DS_Store' |\ - '.fasd' |\ - '.gitattributes' |\ - '.gitconfig' |\ - '.gitignore' |\ - '.inputrc' |\ - '.jack-settings' |\ - '.nvidia-settings-rc' |\ - '.pam_environment' |\ - '.profile' |\ - '.recently-used' |\ - '.selected_editor' |\ - '.Xauthority' |\ - '.Xdefaults' |\ - '.xinitrc' |\ - '.xinputrc' |\ - '.Xresources' |\ - '.zsh_history' |\ - '.zshrc' ) printf -- ''; return ;; + '.bash_aliases' |\ + '.bash_history' |\ + '.bash_logout' |\ + '.bash_profile' |\ + '.bashprofile' | '.project' |\ + '.gitattributes' | '.bashrc' |\ + '.gitconfig' | '.gitignore' |\ + '.jack-settings' | '.DS_Store' |\ + '.nvidia-settings-rc' | '.inputrc' |\ + '.pam_environment' | '.dmrc' |\ + '.recently-used' | '.profile' |\ + '.selected_editor' | '.fasd' |\ + '.Xdefaults' | '.Xauthority' |\ + '.xinitrc' | '.xinputrc' |\ + '.xprofile' | '.Xresources' |\ + '.zsh_history' | '.zshrc' ) printf -- ''; return ;; '.vim' |\ '.viminfo' |\ @@ -307,6 +304,8 @@ get_icon() { # Icon for files whose names have an extension [[ "$2" == *"."* ]] && { case "$2" in + 'locale.gen' |\ + 'prefs.js' |\ 'cmakelists.txt' |\ 'Makefile.ac' |\ 'Makefile.in' |\ @@ -348,6 +347,20 @@ get_icon() { esac case "$3" in + 'efi' | 'menu' |\ + 'cfg' | 'EFI' |\ + 'desktop' | 'name' |\ + 'package-cache' | 'prefs' |\ + 'reg' | 'gradle' |\ + 'bat' | 'conf' |\ + 'cvs' | 'tsv' |\ + 'htaccess' | 'config' |\ + 'htpasswd' | 'pro' |\ + 'ini' | 'rc' |\ + 'toml' | 'yaml' |\ + 'x86_64' | 'x86' |\ + 'yml' | 'properties' ) printf -- ''; return ;; + '7z' | 'apk' |\ 'bz2' | 'cab' |\ 'cpio'| 'deb' |\ @@ -357,19 +370,11 @@ get_icon() { 'rar' | 'rpm' |\ 'tar' | 'tgz' |\ 'xbps'| 'xz' |\ - 'zip' ) printf -- ''; return ;; - - 'bat' | 'conf' |\ - 'cvs' |\ - 'htaccess' |\ - 'htpasswd' |\ - 'ini' | 'rc' |\ - 'toml'| 'yaml' |\ - 'yml' ) printf -- ''; return ;; + 'zip' | 'zst' ) printf -- ''; return ;; 'asp' | 'awk' |\ 'bash'| 'csh' |\ - 'efi' | 'elf' |\ + 'elf' |\ 'fish'| 'ksh' |\ 'ps1' | 'rom' |\ 'zsh' ) printf -- ''; return ;; @@ -380,13 +385,12 @@ get_icon() { 'mpeg'| 'mpg' |\ 'webm' ) printf -- ''; return ;; - 'bmp' | 'gif' |\ 'ico' | 'jpeg' |\ 'jpg' | 'png' |\ 'ppt' | 'pptx' |\ 'webp'| 'GIF' |\ - 'xcf' ) printf -- ''; return ;; + 'xcf' | 'xbm' ) printf -- ''; return ;; 'aup' | 'cue' |\ 'flac'| 'm4a' |\ @@ -414,11 +418,11 @@ get_icon() { 'asm' | 'css' |\ 'less'| 's' |\ - 'sh' ) printf -- ''; return ;; + 'sh' | 'style' ) printf -- ''; return ;; 'db' | 'dump' |\ - 'img' | 'iso' |\ - 'sql' ) printf -- ''; return ;; + 'img' |\ + 'sql' | 'files' ) printf -- ''; return ;; 'f#' | 'fs' |\ 'fsi' | 'fsx' |\ @@ -432,13 +436,13 @@ get_icon() { 'rake'| 'rb' ) printf -- ''; return ;; 'dll' | 'exe' |\ - 'msi' ) printf -- ''; return ;; + 'msi' | 'bin' ) printf -- ''; return ;; 'eex' | 'ex' |\ 'exs' | 'leex' ) printf -- ''; return ;; - 'class' |\ - 'jar' | 'java' ) printf -- ''; return ;; + 'jar' | 'java' ) printf -- ''; return ;; + 'class' ) printf -- '󰏗'; return ;; 'mustache' |\ 'hbs' ) printf -- ''; return ;; @@ -446,6 +450,8 @@ get_icon() { 'json' |\ 'webmanifest' ) printf -- ''; return ;; + 'ttf' | 'otf' ) printf -- ''; return ;; + 'py' | 'pyc' |\ 'pyd' | 'pyo' ) printf -- ''; return ;; @@ -481,7 +487,6 @@ get_icon() { 'php' ) printf -- ''; return ;; 'pp' ) printf -- ''; return ;; 'r' ) printf -- 'ﳒ'; return ;; - 'rproj' ) printf -- '鉶'; return ;; 'rss' ) printf -- ''; return ;; 'scala' ) printf -- ''; return ;; 'styl' ) printf -- ''; return ;; @@ -493,6 +498,13 @@ get_icon() { 'vue' ) printf -- '﵂'; return ;; 'xcplayground' ) printf -- ''; return ;; 'xul' ) printf -- ''; return ;; + + 'lock' ) printf -- ''; return ;; + 'iso' ) printf -- '󰻂'; return ;; + 'uuid' ) printf -- ''; return ;; + 'rej' ) printf -- ''; return ;; + + '1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9') printf -- '󰋗'; return ;; esac } From c1fc6ba69029a63999a859bf5becea964cc5d2f0 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sun, 5 Nov 2023 14:28:30 +0000 Subject: [PATCH 21/46] Add history --- README.md | 13 ++++ fff | 183 +++++++++++++++++++++++++++++++++++++++++++++++------- fff.1 | 14 +++++ 3 files changed, 189 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 9eb1ecf..149fbc3 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ - Display file modification date, time and size (resource-heavy) - Sort files by modification time or alphabetically - `ctrl + d`/`ctrl + u` scrolling +- Working history of directories and picker for them ### Thanks @@ -144,6 +145,7 @@ I: sort files x: view file/dir attributes i: display image with w3m-img u: run ncdu +v: show history down: scroll down up: scroll up @@ -264,6 +266,14 @@ export FFF_FAV7= export FFF_FAV8= export FFF_FAV9= +# History file length. +# (100 lines by default) +# Every cd-on-exit (q) program deletes every line older than +# FFF_HISTORY_LENGTH. +# Example: history has 150 lines, quitting trims history file +# to 100 most recent. +export FFF_HISTORY_LENGTH=200 + # w3m-img offsets. export FFF_W3M_XOFFSET=0 export FFF_W3M_YOFFSET=0 @@ -374,6 +384,9 @@ export FFF_KEY_HIDDEN="." # Open ncdu export FFF_KEY_NCDU="u" + +# Show history of directories. +export FFF_KEY_HISTORY="v" ``` ### Disabling keybindings. diff --git a/fff b/fff index 0cf2e20..d0d3add 100755 --- a/fff +++ b/fff @@ -94,6 +94,7 @@ setup_options() { helping=0 sort=${FFF_SORT_METHOD:=0} details=${FFF_FILE_DETAILS:=0} + history=0 } get_term_size() { @@ -530,6 +531,9 @@ status_line() { if ((helping)); then mark_ui= PWD_escaped=help + elif ((history)); then + mark_ui= + PWD_escaped=history else # Escape the directory string. # Remove all non-printable characters. @@ -632,6 +636,18 @@ print_line() { fi format+=\\e[${fi:-37}m + # History line. + elif ((history)); then + file_name=${list[$1]} + if [[ "$file_name" ]]; then + # Highlight the key(s), escaping any specials in overrides to a human-readable form + format+=\\e[${di:-1;3${FFF_COL1:-2}}m + local action="${file_name%: *}" + format+="$(cat -A <<<"$action" | head -c -2)\\e[${fi:-37}m: " + file_name="${file_name##*: }" + fi + format+=\\e[${fi:-37}m + # If the dir item doesn't exist, end here. elif [[ -z ${list[$1]} ]]; then return @@ -696,7 +712,7 @@ print_line() { format+="\\e[1;3${FFF_COL4:-6};7m" # If the list item is marked for operation. - !((helping)) && [[ ${marked_files[$1]} == "${list[$1]:-null}" ]] && { + !((helping)) && !((history)) && [[ ${marked_files[$1]} == "${list[$1]:-null}" ]] && { format+=\\e[3${FFF_COL3:-1}m${mark_pre} suffix+=${mark_post} } @@ -903,6 +919,10 @@ redraw() { helping=0 find_previous=1 } + ((history)) && { + history=0 + find_previous=1 + } read_dir scroll=0 } @@ -914,6 +934,13 @@ redraw() { scroll=0 } + # If 'help' is passed, list help text. + [[ $1 == hist ]] && { + history=1 + get_history + scroll=0 + } + clear_screen draw_dir status_line @@ -958,6 +985,7 @@ list_help() { "${FFF_KEY_ATTRIBUTES:-x}: view file/dir attributes" "${FFF_KEY_IMAGE:-i}: display image with w3m-img" "${FFF_KEY_NCDU:-u}: open ncdu" + "${FFF_KEY_HISTORY:-u}: show history" '' 'down: scroll down' 'up: scroll up' @@ -971,28 +999,26 @@ list_help() { '' "${FFF_KEY_YANK:-y}: mark copy" "${FFF_KEY_MOVE:-m}: mark move" - "${FFF_KEY_TRASH:-d}: mark trash (~/.local/share/fff/trash/)" + "${FFF_KEY_TRASH:-d}: mark trash" "${FFF_KEY_LINK:-s}: mark symbolic link" "${FFF_KEY_BULK_RENAME:-b}: mark bulk rename" '' "${FFF_KEY_YANK_ALL:-Y}: mark all for copy" "${FFF_KEY_MOVE_ALL:-M}: mark all for move" - "${FFF_KEY_TRASH_ALL:-D}: mark all for trash (~/.local/share/fff/trash/)" + "${FFF_KEY_TRASH_ALL:-D}: mark all for trash" "${FFF_KEY_LINK_ALL:-S}: mark all for symbolic link" "${FFF_KEY_BULK_RENAME_ALL:-B}: mark all for bulk rename" '' "${FFF_KEY_PASTE:-p}: paste/move/delete/bulk_rename" "${FFF_KEY_CLEAR:-c}: clear file selections" '' - '[1-9]: favourites/bookmarks (see customization in man page)' - '' "q: exit with 'cd' (if enabled) or exit this help" "Ctrl+C: exit without 'cd'" '' - "${FFF_KEY_HELP:-?}: show this help" + "Trash directory: ${FFF_TRASH:-${XDG_DATA_HOME}/fff/trash}" + 'Bookmarks [1-9]: ' '' - "trash directory: ${FFF_TRASH:-${XDG_DATA_HOME}/fff/trash}" - 'Bookmarks: ' + "${FFF_KEY_HELP:-?}: show this help" ) # Add bookmarks to list. @@ -1010,6 +1036,28 @@ list_help() { cur_list=("${list[@]}") } +get_history() { + # Set window name. + printf '\e]2;fff: history\e'\\ + + # Turn off icons. + icon_value="$(printf '%s\n' "$FFF_FILE_ICON")" + FFF_FILE_ICON=0 + + # Add history to lines. + list=() + i=1 + while read -r line; do + list+=("$i: $line") + i=$((i+1)) + done < "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/history" + + ((list_total=${#list[@]}-1)) + + # Save the original list in a second list as a backup. + cur_list=("${list[@]}") +} + mark() { # Mark file for operation. # If an item is marked in a second directory, @@ -1135,13 +1183,19 @@ bulk_rename() { } open() { - # Open directories and files. + # Directories if [[ -d $1/ ]]; then search= search_end_early= cd "${1:-/}" ||: + + # Add directory to history. + echo -e "${PWD}\n$(cat "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/history")" > \ + "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/history" + redraw full + # Files elif [[ -f $1 ]]; then # If 'fff' was opened as a file picker, save the opened # file in a file called 'opened_file'. @@ -1225,6 +1279,8 @@ cmd_line() { $'\t') ((helping)) && return + ((history)) && return + comp_glob="$cmd_reply*" # Pass the argument dirs to limit completion to directories. @@ -1253,7 +1309,7 @@ cmd_line() { "") # If there's only one search result and its a directory, # enter it on one enter keypress. - !((helping)) && [[ $2 == search && -d ${list[0]} ]] && ((list_total == 0)) && { + !((helping)) && !((history)) && [[ $2 == search && -d ${list[0]} ]] && ((list_total == 0)) && { # '\e[?25l': Hide the cursor. printf '\e[?25l' @@ -1300,6 +1356,12 @@ cmd_line() { for item in "${cur_list[@]}"; do [[ "$item" == *"$cmd_reply"* ]] && list+=("$item") done + elif ((history)); then + local item + list=() + for item in "${cur_list[@]}"; do + [[ "$item" == *"$cmd_reply"* ]] && list+=("$item") + done else list=("$PWD"/*"$cmd_reply"*) fi @@ -1363,16 +1425,6 @@ key() { } case ${special_key:-$1} in - "${FFF_KEY_HELP:=?}") - ((helping)) && { - FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. - redraw full - return - } - - redraw help - ;; - # Open list item. # 'C' is what bash sees when the right arrow is pressed # ('\e[C' or '\eOC'). @@ -1382,6 +1434,11 @@ key() { ${FFF_KEY_CHILD3:=""}|\ ${FFF_KEY_CHILD4:=$'\eOC'}) open "${list[scroll]}" + + ((history)) && { + list[scroll]=${list[scroll]#* } + open "${list[scroll]}" + } ;; # Go to the parent directory. @@ -1400,7 +1457,7 @@ key() { open "$PWD" # If '$PWD' is '/', do nothing. - elif [[ $PWD && $PWD != / ]]; then + elif [[ $PWD ]]; then find_previous=1 open "${PWD%/*}" fi @@ -1549,6 +1606,8 @@ key() { # Clear all marked files. ${FFF_KEY_CLEAR:=c}) + ((helping)) || ((history)) && return + [[ ${marked_files[*]} ]] && { marked_files=() redraw @@ -1557,6 +1616,8 @@ key() { # Rename list item. ${FFF_KEY_RENAME:=r}) + ((helping)) || ((history)) && return + [[ ! -e ${list[scroll]} ]] && return @@ -1577,6 +1638,8 @@ key() { # Create a directory. ${FFF_KEY_MKDIR:=n}) + ((helping)) || ((history)) && return + cmd_line "Create directory: " "dirs" [[ $cmd_reply ]] && @@ -1594,6 +1657,8 @@ key() { # Create a file. ${FFF_KEY_MKFILE:=f}) + ((helping)) || ((history)) && return + cmd_line "Create file: " [[ $cmd_reply ]] && @@ -1611,6 +1676,8 @@ key() { # Show file attributes. ${FFF_KEY_ATTRIBUTES:=x}) + ((helping)) || ((history)) && return + [[ -e "${list[scroll]}" ]] && { clear_screen status_line "${list[scroll]}" @@ -1632,6 +1699,8 @@ key() { # Toggle executable flag. ${FFF_KEY_EXECUTABLE:=X}) + ((helping)) || ((history)) && return + [[ -f ${list[scroll]} && -w ${list[scroll]} ]] && { if [[ -x ${list[scroll]} ]]; then chmod -x "${list[scroll]}" @@ -1645,11 +1714,15 @@ key() { # Show image in terminal. ${FFF_KEY_IMAGE:=i}) + ((helping)) || ((history)) && return + draw_img ;; # Go to dir. ${FFF_KEY_GO_DIR:=:}) + ((helping)) || ((history)) && return + cmd_line "go to dir: " "dirs" # Let 'cd' know about the current directory. @@ -1662,6 +1735,8 @@ key() { # Open file with. ${FFF_KEY_OPEN_WITH:=o}) + ((helping)) || ((history)) && return + [[ -e "${list[scroll]}" ]] && { cmd_line "open with: " "cmd" @@ -1672,6 +1747,8 @@ key() { # Open file with to run background. ${FFF_KEY_OPEN_WITH_DETACHED:=O}) + ((helping)) || ((history)) && return + [[ -e "${list[scroll]}" ]] && { cmd_line "open with (detached): " "cmd" @@ -1683,6 +1760,8 @@ key() { # Run ncdu to get sizes. ${FFF_KEY_NCDU:=u}) + ((helping)) || ((history)) && return + [[ -e "${list[scroll]}" ]] && { clear_screen reset_terminal @@ -1705,6 +1784,8 @@ key() { # Sort by name (0) time (1). ${FFF_KEY_SORT:=I}) + ((helping)) || ((history)) && return + [ $sort == 0 ] && sort=1 || sort=0 open "$PWD" @@ -1712,6 +1793,8 @@ key() { # Show file details (on/off). ${FFF_KEY_DETAILS:=N}) + ((helping)) || ((history)) && return + [ $details == 0 ] && details=1 || details=0 open "$PWD" @@ -1724,6 +1807,18 @@ key() { # Refresh current dir. ${FFF_KEY_REFRESH:=e}) + ((helping)) && { + list=("${cur_list[@]}") + redraw + return + } + + ((history)) && { + list=("${cur_list[@]}") + redraw + return + } + open "$PWD" ;; @@ -1736,15 +1831,61 @@ key() { open "$favourite" ;; + # Display help. + "${FFF_KEY_HELP:=?}") + ((history)) && return + + ((helping)) && { + # Return to previous state. + details=$saved_details + FFF_FILE_ICON="$icon_value" + redraw full + return + } + + saved_details=$details + details=0 + redraw help + ;; + + # Display history. + "${FFF_KEY_HISTORY:=v}") + ((helping)) && return + + ((history)) && { + # Return to previous state. + details=$saved_details + FFF_FILE_ICON="$icon_value" + redraw full + return + } + + saved_details=$details + details=0 + redraw hist + ;; + # Quit and store current directory in a file for CD on exit. # Don't allow user to redefine 'q' so a bad keybinding doesn't # remove the option to quit. q) + # Delete everything in history after FFF_HISTORY_LENGTH line. + lines_num=${FFF_HISTORY_LENGTH:-100} + sed -i "${lines_num}q" "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/history" + ((helping)) && { + details=$saved_details + FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. + redraw full + return + } + ((history)) && { + details=$saved_details FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. redraw full return } + : "${FFF_CD_FILE:=${XDG_CACHE_HOME:=${HOME}/.cache}/fff/.fff_d}" [[ -w $FFF_CD_FILE ]] && diff --git a/fff.1 b/fff.1 index 8d01f21..eb3a650 100644 --- a/fff.1 +++ b/fff.1 @@ -35,9 +35,12 @@ t: go to trash e: refresh current dir !: open shell in current dir +N: display file details +I: sort files x: view file/dir attributes i: display image with w3m-img u: run ncdu +v: show history down: scroll down up: scroll up @@ -160,6 +163,14 @@ export FFF_FAV7= export FFF_FAV8= export FFF_FAV9= +# History file length. +# (100 lines by default) +# Every cd-on-exit (q) program deletes every line older than +# FFF_HISTORY_LENGTH. +# Example: history has 150 lines, quitting trims history file +# to 100 most recent. +export FFF_HISTORY_LENGTH=200 + # w3m-img offsets. export FFF_W3M_XOFFSET=0 export FFF_W3M_YOFFSET=0 @@ -271,6 +282,9 @@ export FFF_DISPLAY_ICON="I" # Open ncdu export FFF_KEY_NCDU="u" + +# Show history of directories. +export FFF_KEY_HISTORY="v" . .fi From 43349996501414bb4493054a86154b2e9b5e5da8 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sun, 5 Nov 2023 18:09:55 +0000 Subject: [PATCH 22/46] Change marking behaviour --- README.md | 33 ++++++----------- fff | 107 +++++++++++++++++++++++++++++++++++------------------- fff.1 | 33 +++++++---------- 3 files changed, 95 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 149fbc3..b6ac7ac 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ - Sort files by modification time or alphabetically - `ctrl + d`/`ctrl + u` scrolling - Working history of directories and picker for them +- Changed marking to nnn-like (mark with space, then choose command, and execute it) ### Thanks @@ -145,7 +146,7 @@ I: sort files x: view file/dir attributes i: display image with w3m-img u: run ncdu -v: show history +s: show history down: scroll down up: scroll up @@ -157,17 +158,12 @@ n: new dir r: rename X: toggle executable -y: mark copy -m: mark move -d: mark trash (~/.local/share/fff/trash/) -s: mark symbolic link -b: mark bulk rename - -Y: mark all for copy -M: mark all for move -D: mark all for trash (~/.local/share/fff/trash/) -S: mark all for symbolic link -B: mark all for bulk rename +space: mark files for operations: +y: copy +m: move +d: trash (move to FFF_TRASH) +s: symbolic link +b: bulk rename p: execute paste/move/delete/bulk_rename c: clear file selections @@ -344,20 +340,15 @@ export FFF_KEY_GO_TRASH="t" export FFF_KEY_REFRESH="e" ### File operations. - +export FFF_KEY_MARK=" " +export FFF_KEY_MARK_ALL="v" export FFF_KEY_YANK="y" export FFF_KEY_MOVE="m" export FFF_KEY_TRASH="d" export FFF_KEY_LINK="s" export FFF_KEY_BULK_RENAME="b" -export FFF_KEY_YANK_ALL="Y" -export FFF_KEY_MOVE_ALL="M" -export FFF_KEY_TRASH_ALL="D" -export FFF_KEY_LINK_ALL="S" -export FFF_KEY_BULK_RENAME_ALL="B" - -export FFF_KEY_PASTE="p" +export FFF_KEY_EXECUTE="p" export FFF_KEY_CLEAR="c" export FFF_KEY_RENAME="r" @@ -386,7 +377,7 @@ export FFF_KEY_HIDDEN="." export FFF_KEY_NCDU="u" # Show history of directories. -export FFF_KEY_HISTORY="v" +export FFF_KEY_HISTORY="a" ``` ### Disabling keybindings. diff --git a/fff b/fff index d0d3add..11180a3 100755 --- a/fff +++ b/fff @@ -171,7 +171,7 @@ get_icon() { '.git' ) printf -- ''; return ;; 'Desktop' ) printf -- ''; return ;; 'Documents' ) printf -- ''; return ;; - 'Downloads' ) printf -- ''; return ;; + 'Downloads' ) printf -- ''; return ;; 'Dotfiles' ) printf -- ''; return ;; 'Dropbox' ) printf -- ''; return ;; 'Music' ) printf -- ''; return ;; @@ -182,7 +182,7 @@ get_icon() { # Spanish 'Escritorio' ) printf -- ''; return ;; 'Documentos' ) printf -- ''; return ;; - 'Descargas' ) printf -- ''; return ;; + 'Descargas' ) printf -- ''; return ;; 'Música' ) printf -- ''; return ;; 'Imágenes' ) printf -- ''; return ;; 'Público' ) printf -- ''; return ;; @@ -193,7 +193,7 @@ get_icon() { 'Images' ) printf -- ''; return ;; 'Musique' ) printf -- ''; return ;; 'Publique' ) printf -- ''; return ;; - 'Téléchargements' ) printf -- ''; return ;; + 'Téléchargements' ) printf -- ''; return ;; 'Vidéos' ) printf -- ''; return ;; # Portuguese 'Imagens' ) printf -- ''; return ;; @@ -205,7 +205,7 @@ get_icon() { 'Modelli' ) printf -- ''; return ;; 'Musica' ) printf -- ''; return ;; 'Pubblici' ) printf -- ''; return ;; - 'Scaricati' ) printf -- ''; return ;; + 'Scaricati' ) printf -- ''; return ;; 'Scrivania' ) printf -- ''; return ;; 'Video' ) printf -- ''; return ;; # German @@ -219,7 +219,7 @@ get_icon() { 'Dokumentumok' ) printf -- ''; return ;; 'Képek' ) printf -- ''; return ;; 'Zene' ) printf -- ''; return ;; - 'Letöltések' ) printf -- ''; return ;; + 'Letöltések' ) printf -- ''; return ;; 'Videók' ) printf -- ''; return ;; 'Számítógép' ) printf -- ''; return ;; @@ -523,8 +523,12 @@ git_changes() { status_line() { # Status_line to print when files are marked for operation. - local mark_ui="[${#marked_files[@]}] selected (${file_program[*]}) [p] ->" - mark_ui="${marked_files[*]:+"$mark_ui"}" + local mark_ui= + [ ${#marked_files[@]} -gt 0 ] && { + mark_ui="[${#marked_files[@]}] selected " + [ ! -z $file_program ] && \ + mark_ui+="(${file_program[*]}) " + } # Escape the directory string. # Remove all non-printable characters. @@ -1075,6 +1079,7 @@ mark() { mark_dir=$PWD else marked_files=() + file_program=() fi redraw @@ -1092,21 +1097,9 @@ mark() { print_line "$1" fi - # Find the program to use. - case "$2" in - ${FFF_KEY_YANK:=y}|${FFF_KEY_YANK_ALL:=Y}) file_program=(cp -iR) ;; - ${FFF_KEY_MOVE:=m}|${FFF_KEY_MOVE_ALL:=M}) file_program=(mv -i) ;; - ${FFF_KEY_LINK:=s}|${FFF_KEY_LINK_ALL:=S}) file_program=(ln -s) ;; - - # These are 'fff' functions. - ${FFF_KEY_TRASH:=d}|${FFF_KEY_TRASH_ALL:=D}) - file_program=(trash) - ;; - - ${FFF_KEY_BULK_RENAME:=b}|${FFF_KEY_BULK_RENAME_ALL:=B}) - file_program=(bulk_rename) - ;; - esac + # If no programs are marked, clear the type of operation. + [[ -z ${marked_files[*]} ]] && + file_program=() status_line } @@ -1415,6 +1408,14 @@ key() { # Handle special key presses. [[ $1 == $'\e' ]] && { + + # Exit marking with any special key! + [[ ${marked_files[*]} ]] && { + marked_files=() + file_program=() + redraw + } + read "${read_flags[@]}" -rsn 2 # Handle a normal escape key press. @@ -1569,23 +1570,48 @@ key() { ${FFF_KEY_TRASH:=d}|\ ${FFF_KEY_LINK:=s}|\ ${FFF_KEY_BULK_RENAME:=b}) + [[ -z "${marked_files[*]}" ]] && return + + previous_program="${file_program[0]}" + + # Find the program to use. + case "$1" in + ${FFF_KEY_YANK:=y}) file_program=(cp -iR) ;; + ${FFF_KEY_MOVE:=m}) file_program=(mv -i) ;; + ${FFF_KEY_LINK:=s}) file_program=(ln -s) ;; + + # These are 'fff' functions. + ${FFF_KEY_TRASH:=d}) file_program=(trash) ;; + ${FFF_KEY_BULK_RENAME:=b}) file_program=(bulk_rename) ;; + esac + + # Toggle the file program if the same key was pressed. + [[ $previous_program == "${file_program[0]}" ]] && + file_program=() + + status_line + ;; + + # Mark files for operation. + "${FFF_KEY_MARK:=" "}") mark "$scroll" "$1" ;; # Mark all files for operation. - ${FFF_KEY_YANK_ALL:=Y}|\ - ${FFF_KEY_MOVE_ALL:=M}|\ - ${FFF_KEY_TRASH_ALL:=D}|\ - ${FFF_KEY_LINK_ALL:=S}|\ - ${FFF_KEY_BULK_RENAME_ALL:=B}) + "${FFF_KEY_MARK_ALL:=v}") mark all "$1" ;; # Do the file operation. - ${FFF_KEY_PASTE:=p}) + ${FFF_KEY_EXECUTE:=p}) [[ ${marked_files[*]} ]] && { [[ ! -w $PWD ]] && { - cmd_line "warn: no write access to dir." + cmd_line "WARNING: No write access to dir" + return + } + + [[ -z ${file_program[0]} ]] && { + cmd_line "WARNING: No operation selected [y,m,d,b,s]" return } @@ -1599,8 +1625,14 @@ key() { stty -echo marked_files=() + file_program=() setup_terminal redraw full + } || { + [[ -z ${file_program[0]} ]] && { + cmd_line "WARNING: 0 marked files" + return + } } ;; @@ -1610,12 +1642,13 @@ key() { [[ ${marked_files[*]} ]] && { marked_files=() + file_program=() redraw } ;; # Rename list item. - ${FFF_KEY_RENAME:=r}) + ${FFF_KEY_RENAME:=s}) ((helping)) || ((history)) && return [[ ! -e ${list[scroll]} ]] && @@ -1625,14 +1658,14 @@ key() { [[ $cmd_reply ]] && if [[ -e $cmd_reply ]]; then - cmd_line "warn: '$cmd_reply' already exists." + cmd_line "WARNING: '$cmd_reply' already exists" elif [[ -w ${list[scroll]} ]]; then mv "${list[scroll]}" "${PWD}/${cmd_reply}" redraw full else - cmd_line "warn: no write access to file." + cmd_line "WARNING: No write access to file" fi ;; @@ -1644,14 +1677,14 @@ key() { [[ $cmd_reply ]] && if [[ -e $cmd_reply ]]; then - cmd_line "warn: '$cmd_reply' already exists." + cmd_line "WARNING: '$cmd_reply' already exists" elif [[ -w $PWD ]]; then mkdir -p "${PWD}/${cmd_reply}" redraw full else - cmd_line "warn: no write access to dir." + cmd_line "WARNING: No write access to dir" fi ;; @@ -1663,14 +1696,14 @@ key() { [[ $cmd_reply ]] && if [[ -e $cmd_reply ]]; then - cmd_line "warn: '$cmd_reply' already exists." + cmd_line "WARNING: '$cmd_reply' already exists" elif [[ -w $PWD ]]; then : > "$cmd_reply" redraw full else - cmd_line "warn: no write access to dir." + cmd_line "WARNING: No write access to dir" fi ;; @@ -1849,7 +1882,7 @@ key() { ;; # Display history. - "${FFF_KEY_HISTORY:=v}") + "${FFF_KEY_HISTORY:=a}") ((helping)) && return ((history)) && { diff --git a/fff.1 b/fff.1 index eb3a650..2331c05 100644 --- a/fff.1 +++ b/fff.1 @@ -40,7 +40,7 @@ I: sort files x: view file/dir attributes i: display image with w3m-img u: run ncdu -v: show history +s: show history down: scroll down up: scroll up @@ -52,19 +52,14 @@ n: new dir r: rename X: toggle executable -y: mark copy -m: mark move -d: mark trash (~/.local/share/fff/trash/) -s: mark symbolic link -b: mark bulk rename +space: mark files for operations: +y: copy +m: move +d: trash (move to FFF_TRASH) +s: symbolic link +b: bulk rename -Y: mark all for copy -M: mark all for move -D: mark all for trash (~/.local/share/fff/trash/) -S: mark all for symbolic link -B: mark all for bulk rename - -p: paste/move/delete/bulk_rename +p: execute paste/move/delete/bulk_rename c: clear file selections [1-9]: favourites/bookmarks (see customization) @@ -240,18 +235,16 @@ export FFF_KEY_GO_HOME="~" export FFF_KEY_GO_TRASH="t" ### File operations. - +export FFF_KEY_MARK=" " +export FFF_KEY_MARK_ALL="v" export FFF_KEY_YANK="y" export FFF_KEY_MOVE="m" export FFF_KEY_TRASH="d" export FFF_KEY_LINK="s" export FFF_KEY_BULK_RENAME="b" -export FFF_KEY_YANK_ALL="Y" -export FFF_KEY_MOVE_ALL="M" -export FFF_KEY_TRASH_ALL="D" -export FFF_KEY_LINK_ALL="S" -export FFF_KEY_BULK_RENAME_ALL="B" +export FFF_KEY_EXECUTE="p" +export FFF_KEY_CLEAR="c" export FFF_KEY_PASTE="p" export FFF_KEY_CLEAR="c" @@ -284,7 +277,7 @@ export FFF_DISPLAY_ICON="I" export FFF_KEY_NCDU="u" # Show history of directories. -export FFF_KEY_HISTORY="v" +export FFF_KEY_HISTORY="a" . .fi From 6c925204da7ffea999a502158022e69287a5143c Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sun, 5 Nov 2023 18:29:49 +0000 Subject: [PATCH 23/46] Minor changes --- fff | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/fff b/fff index 11180a3..7ddc482 100755 --- a/fff +++ b/fff @@ -172,7 +172,9 @@ get_icon() { 'Desktop' ) printf -- ''; return ;; 'Documents' ) printf -- ''; return ;; 'Downloads' ) printf -- ''; return ;; - 'Dotfiles' ) printf -- ''; return ;; + 'Dotfiles' |\ + 'dotfiles' |\ + '.dotfiles' ) printf -- ''; return ;; 'Dropbox' ) printf -- ''; return ;; 'Music' ) printf -- ''; return ;; 'Pictures' ) printf -- ''; return ;; @@ -989,7 +991,7 @@ list_help() { "${FFF_KEY_ATTRIBUTES:-x}: view file/dir attributes" "${FFF_KEY_IMAGE:-i}: display image with w3m-img" "${FFF_KEY_NCDU:-u}: open ncdu" - "${FFF_KEY_HISTORY:-u}: show history" + "${FFF_KEY_HISTORY:-a}: show history" '' 'down: scroll down' 'up: scroll up' @@ -1001,19 +1003,15 @@ list_help() { "${FFF_KEY_RENAME:-r}: rename" "${FFF_KEY_EXECUTABLE:-X}: toggle executable" '' + "${FFF_KEY_MARK:-" "}: mark" + "${FFF_KEY_MARK:-v}: mark all" "${FFF_KEY_YANK:-y}: mark copy" "${FFF_KEY_MOVE:-m}: mark move" "${FFF_KEY_TRASH:-d}: mark trash" "${FFF_KEY_LINK:-s}: mark symbolic link" "${FFF_KEY_BULK_RENAME:-b}: mark bulk rename" '' - "${FFF_KEY_YANK_ALL:-Y}: mark all for copy" - "${FFF_KEY_MOVE_ALL:-M}: mark all for move" - "${FFF_KEY_TRASH_ALL:-D}: mark all for trash" - "${FFF_KEY_LINK_ALL:-S}: mark all for symbolic link" - "${FFF_KEY_BULK_RENAME_ALL:-B}: mark all for bulk rename" - '' - "${FFF_KEY_PASTE:-p}: paste/move/delete/bulk_rename" + "${FFF_KEY_PASTE:-p}: execute paste/move/delete/bulk_rename" "${FFF_KEY_CLEAR:-c}: clear file selections" '' "q: exit with 'cd' (if enabled) or exit this help" @@ -1979,7 +1977,7 @@ main() { # 'nocaseglob': Glob case insensitively (Used for case insensitive search). # 'nullglob': Don't expand non-matching globs to themselves. - shopt -s nocaseglob nullglob + shopt -s nocaseglob nullglob nocasematch # Trap the exit signal (we need to reset the terminal to a useable state.) trap 'reset_terminal' EXIT From d041d068676dbc3c0c2a6f33e9ffd1b2fdd93f85 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Mon, 6 Nov 2023 19:53:44 +0000 Subject: [PATCH 24/46] Fix nocasematch --- fff | 43 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/fff b/fff index 7ddc482..9a53ca0 100755 --- a/fff +++ b/fff @@ -986,8 +986,8 @@ list_help() { "${FFF_KEY_REFRESH:-e}: refresh current dir" "${FFF_KEY_SHELL:-!}: open shell in current dir" '' - "${FFF_KEY_DETAILS:-N} display file details" - "${FFF_KEY_SORT:-I} sort files" + "${FFF_KEY_DETAILS:-N}: display file details" + "${FFF_KEY_SORT:-I}: sort files" "${FFF_KEY_ATTRIBUTES:-x}: view file/dir attributes" "${FFF_KEY_IMAGE:-i}: display image with w3m-img" "${FFF_KEY_NCDU:-u}: open ncdu" @@ -1104,11 +1104,6 @@ mark() { trash() { # Trash a file. - cmd_line "trash [${#marked_files[@]}] items? [y/n]: " y n - - [[ $cmd_reply != y ]] && - return - if [[ $FFF_TRASH_CMD ]]; then # Pass all but the last argument to the user's # custom script. command is used to prevent this function @@ -1378,32 +1373,6 @@ cmd_line() { } key() { - # Handle ctrl + u scroll up. - [[ $1 == $'\x15' ]] && { - ((scroll != 0)) && { - if ((scroll - ${FFF_SCROLL_UP:=14} < 0)); then - scroll=0 - redraw - else - scroll=$((scroll - ${FFF_SCROLL_UP:=14})) - redraw - fi - } - } - - # Handle ctrl + d for scroll down. - [[ $1 == $'\x04' ]] && { - ((scroll != list_total)) && { - if ((scroll + ${FFF_SCROLL_DOWN:=14} > list_total)); then - scroll=list_total - redraw - else - scroll=$((scroll + ${FFF_SCROLL_DOWN:=14})) - redraw - fi - } - } - # Handle special key presses. [[ $1 == $'\e' ]] && { @@ -1870,10 +1839,12 @@ key() { # Return to previous state. details=$saved_details FFF_FILE_ICON="$icon_value" + shopt -u nocasematch redraw full return } + shopt -s nocaseglob nullglob nocasematch saved_details=$details details=0 redraw help @@ -1887,10 +1858,12 @@ key() { # Return to previous state. details=$saved_details FFF_FILE_ICON="$icon_value" + shopt -u nocasematch redraw full return } + shopt -s nocaseglob nullglob nocasematch saved_details=$details details=0 redraw hist @@ -1908,12 +1881,14 @@ key() { details=$saved_details FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. redraw full + shopt -u nocasematch return } ((history)) && { details=$saved_details FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. redraw full + shopt -u nocasematch return } @@ -1977,7 +1952,7 @@ main() { # 'nocaseglob': Glob case insensitively (Used for case insensitive search). # 'nullglob': Don't expand non-matching globs to themselves. - shopt -s nocaseglob nullglob nocasematch + shopt -s nocaseglob nullglob # Trap the exit signal (we need to reset the terminal to a useable state.) trap 'reset_terminal' EXIT From b0b7b4518f387815f1dc5b6937b419031ded56ed Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Tue, 7 Nov 2023 19:57:27 +0000 Subject: [PATCH 25/46] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b6ac7ac..edbece3 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ - Sort files by modification time or alphabetically - `ctrl + d`/`ctrl + u` scrolling - Working history of directories and picker for them -- Changed marking to nnn-like (mark with space, then choose command, and execute it) +- Changed marking behaviour to nnn-like (mark with space, then choose command, and execute it) ### Thanks From 15c13e1ff32c1cb9d48da51bf00f7c58811870c9 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Wed, 8 Nov 2023 15:17:46 +0000 Subject: [PATCH 26/46] Add ctrl + u/d scrolling again (?) --- fff | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/fff b/fff index 9a53ca0..951b93d 100755 --- a/fff +++ b/fff @@ -1374,6 +1374,32 @@ cmd_line() { key() { # Handle special key presses. + + # Handle ctrl + u scroll up. + [[ $1 == $'\x15' ]] && { + ((scroll != 0)) && { + if ((scroll - ${FFF_SCROLL_UP:=14} < 0)); then + scroll=0 + redraw + else + scroll=$((scroll - ${FFF_SCROLL_UP:=14})) + redraw + fi + } + } + + # Handle ctrl + d for scroll down. + [[ $1 == $'\x04' ]] && { + ((scroll != list_total)) && { + if ((scroll + ${FFF_SCROLL_DOWN:=14} > list_total)); then + scroll=list_total + redraw + else + scroll=$((scroll + ${FFF_SCROLL_DOWN:=14})) + redraw + fi + } + } [[ $1 == $'\e' ]] && { # Exit marking with any special key! From a45555fdc07760aca852014eab8251fbc4b4aed7 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Wed, 8 Nov 2023 15:56:58 +0000 Subject: [PATCH 27/46] Remove w3m image support, change keybindings, remove ncdu --- README.md | 53 ++++++------------- fff | 148 ++++++++---------------------------------------------- fff.1 | 34 ++++--------- 3 files changed, 46 insertions(+), 189 deletions(-) diff --git a/README.md b/README.md index edbece3..abb7063 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,14 @@ - Human-readable size in stats - Git branch in stats - Git branch on status line -- Recursive git signs for changed files -- `ncdu` integration img +- Recursive git signs for changed files img - Display file modification date, time and size (resource-heavy) - Sort files by modification time or alphabetically - `ctrl + d`/`ctrl + u` scrolling - Working history of directories and picker for them - Changed marking behaviour to nnn-like (mark with space, then choose command, and execute it) +- Slightly changed keybindings to better suit more options +- Removed ability to view images (because I don't use it, but can add it for request) ### Thanks @@ -28,7 +29,7 @@ A big part of code in there is from people who made PRs and posted issues to fff - Roy Orbitson (help page) img - Sidd Dino (devicons) - qwool (idea for human-readable size) -- Docbroke (ncdu integration, sorting) +- Docbroke (sorting) - yiselieren (file details) ## Table of Contents @@ -64,17 +65,9 @@ A big part of code in there is from people who made PRs and posted issues to fff - Program handling (*non-text*). - *Not needed on macos and Haiku.* - *Customizable (if not using `xdg-open`): `$FFF_OPENER`.* -- `ncdu` (*optional*) - `Nerd Font` (*optional*) - Icons -**Dependencies for image display** - -- `w3m-img` -- `xdotool` for X. -- `fbset` for the framebuffer. - - ## Installation ### Manual @@ -138,15 +131,13 @@ G: go to bottom /: search t: go to trash ~: go to home -e: refresh current dir +z: refresh current dir !: open shell in current dir -N: display file details -I: sort files +i: display file details +u: sort files x: view file/dir attributes -i: display image with w3m-img -u: run ncdu -s: show history +e: show history down: scroll down up: scroll up @@ -158,7 +149,8 @@ n: new dir r: rename X: toggle executable -space: mark files for operations: +space: mark file +a: mark all files in directory y: copy m: move d: trash (move to FFF_TRASH) @@ -270,10 +262,6 @@ export FFF_FAV9= # to 100 most recent. export FFF_HISTORY_LENGTH=200 -# w3m-img offsets. -export FFF_W3M_XOFFSET=0 -export FFF_W3M_YOFFSET=0 - # File format. # Customize the item string. # Format ('%f' is the current file): "str%fstr" @@ -337,11 +325,11 @@ export FFF_KEY_TO_BOTTOM="G" export FFF_KEY_GO_DIR=":" export FFF_KEY_GO_HOME="~" export FFF_KEY_GO_TRASH="t" -export FFF_KEY_REFRESH="e" +export FFF_KEY_REFRESH="z" ### File operations. export FFF_KEY_MARK=" " -export FFF_KEY_MARK_ALL="v" +export FFF_KEY_MARK_ALL="a" export FFF_KEY_YANK="y" export FFF_KEY_MOVE="m" export FFF_KEY_TRASH="d" @@ -354,15 +342,14 @@ export FFF_KEY_CLEAR="c" export FFF_KEY_RENAME="r" export FFF_KEY_MKDIR="n" export FFF_KEY_MKFILE="f" -export FFF_KEY_IMAGE="i" # display image with w3m-img ### Miscellaneous # Display file details. -export FFF_KEY_DETAILS="N" +export FFF_KEY_DETAILS="i" # Sort files. -export FFF_KEY_SORT="I" +export FFF_KEY_SORT="u" # Show file attributes. export FFF_KEY_ATTRIBUTES="x" @@ -373,11 +360,8 @@ export FFF_KEY_EXECUTABLE="X" # Toggle hidden files. export FFF_KEY_HIDDEN="." -# Open ncdu -export FFF_KEY_NCDU="u" - # Show history of directories. -export FFF_KEY_HISTORY="a" +export FFF_KEY_HISTORY="e" ``` ### Disabling keybindings. @@ -438,10 +422,3 @@ read -srn 1 && key "$REPLY" ## Using `fff` in vim/neovim as a file picker See: [**`fff.vim`**](https://github.com/dylanaraps/fff.vim) - - -## Why? - -¯\\_(ツ)_/¯ - -dont touch my shrug diff --git a/fff b/fff index 951b93d..ebe0986 100755 --- a/fff +++ b/fff @@ -148,12 +148,6 @@ get_ls_colors() { export "${ls_cols[@]}" &>/dev/null } -get_w3m_path() { - # Find the path to the w3m-img library. - w3m_paths=(/usr/{pkg/,}{local/,}{bin,lib,libexec,lib64,libexec64}/w3m/w3mi*) - read -r w3m _ < <(type -p "$FFF_W3M_PATH" w3mimgdisplay "${w3m_paths[@]}") -} - get_mime_type() { # Get a file's mime_type. mime_type=$(file "-${file_flags:-biL}" "$1" 2>/dev/null) @@ -727,8 +721,15 @@ print_line() { # Remove all non-printable characters. file_name=${file_name//[^[:print:]]/^[} - (( ${FFF_FILE_ICON:=0} == 1 )) && \ - icon="$(get_icon "${list[$1]}" "$file_name" "$file_ext") " + # Get icon for file. + (( ${FFF_FILE_ICON:=0} == 1 )) && { + # If file is executable and is not directory. + if [[ -x ${list[$1]} && ! -d ${list[$1]} ]]; then + icon=" " + else + icon="$(get_icon "${list[$1]}" "$file_name" "$file_ext") " + fi + } # Check if current dir is a git repo and has changes, then # display git signs if is. @@ -819,91 +820,6 @@ draw_dir() { ((y=scroll_new_pos)) } -draw_img() { - # Draw an image file on the screen using w3m-img. - # We can use the framebuffer; set win_info_cmd as appropriate. - [[ $(tty) == /dev/tty[0-9]* && -w /dev/fb0 ]] && - win_info_cmd=fbset - - # X isn't running and we can't use the framebuffer, do nothing. - [[ -z $DISPLAY && $win_info_cmd != fbset ]] && - return - - # File isn't an image file, do nothing. - get_mime_type "${list[scroll]}" - [[ $mime_type != image/* ]] && - return - - # w3m-img isn't installed, do nothing. - type -p "$w3m" &>/dev/null || { - cmd_line "error: Couldn't find 'w3m-img', is it installed?" - return - } - - # $win_info_cmd isn't installed, do nothing. - type -p "${win_info_cmd:=xdotool}" &>/dev/null || { - cmd_line "error: Couldn't find '$win_info_cmd', is it installed?" - return - } - - # Get terminal window size in pixels and set it to WIDTH and HEIGHT. - if [[ $win_info_cmd == xdotool ]]; then - IFS=$'\n' read -d "" -ra win_info \ - < <(xdotool getactivewindow getwindowgeometry --shell) - - declare "${win_info[@]}" &>/dev/null || { - cmd_line "error: Failed to retrieve window size." - return - } - else - [[ $(fbset --show) =~ .*\"([0-9]+x[0-9]+)\".* ]] - IFS=x read -r WIDTH HEIGHT <<< "${BASH_REMATCH[1]}" - fi - - # Get the image size in pixels. - read -r img_width img_height < <("$w3m" <<< "5;${list[scroll]}") - - # Subtract the status_line area from the image size. - ((HEIGHT=HEIGHT-HEIGHT*5/LINES)) - - ((img_width > WIDTH)) && { - ((img_height=img_height*WIDTH/img_width)) - ((img_width=WIDTH)) - } - - ((img_height > HEIGHT)) && { - ((img_width=img_width*HEIGHT/img_height)) - ((img_height=HEIGHT)) - } - - clear_screen - status_line "${list[scroll]}" - - # Add a small delay to fix issues in VTE terminals. - ((BASH_VERSINFO[0] > 3)) && - read "${read_flags[@]}" -srn 1 - - # Display the image. - printf '0;1;%s;%s;%s;%s;;;;;%s\n3;\n4\n' \ - "${FFF_W3M_XOFFSET:-0}" \ - "${FFF_W3M_YOFFSET:-0}" \ - "$img_width" \ - "$img_height" \ - "${list[scroll]}" | "$w3m" &>/dev/null - - # Wait for user input. - read -ern 1 - - # Clear the image. - printf '6;%s;%s;%s;%s\n3;' \ - "${FFF_W3M_XOFFSET:-0}" \ - "${FFF_W3M_YOFFSET:-0}" \ - "$WIDTH" \ - "$HEIGHT" | "$w3m" &>/dev/null - - redraw -} - redraw() { changed=() git_branch=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/\1/p') @@ -983,15 +899,13 @@ list_help() { "${FFF_KEY_SEARCH:-/}: search" "${FFF_KEY_GO_TRASH:-t}: go to trash" "${FFF_KEY_GO_HOME:-~}: go to home" - "${FFF_KEY_REFRESH:-e}: refresh current dir" + "${FFF_KEY_REFRESH:-z}: refresh current dir" "${FFF_KEY_SHELL:-!}: open shell in current dir" '' - "${FFF_KEY_DETAILS:-N}: display file details" - "${FFF_KEY_SORT:-I}: sort files" + "${FFF_KEY_DETAILS:-i}: display file details" + "${FFF_KEY_SORT:-u}: sort files" "${FFF_KEY_ATTRIBUTES:-x}: view file/dir attributes" - "${FFF_KEY_IMAGE:-i}: display image with w3m-img" - "${FFF_KEY_NCDU:-u}: open ncdu" - "${FFF_KEY_HISTORY:-a}: show history" + "${FFF_KEY_HISTORY:-e}: show history" '' 'down: scroll down' 'up: scroll up' @@ -1004,7 +918,7 @@ list_help() { "${FFF_KEY_EXECUTABLE:-X}: toggle executable" '' "${FFF_KEY_MARK:-" "}: mark" - "${FFF_KEY_MARK:-v}: mark all" + "${FFF_KEY_MARK_ALL:-a}: mark all" "${FFF_KEY_YANK:-y}: mark copy" "${FFF_KEY_MOVE:-m}: mark move" "${FFF_KEY_TRASH:-d}: mark trash" @@ -1400,6 +1314,7 @@ key() { fi } } + [[ $1 == $'\e' ]] && { # Exit marking with any special key! @@ -1591,7 +1506,7 @@ key() { ;; # Mark all files for operation. - "${FFF_KEY_MARK_ALL:=v}") + "${FFF_KEY_MARK_ALL:=a}") mark all "$1" ;; @@ -1641,7 +1556,7 @@ key() { ;; # Rename list item. - ${FFF_KEY_RENAME:=s}) + ${FFF_KEY_RENAME:=r}) ((helping)) || ((history)) && return [[ ! -e ${list[scroll]} ]] && @@ -1738,13 +1653,6 @@ key() { } ;; - # Show image in terminal. - ${FFF_KEY_IMAGE:=i}) - ((helping)) || ((history)) && return - - draw_img - ;; - # Go to dir. ${FFF_KEY_GO_DIR:=:}) ((helping)) || ((history)) && return @@ -1784,19 +1692,6 @@ key() { } ;; - # Run ncdu to get sizes. - ${FFF_KEY_NCDU:=u}) - ((helping)) || ((history)) && return - - [[ -e "${list[scroll]}" ]] && { - clear_screen - reset_terminal - ncdu "$PWD" - setup_terminal - redraw - } - ;; - # Go to '$HOME'. ${FFF_KEY_GO_HOME:='~'}) open ~ @@ -1809,7 +1704,7 @@ key() { ;; # Sort by name (0) time (1). - ${FFF_KEY_SORT:=I}) + ${FFF_KEY_SORT:=u}) ((helping)) || ((history)) && return [ $sort == 0 ] && sort=1 || sort=0 @@ -1818,7 +1713,7 @@ key() { ;; # Show file details (on/off). - ${FFF_KEY_DETAILS:=N}) + ${FFF_KEY_DETAILS:=i}) ((helping)) || ((history)) && return [ $details == 0 ] && details=1 || details=0 @@ -1832,7 +1727,7 @@ key() { ;; # Refresh current dir. - ${FFF_KEY_REFRESH:=e}) + ${FFF_KEY_REFRESH:=z}) ((helping)) && { list=("${cur_list[@]}") redraw @@ -1877,7 +1772,7 @@ key() { ;; # Display history. - "${FFF_KEY_HISTORY:=a}") + "${FFF_KEY_HISTORY:=e}") ((helping)) && return ((history)) && { @@ -1988,7 +1883,6 @@ main() { get_os get_term_size - get_w3m_path setup_options setup_terminal redraw full diff --git a/fff.1 b/fff.1 index 2331c05..aa112bd 100644 --- a/fff.1 +++ b/fff.1 @@ -32,15 +32,13 @@ G: go to bottom /: search t: go to trash ~: go to home -e: refresh current dir +z: refresh current dir !: open shell in current dir -N: display file details -I: sort files +i: display file details +u: sort files x: view file/dir attributes -i: display image with w3m-img -u: run ncdu -s: show history +e: show history down: scroll down up: scroll up @@ -52,7 +50,8 @@ n: new dir r: rename X: toggle executable -space: mark files for operations: +space: mark file +a: mark all files in directory y: copy m: move d: trash (move to FFF_TRASH) @@ -166,10 +165,6 @@ export FFF_FAV9= # to 100 most recent. export FFF_HISTORY_LENGTH=200 -# w3m-img offsets. -export FFF_W3M_XOFFSET=0 -export FFF_W3M_YOFFSET=0 - # File format. # Customize the item string. # Format ('%f' is the current file): "str%fstr" @@ -193,7 +188,7 @@ export FFF_SCROLL_DOWN=14 . .nf For more information see: - https://github.com/dylanaraps/fff#customizing-the-keybindings + https://github.com/piotr-marendowski/fff#customizing-the-keybindings ### Moving around. @@ -246,9 +241,6 @@ export FFF_KEY_BULK_RENAME="b" export FFF_KEY_EXECUTE="p" export FFF_KEY_CLEAR="c" -export FFF_KEY_PASTE="p" -export FFF_KEY_CLEAR="c" - export FFF_KEY_RENAME="r" export FFF_KEY_MKDIR="n" export FFF_KEY_MKFILE="f" @@ -256,10 +248,10 @@ export FFF_KEY_MKFILE="f" ### Miscellaneous # Display file details. -export FFF_KEY_DETAILS="N" +export FFF_KEY_DETAILS="i" # Sort files. -export FFF_KEY_SORT="I" +export FFF_KEY_SORT="u" # Show file attributes. export FFF_KEY_ATTRIBUTES="x" @@ -270,14 +262,8 @@ export FFF_KEY_EXECUTABLE="X" # Toggle hidden files. export FFF_KEY_HIDDEN="." -# Toggle file icons -export FFF_DISPLAY_ICON="I" - -# Open ncdu -export FFF_KEY_NCDU="u" - # Show history of directories. -export FFF_KEY_HISTORY="a" +export FFF_KEY_HISTORY="e" . .fi From ab3248ffec929039ca51bc96b676d7395b7adadc Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Wed, 8 Nov 2023 16:15:04 +0000 Subject: [PATCH 28/46] Update help --- fff | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/fff b/fff index ebe0986..85739d7 100755 --- a/fff +++ b/fff @@ -912,6 +912,9 @@ list_help() { 'left: go to parent dir' 'right: go to child dir' '' + "ctrl+d: scroll down for ${FFF_SCROLL_DOWN:=14} lines" + "ctrl+u: scroll up for ${FFF_SCROLL_UP:=14} lines" + '' "${FFF_KEY_MKFILE:-f}: new file" "${FFF_KEY_MKDIR:-n}: new dir" "${FFF_KEY_RENAME:-r}: rename" @@ -929,12 +932,12 @@ list_help() { "${FFF_KEY_CLEAR:-c}: clear file selections" '' "q: exit with 'cd' (if enabled) or exit this help" - "Ctrl+C: exit without 'cd'" + "ctrl+c: exit without 'cd'" '' "Trash directory: ${FFF_TRASH:-${XDG_DATA_HOME}/fff/trash}" - 'Bookmarks [1-9]: ' - '' "${FFF_KEY_HELP:-?}: show this help" + '' + 'Bookmarks [1-9]: ' ) # Add bookmarks to list. @@ -1760,12 +1763,10 @@ key() { # Return to previous state. details=$saved_details FFF_FILE_ICON="$icon_value" - shopt -u nocasematch redraw full return } - shopt -s nocaseglob nullglob nocasematch saved_details=$details details=0 redraw help @@ -1779,12 +1780,10 @@ key() { # Return to previous state. details=$saved_details FFF_FILE_ICON="$icon_value" - shopt -u nocasematch redraw full return } - shopt -s nocaseglob nullglob nocasematch saved_details=$details details=0 redraw hist @@ -1802,14 +1801,12 @@ key() { details=$saved_details FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. redraw full - shopt -u nocasematch return } ((history)) && { details=$saved_details FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. redraw full - shopt -u nocasematch return } From c0c76b6085987b1b6d0475ddac1ed8bb68040f38 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Wed, 8 Nov 2023 18:24:17 +0000 Subject: [PATCH 29/46] Make ctrl scrolling smoother --- fff | 55 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/fff b/fff index 85739d7..e53b699 100755 --- a/fff +++ b/fff @@ -1293,28 +1293,51 @@ key() { # Handle special key presses. # Handle ctrl + u scroll up. + # + # Super dumb approach, because it basically goes through + # every line and highlights it. + # Faster version = set scroll and redraw with it, but it + # clears the screen so I set it as is here to look better. [[ $1 == $'\x15' ]] && { ((scroll != 0)) && { - if ((scroll - ${FFF_SCROLL_UP:=14} < 0)); then - scroll=0 - redraw - else - scroll=$((scroll - ${FFF_SCROLL_UP:=14})) - redraw - fi + for ((i=0; i<${FFF_SCROLL_UP:=14}; i++)); do + while ((scroll > 0)); do + ((scroll--)) + + print_line "$((scroll+1))" + + if ((y < 2)); then + printf '\e[L' + else + printf '\e[A' + ((y--)) + fi + + print_line "$scroll" + + [[ "${list[scroll]}" ]] && break + done + done + status_line } } # Handle ctrl + d for scroll down. [[ $1 == $'\x04' ]] && { ((scroll != list_total)) && { - if ((scroll + ${FFF_SCROLL_DOWN:=14} > list_total)); then - scroll=list_total - redraw - else - scroll=$((scroll + ${FFF_SCROLL_DOWN:=14})) - redraw - fi + for ((i=0; i<${FFF_SCROLL_UP:=14}; i++)); do + while ((scroll < list_total)); do + ((scroll++)) + ((y < max_items)) && ((y++)) + + print_line "$((scroll-1))" + printf '\n' + print_line "$scroll" + + [[ "${list[scroll]}" ]] && break + done + done + status_line } } @@ -1733,13 +1756,13 @@ key() { ${FFF_KEY_REFRESH:=z}) ((helping)) && { list=("${cur_list[@]}") - redraw + redraw full return } ((history)) && { list=("${cur_list[@]}") - redraw + redraw full return } From ad98a6d716eeb92e8ac49201a611099fcec4e69b Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Fri, 10 Nov 2023 20:49:55 +0000 Subject: [PATCH 30/46] Add config file and color filenames --- README.md | 24 +++++++++++++++++++++++- fff | 41 ++++++++++++++++++++++++++++++++--------- fff.1 | 11 +++++++++++ 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index abb7063..675437d 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ - Changed marking behaviour to nnn-like (mark with space, then choose command, and execute it) - Slightly changed keybindings to better suit more options - Removed ability to view images (because I don't use it, but can add it for request) +- Optional config file for global configuration +- Colored filenames ### Thanks @@ -31,6 +33,7 @@ A big part of code in there is from people who made PRs and posted issues to fff - qwool (idea for human-readable size) - Docbroke (sorting) - yiselieren (file details) +- Isaac Elenbaas (config file) ## Table of Contents @@ -170,6 +173,8 @@ Ctrl+C: exit without 'cd'. ## Customization +Can be added to your `bashrc` (or other shell's configuration files) and/or can be added to `FFF_CONFIG`. Everything put in `FFF_CONFIG` file will be sourced globally meaning that e.g. Neovim's terminal will have these settings. And I'm not sure why the only option (maybe there are others) not working in config file is `FFF_HIDDEN` which only works, when fff is run inside terminal manually. + ```sh # Show/Hide hidden files on open. # (Off by default) @@ -213,8 +218,20 @@ export FFF_COL4=1 # Status foreground color [0-9] export FFF_COL5=0 +# Selection color +# (inverted foreground by default) +# ('48;2;R;G;B' values separated by ';', don't edit the '48;2;' part!). +# In terminals that support truecolor, this will set the selection color +# to grey, but on others selection will be only white bold text (if this +# is set). +export FFF_COL6="48;2;80;80;80" + +# Colored filenames +# (false by default) +export FFF_COLORED_FILENAMES=true + # Text Editor -export EDITOR="vim" +export EDITOR="nvim" # File Opener export FFF_OPENER="xdg-open" @@ -231,6 +248,11 @@ export FFF_CD_ON_EXIT=0 # If not using XDG, '${HOME}/.cache/fff/fff.d' is used. export FFF_CD_FILE=~/.fff_d +# Config Directory +# Default: '${XDG_CONFIG_HOME/fff}' +# If not using XDG, '${HOME}/.config/fff' is used. +export FFF_CONFIG=~/.config/fff + # Trash Directory # Default: '${XDG_DATA_HOME}/fff/trash' # If not using XDG, '${HOME}/.local/share/fff/trash' is used. diff --git a/fff b/fff index e53b699..f447157 100755 --- a/fff +++ b/fff @@ -72,6 +72,10 @@ setup_options() { # select options so the operation isn't repeated # multiple times in the code. + # Source config file + [[ -f "${FFF_CONFIG:=${XDG_CONFIG_HOME:=${HOME}/.config}/fff}" ]] && + . "${FFF_CONFIG:=${XDG_CONFIG_HOME:=${HOME}/.config}/fff}" + # Format for normal files. [[ $FFF_FILE_FORMAT == *%f* ]] && { file_pre=${FFF_FILE_FORMAT/'%f'*} @@ -163,7 +167,7 @@ get_icon() { case "$2" in # English '.git' ) printf -- ''; return ;; - 'Desktop' ) printf -- ''; return ;; + 'Desktop' ) printf -- '󰇄'; return ;; 'Documents' ) printf -- ''; return ;; 'Downloads' ) printf -- ''; return ;; 'Dotfiles' |\ @@ -175,8 +179,9 @@ get_icon() { 'Public' ) printf -- ''; return ;; 'Templates' ) printf -- ''; return ;; 'Videos' ) printf -- ''; return ;; + 'Games' ) printf -- '󰊗'; return ;; # Spanish - 'Escritorio' ) printf -- ''; return ;; + 'Escritorio' ) printf -- '󰇄'; return ;; 'Documentos' ) printf -- ''; return ;; 'Descargas' ) printf -- ''; return ;; 'Música' ) printf -- ''; return ;; @@ -185,7 +190,7 @@ get_icon() { 'Plantillas' ) printf -- ''; return ;; 'Vídeos' ) printf -- ''; return ;; # French - 'Bureau' ) printf -- ''; return ;; + 'Bureau' ) printf -- '󰇄'; return ;; 'Images' ) printf -- ''; return ;; 'Musique' ) printf -- ''; return ;; 'Publique' ) printf -- ''; return ;; @@ -194,7 +199,7 @@ get_icon() { # Portuguese 'Imagens' ) printf -- ''; return ;; 'Modelos' ) printf -- ''; return ;; - 'Área de trabalho') printf -- ''; return ;; + 'Área de trabalho') printf -- '󰇄'; return ;; # Italian 'Documenti' ) printf -- ''; return ;; 'Immagini' ) printf -- ''; return ;; @@ -202,13 +207,13 @@ get_icon() { 'Musica' ) printf -- ''; return ;; 'Pubblici' ) printf -- ''; return ;; 'Scaricati' ) printf -- ''; return ;; - 'Scrivania' ) printf -- ''; return ;; + 'Scrivania' ) printf -- '󰇄'; return ;; 'Video' ) printf -- ''; return ;; # German 'Bilder' ) printf -- ''; return ;; 'Dokumente' ) printf -- ''; return ;; 'Musik' ) printf -- ''; return ;; - 'Schreibtisch' ) printf -- ''; return ;; + 'Schreibtisch' ) printf -- '󰇄'; return ;; 'Vorlagen' ) printf -- ''; return ;; 'Öffentlich' ) printf -- ''; return ;; # Hungarian @@ -217,7 +222,7 @@ get_icon() { 'Zene' ) printf -- ''; return ;; 'Letöltések' ) printf -- ''; return ;; 'Videók' ) printf -- ''; return ;; - 'Számítógép' ) printf -- ''; return ;; + 'Számítógép' ) printf -- '󰇄'; return ;; * ) printf -- ''; return ;; esac @@ -478,7 +483,7 @@ get_icon() { 'elm' ) printf -- ''; return ;; 'fi' ) printf -- '|'; return ;; 'go' ) printf -- ''; return ;; - 'log' ) printf -- ''; return ;; + 'log' ) printf -- '󱀂'; return ;; 'lua' ) printf -- ''; return ;; 'nix' ) printf -- ''; return ;; 'php' ) printf -- ''; return ;; @@ -707,9 +712,27 @@ print_line() { format+=\\e[${fi:-37}m fi + # Colored filenames, advised to see manual for FFF_COL4 and FFF_COL6. + if [ "${FFF_COLORED_FILENAMES:-false}" = "true" ]; then + case "${file_name##*.}" in + # yellow + "js" | "Makefile" | "png" | "jpg" | "gif" | "webp" \ + | "pdf" | "json" | "yml" | "xml") format+=\\e[${di:-1;33}m ;; + # blue + "md" | "lua" | "css" | "c" | "cpp" | "ts" | "py" \ + | "go" | "mp3") format+=\\e[${di:-1;34}m ;; + # purple + "csharp" | "php" | "h" | "jar" | "diff" | "iso" \ + | "zip" | "tar" | "gz" | "rar" | "zst") format+=\\e[${di:-1;35}m ;; + # orange + "java" | "rb" | "html" | "pl" | "mp4" | "mkv" \ + | "webm" | "mov") format+=\\e[${di:-1;36}m ;; + esac + fi + # If the list item is under the cursor. (($1 == scroll)) && - format+="\\e[1;3${FFF_COL4:-6};7m" + format+="\\e[1;${FFF_COL4:-36};${FFF_COL6:-7}m" # If the list item is marked for operation. !((helping)) && !((history)) && [[ ${marked_files[$1]} == "${list[$1]:-null}" ]] && { diff --git a/fff.1 b/fff.1 index aa112bd..d222e34 100644 --- a/fff.1 +++ b/fff.1 @@ -116,6 +116,17 @@ export FFF_COL4=1 # Status foreground color [0\-9] export FFF_COL5=0 +# Selection color +# (inverted foreground by default) +# ('48;2;R;G;B' values separated by ';', don't edit the '48;2;' part!). +# In terminals that support truecolor, this will set the selection color +# to grey, but on others selection will be only white bold text (if this +# is set). +export FFF_COL6="48;2;80;80;80" + +# Text Editor +export EDITOR="nvim" + # Text Editor export EDITOR="vim" From 0947e06e89ed802e264f33343691d66ae0319708 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 11 Nov 2023 20:35:06 +0000 Subject: [PATCH 31/46] Add clipboard support --- README.md | 8 ++++++++ fff | 11 ++++++++++- fff.1 | 5 +++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 675437d..5f87237 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ - Removed ability to view images (because I don't use it, but can add it for request) - Optional config file for global configuration - Colored filenames +- Copy filename to clipboard ### Thanks @@ -70,6 +71,8 @@ A big part of code in there is from people who made PRs and posted issues to fff - *Customizable (if not using `xdg-open`): `$FFF_OPENER`.* - `Nerd Font` (*optional*) - Icons +- `xclip or any clipboard manager` (*optional*) + - clipboard ## Installation @@ -141,6 +144,7 @@ i: display file details u: sort files x: view file/dir attributes e: show history +Y: copy filename to clipboard down: scroll down up: scroll up @@ -296,6 +300,10 @@ export FFF_FILE_FORMAT="%f" # Example (Add a ' >' before files): FFF_MARK_FORMAT="> %f" export FFF_MARK_FORMAT=" %f*" +# Clipboard program and arguments. +# Default: xclip -sel clip +export FFF_KEY_CLIPBOARD="xclip -sel clip" + # Scroll steps. # (14 by default). export FFF_SCROLL_UP=14 diff --git a/fff b/fff index f447157..28d094e 100755 --- a/fff +++ b/fff @@ -72,7 +72,7 @@ setup_options() { # select options so the operation isn't repeated # multiple times in the code. - # Source config file + # Source config file. [[ -f "${FFF_CONFIG:=${XDG_CONFIG_HOME:=${HOME}/.config}/fff}" ]] && . "${FFF_CONFIG:=${XDG_CONFIG_HOME:=${HOME}/.config}/fff}" @@ -1792,6 +1792,15 @@ key() { open "$PWD" ;; + # Copy filename to clipboard. + ${FFF_KEY_CLIPBOARD:=Y}) + [[ -e "${list[scroll]}" ]] && { + echo "${list[scroll]}" | ${FFF_CLIPBOARD:=xclip -sel clip} 2>/dev/null + + cmd_line "${list[scroll]} copied to clipboard" + } + ;; + # Directory favourites. [1-9]) favourite="FFF_FAV${1}" diff --git a/fff.1 b/fff.1 index d222e34..ee3fd39 100644 --- a/fff.1 +++ b/fff.1 @@ -49,6 +49,7 @@ f: new file n: new dir r: rename X: toggle executable +Y: copy filename to clipboard space: mark file a: mark all files in directory @@ -188,6 +189,10 @@ export FFF_FILE_FORMAT="%f" # Example (Add a ' >' before files): FFF_MARK_FORMAT="> %f" export FFF_MARK_FORMAT=" %f*" +# Clipboard program and arguments. +# Default: xclip -sel clip +export FFF_KEY_CLIPBOARD="xclip -sel clip" + # Scroll steps. # (14 by default). export FFF_SCROLL_UP=14 From 10afb556f2308d9342ceb0218929cca93faac279 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 11 Nov 2023 22:22:14 +0000 Subject: [PATCH 32/46] Update clipboard --- README.md | 7 +++++-- fff | 10 +++------- fff.1 | 7 +++++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 5f87237..5b2e174 100644 --- a/README.md +++ b/README.md @@ -301,8 +301,8 @@ export FFF_FILE_FORMAT="%f" export FFF_MARK_FORMAT=" %f*" # Clipboard program and arguments. -# Default: xclip -sel clip -export FFF_KEY_CLIPBOARD="xclip -sel clip" +# Default: xclip -selection c +export FFF_KEY_CLIPBOARD="xclip -selection c" # Scroll steps. # (14 by default). @@ -392,6 +392,9 @@ export FFF_KEY_HIDDEN="." # Show history of directories. export FFF_KEY_HISTORY="e" + +# Copy filename to clipboard. +export FFF_KEY_CLIPBOARD="Y" ``` ### Disabling keybindings. diff --git a/fff b/fff index 28d094e..4b7a726 100755 --- a/fff +++ b/fff @@ -1,6 +1,4 @@ #!/usr/bin/env bash -# -# fff - fucking fast file-manager. get_os() { # Figure out the current operating system to set some specific variables. @@ -1203,9 +1201,7 @@ cmd_line() { # Tab. $'\t') - ((helping)) && return - - ((history)) && return + ((helping)) || ((history)) && return comp_glob="$cmd_reply*" @@ -1793,9 +1789,9 @@ key() { ;; # Copy filename to clipboard. - ${FFF_KEY_CLIPBOARD:=Y}) + ${FFF_KEY_CLIPBOARD:-Y}) [[ -e "${list[scroll]}" ]] && { - echo "${list[scroll]}" | ${FFF_CLIPBOARD:=xclip -sel clip} 2>/dev/null + echo ${list[scroll]} | ${FFF_CLIPBOARD:=xclip -selection c} 2>/dev/null cmd_line "${list[scroll]} copied to clipboard" } diff --git a/fff.1 b/fff.1 index ee3fd39..7d16047 100644 --- a/fff.1 +++ b/fff.1 @@ -190,8 +190,8 @@ export FFF_FILE_FORMAT="%f" export FFF_MARK_FORMAT=" %f*" # Clipboard program and arguments. -# Default: xclip -sel clip -export FFF_KEY_CLIPBOARD="xclip -sel clip" +# Default: xclip -selection c +export FFF_KEY_CLIPBOARD="xclip -selection c" # Scroll steps. # (14 by default). @@ -280,6 +280,9 @@ export FFF_KEY_HIDDEN="." # Show history of directories. export FFF_KEY_HISTORY="e" + +# Copy filename to clipboard. +export FFF_KEY_CLIPBOARD="Y" . .fi From 0dfbe284bfd0a898f3ee0a718256b7e82c928bf0 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Tue, 14 Nov 2023 18:39:35 +0000 Subject: [PATCH 33/46] Change single file renaming behaviour --- README.md | 11 ++++---- fff | 80 ++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 74 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 5b2e174..10cab6f 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,13 @@ - Sort files by modification time or alphabetically - `ctrl + d`/`ctrl + u` scrolling - Working history of directories and picker for them -- Changed marking behaviour to nnn-like (mark with space, then choose command, and execute it) -- Slightly changed keybindings to better suit more options -- Removed ability to view images (because I don't use it, but can add it for request) +- Changed marking behaviour to nnn-like (mark with space, choose a command, and then execute it) +- Changed keybindings to better suit more options +- Removed ability to view images (because I don't use it, but can add it for a request) - Optional config file for global configuration - Colored filenames - Copy filename to clipboard +- Changed single file renaming behaviour to allow using arrows and automatically display renamed file (and `ctrl + a` to go at the beginning of the filename). ### Thanks @@ -31,10 +32,10 @@ A big part of code in there is from people who made PRs and posted issues to fff - Roy Orbitson (help page) img - Sidd Dino (devicons) -- qwool (idea for human-readable size) +- qwool (human-readable size) - Docbroke (sorting) - yiselieren (file details) -- Isaac Elenbaas (config file) +- Isaac Elenbaas (config file, changing renaming behaviour) ## Table of Contents diff --git a/fff b/fff index 4b7a726..8fd9f72 100755 --- a/fff +++ b/fff @@ -168,10 +168,12 @@ get_icon() { 'Desktop' ) printf -- '󰇄'; return ;; 'Documents' ) printf -- ''; return ;; 'Downloads' ) printf -- ''; return ;; + '.config' |\ 'Dotfiles' |\ 'dotfiles' |\ '.dotfiles' ) printf -- ''; return ;; - 'Dropbox' ) printf -- ''; return ;; + '.cache' ) printf -- ''; return ;; + 'Dropbox' ) printf -- ''; return ;; 'Music' ) printf -- ''; return ;; 'Pictures' ) printf -- ''; return ;; 'Public' ) printf -- ''; return ;; @@ -256,8 +258,8 @@ get_icon() { 'dockerfile' |\ 'Dockerfile' ) printf -- '󰡨'; return ;; - 'dropbox' ) printf -- ''; return ;; - 'exact-match-case-sensitive-2' ) printf -- 'X2'; return ;; + 'dropbox' ) printf -- ''; return ;; + 'exact-match-case-sensitive-2' ) printf -- 'X'; return ;; 'ledger' ) printf -- ''; return ;; 'node_modules' ) printf -- '󰎙'; return ;; 'playlists' ) printf -- ''; return ;; @@ -495,7 +497,7 @@ get_icon() { 'tex' ) printf -- 'ﭨ'; return ;; 'ts' ) printf -- ''; return ;; 'twig' ) printf -- ''; return ;; - 'vue' ) printf -- '﵂'; return ;; + 'vue' ) printf -- ''; return ;; 'xcplayground' ) printf -- ''; return ;; 'xul' ) printf -- ''; return ;; @@ -927,6 +929,7 @@ list_help() { "${FFF_KEY_SORT:-u}: sort files" "${FFF_KEY_ATTRIBUTES:-x}: view file/dir attributes" "${FFF_KEY_HISTORY:-e}: show history" + "${FFF_KEY_CLIPBOARD:-Y}: copy filename to clipboard" '' 'down: scroll down' 'up: scroll up' @@ -1180,7 +1183,20 @@ open_with() { cmd_line() { # Write to the command_line (under status_line). - cmd_reply= + cmd_reply=${list[scroll]##*/} + local status="${1} " + # Position of the cursor relative to the beginning of the reply. + local curpos=${#cmd_reply} + # Lenght of status. + local status_len=${#status} + # Current position of the cursor. + local pos=0 + + # If search or go to or nothing was passed. + [[ "$2" != "rename" ]] && { + cmd_reply= + curpos=0 + } # '\e7': Save cursor position. # '\e[?25h': Unhide the cursor. @@ -1189,11 +1205,24 @@ cmd_line() { # '\r\e[K': Redraw the read prompt on every keypress. # This is mimicking what happens normally. - while IFS= read -rsn 1 -p $'\r\e[K'"${1}${cmd_reply}" read_reply; do + while true; do + pos=$((status_len+curpos)) + + # '\r\e[K': Redraw everything. + # '\e[%s;'"$pos"'H': Go to $pos position at the bottom. + printf '\r\e[K'"${1}${cmd_reply}" + printf '\e[%s;'"$pos"'H' "$LINES" + IFS= read -rsn 1 read_reply + case $read_reply in # Backspace. $'\177'|$'\b') - cmd_reply=${cmd_reply%?} + # Do not delete status. + [ $pos -le $status_len ] && curpos=0 || { + # Delete char at curpos. + cmd_reply="${cmd_reply:0:curpos-1}${cmd_reply:curpos}" + curpos=$((curpos-1)) + } # Clear tab-completion. unset comp c @@ -1218,13 +1247,37 @@ cmd_line() { cmd_reply=${comp[c]} ((c=c >= ${#comp[@]}-1 ? 0 : ++c)) } + + curpos=${#cmd_reply} + ;; + + # Ctrl + a go to the beginning of the reply. + $'\001') + curpos=0 ;; # Escape / Custom 'no' value (used as a replacement for '-n 1'). $'\e'|${3:-null}) - read "${read_flags[@]}" -rsn 2 - cmd_reply= - break + # Read escape sequence and check for arrow keys + read "${read_flags[@]}" -rsn 2 escape_chars + case $escape_chars in + # Left arrow. + '[D'|'OD') + curpos=$((curpos-1)) + # Reset curpos if going out of bounds. + [ $pos -le $status_len ] && curpos=0 + ;; + # Right arrow. + '[C'|'OC') + # Go to right only if previously went to the left. + [ $curpos -lt ${#cmd_reply} ] && curpos=$((curpos+1)) + ;; + + *) + cmd_reply= + break + ;; + esac ;; # Enter/Return. @@ -1255,11 +1308,14 @@ cmd_line() { # Replace '~' with '$HOME'. "~") cmd_reply+=$HOME + curpos=${#cmd_reply} ;; # Anything else, add it to read reply. *) - cmd_reply+=$read_reply + curpos=$((curpos+1)) + # Add letter where is curpos. + cmd_reply="${cmd_reply:0:curpos-1}${read_reply}${cmd_reply:curpos-1}" # Clear tab-completion. unset comp c @@ -1607,7 +1663,7 @@ key() { [[ ! -e ${list[scroll]} ]] && return - cmd_line "rename ${list[scroll]##*/}: " + cmd_line "rename ${list[scroll]##*/}: " "rename" [[ $cmd_reply ]] && if [[ -e $cmd_reply ]]; then From ee014b5254821e0164ee9a8322a3c595b0c36c50 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 16 Nov 2023 19:46:31 +0000 Subject: [PATCH 34/46] Deleted clear option, changed copy files to `c` --- README.md | 32 ++++++++++---------------------- fff | 24 ++++++------------------ fff.1 | 12 +++++------- 3 files changed, 21 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 10cab6f..db9144f 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,14 @@ - Sort files by modification time or alphabetically - `ctrl + d`/`ctrl + u` scrolling - Working history of directories and picker for them -- Changed marking behaviour to nnn-like (mark with space, choose a command, and then execute it) +- Changed marking behavior to nnn-like (mark with space, choose a command, and then execute it) - Changed keybindings to better suit more options - Removed ability to view images (because I don't use it, but can add it for a request) - Optional config file for global configuration - Colored filenames -- Copy filename to clipboard -- Changed single file renaming behaviour to allow using arrows and automatically display renamed file (and `ctrl + a` to go at the beginning of the filename). +- Copy filename to clipboard with `y` and copy file with `c` +- Changed single file renaming behavior to allow using arrows and automatically display renamed file (and `ctrl + a` to go at the beginning of the filename). +- Deleted clear option (clear marks by pressing `FFF_KEY_MARK_ALL`) ### Thanks @@ -35,7 +36,7 @@ A big part of code in there is from people who made PRs and posted issues to fff - qwool (human-readable size) - Docbroke (sorting) - yiselieren (file details) -- Isaac Elenbaas (config file, changing renaming behaviour) +- Isaac Elenbaas (config file, changing renaming behavior) ## Table of Contents @@ -47,7 +48,6 @@ A big part of code in there is from people who made PRs and posted issues to fff * [Manual](#manual) * [CD on Exit](#cd-on-exit) * [Bash and Zsh](#bash-and-zsh) - * [Fish](#fish) * [Usage](#usage) * [Customization](#customization) * [Customizing the keybindings.](#customizing-the-keybindings) @@ -102,16 +102,6 @@ f() { cd "$(cat "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/.fff_d")" } ``` -#### Fish -```sh -# Add this to you config.fish or equivalent. -# Fish don't support recursive calls so use f function -function f - fff $argv - set -q XDG_CACHE_HOME; or set XDG_CACHE_HOME $HOME/.cache - cd (cat $XDG_CACHE_HOME/fff/.fff_d) -end -``` ## Usage @@ -145,7 +135,7 @@ i: display file details u: sort files x: view file/dir attributes e: show history -Y: copy filename to clipboard +y: copy filename to clipboard down: scroll down up: scroll up @@ -159,14 +149,13 @@ X: toggle executable space: mark file a: mark all files in directory -y: copy +c: copy m: move d: trash (move to FFF_TRASH) s: symbolic link b: bulk rename p: execute paste/move/delete/bulk_rename -c: clear file selections [1-9]: favourites/bookmarks (see customization) @@ -361,14 +350,13 @@ export FFF_KEY_REFRESH="z" ### File operations. export FFF_KEY_MARK=" " export FFF_KEY_MARK_ALL="a" -export FFF_KEY_YANK="y" +export FFF_KEY_COPY="c" export FFF_KEY_MOVE="m" export FFF_KEY_TRASH="d" export FFF_KEY_LINK="s" export FFF_KEY_BULK_RENAME="b" export FFF_KEY_EXECUTE="p" -export FFF_KEY_CLEAR="c" export FFF_KEY_RENAME="r" export FFF_KEY_MKDIR="n" @@ -394,8 +382,8 @@ export FFF_KEY_HIDDEN="." # Show history of directories. export FFF_KEY_HISTORY="e" -# Copy filename to clipboard. -export FFF_KEY_CLIPBOARD="Y" +# Yank filename to clipboard. +export FFF_KEY_CLIPBOARD="y" ``` ### Disabling keybindings. diff --git a/fff b/fff index 8fd9f72..e673cb9 100755 --- a/fff +++ b/fff @@ -929,7 +929,7 @@ list_help() { "${FFF_KEY_SORT:-u}: sort files" "${FFF_KEY_ATTRIBUTES:-x}: view file/dir attributes" "${FFF_KEY_HISTORY:-e}: show history" - "${FFF_KEY_CLIPBOARD:-Y}: copy filename to clipboard" + "${FFF_KEY_CLIPBOARD:-y}: yank filename to clipboard" '' 'down: scroll down' 'up: scroll up' @@ -946,14 +946,13 @@ list_help() { '' "${FFF_KEY_MARK:-" "}: mark" "${FFF_KEY_MARK_ALL:-a}: mark all" - "${FFF_KEY_YANK:-y}: mark copy" + "${FFF_KEY_COPY:-c}: mark copy" "${FFF_KEY_MOVE:-m}: mark move" "${FFF_KEY_TRASH:-d}: mark trash" "${FFF_KEY_LINK:-s}: mark symbolic link" "${FFF_KEY_BULK_RENAME:-b}: mark bulk rename" '' "${FFF_KEY_PASTE:-p}: execute paste/move/delete/bulk_rename" - "${FFF_KEY_CLEAR:-c}: clear file selections" '' "q: exit with 'cd' (if enabled) or exit this help" "ctrl+c: exit without 'cd'" @@ -1574,7 +1573,7 @@ key() { ;; # Mark files for operation. - ${FFF_KEY_YANK:=y}|\ + ${FFF_KEY_COPY:=c}|\ ${FFF_KEY_MOVE:=m}|\ ${FFF_KEY_TRASH:=d}|\ ${FFF_KEY_LINK:=s}|\ @@ -1585,7 +1584,7 @@ key() { # Find the program to use. case "$1" in - ${FFF_KEY_YANK:=y}) file_program=(cp -iR) ;; + ${FFF_KEY_COPY:=c}) file_program=(cp -iR) ;; ${FFF_KEY_MOVE:=m}) file_program=(mv -i) ;; ${FFF_KEY_LINK:=s}) file_program=(ln -s) ;; @@ -1645,17 +1644,6 @@ key() { } ;; - # Clear all marked files. - ${FFF_KEY_CLEAR:=c}) - ((helping)) || ((history)) && return - - [[ ${marked_files[*]} ]] && { - marked_files=() - file_program=() - redraw - } - ;; - # Rename list item. ${FFF_KEY_RENAME:=r}) ((helping)) || ((history)) && return @@ -1844,8 +1832,8 @@ key() { open "$PWD" ;; - # Copy filename to clipboard. - ${FFF_KEY_CLIPBOARD:-Y}) + # Yank filename to clipboard. + ${FFF_KEY_CLIPBOARD:-y}) [[ -e "${list[scroll]}" ]] && { echo ${list[scroll]} | ${FFF_CLIPBOARD:=xclip -selection c} 2>/dev/null diff --git a/fff.1 b/fff.1 index 7d16047..a5309bc 100644 --- a/fff.1 +++ b/fff.1 @@ -49,18 +49,17 @@ f: new file n: new dir r: rename X: toggle executable -Y: copy filename to clipboard +y: copy filename to clipboard space: mark file a: mark all files in directory -y: copy +c: copy m: move d: trash (move to FFF_TRASH) s: symbolic link b: bulk rename p: execute paste/move/delete/bulk_rename -c: clear file selections [1-9]: favourites/bookmarks (see customization) @@ -248,14 +247,13 @@ export FFF_KEY_GO_TRASH="t" ### File operations. export FFF_KEY_MARK=" " export FFF_KEY_MARK_ALL="v" -export FFF_KEY_YANK="y" +export FFF_KEY_COPY="c" export FFF_KEY_MOVE="m" export FFF_KEY_TRASH="d" export FFF_KEY_LINK="s" export FFF_KEY_BULK_RENAME="b" export FFF_KEY_EXECUTE="p" -export FFF_KEY_CLEAR="c" export FFF_KEY_RENAME="r" export FFF_KEY_MKDIR="n" @@ -281,8 +279,8 @@ export FFF_KEY_HIDDEN="." # Show history of directories. export FFF_KEY_HISTORY="e" -# Copy filename to clipboard. -export FFF_KEY_CLIPBOARD="Y" +# Yank filename to clipboard. +export FFF_KEY_CLIPBOARD="y" . .fi From f91b6e8f2ec0904eb628c09f3b213a88829df7d4 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Mon, 20 Nov 2023 19:58:27 +0100 Subject: [PATCH 35/46] Some fixes --- README.md | 4 ++-- fff | 54 +++++++++++++++++++++--------------------------------- fff.1 | 4 ++++ 3 files changed, 27 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index db9144f..9e453bf 100644 --- a/README.md +++ b/README.md @@ -221,8 +221,8 @@ export FFF_COL5=0 export FFF_COL6="48;2;80;80;80" # Colored filenames -# (false by default) -export FFF_COLORED_FILENAMES=true +# (0 by default) +export FFF_COLORED_FILENAMES=1 # Text Editor export EDITOR="nvim" diff --git a/fff b/fff index e673cb9..c7844d0 100755 --- a/fff +++ b/fff @@ -84,10 +84,8 @@ setup_options() { # Use affixes provided by the user or use defaults, if necessary. if [[ $FFF_MARK_FORMAT == *%f* ]]; then mark_pre=${FFF_MARK_FORMAT/'%f'*} - mark_post=${FFF_MARK_FORMAT/*'%f'} else mark_pre=" " - mark_post="*" fi # Find supported 'file' arguments. @@ -531,14 +529,26 @@ status_line() { mark_ui+="(${file_program[*]}) " } + # Display git branch and sorting. + git_branch=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/[\1]/p') + + # Display current sorting + [ $sort -eq 0 ] && \ + sort_help="Sort: alpha" || \ + sort_help="Sort: date" + # Escape the directory string. # Remove all non-printable characters. if ((helping)); then mark_ui= PWD_escaped=help + sort_help= + git_branch=" " elif ((history)); then mark_ui= PWD_escaped=history + sort_help= + git_branch=" " else # Escape the directory string. # Remove all non-printable characters. @@ -558,15 +568,6 @@ status_line() { # '\e8': Restore cursor position. # This is more widely supported than '\e[u'. - # Display git branch and sorting. - git_branch=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/[\1]/p') - - if [ $sort -eq 0 ]; then - sort_help="Sort: alpha" - else - sort_help="Sort: date" - fi - printf '\e7\e[%sH\e[3%s;4%sm%*s\r%s %s%s\e[m\e[%sH\e[K\e8' \ "$((LINES-1))" \ "${FFF_COL5:-0}" \ @@ -645,7 +646,7 @@ print_line() { elif ((history)); then file_name=${list[$1]} if [[ "$file_name" ]]; then - # Highlight the key(s), escaping any specials in overrides to a human-readable form + # Highlight the numbers, escaping any specials in overrides to a human-readable form format+=\\e[${di:-1;3${FFF_COL1:-2}}m local action="${file_name%: *}" format+="$(cat -A <<<"$action" | head -c -2)\\e[${fi:-37}m: " @@ -713,7 +714,7 @@ print_line() { fi # Colored filenames, advised to see manual for FFF_COL4 and FFF_COL6. - if [ "${FFF_COLORED_FILENAMES:-false}" = "true" ]; then + if [ "${FFF_COLORED_FILENAMES:-0}" = 1 ]; then case "${file_name##*.}" in # yellow "js" | "Makefile" | "png" | "jpg" | "gif" | "webp" \ @@ -732,12 +733,11 @@ print_line() { # If the list item is under the cursor. (($1 == scroll)) && - format+="\\e[1;${FFF_COL4:-36};${FFF_COL6:-7}m" + format+="\\e[1;${FFF_COL4:-1};${FFF_COL6:-7}m" # If the list item is marked for operation. !((helping)) && !((history)) && [[ ${marked_files[$1]} == "${list[$1]:-null}" ]] && { format+=\\e[3${FFF_COL3:-1}m${mark_pre} - suffix+=${mark_post} } # Escape the directory string. @@ -859,32 +859,26 @@ redraw() { # Redraw the current window. # If 'full' is passed, re-fetch the directory list. - [[ $1 == full ]] && { - ((helping)) && { + if [[ $1 == full ]]; then + ((helping)) || ((history)) && { helping=0 - find_previous=1 - } - ((history)) && { history=0 find_previous=1 } read_dir scroll=0 - } - # If 'help' is passed, list help text. - [[ $1 == help ]] && { + elif [[ $1 == help ]]; then helping=1 list_help scroll=0 - } # If 'help' is passed, list help text. - [[ $1 == hist ]] && { + elif [[ $1 == hist ]]; then history=1 get_history scroll=0 - } + fi clear_screen draw_dir @@ -1157,13 +1151,7 @@ open() { open_with() { # Open directories and files. - if [[ -d $1/ ]]; then - search= - search_end_early= - cd "${1:-/}" ||: - redraw full - - elif [[ -f $1 ]]; then + if [[ -f $1 ]]; then # If 'fff' was opened as a file picker, save the opened # file in a file called 'opened_file'. ((file_picker == 1)) && { diff --git a/fff.1 b/fff.1 index a5309bc..e112fed 100644 --- a/fff.1 +++ b/fff.1 @@ -124,6 +124,10 @@ export FFF_COL5=0 # is set). export FFF_COL6="48;2;80;80;80" +# Colored filenames +# (0 by default) +export FFF_COLORED_FILENAMES=1 + # Text Editor export EDITOR="nvim" From 96b205b0aee098a5da386417564dcebca2ff88c2 Mon Sep 17 00:00:00 2001 From: piotr-marendowski Date: Fri, 1 Dec 2023 17:34:19 +0100 Subject: [PATCH 36/46] Various QOL improvements Such as: - Don't show details if folder is empty. - Warning message now skipable by pressing any key. - Added `Permission denied` warning. - Changed folders to not be bold. --- fff | 519 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 273 insertions(+), 246 deletions(-) diff --git a/fff b/fff index c7844d0..53944fb 100755 --- a/fff +++ b/fff @@ -161,68 +161,70 @@ get_icon() { # Icons for directories [[ -d "$1" ]] && { case "$2" in - # English - '.git' ) printf -- ''; return ;; - 'Desktop' ) printf -- '󰇄'; return ;; - 'Documents' ) printf -- ''; return ;; - 'Downloads' ) printf -- ''; return ;; - '.config' |\ - 'Dotfiles' |\ - 'dotfiles' |\ - '.dotfiles' ) printf -- ''; return ;; - '.cache' ) printf -- ''; return ;; - 'Dropbox' ) printf -- ''; return ;; - 'Music' ) printf -- ''; return ;; - 'Pictures' ) printf -- ''; return ;; - 'Public' ) printf -- ''; return ;; - 'Templates' ) printf -- ''; return ;; - 'Videos' ) printf -- ''; return ;; - 'Games' ) printf -- '󰊗'; return ;; + '.git' ) printf -- '󰊢'; return ;; + 'Desktop' ) printf -- '󰇄'; return ;; + 'Documents' ) printf -- ''; return ;; + 'Downloads' ) printf -- ''; return ;; + '.config' |\ + 'Dotfiles' |\ + 'dotfiles' |\ + '.dotfiles' ) printf -- ''; return ;; + '.cache' ) printf -- ''; return ;; + 'Music' ) printf -- ''; return ;; + 'Pictures' ) printf -- ''; return ;; + 'Public' ) printf -- ''; return ;; + 'Templates' ) printf -- ''; return ;; + 'Videos' ) printf -- ''; return ;; + 'Games' ) printf -- '󰊗'; return ;; + 'home' ) printf -- ''; return ;; + 'mnt' ) printf -- '󰊶'; return ;; + 'Dropbox' ) printf -- ''; return ;; + # Spanish - 'Escritorio' ) printf -- '󰇄'; return ;; - 'Documentos' ) printf -- ''; return ;; - 'Descargas' ) printf -- ''; return ;; - 'Música' ) printf -- ''; return ;; - 'Imágenes' ) printf -- ''; return ;; - 'Público' ) printf -- ''; return ;; - 'Plantillas' ) printf -- ''; return ;; - 'Vídeos' ) printf -- ''; return ;; + 'Escritorio' ) printf -- '󰇄'; return ;; + 'Documentos' ) printf -- ''; return ;; + 'Descargas' ) printf -- ''; return ;; + 'Música' ) printf -- ''; return ;; + 'Imágenes' ) printf -- ''; return ;; + 'Público' ) printf -- ''; return ;; + 'Plantillas' ) printf -- ''; return ;; + 'Vídeos' ) printf -- ''; return ;; # French - 'Bureau' ) printf -- '󰇄'; return ;; - 'Images' ) printf -- ''; return ;; - 'Musique' ) printf -- ''; return ;; - 'Publique' ) printf -- ''; return ;; - 'Téléchargements' ) printf -- ''; return ;; - 'Vidéos' ) printf -- ''; return ;; + 'Bureau' ) printf -- '󰇄'; return ;; + 'Images' ) printf -- ''; return ;; + 'Musique' ) printf -- ''; return ;; + 'Publique' ) printf -- ''; return ;; + 'Téléchargements' ) printf -- ''; return ;; + 'Vidéos' ) printf -- ''; return ;; # Portuguese - 'Imagens' ) printf -- ''; return ;; - 'Modelos' ) printf -- ''; return ;; - 'Área de trabalho') printf -- '󰇄'; return ;; + 'Imagens' ) printf -- ''; return ;; + 'Modelos' ) printf -- ''; return ;; + 'Área de trabalho') printf -- '󰇄'; return ;; # Italian - 'Documenti' ) printf -- ''; return ;; - 'Immagini' ) printf -- ''; return ;; - 'Modelli' ) printf -- ''; return ;; - 'Musica' ) printf -- ''; return ;; - 'Pubblici' ) printf -- ''; return ;; - 'Scaricati' ) printf -- ''; return ;; - 'Scrivania' ) printf -- '󰇄'; return ;; - 'Video' ) printf -- ''; return ;; + 'Documenti' ) printf -- ''; return ;; + 'Immagini' ) printf -- ''; return ;; + 'Modelli' ) printf -- ''; return ;; + 'Musica' ) printf -- ''; return ;; + 'Pubblici' ) printf -- ''; return ;; + 'Scaricati' ) printf -- ''; return ;; + 'Scrivania' ) printf -- '󰇄'; return ;; + 'Video' ) printf -- ''; return ;; # German - 'Bilder' ) printf -- ''; return ;; - 'Dokumente' ) printf -- ''; return ;; - 'Musik' ) printf -- ''; return ;; - 'Schreibtisch' ) printf -- '󰇄'; return ;; - 'Vorlagen' ) printf -- ''; return ;; - 'Öffentlich' ) printf -- ''; return ;; + 'Bilder' ) printf -- ''; return ;; + 'Dokumente' ) printf -- ''; return ;; + 'Musik' ) printf -- ''; return ;; + 'Schreibtisch' ) printf -- '󰇄'; return ;; + 'Vorlagen' ) printf -- ''; return ;; + 'Öffentlich' ) printf -- ''; return ;; # Hungarian - 'Dokumentumok' ) printf -- ''; return ;; - 'Képek' ) printf -- ''; return ;; - 'Zene' ) printf -- ''; return ;; - 'Letöltések' ) printf -- ''; return ;; - 'Videók' ) printf -- ''; return ;; - 'Számítógép' ) printf -- '󰇄'; return ;; - - * ) printf -- ''; return ;; + 'Dokumentumok' ) printf -- ''; return ;; + 'Képek' ) printf -- ''; return ;; + 'Zene' ) printf -- ''; return ;; + 'Letöltések' ) printf -- ''; return ;; + 'Videók' ) printf -- ''; return ;; + 'Számítógép' ) printf -- '󰇄'; return ;; + + * ) printf -- ''; return ;; esac } @@ -264,6 +266,7 @@ get_icon() { 'procfile' ) printf -- ''; return ;; 'README' ) printf -- ''; return ;; 'PKGBUILD' ) printf -- '󰏖'; return ;; + 'log' ) printf -- '󱀂'; return ;; '*' ) printf -- ''; return ;; esac } @@ -340,13 +343,14 @@ get_icon() { '.gitlab-ci.yml' ) printf -- ''; return ;; 'config.ru' ) printf -- ''; return ;; 'docker-compose.yml' ) printf -- ''; return ;; - 'exact-match-case-sensitive-1.txt' ) printf -- 'X1'; return ;; + 'exact-match-case-sensitive-1.txt' ) printf -- 'X'; return ;; 'favicon.ico' ) printf -- ''; return ;; 'mix.lock' ) printf -- ''; return ;; 'react.jsx' ) printf -- ''; return ;; esac case "$3" in + 'shada' |\ 'efi' | 'menu' |\ 'cfg' | 'EFI' |\ 'desktop' | 'name' |\ @@ -486,13 +490,13 @@ get_icon() { 'nix' ) printf -- ''; return ;; 'php' ) printf -- ''; return ;; 'pp' ) printf -- ''; return ;; - 'r' ) printf -- 'ﳒ'; return ;; + 'r' ) printf -- ''; return ;; 'rss' ) printf -- ''; return ;; 'scala' ) printf -- ''; return ;; 'styl' ) printf -- ''; return ;; 'swift' ) printf -- ''; return ;; 't' ) printf -- ''; return ;; - 'tex' ) printf -- 'ﭨ'; return ;; + 'tex' ) printf -- ''; return ;; 'ts' ) printf -- ''; return ;; 'twig' ) printf -- ''; return ;; 'vue' ) printf -- ''; return ;; @@ -660,7 +664,7 @@ print_line() { # Directory. elif [[ -d ${list[$1]} ]]; then - format+=\\e[${di:-1;3${FFF_COL1:-2}}m + format+=\\e[${di:-0;3${FFF_COL1:-4}}m suffix+=/ # Block special file. @@ -718,16 +722,16 @@ print_line() { case "${file_name##*.}" in # yellow "js" | "Makefile" | "png" | "jpg" | "gif" | "webp" \ - | "pdf" | "json" | "yml" | "xml") format+=\\e[${di:-1;33}m ;; + | "pdf" | "json" | "yml" | "xml") format+=\\e[${di:-0;33}m ;; # blue "md" | "lua" | "css" | "c" | "cpp" | "ts" | "py" \ - | "go" | "mp3") format+=\\e[${di:-1;34}m ;; + | "go" | "mp3") format+=\\e[${di:-0;34}m ;; # purple "csharp" | "php" | "h" | "jar" | "diff" | "iso" \ - | "zip" | "tar" | "gz" | "rar" | "zst") format+=\\e[${di:-1;35}m ;; + | "zip" | "tar" | "gz" | "rar" | "zst") format+=\\e[${di:-0;35}m ;; # orange "java" | "rb" | "html" | "pl" | "mp4" | "mkv" \ - | "webm" | "mov") format+=\\e[${di:-1;36}m ;; + | "webm" | "mov") format+=\\e[${di:-0;36}m ;; esac fi @@ -746,8 +750,7 @@ print_line() { # Get icon for file. (( ${FFF_FILE_ICON:=0} == 1 )) && { - # If file is executable and is not directory. - if [[ -x ${list[$1]} && ! -d ${list[$1]} ]]; then + if [[ -x ${list[$1]} && -f ${list[$1]} ]]; then icon=" " else icon="$(get_icon "${list[$1]}" "$file_name" "$file_ext") " @@ -756,16 +759,17 @@ print_line() { # Check if current dir is a git repo and has changes, then # display git signs if is. - if [ " $git_branch" != " " ] && [ -n "$git_output" ]; then + if [ -n "$git_branch" ] && [ -n "$git_output" ]; then (( ${FFF_GIT_CHANGES:=0} == 1 )) && \ - git="$(git_changes "$file_name")" + git="$(git_changes "$file_name") " fi # Display details (date, time and file size). - if (( details == 1 )); then + # If directory is empty then don't show details. + if (( details == 1 )) && [[ ${list[0]} != empty ]]; then local line=' ' - file_size=$("${FFF_STAT_CMD:-stat}" -c "%s" "${list[$1]}" | numfmt --to=iec) + file_size=$("${FFF_STAT_CMD:-stat}" -c "%s" "${list[$1]}" 2> /dev/null | numfmt --to=iec) date="$(date -r ${list[$1]} +"%Y-%m-%d %H:%M" 2> /dev/null)" # If there is error, then just print space to align file names. @@ -773,7 +777,7 @@ print_line() { date=" " line=' ' else - date=" ${date} " + date="${date} " file_size=" ${file_size}B " fi else @@ -786,7 +790,7 @@ print_line() { # https://stackoverflow.com/a/4411098 # This basically makes the file size and file name align. printf '\r%b%s\e[m\r' \ - "${file_pre}${format}${date}${file_size}${line:${#file_size}}${git} ${icon}"\ + "${file_pre}${format}${date}${file_size}${line:${#file_size}}${git}${icon}"\ "${file_name}${suffix}${file_post}" } @@ -998,8 +1002,8 @@ mark() { # Mark file for operation. # If an item is marked in a second directory, # clear the marked files. - [[ $PWD != "$mark_dir" ]] && - marked_files=() + # [[ $PWD != "$mark_dir" ]] && + # marked_files=() # Don't allow the user to mark the empty directory list item. [[ ${list[0]} == empty && -z ${list[1]} ]] && @@ -1008,7 +1012,7 @@ mark() { if [[ $1 == all ]]; then if ((${#marked_files[@]} != ${#list[@]})); then marked_files=("${list[@]}") - mark_dir=$PWD + # mark_dir=$PWD else marked_files=() file_program=() @@ -1018,10 +1022,9 @@ mark() { else if [[ ${marked_files[$1]} == "${list[$1]}" ]]; then unset 'marked_files[scroll]' - else marked_files[$1]="${list[$1]}" - mark_dir=$PWD + # mark_dir=$PWD fi # Clear line before changing it. @@ -1045,7 +1048,7 @@ trash() { command "$FFF_TRASH_CMD" "${@:1:$#-1}" else - cd "$FFF_TRASH" || cmd_line "error: Can't cd to trash directory." + cd "$FFF_TRASH" || cmd_line "warning: Can't cd to trash directory." if cp -alf "$@" &>/dev/null; then rm -r "${@:1:$#-1}" @@ -1073,7 +1076,7 @@ bulk_rename() { # If the user deleted a line, stop here. ((${#marked_files[@]} != ${#changed_files[@]})) && { rm "$rename_file" - cmd_line "error: Line mismatch in rename file. Doing nothing." + cmd_line "warning: Line mismatch in rename file. Doing nothing." return } @@ -1107,13 +1110,17 @@ open() { if [[ -d $1/ ]]; then search= search_end_early= - cd "${1:-/}" ||: - - # Add directory to history. - echo -e "${PWD}\n$(cat "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/history")" > \ - "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/history" - - redraw full + cd "${1:-/}" && { + # Add directory to history. + redraw full + echo -e "${PWD}\n$(cat "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/history")" > \ + "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/history" + } || { + # Catch the error and redraw at current position. + clear_screen + draw_dir + cmd_line "warning: Permission denied: ${1}" + } # Files elif [[ -f $1 ]]; then @@ -1179,168 +1186,188 @@ cmd_line() { # Current position of the cursor. local pos=0 - # If search or go to or nothing was passed. - [[ "$2" != "rename" ]] && { - cmd_reply= - curpos=0 - } - # '\e7': Save cursor position. # '\e[?25h': Unhide the cursor. # '\e[%sH': Move cursor to bottom (cmd_line). printf '\e7\e[%sH\e[?25h' "$LINES" + + # If nothing is passed then handle it as error, + # and run search/rename. + [ -n "$2" ] && { + + # If search or go to or nothing was passed. + [[ "$2" != "rename" ]] && { + cmd_reply= + curpos=0 + } - # '\r\e[K': Redraw the read prompt on every keypress. - # This is mimicking what happens normally. - while true; do - pos=$((status_len+curpos)) - - # '\r\e[K': Redraw everything. - # '\e[%s;'"$pos"'H': Go to $pos position at the bottom. - printf '\r\e[K'"${1}${cmd_reply}" - printf '\e[%s;'"$pos"'H' "$LINES" - IFS= read -rsn 1 read_reply - - case $read_reply in - # Backspace. - $'\177'|$'\b') - # Do not delete status. - [ $pos -le $status_len ] && curpos=0 || { - # Delete char at curpos. - cmd_reply="${cmd_reply:0:curpos-1}${cmd_reply:curpos}" - curpos=$((curpos-1)) - } - - # Clear tab-completion. - unset comp c - ;; - - # Tab. - $'\t') - ((helping)) || ((history)) && return - - comp_glob="$cmd_reply*" - - # Pass the argument dirs to limit completion to directories. - [[ $2 == dirs ]] && - comp_glob="$cmd_reply*/" - - # Generate a completion list once. - [[ -z ${comp[0]} ]] && - IFS=$'\n' read -d "" -ra comp < <(compgen -G "$comp_glob") - - # On each tab press, cycle through the completion list. - [[ -n ${comp[c]} ]] && { - cmd_reply=${comp[c]} - ((c=c >= ${#comp[@]}-1 ? 0 : ++c)) - } - - curpos=${#cmd_reply} - ;; - - # Ctrl + a go to the beginning of the reply. - $'\001') - curpos=0 - ;; - - # Escape / Custom 'no' value (used as a replacement for '-n 1'). - $'\e'|${3:-null}) - # Read escape sequence and check for arrow keys - read "${read_flags[@]}" -rsn 2 escape_chars - case $escape_chars in - # Left arrow. - '[D'|'OD') + while true; do + pos=$((status_len+curpos)) + # '\r\e[K': Redraw everything. + # '\e[%s;'"$pos"'H': Go to $pos position at the bottom. + # '\e[5 q': Change cursor to vertical bar. + printf '\r\e[K'"${1}${cmd_reply}" + printf '\e[%s;'"$pos"'H' "$LINES" + printf '\e[5 q' + IFS= read -rsn 1 read_reply + + case $read_reply in + # Backspace. + $'\177'|$'\b') + # Do not delete status. + [ $pos -le $status_len ] && curpos=0 || { + # Delete char at curpos. + cmd_reply="${cmd_reply:0:curpos-1}${cmd_reply:curpos}" curpos=$((curpos-1)) - # Reset curpos if going out of bounds. - [ $pos -le $status_len ] && curpos=0 - ;; - # Right arrow. - '[C'|'OC') - # Go to right only if previously went to the left. - [ $curpos -lt ${#cmd_reply} ] && curpos=$((curpos+1)) - ;; - - *) - cmd_reply= - break - ;; - esac - ;; - - # Enter/Return. - "") - # If there's only one search result and its a directory, - # enter it on one enter keypress. - !((helping)) && !((history)) && [[ $2 == search && -d ${list[0]} ]] && ((list_total == 0)) && { - # '\e[?25l': Hide the cursor. - printf '\e[?25l' + } - open "${list[0]}" - search_end_early=1 - - # Unset tab completion variables since we're done. + # Clear tab-completion. unset comp c - return - } - - break - ;; - - # Custom 'yes' value (used as a replacement for '-n 1'). - ${2:-null}) - cmd_reply=$read_reply - break - ;; - - # Replace '~' with '$HOME'. - "~") - cmd_reply+=$HOME - curpos=${#cmd_reply} - ;; - - # Anything else, add it to read reply. - *) - curpos=$((curpos+1)) - # Add letter where is curpos. - cmd_reply="${cmd_reply:0:curpos-1}${read_reply}${cmd_reply:curpos-1}" - - # Clear tab-completion. - unset comp c - ;; - esac + ;; + + # Tab. + $'\t') + ((helping)) || ((history)) && return + + comp_glob="$cmd_reply*" + + # Pass the argument dirs to limit completion to directories. + [[ $2 == dirs ]] && + comp_glob="$cmd_reply*/" + + # Generate a completion list once. + [[ -z ${comp[0]} ]] && + IFS=$'\n' read -d "" -ra comp < <(compgen -G "$comp_glob") + + # On each tab press, cycle through the completion list. + [[ -n ${comp[c]} ]] && { + cmd_reply=${comp[c]} + ((c=c >= ${#comp[@]}-1 ? 0 : ++c)) + } + + curpos=${#cmd_reply} + ;; + + # Ctrl + a go to the beginning of the reply. + $'\001') + curpos=0 + ;; + + # Escape / Custom 'no' value (used as a replacement for '-n 1'). + $'\e'|${3:-null}) + # Read escape sequence and check for arrow keys + read "${read_flags[@]}" -rsn 2 escape_chars + case $escape_chars in + # Left arrow. + '[D'|'OD') + curpos=$((curpos-1)) + # Reset curpos if going out of bounds. + [ $pos -le $status_len ] && curpos=0 + ;; + # Right arrow. + '[C'|'OC') + # Go to right only if previously went to the left. + [ $curpos -lt ${#cmd_reply} ] && curpos=$((curpos+1)) + ;; + + *) + cmd_reply= + break + ;; + esac + ;; + + # Enter/Return. + "") + # If there's only one search result and its a directory, + # enter it on one enter keypress. + !((helping)) && !((history)) && [[ $2 == search && -d ${list[0]} ]] && ((list_total == 0)) && { + # '\e[?25l': Hide the cursor. + printf '\e[?25l' + + open "${list[0]}" + search_end_early=1 + + # Unset tab completion variables since we're done. + unset comp c + return + } + + break + ;; + + # Custom 'yes' value (used as a replacement for '-n 1'). + ${2:-null}) + cmd_reply=$read_reply + break + ;; + + # Replace '~' with '$HOME'. + "~") + cmd_reply+=$HOME + curpos=${#cmd_reply} + ;; + + # Anything else, add it to read reply. + *) + curpos=$((curpos+1)) + # Add letter where is curpos. + cmd_reply="${cmd_reply:0:curpos-1}${read_reply}${cmd_reply:curpos-1}" + + # Clear tab-completion. + unset comp c + ;; + esac - # Search on keypress if search passed as an argument. - [[ $2 == search ]] && { - # '\e[?25l': Hide the cursor. - printf '\e[?25l' - - # Use a greedy glob to search. - if ((helping)); then - local item - list=() - for item in "${cur_list[@]}"; do - [[ "$item" == *"$cmd_reply"* ]] && list+=("$item") - done - elif ((history)); then - local item - list=() - for item in "${cur_list[@]}"; do - [[ "$item" == *"$cmd_reply"* ]] && list+=("$item") - done - else - list=("$PWD"/*"$cmd_reply"*) - fi - ((list_total=${#list[@]}-1)) + # Search on keypress if search passed as an argument. + [[ $2 == search ]] && { + # '\e[?25l': Hide the cursor. + printf '\e[?25l' + + # Use a greedy glob to search. + if ((helping)); then + local item + list=() + for item in "${cur_list[@]}"; do + [[ "$item" == *"$cmd_reply"* ]] && list+=("$item") + done + elif ((history)); then + local item + list=() + for item in "${cur_list[@]}"; do + [[ "$item" == *"$cmd_reply"* ]] && list+=("$item") + done + else + list=("$PWD"/*"$cmd_reply"*) + fi + ((list_total=${#list[@]}-1)) - # Draw the search results on screen. - scroll=0 - redraw + # Draw the search results on screen. + scroll=0 + redraw - # '\e[%sH': Move cursor back to cmd-line. - # '\e[?25h': Unhide the cursor. - printf '\e[%sH\e[?25h' "$LINES" - } - done + # '\e[%sH': Move cursor back to cmd_line. + # '\e[?25h': Unhide the cursor. + printf '\e[%sH\e[?25h' "$LINES" + } + done + } || { + while true; do + pos=$((status_len+curpos)) + # '\r\e[K'"${1}": Redraw everything. + # '\e[%s' "$LINES": Go to the last position at the bottom. + printf '\r\e[K'"${1}" + printf '\e[%s' "$LINES" + IFS= read -rsn 1 read_reply + case $read_reply in + *) + # Clear tab-completion. + unset comp c + break + ;; + esac + done + } # Unset tab completion variables since we're done. unset comp c @@ -1602,12 +1629,12 @@ key() { ${FFF_KEY_EXECUTE:=p}) [[ ${marked_files[*]} ]] && { [[ ! -w $PWD ]] && { - cmd_line "WARNING: No write access to dir" + cmd_line "warning: No write access to dir" return } [[ -z ${file_program[0]} ]] && { - cmd_line "WARNING: No operation selected [y,m,d,b,s]" + cmd_line "warning: No operation selected [y,m,d,b,s]" return } @@ -1626,7 +1653,7 @@ key() { redraw full } || { [[ -z ${file_program[0]} ]] && { - cmd_line "WARNING: 0 marked files" + cmd_line "warning: 0 marked files" return } } @@ -1643,14 +1670,14 @@ key() { [[ $cmd_reply ]] && if [[ -e $cmd_reply ]]; then - cmd_line "WARNING: '$cmd_reply' already exists" + cmd_line "warning: '$cmd_reply' already exists" elif [[ -w ${list[scroll]} ]]; then mv "${list[scroll]}" "${PWD}/${cmd_reply}" redraw full else - cmd_line "WARNING: No write access to file" + cmd_line "warning: No write access to file" fi ;; @@ -1662,14 +1689,14 @@ key() { [[ $cmd_reply ]] && if [[ -e $cmd_reply ]]; then - cmd_line "WARNING: '$cmd_reply' already exists" + cmd_line "warning: '$cmd_reply' already exists" elif [[ -w $PWD ]]; then mkdir -p "${PWD}/${cmd_reply}" redraw full else - cmd_line "WARNING: No write access to dir" + cmd_line "warning: No write access to dir" fi ;; @@ -1681,14 +1708,14 @@ key() { [[ $cmd_reply ]] && if [[ -e $cmd_reply ]]; then - cmd_line "WARNING: '$cmd_reply' already exists" + cmd_line "warning: '$cmd_reply' already exists" elif [[ -w $PWD ]]; then : > "$cmd_reply" redraw full else - cmd_line "WARNING: No write access to dir" + cmd_line "warning: No write access to dir" fi ;; From dac63f627f7313430cdcfe9cf8d671e543431c1e Mon Sep 17 00:00:00 2001 From: piotr-marendowski Date: Fri, 1 Dec 2023 17:48:17 +0100 Subject: [PATCH 37/46] Fix space for items without date --- fff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fff b/fff index 53944fb..90b44a8 100755 --- a/fff +++ b/fff @@ -770,7 +770,7 @@ print_line() { local line=' ' file_size=$("${FFF_STAT_CMD:-stat}" -c "%s" "${list[$1]}" 2> /dev/null | numfmt --to=iec) - date="$(date -r ${list[$1]} +"%Y-%m-%d %H:%M" 2> /dev/null)" + date="$(date -r ${list[$1]} +"%Y-%m-%d %H:%M" 2> /dev/null) " # If there is error, then just print space to align file names. if [ "$?" -ne "0" ]; then From 33a641a19c092a6277494e1d9006969f317b9415 Mon Sep 17 00:00:00 2001 From: piotr-marendowski Date: Sat, 2 Dec 2023 11:48:12 +0100 Subject: [PATCH 38/46] Revert removing space between left border, add space on the end of items --- fff | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fff b/fff index 90b44a8..c52572d 100755 --- a/fff +++ b/fff @@ -761,7 +761,7 @@ print_line() { # display git signs if is. if [ -n "$git_branch" ] && [ -n "$git_output" ]; then (( ${FFF_GIT_CHANGES:=0} == 1 )) && \ - git="$(git_changes "$file_name") " + git="$(git_changes "$file_name")" fi # Display details (date, time and file size). @@ -770,7 +770,7 @@ print_line() { local line=' ' file_size=$("${FFF_STAT_CMD:-stat}" -c "%s" "${list[$1]}" 2> /dev/null | numfmt --to=iec) - date="$(date -r ${list[$1]} +"%Y-%m-%d %H:%M" 2> /dev/null) " + date=" $(date -r ${list[$1]} +"%Y-%m-%d %H:%M" 2> /dev/null)" # If there is error, then just print space to align file names. if [ "$?" -ne "0" ]; then @@ -790,8 +790,8 @@ print_line() { # https://stackoverflow.com/a/4411098 # This basically makes the file size and file name align. printf '\r%b%s\e[m\r' \ - "${file_pre}${format}${date}${file_size}${line:${#file_size}}${git}${icon}"\ - "${file_name}${suffix}${file_post}" + "${file_pre}${format}${date}${file_size}${line:${#file_size}}${git} ${icon}"\ + "${file_name}${suffix}${file_post} " } draw_dir() { From 0c4b43248db5a8450cf822f70a051fa8c6409937 Mon Sep 17 00:00:00 2001 From: piotr-marendowski Date: Sat, 2 Dec 2023 20:27:30 +0100 Subject: [PATCH 39/46] Delete other languages --- fff | 46 +--------------------------------------------- 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/fff b/fff index c52572d..534b0f3 100755 --- a/fff +++ b/fff @@ -180,51 +180,7 @@ get_icon() { 'mnt' ) printf -- '󰊶'; return ;; 'Dropbox' ) printf -- ''; return ;; - # Spanish - 'Escritorio' ) printf -- '󰇄'; return ;; - 'Documentos' ) printf -- ''; return ;; - 'Descargas' ) printf -- ''; return ;; - 'Música' ) printf -- ''; return ;; - 'Imágenes' ) printf -- ''; return ;; - 'Público' ) printf -- ''; return ;; - 'Plantillas' ) printf -- ''; return ;; - 'Vídeos' ) printf -- ''; return ;; - # French - 'Bureau' ) printf -- '󰇄'; return ;; - 'Images' ) printf -- ''; return ;; - 'Musique' ) printf -- ''; return ;; - 'Publique' ) printf -- ''; return ;; - 'Téléchargements' ) printf -- ''; return ;; - 'Vidéos' ) printf -- ''; return ;; - # Portuguese - 'Imagens' ) printf -- ''; return ;; - 'Modelos' ) printf -- ''; return ;; - 'Área de trabalho') printf -- '󰇄'; return ;; - # Italian - 'Documenti' ) printf -- ''; return ;; - 'Immagini' ) printf -- ''; return ;; - 'Modelli' ) printf -- ''; return ;; - 'Musica' ) printf -- ''; return ;; - 'Pubblici' ) printf -- ''; return ;; - 'Scaricati' ) printf -- ''; return ;; - 'Scrivania' ) printf -- '󰇄'; return ;; - 'Video' ) printf -- ''; return ;; - # German - 'Bilder' ) printf -- ''; return ;; - 'Dokumente' ) printf -- ''; return ;; - 'Musik' ) printf -- ''; return ;; - 'Schreibtisch' ) printf -- '󰇄'; return ;; - 'Vorlagen' ) printf -- ''; return ;; - 'Öffentlich' ) printf -- ''; return ;; - # Hungarian - 'Dokumentumok' ) printf -- ''; return ;; - 'Képek' ) printf -- ''; return ;; - 'Zene' ) printf -- ''; return ;; - 'Letöltések' ) printf -- ''; return ;; - 'Videók' ) printf -- ''; return ;; - 'Számítógép' ) printf -- '󰇄'; return ;; - - * ) printf -- ''; return ;; + * ) printf -- ''; return ;; esac } From 090d9ccb6443346d28101d4ffa2eaab5fbb9d803 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 16 Dec 2023 11:57:48 +0100 Subject: [PATCH 40/46] QOL improvements, multiple file open with and move status line down Changes: - Multiple file open with (normal and detached) - Move status line one line down and hide it on messages/actions - Hide cursor on `Permission denied` warning - Fixed icons reappearing after entering a directory from history - Let user mark multiple files with multiple directories at time - Fixed marks not reappearing after entering a directory with marks --- README.md | 3 +- fff | 90 ++++++++++++++++--------------------------------------- 2 files changed, 28 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index 9e453bf..c0e558f 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,10 @@ - Removed ability to view images (because I don't use it, but can add it for a request) - Optional config file for global configuration - Colored filenames -- Copy filename to clipboard with `y` and copy file with `c` +- Copy filename to clipboard with `y` and copy file with `c` (when marking) - Changed single file renaming behavior to allow using arrows and automatically display renamed file (and `ctrl + a` to go at the beginning of the filename). - Deleted clear option (clear marks by pressing `FFF_KEY_MARK_ALL`) +- Mark and open with multiple files at time ### Thanks diff --git a/fff b/fff index 534b0f3..659f7b0 100755 --- a/fff +++ b/fff @@ -499,14 +499,9 @@ status_line() { # Escape the directory string. # Remove all non-printable characters. - if ((helping)); then + if ((helping)) || ((history)); then mark_ui= - PWD_escaped=help - sort_help= - git_branch=" " - elif ((history)); then - mark_ui= - PWD_escaped=history + PWD_escaped=" " sort_help= git_branch=" " else @@ -529,14 +524,14 @@ status_line() { # This is more widely supported than '\e[u'. printf '\e7\e[%sH\e[3%s;4%sm%*s\r%s %s%s\e[m\e[%sH\e[K\e8' \ - "$((LINES-1))" \ + "$LINES" \ "${FFF_COL5:-0}" \ "${FFF_COL2:-1}" \ "$COLUMNS" "" \ "($((scroll+1))/$((list_total+1)))" \ "$mark_ui" \ "${1:-${PWD_escaped:-/} $git_branch $sort_help}" \ - "$LINES" + "$((LINES-1))" } read_dir() { @@ -591,7 +586,7 @@ print_line() { local git='' # Help line - if ((helping)); then + if ((helping)) || ((history)); then file_name=${list[$1]} if [[ "$file_name" ]]; then # Highlight the key(s), escaping any specials in overrides to a human-readable form @@ -600,19 +595,6 @@ print_line() { format+="$(cat -A <<<"$action" | head -c -2)\\e[${fi:-37}m: " file_name="${file_name##*: }" fi - format+=\\e[${fi:-37}m - - # History line. - elif ((history)); then - file_name=${list[$1]} - if [[ "$file_name" ]]; then - # Highlight the numbers, escaping any specials in overrides to a human-readable form - format+=\\e[${di:-1;3${FFF_COL1:-2}}m - local action="${file_name%: *}" - format+="$(cat -A <<<"$action" | head -c -2)\\e[${fi:-37}m: " - file_name="${file_name##*: }" - fi - format+=\\e[${fi:-37}m # If the dir item doesn't exist, end here. elif [[ -z ${list[$1]} ]]; then @@ -628,8 +610,8 @@ print_line() { format+=\\e[${bd:-40;33;01}m # Character special file. - elif [[ -c ${list[$1]} ]]; then - format+=\\e[${cd:-40;33;01}m + # elif [[ -c ${list[$1]} ]]; then + # format+=\\e[${cd:-40;33;01}m # Executable file. elif [[ -x ${list[$1]} ]]; then @@ -644,12 +626,12 @@ print_line() { format+=\\e[${ln:-01;36}m # Fifo file. - elif [[ -p ${list[$1]} ]]; then - format+=\\e[${pi:-40;33}m + # elif [[ -p ${list[$1]} ]]; then + # format+=\\e[${pi:-40;33}m # Socket file. - elif [[ -S ${list[$1]} ]]; then - format+=\\e[${so:-01;35}m + # elif [[ -S ${list[$1]} ]]; then + # format+=\\e[${so:-01;35}m # Color files that end in a pattern as defined in LS_COLORS. # 'BASH_REMATCH' is an array that stores each REGEX match. @@ -850,7 +832,7 @@ list_help() { printf '\e]2;fff: help\e'\\ # Turn off icons. - icon_value="$(printf '%s\n' "$FFF_FILE_ICON")" + icon_value=${FFF_FILE_ICON:-0} FFF_FILE_ICON=0 list=( @@ -937,7 +919,7 @@ get_history() { printf '\e]2;fff: history\e'\\ # Turn off icons. - icon_value="$(printf '%s\n' "$FFF_FILE_ICON")" + icon_value=${FFF_FILE_ICON:-0} FFF_FILE_ICON=0 # Add history to lines. @@ -955,12 +937,6 @@ get_history() { } mark() { - # Mark file for operation. - # If an item is marked in a second directory, - # clear the marked files. - # [[ $PWD != "$mark_dir" ]] && - # marked_files=() - # Don't allow the user to mark the empty directory list item. [[ ${list[0]} == empty && -z ${list[1]} ]] && return @@ -968,7 +944,6 @@ mark() { if [[ $1 == all ]]; then if ((${#marked_files[@]} != ${#list[@]})); then marked_files=("${list[@]}") - # mark_dir=$PWD else marked_files=() file_program=() @@ -980,7 +955,6 @@ mark() { unset 'marked_files[scroll]' else marked_files[$1]="${list[$1]}" - # mark_dir=$PWD fi # Clear line before changing it. @@ -1281,13 +1255,7 @@ cmd_line() { printf '\e[?25l' # Use a greedy glob to search. - if ((helping)); then - local item - list=() - for item in "${cur_list[@]}"; do - [[ "$item" == *"$cmd_reply"* ]] && list+=("$item") - done - elif ((history)); then + if ((helping)) || ((history)); then local item list=() for item in "${cur_list[@]}"; do @@ -1311,9 +1279,10 @@ cmd_line() { while true; do pos=$((status_len+curpos)) # '\r\e[K'"${1}": Redraw everything. - # '\e[%s' "$LINES": Go to the last position at the bottom. + # '\e[%s\e[?25l' "$LINES": Go to the last position at the bottom + # and hide the cursor. printf '\r\e[K'"${1}" - printf '\e[%s' "$LINES" + printf '\e[%s\e[?25l' "$LINES" IFS= read -rsn 1 read_reply case $read_reply in *) @@ -1332,6 +1301,7 @@ cmd_line() { # '\e[?25l': Hide the cursor. # '\e8': Restore cursor position. printf '\e[2K\e[?25l\e8' + status_line } key() { @@ -1416,6 +1386,8 @@ key() { open "${list[scroll]}" ((history)) && { + details=$saved_details + FFF_FILE_ICON="$icon_value" list[scroll]=${list[scroll]#* } open "${list[scroll]}" } @@ -1528,6 +1500,8 @@ key() { else search=1 fi + + status_line ;; # Spawn a shell. @@ -1571,8 +1545,8 @@ key() { status_line ;; - # Mark files for operation. - "${FFF_KEY_MARK:=" "}") + # Mark files for operation. + "${FFF_KEY_MARK:=" "}") mark "$scroll" "$1" ;; @@ -1788,13 +1762,7 @@ key() { # Refresh current dir. ${FFF_KEY_REFRESH:=z}) - ((helping)) && { - list=("${cur_list[@]}") - redraw full - return - } - - ((history)) && { + ((helping)) || ((history)) && { list=("${cur_list[@]}") redraw full return @@ -1863,13 +1831,7 @@ key() { lines_num=${FFF_HISTORY_LENGTH:-100} sed -i "${lines_num}q" "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/history" - ((helping)) && { - details=$saved_details - FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. - redraw full - return - } - ((history)) && { + ((helping)) || ((history)) && { details=$saved_details FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. redraw full From de2b9f542c0c132bc894bb5d4eacc535709aa1b4 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 16 Dec 2023 12:30:55 +0100 Subject: [PATCH 41/46] Add multiple file `open with` --- fff | 62 ++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/fff b/fff index 659f7b0..ea06171 100755 --- a/fff +++ b/fff @@ -1087,22 +1087,19 @@ open() { } open_with() { - # Open directories and files. - if [[ -f $1 ]]; then - # If 'fff' was opened as a file picker, save the opened - # file in a file called 'opened_file'. - ((file_picker == 1)) && { - printf '%s\n' "$1" > \ - "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/opened_file" - exit - } + # If 'fff' was opened as a file picker, save the opened + # file in a file called 'opened_file'. + ((file_picker == 1)) && { + printf '%s\n' $2 > \ + "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/opened_file" + exit + } - clear_screen - reset_terminal - "$2" "$1" - setup_terminal - redraw - fi + clear_screen + reset_terminal + $1 $2 + setup_terminal + redraw } cmd_line() { @@ -1705,11 +1702,20 @@ key() { ${FFF_KEY_OPEN_WITH:=o}) ((helping)) || ((history)) && return - [[ -e "${list[scroll]}" ]] && { - cmd_line "open with: " "cmd" + cmd_line "open with: " "cmd" + [[ $cmd_reply ]] && { + if ! command -v $cmd_reply > /dev/null; then + redraw full + cmd_line "warning: command ${cmd_reply} not found" + return + fi + + if [[ ${#marked_files[@]} -ne 0 ]]; then + open_with "${cmd_reply}" "${marked_files[*]}" - [[ $cmd_reply ]] && - open_with "${list[scroll]}" "${cmd_reply}" + elif [[ -e "${list[scroll]}" ]]; then + open_with "${cmd_reply}" "${list[scroll]}" + fi } ;; @@ -1717,12 +1723,22 @@ key() { ${FFF_KEY_OPEN_WITH_DETACHED:=O}) ((helping)) || ((history)) && return - [[ -e "${list[scroll]}" ]] && { - cmd_line "open with (detached): " "cmd" + cmd_line "open with (detached): " "cmd" + [[ $cmd_reply ]] && { + if ! type $cmd_reply > /dev/null; then + redraw full + cmd_line "warning: command ${cmd_reply} not found" + return + fi + + if [[ ${#marked_files[@]} -ne 0 ]]; then + nohup "${cmd_reply}" "${marked_files[*]}" &>/dev/null & - [[ $cmd_reply ]] && + elif [[ -e "${list[scroll]}" ]]; then nohup "${cmd_reply}" "${list[scroll]}" &>/dev/null & - disown + fi + + disown } ;; From 010fb016fec5b2abf90993f6661f1e05a98bf259 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sun, 24 Dec 2023 10:43:19 +0100 Subject: [PATCH 42/46] Add sixel image support, remove colored filenames, another QOL stuff Changes: - Added sixel support (which requires img2sixel command from libsixel) - Removed colored filenames (mostly to speed things up a bit) - Increased the number of currently visible lines by 1 to take advantage of previous changes with the status line - Fixed creating a file - Fixed icon disappearing after opening directory from history - Changed rename command look - Fixed weird history behaviour with current cursor position formatting - Fixed disappearing icons when going back from history - Tried to speed things up (and have in plans to overhaul the behaviour of opening the directory to make it even faster) --- README.md | 20 ++-- fff | 328 +++++++++++++++++++++++++++--------------------------- fff.1 | 8 ++ 3 files changed, 182 insertions(+), 174 deletions(-) diff --git a/README.md b/README.md index c0e558f..5f86efc 100644 --- a/README.md +++ b/README.md @@ -9,23 +9,22 @@ - [Nerd Fonts devicons](https://www.nerdfonts.com/#home) support - Help page on `?` - `Open with` commands -- Human-readable size in stats -- Git branch in stats +- `ctrl + d`/`ctrl + u` scrolling +- view images using [sixel](https://github.com/saitoha/libsixel) - Git branch on status line - Recursive git signs for changed files img - Display file modification date, time and size (resource-heavy) - Sort files by modification time or alphabetically -- `ctrl + d`/`ctrl + u` scrolling - Working history of directories and picker for them - Changed marking behavior to nnn-like (mark with space, choose a command, and then execute it) - Changed keybindings to better suit more options -- Removed ability to view images (because I don't use it, but can add it for a request) - Optional config file for global configuration -- Colored filenames +- Git branch in stats - Copy filename to clipboard with `y` and copy file with `c` (when marking) - Changed single file renaming behavior to allow using arrows and automatically display renamed file (and `ctrl + a` to go at the beginning of the filename). - Deleted clear option (clear marks by pressing `FFF_KEY_MARK_ALL`) - Mark and open with multiple files at time +- Human-readable size in stats ### Thanks @@ -221,10 +220,6 @@ export FFF_COL5=0 # is set). export FFF_COL6="48;2;80;80;80" -# Colored filenames -# (0 by default) -export FFF_COLORED_FILENAMES=1 - # Text Editor export EDITOR="nvim" @@ -299,6 +294,10 @@ export FFF_KEY_CLIPBOARD="xclip -selection c" # (14 by default). export FFF_SCROLL_UP=14 export FFF_SCROLL_DOWN=14 + +# Sixel image program. +# Default: img2sixel +export FFF_SIXEL_CMD="img2sixel" ``` ## Customizing the keybindings. @@ -368,6 +367,9 @@ export FFF_KEY_MKFILE="f" # Display file details. export FFF_KEY_DETAILS="i" +# Display an image using sixel. +export FFF_KEY_SIXEL="I" + # Sort files. export FFF_KEY_SORT="u" diff --git a/fff b/fff index ea06171..ab4efe3 100755 --- a/fff +++ b/fff @@ -103,7 +103,7 @@ get_term_size() { read -r LINES COLUMNS < <(stty size) # Max list items that fit in the scroll area. - ((max_items=LINES-3)) + ((max_items=LINES-2)) } get_ls_colors() { @@ -183,7 +183,6 @@ get_icon() { * ) printf -- ''; return ;; esac } - # Icons for files with no extension [[ "$2" == "$3" ]] && { case "$2" in @@ -226,7 +225,6 @@ get_icon() { '*' ) printf -- ''; return ;; esac } - # Icon for files with the name starting with '.' # without an extension [[ "$2" == ".$3" ]] && { @@ -259,7 +257,6 @@ get_icon() { '*' ) printf -- ''; return ;; esac } - # Icon for files whose names have an extension [[ "$2" == *"."* ]] && { case "$2" in @@ -468,24 +465,15 @@ get_icon() { esac } - printf -- ''; return } -git_changes() { - if [[ " ${changed[@]} " =~ " $1 " ]]; then - printf -- '+'; return - else - printf -- ' '; return - fi -} - status_line() { # Status_line to print when files are marked for operation. local mark_ui= [ ${#marked_files[@]} -gt 0 ] && { mark_ui="[${#marked_files[@]}] selected " - [ ! -z $file_program ] && \ + [[ -n $file_program ]] && \ mark_ui+="(${file_program[*]}) " } @@ -493,7 +481,7 @@ status_line() { git_branch=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/[\1]/p') # Display current sorting - [ $sort -eq 0 ] && \ + [ "$sort" -eq 0 ] && \ sort_help="Sort: alpha" || \ sort_help="Sort: date" @@ -503,7 +491,7 @@ status_line() { mark_ui= PWD_escaped=" " sort_help= - git_branch=" " + git_branch= else # Escape the directory string. # Remove all non-printable characters. @@ -560,15 +548,14 @@ read_dir() { fi done - [ $sort == 1 ] && \ - dirs=($(stat -c '%Y=%n' "${dirs[@]}" | sort -nr | cut -d '=' -f2)) \ + [ "$sort" == 1 ] && \ + dirs=("$(stat -c '%Y=%n' "${dirs[@]}" | sort -nr | cut -d '=' -f2)") \ files=($(stat -c '%Y=%n' "${files[@]}" | sort -nr | cut -d '=' -f2)) list=("${dirs[@]}" "${files[@]}") # Indicate that the directory is empty. - [[ -z ${list[0]} ]] && - list[0]=empty + [[ -z ${list[0]} ]] && list[0]=empty ((list_total=${#list[@]}-1)) @@ -583,18 +570,24 @@ print_line() { local format local suffix local icon - local git='' + local git - # Help line + # History and help pages. if ((helping)) || ((history)); then file_name=${list[$1]} - if [[ "$file_name" ]]; then - # Highlight the key(s), escaping any specials in overrides to a human-readable form - format+=\\e[${di:-1;3${FFF_COL1:-2}}m - local action="${file_name%: *}" - format+="$(cat -A <<<"$action" | head -c -2)\\e[${fi:-37}m: " + [[ "$file_name" ]] && { + # Highlight the key(s)/numbers. + format+="\\e[${di:-1;3${FFF_COL1:-2}}m" + ((helping)) && local action="${file_name%: *}" + format+="$(cat -A <<<"$action" | head -c -2)\\e[${fi:-37}m " file_name="${file_name##*: }" - fi + + # Check if item is selected. + (($1 == scroll)) && format+="\\e[1;${FFF_COL4:-1};${FFF_COL6:-7}m" + printf '\r%b\e[m\r' "${format}${file_name}" + + return + } # If the dir item doesn't exist, end here. elif [[ -z ${list[$1]} ]]; then @@ -605,14 +598,6 @@ print_line() { format+=\\e[${di:-0;3${FFF_COL1:-4}}m suffix+=/ - # Block special file. - elif [[ -b ${list[$1]} ]]; then - format+=\\e[${bd:-40;33;01}m - - # Character special file. - # elif [[ -c ${list[$1]} ]]; then - # format+=\\e[${cd:-40;33;01}m - # Executable file. elif [[ -x ${list[$1]} ]]; then format+=\\e[${ex:-01;32}m @@ -625,14 +610,6 @@ print_line() { elif [[ -h ${list[$1]} ]]; then format+=\\e[${ln:-01;36}m - # Fifo file. - # elif [[ -p ${list[$1]} ]]; then - # format+=\\e[${pi:-40;33}m - - # Socket file. - # elif [[ -S ${list[$1]} ]]; then - # format+=\\e[${so:-01;35}m - # Color files that end in a pattern as defined in LS_COLORS. # 'BASH_REMATCH' is an array that stores each REGEX match. elif [[ $FFF_LS_COLORS == 1 && @@ -655,32 +632,13 @@ print_line() { format+=\\e[${fi:-37}m fi - # Colored filenames, advised to see manual for FFF_COL4 and FFF_COL6. - if [ "${FFF_COLORED_FILENAMES:-0}" = 1 ]; then - case "${file_name##*.}" in - # yellow - "js" | "Makefile" | "png" | "jpg" | "gif" | "webp" \ - | "pdf" | "json" | "yml" | "xml") format+=\\e[${di:-0;33}m ;; - # blue - "md" | "lua" | "css" | "c" | "cpp" | "ts" | "py" \ - | "go" | "mp3") format+=\\e[${di:-0;34}m ;; - # purple - "csharp" | "php" | "h" | "jar" | "diff" | "iso" \ - | "zip" | "tar" | "gz" | "rar" | "zst") format+=\\e[${di:-0;35}m ;; - # orange - "java" | "rb" | "html" | "pl" | "mp4" | "mkv" \ - | "webm" | "mov") format+=\\e[${di:-0;36}m ;; - esac - fi - # If the list item is under the cursor. (($1 == scroll)) && format+="\\e[1;${FFF_COL4:-1};${FFF_COL6:-7}m" # If the list item is marked for operation. - !((helping)) && !((history)) && [[ ${marked_files[$1]} == "${list[$1]:-null}" ]] && { + [[ ${marked_files[$1]} == "${list[$1]:-null}" ]] && format+=\\e[3${FFF_COL3:-1}m${mark_pre} - } # Escape the directory string. # Remove all non-printable characters. @@ -695,11 +653,11 @@ print_line() { fi } - # Check if current dir is a git repo and has changes, then - # display git signs if is. + # Check if current dir is a git repo and has changes, + # then display git signs if it is. if [ -n "$git_branch" ] && [ -n "$git_output" ]; then - (( ${FFF_GIT_CHANGES:=0} == 1 )) && \ - git="$(git_changes "$file_name")" + (( ${FFF_GIT_CHANGES:=0} == 1 )) && + [[ " ${changed[@]} " =~ " $file_name " ]] && git="+ " || git=" " fi # Display details (date, time and file size). @@ -708,27 +666,27 @@ print_line() { local line=' ' file_size=$("${FFF_STAT_CMD:-stat}" -c "%s" "${list[$1]}" 2> /dev/null | numfmt --to=iec) - date=" $(date -r ${list[$1]} +"%Y-%m-%d %H:%M" 2> /dev/null)" + date="$(date -r ${list[$1]} +"%Y-%m-%d %H:%M" 2> /dev/null)" # If there is error, then just print space to align file names. if [ "$?" -ne "0" ]; then date=" " line=' ' else - date="${date} " + date=" ${date} " file_size=" ${file_size}B " fi else - file_size='' - date='' - line='' + file_size= + date= + line= fi # ${file_size}${line:${#file_size}} # https://stackoverflow.com/a/4411098 # This basically makes the file size and file name align. printf '\r%b%s\e[m\r' \ - "${file_pre}${format}${date}${file_size}${line:${#file_size}}${git} ${icon}"\ + "${file_pre}${format}${date}${file_size}${line:${#file_size}} ${git}${icon}"\ "${file_name}${suffix}${file_post} " } @@ -862,6 +820,7 @@ list_help() { "${FFF_KEY_SHELL:-!}: open shell in current dir" '' "${FFF_KEY_DETAILS:-i}: display file details" + "${FFF_KEY_SIXEL:-I}: display an image using sixel" "${FFF_KEY_SORT:-u}: sort files" "${FFF_KEY_ATTRIBUTES:-x}: view file/dir attributes" "${FFF_KEY_HISTORY:-e}: show history" @@ -978,7 +937,7 @@ trash() { command "$FFF_TRASH_CMD" "${@:1:$#-1}" else - cd "$FFF_TRASH" || cmd_line "warning: Can't cd to trash directory." + cd "$FFF_TRASH" || cmd_line "\e[0;31mWarning!\e[0m Can't cd to trash directory." if cp -alf "$@" &>/dev/null; then rm -r "${@:1:$#-1}" @@ -1006,7 +965,7 @@ bulk_rename() { # If the user deleted a line, stop here. ((${#marked_files[@]} != ${#changed_files[@]})) && { rm "$rename_file" - cmd_line "warning: Line mismatch in rename file. Doing nothing." + cmd_line "\e[0;31mWarning!\e[0m Line mismatch in rename file. Doing nothing." return } @@ -1049,7 +1008,7 @@ open() { # Catch the error and redraw at current position. clear_screen draw_dir - cmd_line "warning: Permission denied: ${1}" + cmd_line "\e[0;31mWarning!\e[0m Permission denied: ${1}" } # Files @@ -1208,7 +1167,9 @@ cmd_line() { "") # If there's only one search result and its a directory, # enter it on one enter keypress. - !((helping)) && !((history)) && [[ $2 == search && -d ${list[0]} ]] && ((list_total == 0)) && { + ! ((helping)) && ! ((history)) && \ + [[ $2 == search && -d ${list[0]} ]] && \ + ((list_total == 0)) && { # '\e[?25l': Hide the cursor. printf '\e[?25l' @@ -1224,7 +1185,7 @@ cmd_line() { ;; # Custom 'yes' value (used as a replacement for '-n 1'). - ${2:-null}) + "${2:-null}") cmd_reply=$read_reply break ;; @@ -1275,10 +1236,11 @@ cmd_line() { } || { while true; do pos=$((status_len+curpos)) - # '\r\e[K'"${1}": Redraw everything. + # '\r\e[K'"$1": Redraw everything. # '\e[%s\e[?25l' "$LINES": Go to the last position at the bottom # and hide the cursor. - printf '\r\e[K'"${1}" + # Cannot write ..%s.." "$1", because of no color in warning. + printf '\r\e[K'"$1" printf '\e[%s\e[?25l' "$LINES" IFS= read -rsn 1 read_reply case $read_reply in @@ -1355,7 +1317,7 @@ key() { [[ $1 == $'\e' ]] && { - # Exit marking with any special key! + # Exit marking with any special key. [[ ${marked_files[*]} ]] && { marked_files=() file_program=() @@ -1376,18 +1338,18 @@ key() { # 'C' is what bash sees when the right arrow is pressed # ('\e[C' or '\eOC'). # '' is what bash sees when the enter/return key is pressed. - ${FFF_KEY_CHILD1:=l}|\ - ${FFF_KEY_CHILD2:=$'\e[C'}|\ - ${FFF_KEY_CHILD3:=""}|\ - ${FFF_KEY_CHILD4:=$'\eOC'}) - open "${list[scroll]}" - + "${FFF_KEY_CHILD1:=l}" |\ + "${FFF_KEY_CHILD2:=$'\e[C'}"|\ + "${FFF_KEY_CHILD3:=""}" |\ + "${FFF_KEY_CHILD4:=$'\eOC'}") + # If history then return to the previous state. ((history)) && { details=$saved_details FFF_FILE_ICON="$icon_value" list[scroll]=${list[scroll]#* } - open "${list[scroll]}" } + + open "${list[scroll]}" ;; # Go to the parent directory. @@ -1395,14 +1357,19 @@ key() { # ('\e[D' or '\eOD'). # '\177' and '\b' are what bash sometimes sees when the backspace # key is pressed. - ${FFF_KEY_PARENT1:=h}|\ - ${FFF_KEY_PARENT2:=$'\e[D'}|\ - ${FFF_KEY_PARENT3:=$'\177'}|\ - ${FFF_KEY_PARENT4:=$'\b'}|\ - ${FFF_KEY_PARENT5:=$'\eOD'}) + "${FFF_KEY_PARENT1:=h}" |\ + "${FFF_KEY_PARENT2:=$'\e[D'}"|\ + "${FFF_KEY_PARENT3:=$'\177'}"|\ + "${FFF_KEY_PARENT4:=$'\b'}" |\ + "${FFF_KEY_PARENT5:=$'\eOD'}") + # If history/help then return to the previous state. + if ((history)) || ((helping)); then + details=$saved_details + FFF_FILE_ICON="$icon_value" + open "$PWD" # If a search was done, clear the results and open the current dir. - if ((search == 1 && search_end_early != 1)); then + elif ((search == 1 && search_end_early != 1)); then open "$PWD" # If '$PWD' is '/', do nothing. @@ -1415,9 +1382,9 @@ key() { # Scroll down. # 'B' is what bash sees when the down arrow is pressed # ('\e[B' or '\eOB'). - ${FFF_KEY_SCROLL_DOWN1:=j}|\ - ${FFF_KEY_SCROLL_DOWN2:=$'\e[B'}|\ - ${FFF_KEY_SCROLL_DOWN3:=$'\eOB'}) + "${FFF_KEY_SCROLL_DOWN1:=j}" |\ + "${FFF_KEY_SCROLL_DOWN2:=$'\e[B'}"|\ + "${FFF_KEY_SCROLL_DOWN3:=$'\eOB'}") while ((scroll < list_total)); do ((scroll++)) ((y < max_items)) && ((y++)) @@ -1434,9 +1401,9 @@ key() { # Scroll up. # 'A' is what bash sees when the up arrow is pressed # ('\e[A' or '\eOA'). - ${FFF_KEY_SCROLL_UP1:=k}|\ - ${FFF_KEY_SCROLL_UP2:=$'\e[A'}|\ - ${FFF_KEY_SCROLL_UP3:=$'\eOA'}) + "${FFF_KEY_SCROLL_UP1:=k}" |\ + "${FFF_KEY_SCROLL_UP2:=$'\e[A'}"|\ + "${FFF_KEY_SCROLL_UP3:=$'\eOA'}") # '\e[1L': Insert a line above the cursor. # '\e[A': Move cursor up a line. while ((scroll > 0)); do @@ -1459,7 +1426,7 @@ key() { ;; # Go to top. - ${FFF_KEY_TO_TOP:=g}) + "${FFF_KEY_TO_TOP:=g}") ((scroll != 0)) && { scroll=0 redraw @@ -1467,7 +1434,7 @@ key() { ;; # Go to bottom. - ${FFF_KEY_TO_BOTTOM:=G}) + "${FFF_KEY_TO_BOTTOM:=G}") ((scroll != list_total)) && { ((scroll=list_total)) redraw @@ -1475,7 +1442,9 @@ key() { ;; # Show hidden files. - ${FFF_KEY_HIDDEN:=.}) + "${FFF_KEY_HIDDEN:=.}") + ((helping)) || ((history)) && return + # 'a=a>0?0:++a': Toggle between both values of 'shopt_flags'. # This also works for '3' or more values with # some modification. @@ -1485,24 +1454,22 @@ key() { ;; # Search. - ${FFF_KEY_SEARCH:=/}) + "${FFF_KEY_SEARCH:=/}") cmd_line "/" "search" # If the search came up empty, redraw the current dir. - if [[ -z ${list[*]} ]]; then + [[ -z ${list[*]} ]] && { list=("${cur_list[@]}") ((list_total=${#list[@]}-1)) redraw search= - else - search=1 - fi + } || search=1 status_line ;; # Spawn a shell. - ${FFF_KEY_SHELL:=!}) + "${FFF_KEY_SHELL:=!}") reset_terminal # Make fff aware of how many times it is nested. @@ -1515,24 +1482,26 @@ key() { ;; # Mark files for operation. - ${FFF_KEY_COPY:=c}|\ - ${FFF_KEY_MOVE:=m}|\ - ${FFF_KEY_TRASH:=d}|\ - ${FFF_KEY_LINK:=s}|\ - ${FFF_KEY_BULK_RENAME:=b}) + "${FFF_KEY_COPY:=c}" |\ + "${FFF_KEY_MOVE:=m}" |\ + "${FFF_KEY_TRASH:=d}" |\ + "${FFF_KEY_LINK:=s}" |\ + "${FFF_KEY_BULK_RENAME:=b}") + ((helping)) || ((history)) && return + [[ -z "${marked_files[*]}" ]] && return previous_program="${file_program[0]}" # Find the program to use. case "$1" in - ${FFF_KEY_COPY:=c}) file_program=(cp -iR) ;; - ${FFF_KEY_MOVE:=m}) file_program=(mv -i) ;; - ${FFF_KEY_LINK:=s}) file_program=(ln -s) ;; + "${FFF_KEY_COPY:=c}") file_program=(cp -iR) ;; + "${FFF_KEY_MOVE:=m}") file_program=(mv -i) ;; + "${FFF_KEY_LINK:=s}") file_program=(ln -s) ;; # These are 'fff' functions. - ${FFF_KEY_TRASH:=d}) file_program=(trash) ;; - ${FFF_KEY_BULK_RENAME:=b}) file_program=(bulk_rename) ;; + "${FFF_KEY_TRASH:=d}") file_program=(trash) ;; + "${FFF_KEY_BULK_RENAME:=b}") file_program=(bulk_rename) ;; esac # Toggle the file program if the same key was pressed. @@ -1544,24 +1513,30 @@ key() { # Mark files for operation. "${FFF_KEY_MARK:=" "}") + ((helping)) || ((history)) && return + mark "$scroll" "$1" ;; # Mark all files for operation. "${FFF_KEY_MARK_ALL:=a}") + ((helping)) || ((history)) && return + mark all "$1" ;; # Do the file operation. - ${FFF_KEY_EXECUTE:=p}) + "${FFF_KEY_EXECUTE:=p}") + ((helping)) || ((history)) && return + [[ ${marked_files[*]} ]] && { [[ ! -w $PWD ]] && { - cmd_line "warning: No write access to dir" + cmd_line "\e[0;31mWarning!\e[0m No write access to dir" return } [[ -z ${file_program[0]} ]] && { - cmd_line "warning: No operation selected [y,m,d,b,s]" + cmd_line "\e[0;31mWarning!\e[0m No operation selected [y,m,d,b,s]" return } @@ -1580,74 +1555,74 @@ key() { redraw full } || { [[ -z ${file_program[0]} ]] && { - cmd_line "warning: 0 marked files" + cmd_line "\e[0;31mWarning!\e[0m 0 marked files" return } } ;; # Rename list item. - ${FFF_KEY_RENAME:=r}) + "${FFF_KEY_RENAME:=r}") ((helping)) || ((history)) && return - [[ ! -e ${list[scroll]} ]] && - return + [[ ! -e ${list[scroll]} ]] && return - cmd_line "rename ${list[scroll]##*/}: " "rename" + cmd_line "Rename: " "rename" [[ $cmd_reply ]] && if [[ -e $cmd_reply ]]; then - cmd_line "warning: '$cmd_reply' already exists" + cmd_line "\e[0;31mWarning!\e[0m '$cmd_reply' already exists" elif [[ -w ${list[scroll]} ]]; then mv "${list[scroll]}" "${PWD}/${cmd_reply}" redraw full else - cmd_line "warning: No write access to file" + cmd_line "\e[0;31mWarning!\e[0m No write access to file" fi ;; # Create a directory. - ${FFF_KEY_MKDIR:=n}) + "${FFF_KEY_MKDIR:=n}") ((helping)) || ((history)) && return cmd_line "Create directory: " "dirs" [[ $cmd_reply ]] && if [[ -e $cmd_reply ]]; then - cmd_line "warning: '$cmd_reply' already exists" + cmd_line "\e[0;31mWarning!\e[0m '$cmd_reply' already exists" elif [[ -w $PWD ]]; then mkdir -p "${PWD}/${cmd_reply}" redraw full else - cmd_line "warning: No write access to dir" + cmd_line "\e[0;31mWarning!\e[0m No write access to dir" fi ;; # Create a file. - ${FFF_KEY_MKFILE:=f}) + "${FFF_KEY_MKFILE:=f}") ((helping)) || ((history)) && return - cmd_line "Create file: " + cmd_line "Create file: " "file" - [[ $cmd_reply ]] && + [[ $cmd_reply ]] && { if [[ -e $cmd_reply ]]; then - cmd_line "warning: '$cmd_reply' already exists" + cmd_line "\e[0;31mWarning!\e[0m '$cmd_reply' already exists" elif [[ -w $PWD ]]; then : > "$cmd_reply" redraw full else - cmd_line "warning: No write access to dir" + cmd_line "\e[0;31mWarning!\e[0m No write access to dir" fi + } ;; # Show file attributes. - ${FFF_KEY_ATTRIBUTES:=x}) + "${FFF_KEY_ATTRIBUTES:=x}") ((helping)) || ((history)) && return [[ -e "${list[scroll]}" ]] && { @@ -1670,7 +1645,7 @@ key() { ;; # Toggle executable flag. - ${FFF_KEY_EXECUTABLE:=X}) + "${FFF_KEY_EXECUTABLE:=X}") ((helping)) || ((history)) && return [[ -f ${list[scroll]} && -w ${list[scroll]} ]] && { @@ -1685,7 +1660,7 @@ key() { ;; # Go to dir. - ${FFF_KEY_GO_DIR:=:}) + "${FFF_KEY_GO_DIR:=:}") ((helping)) || ((history)) && return cmd_line "go to dir: " "dirs" @@ -1699,14 +1674,14 @@ key() { ;; # Open file with. - ${FFF_KEY_OPEN_WITH:=o}) + "${FFF_KEY_OPEN_WITH:=o}") ((helping)) || ((history)) && return cmd_line "open with: " "cmd" [[ $cmd_reply ]] && { if ! command -v $cmd_reply > /dev/null; then redraw full - cmd_line "warning: command ${cmd_reply} not found" + cmd_line "\e[0;31mWarning!\e[0m Command ${cmd_reply} not found" return fi @@ -1720,14 +1695,14 @@ key() { ;; # Open file with to run background. - ${FFF_KEY_OPEN_WITH_DETACHED:=O}) + "${FFF_KEY_OPEN_WITH_DETACHED:=O}") ((helping)) || ((history)) && return cmd_line "open with (detached): " "cmd" [[ $cmd_reply ]] && { if ! type $cmd_reply > /dev/null; then redraw full - cmd_line "warning: command ${cmd_reply} not found" + cmd_line "\e[0;31mWarning!\e[0m Command ${cmd_reply} not found" return fi @@ -1748,36 +1723,36 @@ key() { ;; # Go to trash. - ${FFF_KEY_GO_TRASH:=t}) + "${FFF_KEY_GO_TRASH:=t}") get_os open "$FFF_TRASH" ;; # Sort by name (0) time (1). - ${FFF_KEY_SORT:=u}) + "${FFF_KEY_SORT:=u}") ((helping)) || ((history)) && return - [ $sort == 0 ] && sort=1 || sort=0 + [ "$sort" == 0 ] && sort=1 || sort=0 open "$PWD" ;; # Show file details (on/off). - ${FFF_KEY_DETAILS:=i}) + "${FFF_KEY_DETAILS:=i}") ((helping)) || ((history)) && return - [ $details == 0 ] && details=1 || details=0 + [ "$details" == 0 ] && details=1 || details=0 open "$PWD" ;; # Go to previous dir. - ${FFF_KEY_PREVIOUS:=-}) + "${FFF_KEY_PREVIOUS:=-}") open "$OLDPWD" ;; # Refresh current dir. - ${FFF_KEY_REFRESH:=z}) + "${FFF_KEY_REFRESH:=z}") ((helping)) || ((history)) && { list=("${cur_list[@]}") redraw full @@ -1788,9 +1763,15 @@ key() { ;; # Yank filename to clipboard. - ${FFF_KEY_CLIPBOARD:-y}) + "${FFF_KEY_CLIPBOARD:-y}") + if ! command -v ${FFF_CLIPBOARD:=xclip -selection c} > /dev/null; then + redraw full + cmd_line "\e[0;31mWarning!\e[0m Cannot run '${FFF_CLIPBOARD:=xclip -selection c}'" + return + fi + [[ -e "${list[scroll]}" ]] && { - echo ${list[scroll]} | ${FFF_CLIPBOARD:=xclip -selection c} 2>/dev/null + echo "${list[scroll]}" | ${FFF_CLIPBOARD:=xclip -selection c} 2>/dev/null cmd_line "${list[scroll]} copied to clipboard" } @@ -1801,8 +1782,7 @@ key() { favourite="FFF_FAV${1}" favourite="${!favourite}" - [[ $favourite ]] && - open "$favourite" + [[ $favourite ]] && open "$favourite" ;; # Display help. @@ -1810,7 +1790,7 @@ key() { ((history)) && return ((helping)) && { - # Return to previous state. + # Return to the previous state. details=$saved_details FFF_FILE_ICON="$icon_value" redraw full @@ -1827,7 +1807,7 @@ key() { ((helping)) && return ((history)) && { - # Return to previous state. + # Return to the previous state. details=$saved_details FFF_FILE_ICON="$icon_value" redraw full @@ -1839,14 +1819,29 @@ key() { redraw hist ;; + # Display image using img2sixel. + "${FFF_KEY_SIXEL:=I}") + ((helping)) || ((history)) && return + + if ! command -v img2sixel > /dev/null; then + redraw full + cmd_line "\e[0;31mWarning!\e[0m Command img2sixel not found" + return + fi + + # https://stackoverflow.com/questions/25941394/how-does-bash-deal-with-nested-quotes + [[ -e "${list[scroll]}" ]] && { + clear_screen + "${FFF_SIXEL_CMD:-img2sixel}" "${list[scroll]}" && read -rsn1 + setup_terminal + redraw + } + ;; + # Quit and store current directory in a file for CD on exit. # Don't allow user to redefine 'q' so a bad keybinding doesn't # remove the option to quit. - q) - # Delete everything in history after FFF_HISTORY_LENGTH line. - lines_num=${FFF_HISTORY_LENGTH:-100} - sed -i "${lines_num}q" "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/history" - + "q") ((helping)) || ((history)) && { details=$saved_details FFF_FILE_ICON="$icon_value" # Set FFF_FILE_ICON to previous state. @@ -1854,10 +1849,13 @@ key() { return } + # Delete everything in history after FFF_HISTORY_LENGTH line. + lines_num=${FFF_HISTORY_LENGTH:-100} + sed -i "${lines_num}q" "${XDG_CACHE_HOME:=${HOME}/.cache}/fff/history" + : "${FFF_CD_FILE:=${XDG_CACHE_HOME:=${HOME}/.cache}/fff/.fff_d}" - [[ -w $FFF_CD_FILE ]] && - rm "$FFF_CD_FILE" + [[ -w $FFF_CD_FILE ]] && rm "$FFF_CD_FILE" [[ ${FFF_CD_ON_EXIT:=1} == 1 ]] && printf '%s\n' "$PWD" > "$FFF_CD_FILE" diff --git a/fff.1 b/fff.1 index e112fed..4541dc0 100644 --- a/fff.1 +++ b/fff.1 @@ -36,6 +36,7 @@ z: refresh current dir !: open shell in current dir i: display file details +I: display an image using sixel u: sort files x: view file/dir attributes e: show history @@ -200,6 +201,10 @@ export FFF_KEY_CLIPBOARD="xclip -selection c" # (14 by default). export FFF_SCROLL_UP=14 export FFF_SCROLL_DOWN=14 + +# Sixel image program. +# Default: img2sixel +export FFF_SIXEL_CMD="img2sixel" . .fi . @@ -268,6 +273,9 @@ export FFF_KEY_MKFILE="f" # Display file details. export FFF_KEY_DETAILS="i" +# Display an image using sixel. +export FFF_KEY_SIXEL="I" + # Sort files. export FFF_KEY_SORT="u" From ce9c26bd7ab9b92f9dc5ce893a501c09ede07e1a Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sun, 24 Dec 2023 11:22:41 +0100 Subject: [PATCH 43/46] Fix sorting --- fff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fff b/fff index ab4efe3..4b842a5 100755 --- a/fff +++ b/fff @@ -549,7 +549,7 @@ read_dir() { done [ "$sort" == 1 ] && \ - dirs=("$(stat -c '%Y=%n' "${dirs[@]}" | sort -nr | cut -d '=' -f2)") \ + dirs=($(stat -c '%Y=%n' "${dirs[@]}" | sort -nr | cut -d '=' -f2)) \ files=($(stat -c '%Y=%n' "${files[@]}" | sort -nr | cut -d '=' -f2)) list=("${dirs[@]}" "${files[@]}") From d1e7bfdd9d21c68c2180686dc7eb2ab55615002d Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Tue, 26 Dec 2023 16:48:00 +0100 Subject: [PATCH 44/46] Optimize `ctrl + d/u` actions This commit optimizes (FINALLY!) the `ctrl` + `d/u` actions. It does it by not printing 14 lines line-by-line, but it jumps quickly to the desired line, and if it isn't on screen, then it will quickly jump to the last visible edge, and then print line-by-line. This speeds up jumping a lot when details are on, but still relies on the speed of printing a line. Printing a line could be made faster only by doing two things: 1. Heavily refactoring the whole `read_dir` and associated functions, to implement some sort of lazy loading for directories. 2. Make details more faster by using other tools for checking date and time. Less refactoring, but still some. --- fff | 174 +++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 130 insertions(+), 44 deletions(-) diff --git a/fff b/fff index 4b842a5..05c3ff8 100755 --- a/fff +++ b/fff @@ -13,8 +13,7 @@ get_os() { haiku) opener=open - [[ -z $FFF_TRASH_CMD ]] && - FFF_TRASH_CMD=trash + [[ -z $FFF_TRASH_CMD ]] && FFF_TRASH_CMD=trash [[ $FFF_TRASH_CMD == trash ]] && { FFF_TRASH=$(finddir -v "$PWD" B_TRASH_DIRECTORY) @@ -473,7 +472,7 @@ status_line() { local mark_ui= [ ${#marked_files[@]} -gt 0 ] && { mark_ui="[${#marked_files[@]}] selected " - [[ -n $file_program ]] && \ + [[ -n $file_program ]] && mark_ui+="(${file_program[*]}) " } @@ -510,7 +509,6 @@ status_line() { # '\e[H\e[K': Clear line below status_line. # '\e8': Restore cursor position. # This is more widely supported than '\e[u'. - printf '\e7\e[%sH\e[3%s;4%sm%*s\r%s %s%s\e[m\e[%sH\e[K\e8' \ "$LINES" \ "${FFF_COL5:-0}" \ @@ -537,20 +535,21 @@ read_dir() { for item in "$PWD"/*; do if [[ -d $item ]]; then dirs+=("$item") - # Find the position of the child directory in the # parent directory list. [[ $item == "$OLDPWD" ]] && ((previous_index=item_index)) + ((item_index++)) else files+=("$item") fi done - [ "$sort" == 1 ] && \ - dirs=($(stat -c '%Y=%n' "${dirs[@]}" | sort -nr | cut -d '=' -f2)) \ + [ "$sort" == 1 ] && { + dirs=($(stat -c '%Y=%n' "${dirs[@]}" | sort -nr | cut -d '=' -f2)) files=($(stat -c '%Y=%n' "${files[@]}" | sort -nr | cut -d '=' -f2)) + } list=("${dirs[@]}" "${files[@]}") @@ -644,14 +643,9 @@ print_line() { # Remove all non-printable characters. file_name=${file_name//[^[:print:]]/^[} - # Get icon for file. - (( ${FFF_FILE_ICON:=0} == 1 )) && { - if [[ -x ${list[$1]} && -f ${list[$1]} ]]; then - icon=" " - else - icon="$(get_icon "${list[$1]}" "$file_name" "$file_ext") " - fi - } + # Get icon. + (( ${FFF_FILE_ICON:=0} == 1 )) && + icon="$(get_icon "${list[$1]}" "$file_name" "$file_ext") " # Check if current dir is a git repo and has changes, # then display git signs if it is. @@ -747,7 +741,7 @@ redraw() { changed=() git_branch=$(git branch 2> /dev/null | sed -n -e 's/^\* \(.*\)/\1/p') # Check if git branch name is not empty, then get changed files. - if [ " $git_branch" != " " ]; then + [ -n "$git_branch" ] && { git_output=$(git status -s -unormal) while read -r line; do # Get elements. @@ -755,7 +749,7 @@ redraw() { element="${line%%/*}" changed+=("$element") done <<< "$git_output" - fi + } # Redraw the current window. # If 'full' is passed, re-fetch the directory list. @@ -772,7 +766,6 @@ redraw() { helping=1 list_help scroll=0 - # If 'help' is passed, list help text. elif [[ $1 == hist ]]; then history=1 @@ -911,7 +904,7 @@ mark() { redraw else if [[ ${marked_files[$1]} == "${list[$1]}" ]]; then - unset 'marked_files[scroll]' + unset 'marked_files[$1]' else marked_files[$1]="${list[$1]}" fi @@ -1056,6 +1049,8 @@ open_with() { clear_screen reset_terminal + # Warning: when opening file(s) with spaces in it it will + # recognize it as separate files!!! $1 $2 setup_terminal redraw @@ -1080,7 +1075,6 @@ cmd_line() { # If nothing is passed then handle it as error, # and run search/rename. [ -n "$2" ] && { - # If search or go to or nothing was passed. [[ "$2" != "rename" ]] && { cmd_reply= @@ -1267,39 +1261,130 @@ key() { # Handle special key presses. # Handle ctrl + u scroll up. - # - # Super dumb approach, because it basically goes through - # every line and highlights it. - # Faster version = set scroll and redraw with it, but it - # clears the screen so I set it as is here to look better. [[ $1 == $'\x15' ]] && { - ((scroll != 0)) && { - for ((i=0; i<${FFF_SCROLL_UP:=14}; i++)); do - while ((scroll > 0)); do - ((scroll--)) + # Get the length to the first element and check if + # there is space for this jump. + # + # space_for_jump = length to the first element in the + # whole list + # scroll = current cursor position number in the list + # jump_len = if there is space = n jump, if not + # then is length to the first element + space_for_jump=${scroll} + + if [[ ${space_for_jump} -gt ${FFF_SCROLL_UP:=14} ]]; then + jump_len=${FFF_SCROLL_UP:=14} + else + jump_len=${space_for_jump} + fi - print_line "$((scroll+1))" + # Check if the new position after jump is on the screen, + # then simply jump to it, otherwise go to the first + # visible/printed line and then go line-by-line printing it. + # + # new_pos_after_jump = scroll + jump number + # y = position of the scroll in the visible area + # visible_jump = how many already visible lines to jump + # invisible_jump = how many invisible lines to jump after it + ((new_pos_after_jump=$y-$jump_len)) + + if [[ $new_pos_after_jump -ge 0 ]]; then + ((visible_jump=$jump_len)) + invisible_jump=0 + else + ((visible_jump=$y)) + ((invisible_jump=$jump_len-$y)) + fi - if ((y < 2)); then - printf '\e[L' - else - printf '\e[A' - ((y--)) - fi + ((scroll=scroll-$visible_jump)) - print_line "$scroll" + print_line "$((scroll+visible_jump))" - [[ "${list[scroll]}" ]] && break - done + # Scroll n places up = print n * line/form feed. + for ((i=0; i<$visible_jump; i++)); do + if ((y < 2)); then + printf '\e[L' + else + printf '\e[A' + ((y--)) + fi + done + + # Scroll up and print new elements. + for ((i=0; i<$invisible_jump; i++)); do + while ((scroll > 0)); do + ((scroll--)) + + print_line "$((scroll+1))" + + if ((y < 2)); then + printf '\e[L' + else + printf '\e[A' + ((y--)) + fi + + print_line "$scroll" + + [[ "${list[scroll]}" ]] && break done - status_line - } + done + + print_line "$scroll" + status_line + } # Handle ctrl + d for scroll down. [[ $1 == $'\x04' ]] && { ((scroll != list_total)) && { - for ((i=0; i<${FFF_SCROLL_UP:=14}; i++)); do + # Get the length to the last element and check if + # there is space for this jump. + # + # space_for_jump = length to the end of the whole list + # ${#list[@]} = number of all elements in the list + # scroll = current cursor position number + # jump_len = if there is space = n jump, if not + # then is length to the last element + ((space_for_jump=${#list[@]} - $scroll)) + + if [[ ${space_for_jump} -gt ${FFF_SCROLL_DOWN:=14} ]]; then + jump_len=${FFF_SCROLL_DOWN:=14} + else + ((jump_len=${space_for_jump}-1)) + fi + + # Check if the new position after jump is on the screen, + # then simply jump to it, otherwise go to the last + # visible/printed line and then go line-by-line printing it. + # + # new_pos_after_jump = scroll + jump number + # max_items = length of the items that can fit in the screen + # y = position of the scroll in the visible area + # visible_jump = how many already visible lines to jump + # invisible_jump = how many invisible lines to jump after it + ((new_pos_after_jump=$y+$jump_len)) + + if [[ $new_pos_after_jump -le $max_items ]]; then + visible_jump=$jump_len + invisible_jump=0 + else + ((visible_jump=${max_items}-$y)) + ((invisible_jump=${new_pos_after_jump}-${max_items})) + fi + + ((scroll=scroll+$visible_jump)) + ((y < max_items)) && ((y=y+$visible_jump)) + + print_line "$((scroll-$visible_jump))" + + # Scroll n places down = print n * '\n'. + for ((i=0; i<$visible_jump; i++)); do + printf '\n' + done + + # Scroll down and print new elements. + for ((i=0; i<$invisible_jump; i++)); do while ((scroll < list_total)); do ((scroll++)) ((y < max_items)) && ((y++)) @@ -1311,12 +1396,13 @@ key() { [[ "${list[scroll]}" ]] && break done done + + print_line "$scroll" status_line } } [[ $1 == $'\e' ]] && { - # Exit marking with any special key. [[ ${marked_files[*]} ]] && { marked_files=() @@ -1509,7 +1595,7 @@ key() { file_program=() status_line - ;; + ;; # Mark files for operation. "${FFF_KEY_MARK:=" "}") From 33c1a55768dad27c7e78a6f7dd1de9ecb6a028b5 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Sat, 3 Feb 2024 11:34:12 +0100 Subject: [PATCH 45/46] Update README, change behaviour of moving files to trash to NOT ask to remove write protected files --- README.md | 10 ++++------ fff | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5f86efc..38b61ea 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,8 @@ A big part of code in there is from people who made PRs and posted issues to fff - Icons - `xclip or any clipboard manager` (*optional*) - clipboard +- `libsixel` (*optional*) + - sixel support ## Installation @@ -84,10 +86,6 @@ A big part of code in there is from people who made PRs and posted issues to fff 2. Change working directory to `fff`. - `cd fff` 3. Run `make install` inside the script directory to install the script. - - **El Capitan**: `make PREFIX=/usr/local install` - - **Haiku**: `make PREFIX="$(finddir B_USER_NONPACKAGED_DIRECTORY)" MANDIR='$(PREFIX)/documentation/man' DOCDIR='$(PREFIX)/documentation/fff' install` - - **OpenIndiana**: `gmake install` - - **MinGW/MSys**: `make -i install` - **NOTE**: You may have to run this as root. **NOTE:** `fff` can be uninstalled easily using `make uninstall`. This removes all of files from your system. @@ -115,7 +113,7 @@ enter: go to child dir/open file backspace: go to parent dir o: open file with -O: open file with GUI program detached from file manager +O: open file with a GUI program detached from file manager -: Go to previous dir. @@ -446,4 +444,4 @@ read -srn 1 && key "$REPLY" ## Using `fff` in vim/neovim as a file picker -See: [**`fff.vim`**](https://github.com/dylanaraps/fff.vim) +See: [**`fff.vim`**](https://github.com/dylanaraps/fff.vim) or [**`fm-nvim`**](https://github.com/is0n/fm-nvim) diff --git a/fff b/fff index 05c3ff8..0555560 100755 --- a/fff +++ b/fff @@ -933,7 +933,7 @@ trash() { cd "$FFF_TRASH" || cmd_line "\e[0;31mWarning!\e[0m Can't cd to trash directory." if cp -alf "$@" &>/dev/null; then - rm -r "${@:1:$#-1}" + rm -rf "${@:1:$#-1}" else mv -f "$@" fi From 8b2ff7897750b512c7d0bb6fe2c212930a2277f5 Mon Sep 17 00:00:00 2001 From: Piotr Marendowski Date: Thu, 29 Feb 2024 20:41:10 +0100 Subject: [PATCH 46/46] Update README, man entry --- README.md | 6 ++++-- fff.1 | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 38b61ea..28166ea 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,9 @@ Ctrl+C: exit without 'cd'. ## Customization -Can be added to your `bashrc` (or other shell's configuration files) and/or can be added to `FFF_CONFIG`. Everything put in `FFF_CONFIG` file will be sourced globally meaning that e.g. Neovim's terminal will have these settings. And I'm not sure why the only option (maybe there are others) not working in config file is `FFF_HIDDEN` which only works, when fff is run inside terminal manually. +`FFF_CONFIG` can be added to your `bashrc` (or other shell's configuration files). Everything put in `FFF_CONFIG` file will be sourced globally meaning that e.g. Neovim's terminal will have these settings. + +Personal note (can be unreproducible for your): I'm not sure why the only option (maybe there are others) not working in config file is `FFF_HIDDEN` which only works, when fff is run inside terminal manually. ```sh # Show/Hide hidden files on open. @@ -236,7 +238,7 @@ export FFF_CD_ON_EXIT=0 # If not using XDG, '${HOME}/.cache/fff/fff.d' is used. export FFF_CD_FILE=~/.fff_d -# Config Directory +# Config File # Default: '${XDG_CONFIG_HOME/fff}' # If not using XDG, '${HOME}/.config/fff' is used. export FFF_CONFIG=~/.config/fff diff --git a/fff.1 b/fff.1 index 4541dc0..c035faa 100644 --- a/fff.1 +++ b/fff.1 @@ -150,6 +150,11 @@ export FFF_CD_ON_EXIT=1 # If not using XDG, '${HOME}/.cache/fff/fff.d' is used. export FFF_CD_FILE=~/.fff_d +# Config File +# Default: '${XDG_CONFIG_HOME/fff}' +# If not using XDG, '${HOME}/.config/fff' is used. +export FFF_CONFIG=~/.config/fff + # Trash Directory # Default: '${XDG_DATA_HOME}/fff/trash' # If not using XDG, '${XDG_DATA_HOME}/fff/trash' is used.