Download
303 lines 7.3 KiBBashModified 2026-10-24executable raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
#!/bin/sh
# This file defines the key bindings for bb. It works by a very hacky script on
# the line below that prints out the rest of this file, converted into `bbcmd
# bind:` commands. Thanks to the hackiness, the code below is also valid shell
# code, so syntax highlighting should work normally.
#
# The format is: ## <key>(,<key>)*:[ ]+<description>(\n script)+
#
# May God have mercy on my soul for creating this abomination:
awk 'NR<='$LINENO'{next} /^##/{sub(/: /, ":# "); sub(/^## /,"\0bind:")} /./{print}' "$0" | bbcmd; exit

## Section: BB Commands
## ?,F1: Show Help menu
bbcmd help

## q,Q: Quit
bbcmd quit

## Ctrl-c: Send interrupt signal
kill -INT $PPID

## Ctrl-z: Suspend
kill -TSTP $PPID

## Ctrl-\: Quit and generate core dump
kill -QUIT $PPID

## +: Run a bb command
bbcmd "$(bbask '+')"
bbcmd refresh

## Section: File Navigation
## j,Down: Next file
bbcmd move:+1

## k,Up: Previous file
bbcmd move:-1

## h,Left: Parent directory
bbcmd cd:..

## l,Right: Enter directory
if [ -d "$BB" ]; then bbcmd cd:"$BB";
elif [ -L "$BB" ]; then bbcmd goto:"$(readlink -f "$BB")"; fi

## Ctrl-f: Search for file
file="$(find . -mindepth 1 -printf '%P\0' | bbpick "Find: ")"
bbcmd goto:"$file"

## /: Pick a file
file="$(printf "%s\0" $BBGLOB | bbpick "Pick: ")"
bbcmd goto:"$file"

## *: Set the glob
glob="$(bbask "Show files matching: ")"
bbcmd glob:"$glob"

## Ctrl-g: Go to directory
dir="$(bbask "Go to directory: ")"
bbcmd cd:"$dir"

## m: Mark this directory
mkdir -p "$XDG_CONFIG_HOME/bb/marks"
ln -sT "$2" "$XDG_CONFIG_HOME/bb/marks/$1" 2>/dev/null
mark="$(bbask "Mark: ")"
ln -s "$PWD" "$XDG_CONFIG_HOME"/bb/marks/"$mark"

## ': Go to a marked directory
[ -d "$XDG_CONFIG_HOME"/bb/marks ]
mark="$(find "$XDG_CONFIG_HOME"/bb/marks/ -mindepth 1 -type l -printf '%P\0' | bbpick "Jump to: ")"
mark="$(readlink -f "$XDG_CONFIG_HOME"/bb/marks/"$mark")"
bbcmd cd:"$mark"

## [,Backspace: Go to previous directory
bbcmd cd:-

## ]: Go to next directory
bbcmd cd:+

## ;: Show selected files
printf '%s\n' "$@" | less

## g,Home: Go to first file
bbcmd move:0

## G,End: Go to last file
bbcmd move:100%n

## PgDn: Page down
bbcmd scroll:+100%

## PgUp: Page up
bbcmd scroll:-100%

## Ctrl-d: Half page down
bbcmd scroll:+50%

## Ctrl-u: Half page up
bbcmd scroll:-50%

## Mouse wheel down: Scroll down
bbcmd scroll:+3

## Mouse wheel up: Scroll up
bbcmd scroll:-3


## Section: File Selection
## v,V,Space: Toggle selection at cursor
bbcmd toggle:"$BB"

## Escape: Clear selection
bbcmd deselect

## S: Select pattern
patt="$(bbask "Select: ")"
bbcmd select: $patt

## U: Unselect pattern
patt="$(bbask "Unselect: ")"
bbcmd deselect: $patt

## Comma: Save the current settings
bbconfirm "Save the current settings? "
echo "bbcmd glob:'$BBGLOB' sort:'$BBSORT' columns:'$BBCOLUMNS' $BBINTERLEAVE" > "$XDG_DATA_HOME"/bb/settings.sh

## Ctrl-s: Save the selection
savename="$(bbask "Save selection as: ")"
savedir="$XDG_DATA_HOME/bb/${savename%.sel}.sel"
[ -d "$savedir" ] && { bbconfirm "Do you want to overwrite the existing save? " || exit; }
rm -rf "$savedir"
[ $# -gt 0 ] && mkdir -p "$savedir"
for f; do ln -sT "$f" "$savedir/${f##*/}" || exit 1; done
echo "Saved."
bbpause

## Ctrl-o: Open a saved selection
[ -d "$XDG_DATA_HOME"/bb ]
[ $# -gt 0 ] && bbconfirm "The current selection will be discarded. "
loadpath="$(find "$XDG_DATA_HOME"/bb/ -mindepth 1 -maxdepth 1 -name '*.sel' -printf '%P\0' | bbpick "Load selection: ")"
find "$XDG_DATA_HOME/bb/$loadpath" -mindepth 1 -maxdepth 1 -printf '%l\0' | bbcmd deselect select:
bbcmd goto sort:'+*' interleave

## J: Spread selection down
bbcmd spread:+1

## K: Spread selection up
bbcmd spread:-1

## Shift-Home: Spread the selection to the top
bbcmd spread:0

## Shift-End: Spread the selection to the bottom
bbcmd spread:100%n

## Ctrl-a: Select all files here
bbcmd select


## Section: File Actions
## Left click: Move cursor to file
if [ "$BBCLICKED" = "<column label>" ]; then
    bbcmd sort:"~$BBMOUSECOL"
elif [ "$BBCLICKED" -a "$BBMOUSECOL" = "*" ]; then
    bbcmd toggle:"$BBCLICKED"
elif [ "$BBCLICKED" ]; then
    bbcmd goto:"$BBCLICKED"
fi

## Enter,Double left click: Open file/directory
if [ -d "$BB" ]; then bbcmd cd:"$BB"
elif [ "$(uname)" = "Darwin" ]; then
    if expr "$(file -bI "$BB")" : '\(text/\|inode/empty\)' >/dev/null; then $EDITOR "$BB"
    else open "$BB"; fi
else
    if expr "$(file -bi "$BB")" : '\(text/\|inode/x-empty\)' >/dev/null; then $EDITOR "$BB"
    else xdg-open "$BB"; fi
fi

## e: Edit file in $EDITOR
$EDITOR "$BB"

## Ctrl-v: Move files here
printf "\033[1mMoving the following to here:\n\033[33m$(printf '  %s\n' "$@")\033[0m" | bbunscroll | more
bbconfirm
printf "\033[1G\033[KMoving..."
mv -i "$@" .
printf "done."
bbcmd deselect refresh
bbcmd sel: "${@##*/}"

## c: Copy a file
[ $# -gt 0 ]
printf "\033[1mCopying the following to here:\n\033[33m$(printf '  %s\n' "$@")\033[0m" | bbunscroll | more
bbconfirm
printf "\033[1G\033[KCopying..."
for f; do
    if [ "./${f##*/}" -ef "$f" ]; then
        cp -ri "$f" "$f.copy" || break
    else cp -ri "$f" . || break; fi
done
printf 'done.'
bbcmd refresh

## Ctrl-n: New file/directory
case "$(printf '%s\0' File Directory | bbpick "Create new: ")" in
    File)
        name="$(bbask "New File: ")" && printf '' >"$name"
        ;;
    Directory)
        name="$(bbask "New Directory: ")" && mkdir -- "$name"
        ;;
    *) exit
        ;;
esac
bbcmd goto:"$name" refresh

## Section: Shell Commands
## Colon: Run a command
cmd="$(bbask ':')"
sh -c "$cmd" -- "$@" || true
bbpause
bbcmd refresh

## |: Pipe selected files to a command
cmd="$(bbask '|')"
if [ $# -eq 0 ]; then set -- "$BB"; fi
printf '%s\n' "$@" | sh -c "$cmd" || true
bbpause
bbcmd refresh

## @: Pass selected files as args to a command
cmd="$(bbask '@')"
if [ $# -eq 0 ]; then set -- "$BB"; fi
sh -c "$cmd \"\$@\"" -- "$@" || true
bbpause
bbcmd refresh

## $: Pass the cursor as an argument to a command
cmd="$(bbask '$')"
sh -c "$cmd \"\$1\"" -- "$BB" || true
bbpause
bbcmd refresh

## >: Open a shell
tput rmcup; tput cvvis
$SHELL || true
bbcmd refresh

## f: Resume suspended process
bbcmd fg


## Section: Viewing Options
## s: Sort by...
new_sort="$(bbask -1 "Sort (n)ame (s)ize (m)odification (c)reation (a)ccess (r)andom (p)ermissions: ")"
bbcmd sort:"~$new_sort"

## ---,#: Set columns
columns="$(bbask "Set columns (*)selected (a)ccessed (c)reated (m)odified (n)ame (p)ermissions (r)andom (s)ize: ")"
bbcmd col:"$columns"

## .: Toggle dotfile visibility
if [ "$BBGLOB" = ".* *" ]; then
    bbcmd glob:"*"
else
    bbcmd glob:".* *"
fi

## i: Toggle interleaving files and directories
bbcmd interleave

## F5,Ctrl-l,Ctrl-r: Refresh view
bbcmd refresh

## Ctrl-b: Bind a key to a script
key="$(bbask -1 "Press key to bind...")"
echo
script="$(bbask "Bind script: ")"
bbcmd bind:"$key":"{ $script; } || bbpause"

## 1: Run action on files
missing_cursor() {
    for f; do
        if [ "$f" = "$BB" ]; then return 1; fi
    done
}
if [ $# -gt 0 ]; then
    if missing_cursor "$@"; then
        intended="$(printf '%s\0' 'Cursor file' 'Selected files' 'Both' | bbpick 'Which do you mean? ')"
        case "$intended" in
            Cursor*) set -- "$BB";;
            Selected*) ;;
            Both) set -- "$BB" "$@" ;;
            *) exit 1;;
        esac
    fi
else
    set -- "$BB"
fi
picked=$(sed -n 's/^## *//p' /etc/bb/bbactions | fzf --height=1)
[ -n "$picked" ] || exit 1
sh -c "$(bp "$picked"'\(\n braces)' /etc/bb/bbactions)" -- "$@" || bbpause