@@ -41,7 +41,13 @@ fzf() { # {{{ | |||
shift | |||
fi | |||
branch=$(git status 2> /dev/null | sed 's/On branch />/;q') | |||
command fzf --inline-info --ansi --cycle --prompt="fzgit${branch}>${prompt} " "$@" | |||
opts=( +s -e -i --reverse --cycle --prompt="fzgit${branch}>${prompt} " ) | |||
[[ -v FZMP_FZF_OPTIONS ]] && opts=( $FZMP_FZF_OPTIONS ) | |||
command fzf "${opts[@]}" \ | |||
--inline-info \ | |||
--ansi \ | |||
--no-clear \ | |||
"$@" | |||
} | |||
# }}} | |||
@@ -192,7 +198,6 @@ declare -A implemented_git_cmds=( | |||
git_log() { # {{{ | |||
local show="git show --color=always \"\$(grep -m1 -o \"[a-f0-9]\{7\}\" <<< {})\"" | |||
fzf --prompt='log' -e --no-sort --tiebreak=index \ | |||
--preview-window=up \ | |||
--bind="enter:execute:$show | less -R" \ | |||
--preview="$show" \ | |||
< <(git log --graph --color=always \ | |||
@@ -276,4 +281,13 @@ main() { | |||
done | |||
} | |||
reset_screen() { | |||
tput rmcup | |||
} | |||
finish() { | |||
reset_screen | |||
} | |||
trap finish EXIT SIGINT SIGTERM | |||
main |
@@ -9,13 +9,12 @@ OPTIONS: | |||
search all songs in the library (or F1 when running) | |||
-a --artist | |||
search artist then filter by album (or F2 when running) | |||
-p --playlist | |||
search the current playlist (or F3 when running) | |||
playlist view has the following keybinds: | |||
> go to the next song in the playlist | |||
< go to the previous song in the playlist | |||
C-d delete the selected songs from the playlist | |||
> go to the next song in the playlist | |||
< go to the previous song in the playlist | |||
Ctrl-d delete the selected songs from the playlist | |||
-g --genre | |||
list genres (or F4 when running) | |||
-h --help | |||
@@ -34,23 +33,23 @@ CONFIGURATION: | |||
[[[%artist% / ][[(%date%) ]%album% / ][[%track% - ][%title%]]]|%file%] | |||
For colorized output try: | |||
[[[\e\[32m%artist%\e\[0m / ][\e\[31m[(%date%) ]%album%\e\[0m / ][\e\[34m[%track% - ][%title%]\e\[0m]]|%file%] | |||
playlist_view_key | |||
track_view_key | |||
artist_view_key | |||
genre_view_key | |||
playlist_view_key (default F1) | |||
track_view_key (default F2) | |||
artist_view_key (default F3) | |||
genre_view_key (default F4) | |||
allows customizing which keys fire the different views | |||
findadd_key | |||
adds all songs by artist/genre/album | |||
defaults to Ctrl-x | |||
adds all songs under the cursor by artist/genre/album | |||
defaults to ctrl-space | |||
fzf_options | |||
Command line options to be passed directly to fzf. | |||
Changing this will override the default options: +s -e -i --reverse --cycle | |||
To use the jump feature of fzf you can try: | |||
+s -e -i --reverse --cycle --bind=`:jump | |||
or add this to your FZF_DEFAULT_OPTS | |||
It also helps to have a bind for toggle-all, e.g. | |||
+s -e -i --reverse --cycle --bind=`:jump --bind="Ctrl-A:toggle-all" | |||
This can also be overridden with the environment variable FZMP_FZF_OPTIONS | |||
+s -e -i --reverse --cycle --bind=`:jump --bind="ctrl-t:toggle-all" | |||
individual sessions also override with the environment variable FZMP_FZF_OPTIONS | |||
fzmp will also inherit options from FZF_DEFAULT_OPTS | |||
HELP | |||
} | |||
@@ -67,7 +66,7 @@ bindings=( | |||
[track]='f2' | |||
[artist]='f3' | |||
[genre]='f4' | |||
[findadd]='ctrl-x' | |||
[findadd]='ctrl-space' | |||
) | |||
do_binding() { | |||
@@ -182,6 +181,7 @@ parse_config_file() { | |||
esac | |||
done < "$config_file" | |||
IFS=',' key_bindings="${bindings[*]}" | |||
key_bindings="${key_bindings/,${bindings[findadd]}}" | |||
findadd_key="${bindings[findadd]}" | |||
if (( ${#config_err[@]} > 0 )); then | |||
err 'there were errors parsing config file:' | |||
@@ -218,7 +218,7 @@ filter_by_genres() { | |||
(( ${#choice[@]} > 0 )) || die | |||
case "${choice[0]}" in | |||
enter) filter_by_artist_from_genre "${choice[1]}" ;; | |||
*) do_binding "${choice[0]}" || exit ;; | |||
*) do_binding "${choice[0]}" || "$default_filter" ;; | |||
esac | |||
} | |||
@@ -272,7 +272,7 @@ filter_by_album_from_artist() { | |||
filter_songs_from_album() { | |||
local album artist choice | |||
[[ -z "$1" || -z "$2" ]] && die | |||
[[ -z "$1" || -z "$2" ]] && exit 999 | |||
artist="$1" | |||
album="$2" | |||
mapfile -t choice < <(mpc search -f '%file%\t[[[%track% - ][%title%]]|%file%]' artist "${artist}" album "${album}" | | |||
@@ -280,7 +280,7 @@ filter_songs_from_album() { | |||
--multi \ | |||
--with-nth='2..' \ | |||
--delimiter='\t' \ | |||
--expect='f1,f2,f3,enter' | | |||
--expect="${key_bindings},enter" | | |||
cut -f1) | |||
case "${choice[0]}" in | |||
'enter') printf '%s\n' "${choice[@]:1}" | add_songs play ;; |
@@ -37,34 +37,35 @@ fzf() { | |||
pick_files() { | |||
local files fzpick | |||
mapfile -t files < <(find . -maxdepth 1 2> /dev/null | sort -h | sed '1d; s|^\./||') | |||
fzpick=$( for f in "${files[@]}"; do | |||
if [[ -d "$f" ]]; then | |||
printf '%s/\n' "$f" | |||
elif [[ -L "$f" ]]; then | |||
printf '%s@\n' "$f" | |||
else | |||
printf '%s\n' "$f" | |||
fi | |||
done | fzf --multi --header='move these files' ) || return 1 | |||
for f in "${fzpick[@]}"; do | |||
realpath -s "$f" | |||
done | |||
find . -maxdepth 1 2> /dev/null | | |||
sort -h | | |||
sed '1d; s|^\./||' | | |||
while read -r f; do | |||
if [[ -d "$f" ]]; then | |||
printf '%s/\n' "$f" | |||
elif [[ -L "$f" ]]; then | |||
printf '%s@\n' "$f" | |||
else | |||
printf '%s\n' "$f" | |||
fi | |||
done | | |||
fzf --multi --header='move these files' || return 1 | |||
} | |||
pick_destination() { | |||
local cwd browse_dir browse_info query dirs | |||
cwd=$(pwd) | |||
while [[ "$browse_dir" != "$cwd" ]]; do | |||
dirs=$( (echo '..'; find -maxdepth 1 -type d 2> /dev/null ) | | |||
sed 's|./||' | | |||
sort -h) | |||
mapfile -t browse_info < <( | |||
{ echo '..'; find . -maxdepth 1 -type d 2> /dev/null; } | | |||
sed 's|^./||' | | |||
sort -h | | |||
fzf --print-query \ | |||
--history="${HOME}/.cache/fzmv_history" \ | |||
--header="${errors:-move files here}" <<< "$dirs") | |||
--header="${errors:-move files here}") | |||
query=${browse_info[0]} | |||
browse_dir=${browse_info[1]} | |||
files=( "${browse_info[@]:2}" ) | |||
[[ -d "$query" ]] && browse_dir="$query" | |||
[[ ! -d "$browse_dir" ]] && return 1 | |||
if [[ "$browse_dir" == '.' && $(realpath "$browse_dir") != "$cwd" ]]; then |
@@ -7,21 +7,29 @@ colors[blue]=$(tput setaf 4) | |||
colors[reset]=$(tput sgr0) | |||
declare processes=4 | |||
declare quiet | |||
declare force | |||
declare -a dirs | |||
declare -a ignore_dir | |||
declare -a ignore_dirs | |||
declare -a errs | |||
usage() { | |||
LESS=-FEXR less <<'HELP' | |||
gitup [dir] [OPTIONS] | |||
gitup [OPTIONS] [dirs] | |||
search for git repos and update them | |||
if unspecified, dir defaults to $HOME | |||
-p [number] how many processes to run git pull in parallel | |||
-q quiet level, may be stacked | |||
first level suppresses output from `git pull` | |||
second level suppresses job info | |||
-h print this help | |||
-i [dir] comma separated list of directory paths to not search | |||
-p [number] how many processes to run `git pull` in parallel | |||
-q quiet level, may be stacked | |||
first level suppresses output from `git pull` | |||
second level suppresses job info | |||
-F don't run interactively, `git pull` all dirs | |||
use with caution, make sure you know which dirs will be matched | |||
works best if gitup is provided a list of dirs known to have git repos | |||
-h print this help | |||
HELP | |||
} | |||
@@ -29,9 +37,9 @@ color() { | |||
local c | |||
c="$1" | |||
shift | |||
printf '%s' "${colors[$c]}" >&2 | |||
printf '%s\n' "$@" >&2 | |||
printf '%s' "${colors[reset]}" >&2 | |||
printf '%s' "${colors[$c]}" | |||
printf '%s\n' "$@" | |||
printf '%s' "${colors[reset]}" | |||
} | |||
err() { | |||
@@ -59,11 +67,13 @@ has() { | |||
has -v fzf git || die | |||
while getopts ":hqp:" x; do | |||
while getopts ':hqp:i:F' x; do o="$OPTARG" | |||
case "$x" in | |||
h) usage; exit; ;; | |||
p) processes="$OPTARG" ;; | |||
q) (( quiet++ )) ;; | |||
p) processes="$o" ;; | |||
q) (( ++quiet )) ;; | |||
i) IFS=',' read -ra ignore_dir <<< "$o" ;; | |||
F) (( ++force )) ;; | |||
esac | |||
done | |||
shift $(( OPTIND - 1 )) | |||
@@ -75,10 +85,19 @@ while :; do | |||
shift || break | |||
done | |||
for o in "${ignore_dir[@]}"; do | |||
ignore_dirs+=( -path "*/$o" -o ) | |||
done | |||
(( ${#dirs[@]} > 0 )) || dirs=("$HOME") | |||
mapfile -t repos < <(find -L "${dirs[@]}" -name '.git' -printf '%h\n' 2> /dev/null \ | |||
| fzf --multi --cycle --inline-info) | |||
mapfile -t repos < <(find "${dirs[@]}" \ | |||
\( "${ignore_dirs[@]}" \ | |||
-fstype 'devfs' \ | |||
-o -fstype 'devtmpfs' \ | |||
-o -fstype 'proc' \ | |||
\) -prune -o -name '.git' -printf '%h\n' 2> /dev/null | | |||
fzf --multi --cycle --inline-info +s -e ${force:+-f /}) | |||
(( ${#repos[@]} > 0 )) || exit | |||
@@ -90,7 +109,7 @@ update() { | |||
if git -C "$dir" pull ${quiet:+-q}; then | |||
(( quiet > 1 )) || color green ":: updated $name" | |||
else | |||
color red ":: failed to update $name" | |||
errs+=( "$name" ) | |||
fi | |||
} | |||
@@ -100,4 +119,8 @@ for d in "${repos[@]}"; do | |||
done | |||
wait | |||
printf '%d repos updated\n' "${#repos[@]}" | |||
if (( "${#errs[@]}" > 0 )); then | |||
color red 'The following packages failed to update:' | |||
color red " ${errs[*]}" | |||
fi | |||
color green "updated ${#repos[@]} repos" |
@@ -106,7 +106,10 @@ list_pastes() { | |||
if [[ -n "$url" ]]; then | |||
mapfile -t res <<< "$url" | |||
if [[ "${res[0]}" = 'Ctrl-D' ]]; then | |||
ix -d "${res[1]}" | |||
id="${res[1]}" | |||
id="${id#*ix.io/}" | |||
id="${id%%$'\t'*}" | |||
ix -d "$id" | |||
list_pastes | |||
exit | |||
fi | |||
@@ -125,7 +128,8 @@ while getopts ":hld:i:n:" x; do | |||
d) curl -s "${opts[@]}" -X DELETE "$OPTARG"; exit ;; | |||
l) | |||
if [[ -e ~/.netrc ]]; then | |||
list_pastes | cut -d' ' -f1 | xclip | |||
url=$(list_pastes) | |||
[[ -n "$url" ]] && cut -f1 <<< "$url" | tee | xclip | |||
else | |||
die 'no netrc found' | |||
fi |
@@ -8,7 +8,6 @@ declare global=0 | |||
declare -A colors | |||
colors[red]=$(tput setaf 1) | |||
colors[green]=$(tput setaf 2) | |||
colors[blue]=$(tput setaf 4) | |||
colors[reset]=$(tput sgr0) | |||
color() { | |||
@@ -26,7 +25,7 @@ die() { | |||
} | |||
has() { | |||
local v=0 | |||
local v c | |||
if [[ $1 = '-v' ]]; then | |||
v=1 | |||
shift | |||
@@ -43,10 +42,7 @@ select_from() { | |||
local cmd='command -v' | |||
for a; do | |||
case "$a" in | |||
-c) | |||
cmd="$2" | |||
shift 2 | |||
;; | |||
-c) cmd="$2"; shift 2 ;; | |||
esac | |||
done | |||
for c; do | |||
@@ -72,7 +68,7 @@ if [[ $1 = '-r' || $1 = '--remove' ]]; then | |||
die | |||
fi | |||
printf 'searching...\r' | |||
printf '%ssearching...%s\r' "${colors[green]}" "${colors[reset]}" | |||
search=$(npm search --json "$*") || exit | |||
search=$(jq -r '.[] | "\(.name)|\(.version)|\(.description)"' <<< "$search" | column -t -s'|') | |||
@@ -87,7 +83,7 @@ mapfile -t packages < <(fzf --multi \ | |||
key="${packages[0]}" | |||
case "${key,,}" in | |||
esc) die 'cancelled' ;; | |||
esc) die ;; | |||
ctrl-d) savedev=1 ;; | |||
ctrl-g) global=1 ;; | |||
ctrl-v) | |||
@@ -98,7 +94,7 @@ case "${key,,}" in | |||
fzf --header="choose version for $package | C-d saves as devDependency" --tac --expect='ctrl-d,esc') | |||
key="${version[0]}" | |||
case "${key,,}" in | |||
esc) die 'cancelled' ;; | |||
esc) die ;; | |||
ctrl-d) savedev=1 ;; | |||
esac | |||
packages=( "${package}@${version[1]}" ) | |||
@@ -112,7 +108,7 @@ if (( ${#packages[@]} > 1 )); then | |||
packages=( "${packages[@]%% *}" ) | |||
fi | |||
printf "installing...\r" | |||
printf '%sinstalling...%s\r' "${colors[green]}" "${colors[reset]}" | |||
if (( global > 0 )); then | |||
npm install -g "${args[@]}" "${packages[@]}" | |||
elif has yarn; then |
@@ -25,7 +25,25 @@ die() { | |||
exit 1 | |||
} | |||
has -v fzf || die | |||
select_from() { | |||
local o c cmd OPTARG OPTIND | |||
cmd='command -v' | |||
while getopts 'c:' o; do | |||
case "$o" in | |||
c) cmd="$OPTARG" ;; | |||
esac | |||
done | |||
shift "$((OPTIND-1))" | |||
for c; do | |||
if $cmd "${c%% *}" &> /dev/null; then | |||
echo "$c" | |||
return 0 | |||
fi | |||
done | |||
return 1 | |||
} | |||
has -v fzf expac || die | |||
fzf() { | |||
command fzf -e --multi --no-hscroll --inline-info --cycle --bind='Ctrl-a:toggle-all' "$@" | |||
@@ -40,10 +58,12 @@ if (( $# > 0 )); then | |||
exit | |||
fi | |||
preview=$(select_from pacaur pacman) | |||
if (( by_size )); then | |||
mapfile -t pkgs < <(expac -H M '%m\t%n' | sort -hr | fzf --preview='pacman -Si {3}' -q '!^lib ' | cut -f2) | |||
mapfile -t pkgs < <(expac -H M '%m\t%n' | sort -hr | fzf +s --preview="$preview --color=always -Si {3}" -q '!^lib ' | cut -f2) | |||
else | |||
mapfile -t pkgs < <(expac '%n' | fzf --preview='pacman -Si {1}' -q '!^lib ' | cut -d' ' -f1) | |||
mapfile -t pkgs < <(expac '%n' | fzf +s --preview="$preview --color=always -Si {1}" -q '!^lib ' | cut -d' ' -f1) | |||
fi | |||
(( ${#pkgs[@]} > 0 )) && sudo pacman -Rcusn "${pkgs[@]}" |
@@ -88,7 +88,7 @@ debian() { | |||
arch() { | |||
local search packages | |||
search='pacman' | |||
[[ -n "$1" ]] && search=$(select_from 'pacaur' 'yaourt' 'packer' 'apacman' 'pacman') | |||
[[ -n "$1" ]] && search=$(select_from 'pacaur' 'trizen' 'yaourt' 'packer' 'apacman' 'pacman') | |||
packages=$(fzf --preview="$search -Si {2}" \ | |||
< <( $search -Ss "$1" | | |||
gawk '{ | |||
@@ -114,8 +114,8 @@ void() { | |||
} | |||
fedora() { | |||
fzf --preview='p={}; p="${p%% *}"; dnf -q info "${p%.*}"' \ | |||
< <(dnf -qC repoquery --qf "${c_green}%{name} ${c_reset}%{version} - %{summary}" \*) | | |||
fzf --query="$*" --preview='p={}; p="${p%% *}"; dnf -q info "${p%.*}"' \ | |||
< <(dnf -qC repoquery --qf "${c_green}%{name} ${c_reset} - %{summary}" \*) | | |||
awk '{ package=$1; sub(/\.\S+/, "", package); print package }' | | |||
install 'sudo dnf install' | |||
} | |||
@@ -144,3 +144,6 @@ case "$distro" in | |||
fedora) fedora "$request" ;; | |||
*) die 'unknown distro :(' ;; | |||
esac | |||
# TODO: homebrew: brew desc -s | |||
# sample output: https://pastebin.com/raw/3frRf6C7 |
@@ -44,7 +44,7 @@ select_from() { | |||
has -v fzf || die | |||
helper=$(select_from 'pacaur' 'yaourt' 'packer' 'apacman' 'pacman') | |||
helper=$(select_from pacaur trizen packer apacman pacman) | |||
mapfile -t pkgs < <( | |||
$helper -Qu --color=always | |
@@ -63,7 +63,7 @@ for s in "${!domains[@]}"; do | |||
ssh "${domains[$s]}" "find ${paths[$s]}" | sed -r "s|^|${domains[$s]}:|" >> "$fifo" & | |||
done | |||
mapfile -t files < <( fzf -e --inline-info --multi --cycle --bind='Ctrl-A:toggle-all,`:jump' < "$fifo" ) | |||
mapfile -t files < <(fzf -e --inline-info +s --multi --cycle --bind='Ctrl-A:toggle-all,`:jump' < "$fifo") | |||
if (( ${#files[@]} )); then | |||
rsync --protect-args -auvzP -e ssh "${files[@]}" . |