Some overhaul and refactoring. bbstartup.sh and bindings.bb have been
moved into scripts/bbstartup and scripts/bbbindkeys alongside the other scripts. Some minor bugs have been fixed as well, and a few bindings added.
This commit is contained in:
parent
adcb0a43e0
commit
e0a30fe02b
3
Makefile
3
Makefile
@ -25,7 +25,7 @@ install: $(NAME)
|
|||||||
[ ! "$$prefix" ] && prefix="/usr/local"; \
|
[ ! "$$prefix" ] && prefix="/usr/local"; \
|
||||||
[ ! "$$sysconfdir" ] && sysconfdir=/etc; \
|
[ ! "$$sysconfdir" ] && sysconfdir=/etc; \
|
||||||
mkdir -pv -m 755 "$$prefix/share/man/man1" "$$prefix/bin" "$$sysconfdir/xdg/bb" \
|
mkdir -pv -m 755 "$$prefix/share/man/man1" "$$prefix/bin" "$$sysconfdir/xdg/bb" \
|
||||||
&& cp -rv bindings.bb scripts/* "$$sysconfdir/xdg/bb/" \
|
&& cp -rv scripts/* "$$sysconfdir/xdg/bb/" \
|
||||||
&& cp -v bb.1 bbcmd.1 "$$prefix/share/man/man1/" \
|
&& cp -v bb.1 bbcmd.1 "$$prefix/share/man/man1/" \
|
||||||
&& rm -f "$$prefix/bin/$(NAME)" \
|
&& rm -f "$$prefix/bin/$(NAME)" \
|
||||||
&& cp -v $(NAME) "$$prefix/bin/"
|
&& cp -v $(NAME) "$$prefix/bin/"
|
||||||
@ -42,3 +42,4 @@ uninstall:
|
|||||||
rm -rvf "$$prefix/bin/$(NAME)" "$$prefix/share/man/man1/bb.1" "$$prefix/share/man/man1/bbcmd.1" "$$sysconfdir/xdg/bb"; \
|
rm -rvf "$$prefix/bin/$(NAME)" "$$prefix/share/man/man1/bb.1" "$$prefix/share/man/man1/bbcmd.1" "$$sysconfdir/xdg/bb"; \
|
||||||
printf "\033[1mIf you created any config files in ~/.config/bb, you may want to delete them manually.\033[0m\n"
|
printf "\033[1mIf you created any config files in ~/.config/bb, you may want to delete them manually.\033[0m\n"
|
||||||
|
|
||||||
|
.PHONY: all, clean, install, uninstall
|
||||||
|
26
README.md
26
README.md
@ -51,7 +51,7 @@ The core idea behind `bb` is that `bb` is a file **browser**, not a file
|
|||||||
to the filesystem (passing selected files as arguments), rather than
|
to the filesystem (passing selected files as arguments), rather than
|
||||||
reinventing the wheel by hard-coding operations like `rm`, `mv`, `cp`, `touch`,
|
reinventing the wheel by hard-coding operations like `rm`, `mv`, `cp`, `touch`,
|
||||||
and so on. Shell scripts can be bound to keypresses in
|
and so on. Shell scripts can be bound to keypresses in
|
||||||
`~/.config/bb/bindings.bb`. For example, `D` is bound to a script that prints a
|
`~/.config/bb/bbbindkeys`. For example, `D` is bound to a script that prints a
|
||||||
confirmation message, then runs `rm -rf "$@" && bbcmd deselect refresh`,
|
confirmation message, then runs `rm -rf "$@" && bbcmd deselect refresh`,
|
||||||
which means selecting `file1` and `file2`, then pressing `D` will cause `bb` to
|
which means selecting `file1` and `file2`, then pressing `D` will cause `bb` to
|
||||||
run the shell command `rm -rf file1 file2` and then tell `bb` to deselect all
|
run the shell command `rm -rf file1 file2` and then tell `bb` to deselect all
|
||||||
@ -59,20 +59,18 @@ run the shell command `rm -rf file1 file2` and then tell `bb` to deselect all
|
|||||||
|
|
||||||
## Customizing bb
|
## Customizing bb
|
||||||
|
|
||||||
`bb` runs a script at startup (by default [bbstartup.sh](bbstartup.sh), installed
|
When `bb` launches, it first updates `bb`'s `$PATH` environment variable to
|
||||||
to `/etc/xdg/bb/bbstartup.sh`) that sets up `bb`'s key bindings and a few other
|
include, in order, `~/.config/bb` and `/etc/xdg/bb`. Then, `bb` will run the
|
||||||
minor things. You can override this with your own custom startup script by creating
|
command `bbstartup` (the default implementation is found at
|
||||||
a file at `~/.config/bb/bbstartup.sh`. The default startup script loads key bindings
|
[scripts/bbstartup](scripts/bbstartup), along with other default `bb` commands).
|
||||||
from (in order) `/etc/xdg/bb/bindings.bb` and `~/.config/bb/bindings.bb` (or if
|
`bbstartup` will call `bbbindkeys` and may also set up configuration options like
|
||||||
neither exists, from the local directory).
|
which columns to display and what sort order to use. All of these behaviors can
|
||||||
|
be customized by creating custom local versions of these files in `~/.config/bb/`.
|
||||||
|
The default versions can be found in `/etc/xdg/bb/`.
|
||||||
|
|
||||||
`bb` comes with a bunch of pre-defined bindings for basic actions in
|
You can also create temporary bindings at runtime by hitting `Ctrl-b`, pressing
|
||||||
[bindings.bb](bindings.bb) (installed to `/etc/xdg/bb/bindings.bb`). It's very
|
the key you want to bind, and then entering in a script to run (in case you
|
||||||
easy to add new bindings for whatever custom scripts you want to run, just
|
want to set up an easy way to repeat some custom workflow).
|
||||||
create a file called `~/.config/bb/bindings.bb` and put your bindings there.
|
|
||||||
You can also create bindings at runtime by hitting `Ctrl-b`, pressing the key
|
|
||||||
you want to bind, and then entering in a script to run (in case you want to set
|
|
||||||
up an easy way to repeat some custom workflow).
|
|
||||||
|
|
||||||
### API
|
### API
|
||||||
|
|
||||||
|
16
bb.c
16
bb.c
@ -534,6 +534,7 @@ void print_bindings(int fd)
|
|||||||
*/
|
*/
|
||||||
void run_bbcmd(bb_t *bb, const char *cmd)
|
void run_bbcmd(bb_t *bb, const char *cmd)
|
||||||
{
|
{
|
||||||
|
while (*cmd == ' ' || *cmd == '\n') ++cmd;
|
||||||
if (strncmp(cmd, "bbcmd ", strlen("bbcmd ")) == 0) cmd = &cmd[strlen("bbcmd ")];
|
if (strncmp(cmd, "bbcmd ", strlen("bbcmd ")) == 0) cmd = &cmd[strlen("bbcmd ")];
|
||||||
const char *value = strchr(cmd, ':');
|
const char *value = strchr(cmd, ':');
|
||||||
if (value) ++value;
|
if (value) ++value;
|
||||||
@ -563,8 +564,15 @@ void run_bbcmd(bb_t *bb, const char *cmd)
|
|||||||
for (size_t i = 0; i < sizeof(bindings)/sizeof(bindings[0]); i++) {
|
for (size_t i = 0; i < sizeof(bindings)/sizeof(bindings[0]); i++) {
|
||||||
if (bindings[i].script && (bindings[i].key != keyval || is_section))
|
if (bindings[i].script && (bindings[i].key != keyval || is_section))
|
||||||
continue;
|
continue;
|
||||||
binding_t binding = {keyval, memcheck(strdup(script)),
|
char *script2;
|
||||||
memcheck(strdup(description))};
|
if (is_simple_bbcmd(script)) {
|
||||||
|
script2 = memcheck(strdup(script));
|
||||||
|
} else {
|
||||||
|
const char *prefix = "set -e\n";
|
||||||
|
script2 = memcheck(calloc(strlen(prefix) + strlen(script) + 1, 1));
|
||||||
|
sprintf(script2, "%s%s", prefix, script);
|
||||||
|
}
|
||||||
|
binding_t binding = {keyval, script2, memcheck(strdup(description))};
|
||||||
if (bindings[i].key == keyval) {
|
if (bindings[i].key == keyval) {
|
||||||
free(bindings[i].description);
|
free(bindings[i].description);
|
||||||
free(bindings[i].script);
|
free(bindings[i].script);
|
||||||
@ -1194,9 +1202,9 @@ int main(int argc, char *argv[])
|
|||||||
struct sigaction sa_winch = {.sa_handler = &update_term_size};
|
struct sigaction sa_winch = {.sa_handler = &update_term_size};
|
||||||
sigaction(SIGWINCH, &sa_winch, NULL);
|
sigaction(SIGWINCH, &sa_winch, NULL);
|
||||||
update_term_size(0);
|
update_term_size(0);
|
||||||
// Wait 10ms at a time for terminal to initialize if necessary
|
// Wait 100us at a time for terminal to initialize if necessary
|
||||||
while (winsize.ws_row == 0)
|
while (winsize.ws_row == 0)
|
||||||
usleep(10000);
|
usleep(100);
|
||||||
|
|
||||||
// Set up environment variables
|
// Set up environment variables
|
||||||
// Default values
|
// Default values
|
||||||
|
2
bb.h
2
bb.h
@ -26,7 +26,7 @@
|
|||||||
#include "bterm.h"
|
#include "bterm.h"
|
||||||
|
|
||||||
// Macros:
|
// Macros:
|
||||||
#define BB_VERSION "0.26.0"
|
#define BB_VERSION "0.27.0"
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
#define PATH_MAX 4096
|
#define PATH_MAX 4096
|
||||||
|
215
bindings.bb
215
bindings.bb
@ -1,215 +0,0 @@
|
|||||||
# This file defines the key bindings for bb
|
|
||||||
# The format is: <key>(,<key>)*:[ ]*#<description>(\n[ ]+script)+
|
|
||||||
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
|
|
||||||
|
|
||||||
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 "$BBCURSOR" ]; then bbcmd cd:"$BBCURSOR"; fi
|
|
||||||
Ctrl-f: # Search for file
|
|
||||||
file="$(
|
|
||||||
find $BBGLOB -mindepth 1 -printf '%P\0' | bbpick "Find: "
|
|
||||||
)" && bbcmd goto:"$file"
|
|
||||||
/: # Pick a file
|
|
||||||
file="$(printf "%s\0" $BBGLOB | bbpick "Pick: ")" || exit
|
|
||||||
bbcmd goto:"$file"
|
|
||||||
*: # Set the glob
|
|
||||||
glob="$(bbask "Show files matching: ")" && bbcmd glob:"$glob"
|
|
||||||
Ctrl-g: # Go to directory
|
|
||||||
cd="$(bbask "Go to directory: ")" && bbcmd cd:"$cd"
|
|
||||||
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 ] || exit
|
|
||||||
mark="$(find "$XDG_CONFIG_HOME"/bb/marks/ -mindepth 1 -type l -printf '%P\0' | bbpick "Jump to: ")" &&
|
|
||||||
bbcmd cd:"$(readlink -f "$XDG_CONFIG_HOME"/bb/marks/"$mark")"
|
|
||||||
-,Backspace: # Go to previous directory
|
|
||||||
[ "$BBPREVPATH" ] && bbcmd cd:"$BBPREVPATH"
|
|
||||||
;: # Show selected files
|
|
||||||
bbcmd cd:'<selection>'
|
|
||||||
0: # Go to intitial directory
|
|
||||||
bbcmd cd:"$BBINITIALPATH"
|
|
||||||
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:"$BBCURSOR"
|
|
||||||
Escape: # Clear selection
|
|
||||||
bbcmd deselect
|
|
||||||
S: # Select pattern
|
|
||||||
patt="$(bbask "Select: ")" && bbcmd select: $patt
|
|
||||||
U: # Unselect pattern
|
|
||||||
patt="$(bbask "Unselect: ")" && bbcmd deselect: $patt
|
|
||||||
Ctrl-s: # Save the selection
|
|
||||||
[ $# -gt 0 ] && savename="$(bbask "Save selection as: ")" || exit 1
|
|
||||||
mkdir -p "$XDG_DATA_HOME"/bb
|
|
||||||
if ! expr "$savename" : ".*\.sel" >/dev/null; then savename="$savename.sel"; fi
|
|
||||||
printf '%s\0' "$@" > "$XDG_DATA_HOME"/bb/"$savename"
|
|
||||||
Ctrl-o: # Open a saved selection
|
|
||||||
[ -d "$XDG_DATA_HOME"/bb ] || exit
|
|
||||||
[ $# -gt 0 ] && ! bbconfirm "The current selection will be discarded. " && exit 1
|
|
||||||
loadpath="$(find "$XDG_DATA_HOME"/bb/ -mindepth 1 -name '*.sel' -printf '%P\0' | bbpick "Load selection: ")" &&
|
|
||||||
cat "$XDG_DATA_HOME"/bb/"$loadpath" | bbcmd deselect select:
|
|
||||||
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 "$BBCURSOR" ]; then bbcmd cd:"$BBCURSOR"
|
|
||||||
elif [ "$(uname)" = "Darwin" ]; then
|
|
||||||
if expr "$(file -bI "$BBCURSOR")" : '\(text/\|inode/empty\)' >/dev/null; then $EDITOR "$BBCURSOR"
|
|
||||||
else open "$BBCURSOR"; fi
|
|
||||||
else
|
|
||||||
if expr "$(file -bi "$BBCURSOR")" : '\(text/\|inode/x-empty\)' >/dev/null; then $EDITOR "$BBCURSOR"
|
|
||||||
else xdg-open "$BBCURSOR"; fi
|
|
||||||
fi
|
|
||||||
e: # Edit file in $EDITOR
|
|
||||||
$EDITOR "$BBCURSOR" || bbpause
|
|
||||||
d,Delete: # Delete
|
|
||||||
case "$(bbtargets "$BBCURSOR" "$@")" in
|
|
||||||
cursor) set -- "$BBCURSOR" ;;
|
|
||||||
both) set -- "$BBCURSOR" "$@" ;;
|
|
||||||
esac
|
|
||||||
printf "\033[1mDeleting the following:\n\033[33m$(printf ' %s\n' "$@")\033[0m" | bbunscroll | more &&
|
|
||||||
bbconfirm && rm -rf "$@" && bbcmd deselect refresh
|
|
||||||
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 && for f; do bbcmd sel:"$(basename "$f")"; done
|
|
||||||
c: # Copy a file
|
|
||||||
case "$(bbtargets "$BBCURSOR" "$@")" in
|
|
||||||
cursor) set -- "$BBCURSOR";;
|
|
||||||
both) set -- "$BBCURSOR" "$@";;
|
|
||||||
esac
|
|
||||||
[ $# -gt 0 ] || exit
|
|
||||||
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 [ "./$(basename "$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: ")" && touch -- "$name"
|
|
||||||
;;
|
|
||||||
Directory)
|
|
||||||
name="$(bbask "New Directory: ")" && mkdir -- "$name"
|
|
||||||
;;
|
|
||||||
*) exit
|
|
||||||
;;
|
|
||||||
esac && bbcmd goto:"$name" refresh || bbpause
|
|
||||||
p: # Page through a file with `less`
|
|
||||||
less -XK "$BBCURSOR"
|
|
||||||
r,F2: # Rename files
|
|
||||||
case "$(bbtargets "$BBCURSOR" "$@")" in
|
|
||||||
cursor) set -- "$BBCURSOR";;
|
|
||||||
both) set -- "$BBCURSOR" "$@";;
|
|
||||||
esac
|
|
||||||
for f; do
|
|
||||||
newname="$(bbask "Rename $(printf "\033[33m%s\033[39m" "$(basename "$f")"): " "$(basename "$f")")" || break
|
|
||||||
r="$(dirname "$f")/$newname"
|
|
||||||
[ "$r" = "$f" ] && continue
|
|
||||||
[ -e "$r" ] && printf "\033[31;1m$r already exists! It will be overwritten.\033[0m "
|
|
||||||
&& bbconfirm && { rm -rf "$r" || { bbpause; exit; }; }
|
|
||||||
mv "$f" "$r" || { bbpause; exit; }
|
|
||||||
bbcmd deselect:"$f" select:"$r"
|
|
||||||
[ "$f" = "$BBCURSOR" ] && bbcmd goto:"$r"
|
|
||||||
done
|
|
||||||
bbcmd refresh
|
|
||||||
~: # Regex rename files
|
|
||||||
if ! command -v rename >/dev/null; then
|
|
||||||
printf '\033[31;1mThe `rename` command is not installed. Please install it to use this key binding.\033[0m\n'
|
|
||||||
bbpause; exit 1
|
|
||||||
fi
|
|
||||||
if [ $# -eq 0 ]; then set -- $BBGLOB; fi
|
|
||||||
set -e
|
|
||||||
patt="$(bbask "Replace pattern: ")"
|
|
||||||
rep="$(bbask "Replacement: ")"
|
|
||||||
printf "\033[1mRenaming:\n\033[33m$(if [ $# -gt 0 ]; then rename -nv "$patt" "$rep" "$@"; else rename -nv "$patt" "$rep" *; fi)\033[0m" | bbunscroll | more
|
|
||||||
bbconfirm
|
|
||||||
if [ $# -eq 0 ]; then set -- *; [ -e "$1" ] || exit 1; fi
|
|
||||||
rename -i "$patt" "$rep" "$@"
|
|
||||||
bbcmd deselect refresh
|
|
||||||
|
|
||||||
Section: Shell Commands
|
|
||||||
:: # Run a command
|
|
||||||
cmd="$(bbask ':')" && sh -c "$cmd" -- "$@"; bbcmd refresh; bbpause
|
|
||||||
|: # Pipe selected files to a command
|
|
||||||
cmd="$(bbask '|')" && printf '%s\n' "$@" | sh -c "$cmd"; bbcmd refresh; bbpause
|
|
||||||
@: # Pipe selected files to a command
|
|
||||||
cmd="$(bbask '@')" && sh -c "$cmd \"$$@\"" -- "$@"; bbcmd refresh; bbpause
|
|
||||||
>: # Open a shell
|
|
||||||
tput rmcup; tput cvvis; $SHELL; bbcmd refresh
|
|
||||||
f: # Resume suspended process
|
|
||||||
bbcmd fg
|
|
||||||
|
|
||||||
Section: Viewing Options
|
|
||||||
s: # Sort by...
|
|
||||||
sort="$(bbask -1 "Sort (n)ame (s)ize (m)odification (c)reation (a)ccess (r)andom (p)ermissions: ")" &&
|
|
||||||
bbcmd sort:"~$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: # 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" || bbpause
|
|
||||||
|
|
||||||
Section: User Bindings
|
|
1
bterm.h
1
bterm.h
@ -118,6 +118,7 @@ static keyname_t key_names[] = {
|
|||||||
{KEY_CTRL_2, "Ctrl-2"}, {KEY_CTRL_3, "Ctrl-3"}, {KEY_CTRL_4, "Ctrl-4"},
|
{KEY_CTRL_2, "Ctrl-2"}, {KEY_CTRL_3, "Ctrl-3"}, {KEY_CTRL_4, "Ctrl-4"},
|
||||||
{KEY_CTRL_5, "Ctrl-5"}, {KEY_CTRL_6, "Ctrl-6"}, {KEY_CTRL_7, "Ctrl-7"},
|
{KEY_CTRL_5, "Ctrl-5"}, {KEY_CTRL_6, "Ctrl-6"}, {KEY_CTRL_7, "Ctrl-7"},
|
||||||
{KEY_CTRL_5, "Ctrl-8"}, {KEY_CTRL_6, "Ctrl-9"},
|
{KEY_CTRL_5, "Ctrl-8"}, {KEY_CTRL_6, "Ctrl-9"},
|
||||||
|
{':', "Colon"},
|
||||||
};
|
};
|
||||||
|
|
||||||
int bgetkey(FILE *in, int *mouse_x, int *mouse_y);
|
int bgetkey(FILE *in, int *mouse_x, int *mouse_y);
|
||||||
|
318
scripts/bbbindkeys
Executable file
318
scripts/bbbindkeys
Executable file
@ -0,0 +1,318 @@
|
|||||||
|
#!/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:
|
||||||
|
sed '1,'$LINENO'd; /^$/d; s/^## \(.*\): \(.*\)/\x00bind:\1:# \2/; $a\\x00' "$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
|
||||||
|
|
||||||
|
## 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 "$BBCURSOR" ]; then bbcmd cd:"$BBCURSOR"; fi
|
||||||
|
|
||||||
|
## Ctrl-f: Search for file
|
||||||
|
file="$(find $BBGLOB -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
|
||||||
|
[ "$BBPREVPATH" ] && bbcmd cd:"$BBPREVPATH"
|
||||||
|
|
||||||
|
## ;: Show selected files
|
||||||
|
bbcmd cd:'<selection>'
|
||||||
|
|
||||||
|
## 0: Go to intitial directory
|
||||||
|
bbcmd cd:"$BBINITIALPATH"
|
||||||
|
|
||||||
|
## 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:"$BBCURSOR"
|
||||||
|
|
||||||
|
## Escape: Clear selection
|
||||||
|
bbcmd deselect
|
||||||
|
|
||||||
|
## S: Select pattern
|
||||||
|
patt="$(bbask "Select: ")"
|
||||||
|
bbcmd select: $patt
|
||||||
|
|
||||||
|
## U: Unselect pattern
|
||||||
|
patt="$(bbask "Unselect: ")"
|
||||||
|
bbcmd deselect: $patt
|
||||||
|
|
||||||
|
## Ctrl-s: Save the selection
|
||||||
|
[ $# -gt 0 ]
|
||||||
|
savename="$(bbask "Save selection as: ")"
|
||||||
|
mkdir -p "$XDG_DATA_HOME"/bb
|
||||||
|
if ! expr "$savename" : ".*\.sel" >/dev/null; then savename="$savename.sel"; fi
|
||||||
|
printf '%s\0' "$@" > "$XDG_DATA_HOME"/bb/"$savename"
|
||||||
|
|
||||||
|
## 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 -name '*.sel' -printf '%P\0' | bbpick "Load selection: ")"
|
||||||
|
cat "$XDG_DATA_HOME"/bb/"$loadpath" | bbcmd deselect select:
|
||||||
|
|
||||||
|
## 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 "$BBCURSOR" ]; then bbcmd cd:"$BBCURSOR"
|
||||||
|
elif [ "$(uname)" = "Darwin" ]; then
|
||||||
|
if expr "$(file -bI "$BBCURSOR")" : '\(text/\|inode/empty\)' >/dev/null; then $EDITOR "$BBCURSOR"
|
||||||
|
else open "$BBCURSOR"; fi
|
||||||
|
else
|
||||||
|
if expr "$(file -bi "$BBCURSOR")" : '\(text/\|inode/x-empty\)' >/dev/null; then $EDITOR "$BBCURSOR"
|
||||||
|
else xdg-open "$BBCURSOR"; fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
## e: Edit file in $EDITOR
|
||||||
|
$EDITOR "$BBCURSOR"
|
||||||
|
|
||||||
|
## d,Delete: Delete
|
||||||
|
case "$(bbtargets "$BBCURSOR" "$@")" in
|
||||||
|
cursor) set -- "$BBCURSOR" ;;
|
||||||
|
both) set -- "$BBCURSOR" "$@" ;;
|
||||||
|
esac
|
||||||
|
printf "\033[1mDeleting the following:\n\033[33m$(printf ' %s\n' "$@")\033[0m" | bbunscroll | more
|
||||||
|
bbconfirm
|
||||||
|
rm -rf "$@"
|
||||||
|
bbcmd deselect refresh
|
||||||
|
|
||||||
|
## 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
|
||||||
|
for f; do bbcmd sel:"$(basename "$f")"; done
|
||||||
|
|
||||||
|
## c: Copy a file
|
||||||
|
case "$(bbtargets "$BBCURSOR" "$@")" in
|
||||||
|
cursor) set -- "$BBCURSOR";;
|
||||||
|
both) set -- "$BBCURSOR" "$@";;
|
||||||
|
esac
|
||||||
|
[ $# -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 [ "./$(basename "$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: ")" && touch -- "$name"
|
||||||
|
;;
|
||||||
|
Directory)
|
||||||
|
name="$(bbask "New Directory: ")" && mkdir -- "$name"
|
||||||
|
;;
|
||||||
|
*) exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
bbcmd goto:"$name" refresh
|
||||||
|
|
||||||
|
## p: Page through a file with `less`
|
||||||
|
less -XK "$BBCURSOR"
|
||||||
|
|
||||||
|
## r,F2: Rename files
|
||||||
|
case "$(bbtargets "$BBCURSOR" "$@")" in
|
||||||
|
cursor) set -- "$BBCURSOR";;
|
||||||
|
both) set -- "$BBCURSOR" "$@";;
|
||||||
|
esac
|
||||||
|
for f; do
|
||||||
|
newname="$(bbask "Rename $(printf "\033[33m%s\033[39m" "$(basename "$f")"): " "$(basename "$f")")" || break
|
||||||
|
r="$(dirname "$f")/$newname"
|
||||||
|
[ "$r" = "$f" ] && continue
|
||||||
|
[ -e "$r" ] && printf "\033[31;1m$r already exists! It will be overwritten.\033[0m "
|
||||||
|
&& bbconfirm && { rm -rf "$r" || { bbpause; exit; }; }
|
||||||
|
mv "$f" "$r" || { bbpause; exit; }
|
||||||
|
bbcmd deselect:"$f" select:"$r"
|
||||||
|
[ "$f" = "$BBCURSOR" ] && bbcmd goto:"$r"
|
||||||
|
done
|
||||||
|
bbcmd refresh
|
||||||
|
|
||||||
|
## ~: Regex rename files
|
||||||
|
if ! command -v rename >/dev/null; then
|
||||||
|
printf '\033[31;1mThe `rename` command is not installed. Please install it to use this key binding.\033[0m\n'
|
||||||
|
bbpause; exit 1
|
||||||
|
fi
|
||||||
|
if [ $# -eq 0 ]; then set -- $BBGLOB; fi
|
||||||
|
patt="$(bbask "Replace pattern: ")"
|
||||||
|
rep="$(bbask "Replacement: ")"
|
||||||
|
printf "\033[1mRenaming:\n\033[33m$(rename -nv "$patt" "$rep" "$@")\033[0m" | bbunscroll | more
|
||||||
|
bbconfirm
|
||||||
|
rename -i "$patt" "$rep" "$@"
|
||||||
|
bbcmd deselect 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 -- "$BBCURSOR"; 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 -- "$BBCURSOR"; fi
|
||||||
|
sh -c "$cmd \"\$@\"" -- "$@" || true
|
||||||
|
bbpause
|
||||||
|
bbcmd refresh
|
||||||
|
|
||||||
|
## $: Pass the cursor as an argument to a command
|
||||||
|
cmd="$(bbask '$')"
|
||||||
|
sh -c "$cmd \"\$1\"" -- "$BBCURSOR" || 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...
|
||||||
|
sort="$(bbask -1 "Sort (n)ame (s)ize (m)odification (c)reation (a)ccess (r)andom (p)ermissions: ")"
|
||||||
|
bbcmd sort:"~$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: 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"
|
||||||
|
|
||||||
|
|
||||||
|
## Section: User Bindings
|
@ -4,11 +4,7 @@
|
|||||||
[ ! -d "$XDG_DATA_HOME/bb" ] && mkdir -p "$XDG_DATA_HOME/bb"
|
[ ! -d "$XDG_DATA_HOME/bb" ] && mkdir -p "$XDG_DATA_HOME/bb"
|
||||||
|
|
||||||
# Load key bindings
|
# Load key bindings
|
||||||
if [ "$BBPATH" ]; then
|
bbbindkeys
|
||||||
cat "$BBPATH/bindings.bb" "$XDG_CONFIG_HOME/bb/bindings.bb"
|
|
||||||
else
|
|
||||||
cat "$sysconfdir/xdg/bb/bindings.bb" "$XDG_CONFIG_HOME/bb/bindings.bb"
|
|
||||||
fi 2>/dev/null | awk '/^#/ {next} /^[^ ]/ {printf "\0bind:"} {print $0} END {printf "\0"}' >> "$BBCMD"
|
|
||||||
|
|
||||||
if [ -e "$XDG_DATA_HOME/bb/settings.sh" ]; then
|
if [ -e "$XDG_DATA_HOME/bb/settings.sh" ]; then
|
||||||
. "$XDG_DATA_HOME/bb/settings.sh"
|
. "$XDG_DATA_HOME/bb/settings.sh"
|
||||||
|
Loading…
Reference in New Issue
Block a user