/* BB Key Bindings User-defined key bindings go in config.h, which is created by running `make` (config.def.h is for keeping the defaults around, just in case) The basic structure is: (for the help menu) (whether to run in a full terminal window or silently, etc.) When the scripts are run, the following values are provided as environment variables: $@ (the list of arguments): the full paths of the selected files $BBCURSOR: the full name of the file under the cursor $BB_DEPTH: the number of `bb` instances deep (in case you want to run a shell and have that shell print something special in the prompt) $BBCMD: a file to which `bb` commands can be written (used internally) In order to modify bb's internal state, you can call `bb +cmd`, where "cmd" is one of the following commands (or a unique prefix of one): .:[01] Whether to show "." in each directory ..:[01] Whether to show ".." in each directory cd: Navigate to columns: Change which columns are visible, and in what order deselect: Deselect dotfiles:[01] Whether dotfiles are visible goto: Move the cursor to (changing directory if needed) interleave:[01] Whether or not directories should be interleaved with files in the display jump: Jump to the mark associated with mark:[=] Associate with (or current dir, if blank) move: Move the cursor a numeric amount quit Quit bb refresh Refresh the file listing scroll: Scroll the view a numeric amount select: Select sort:([+-]method)+ List of sortings (if equal on one, move to the next) spread: Spread the selection state at the cursor toggle: Toggle the selection status of Internally, bb will write the commands (NUL terminated) to $BBCMD, if $BBCMD is set, and read the file when file browsing resumes. These commands can also be passed to bb at startup, and will run immediately. E.g. `bb +col:n +sort:r .` will launch `bb` only showing the name column, randomly sorted. *Note: for numeric-based commands (like scroll), the number can be either an absolute value or a relative value (starting with '+' or '-'), and/or a percent (ending with '%'). Scrolling and moving, '%' means percent of screen height, and '%n' means percent of number of files (e.g. +50% means half a screen height down, and 100%n means the last file) */ #include "bterm.h" // Configurable options: #define KEY_DELAY 50 #define SCROLLOFF MIN(5, (termheight-4)/2) #define QUOTE(s) #s #define CMDFILE_FORMAT "/tmp/bb.XXXXXX" #define SORT_INDICATOR "↓" #define RSORT_INDICATOR "↑" #define SELECTED_INDICATOR " \033[31;7m \033[0m" #define NOT_SELECTED_INDICATOR " " #define TITLE_COLOR "\033[37;1m" #define NORMAL_COLOR "\033[37m" #define CURSOR_COLOR "\033[43;30;1m" #define LINK_COLOR "\033[35m" #define DIR_COLOR "\033[34m" #define EXECUTABLE_COLOR "\033[31m" #define PAUSE " read -n1 -p '\033[2mPress any key to continue...\033[0m\033[?25l'" #define NORMAL_TERM (1<<0) #define AT_CURSOR (1<<1) #define MAX_REBINDINGS 8 typedef struct { int keys[MAX_REBINDINGS+1]; const char *command; const char *description; int flags; } binding_t; typedef struct { int width; const char *name; } column_t; // These commands will run at startup (before command-line arguments) extern const char *startupcmds[]; extern const column_t columns[128]; const char *startupcmds[] = { ////////////////////////////////////////////// // User-defined startup commands can go here ////////////////////////////////////////////// // Set some default marks: "+mark:0", "+mark:~=~", "+mark:h=~", "+mark:/=/", "+mark:c=~/.config", "+mark:l=~/.local", "+mark:s=", // Default column and sorting options: "+sort:+n", "+col:*smpn", "+..", NULL, // NULL-terminated array }; // Column widths: const column_t columns[128] = { ['*'] = {2, "*"}, ['a'] = {21, " Accessed"}, ['c'] = {21, " Created"}, ['m'] = {21, " Modified"}, ['n'] = {40, "Name"}, ['p'] = {5, "Permissions"}, ['r'] = {2, "Random"}, ['s'] = {9, "Size"}, }; #ifdef __APPLE__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" #endif extern binding_t bindings[]; #define B(s) "\033[1m" s "\033[22m" binding_t bindings[] = { /************************************************************************* * User-defined custom scripts can go here * Format is: {{keys}, "script", "help text", flags} * * For longer scripts you can use QUOTE(...) instead of "..." and all * quotation marks and newlines and backslashes will get escaped properly. * * Please note that these are sh scripts, not bash scripts, so bash-isms * won't work unless you make your script use `bash -c ""` ************************************************************************/ {{'?', KEY_F1}, "bb -b | $PAGER -r", B("Help")" menu", NORMAL_TERM}, {{'q', 'Q'}, "+quit", B("Quit")}, {{'j', KEY_ARROW_DOWN}, "+move:+1", B("Next")" file"}, {{'k', KEY_ARROW_UP}, "+move:-1", B("Previous")" file"}, {{'h', KEY_ARROW_LEFT}, "+cd:..", B("Parent")" directory"}, {{'l', KEY_ARROW_RIGHT}, "test -d \"$BBCURSOR\" && bb \"+cd:$BBCURSOR\"", B("Enter")" a directory"}, {{'\r', KEY_MOUSE_DOUBLE_LEFT}, #ifdef __APPLE__ QUOTE( if test -d "$BBCURSOR"; then bb "+cd:$BBCURSOR"; elif test -x "$BBCURSOR"; then "$BBCURSOR"; read -p 'Press any key to continue...' -n1; elif file -bI "$BBCURSOR" | grep '^\(text/\|inode/empty\)' >/dev/null; then $EDITOR "$BBCURSOR"; else open "$BBCURSOR"; fi )/*ENDQUOTE*/, #else QUOTE( if test -d "$BBCURSOR"; then bb "+cd:$BBCURSOR"; elif file -bi "$BBCURSOR" | grep '^\(text/\|inode/empty\)' >/dev/null; then $EDITOR "$BBCURSOR"; else xdg-open "$BBCURSOR"; fi )/*ENDQUOTE*/, #endif B("Open")" file/directory", NORMAL_TERM}, {{' ','v','V'}, "+toggle", B("Toggle")" selection"}, {{KEY_ESC}, "+deselect:*", B("Clear")" selection"}, {{'e'}, "$EDITOR \"$@\"", B("Edit")" file in $EDITOR", NORMAL_TERM}, {{KEY_CTRL_F}, "bb \"+g:`fzf`\"", B("Fuzzy search")" for file", NORMAL_TERM}, {{'/'}, "bb \"+g:`ls -a|fzf`\"", B("Fuzzy select")" file", NORMAL_TERM}, {{'d', KEY_DELETE}, "rm -rfi \"$@\"; bb '+de:*' +r", B("Delete")" files", AT_CURSOR}, {{'D'}, "rm -rf \"$@\"; bb '+de:*' +r", B("Delete")" files (without confirmation)"}, {{'M'}, "mv -i \"$@\" .; bb '+de:*' +r; for f; do bb \"+sel:`pwd`/`basename \"$f\"`\"; done", B("Move")" files to current directory"}, {{'c'}, "cp -i \"$@\" .; bb +r", B("Copy")" files to current directory"}, {{'C'}, "bb '+de:*'; for f; do cp \"$f\" \"$f.copy\" && bb \"+sel:$f.copy\"; done; bb +r", B("Clone")" files"}, {{'n'}, "name=`bb '?New file: '` && touch \"$name\"; bb +r \"+goto:$name\"", B("New file")}, {{'N'}, "name=`bb '?New dir: '` && mkdir \"$name\"; bb +r \"+goto:$name\"", B("New directory")}, {{'|'}, "cmd=`bb '?|'` && printf '%s\\n' \"$@\" | sh -c \"$cmd\"; " PAUSE "; bb +r", B("Pipe")" selected files to a command"}, {{':'}, "sh -c \"`bb '?:'`\" -- \"$@\"; " PAUSE "; bb +refresh", B("Run")" a command"}, {{'>'}, "$SHELL", "Open a "B("shell"), NORMAL_TERM}, {{'m'}, "read -n1 -p 'Mark: ' m && bb \"+mark:$m;$PWD\"", "Set "B("mark")}, {{'\''}, "read -n1 -p 'Jump: ' j && bb \"+jump:$j\"", B("Jump")" to mark"}, {{'r'}, QUOTE( bb '+deselect:*' +refresh; for f; do if renamed="$(dirname "$f")/$(bb '?Rename: ' "$(basename "$f")")" && test "$f" != "$renamed" && mv -i "$f" "$renamed"; then test $BBSELECTED && bb "+select:$renamed"; elif test $BBSELECTED; then bb "+select:$f"; fi done)/*ENDQUOTE*/, B("Rename")" files", AT_CURSOR}, {{'R'}, QUOTE( if patt="`bb '?Rename pattern: ' 's/'`"; then true; else bb +r; exit; fi; if sed -E "$patt" /dev/null 2>/dev/null && bb "+sel:$f"; done )/*ENDQUOTE*/, B("Regex select")" files"}, {{'J'}, "+spread:+1", B("Spread")" selection down"}, {{'K'}, "+spread:-1", B("Spread")" selection up"}, {{'b'}, "bb \"+`bb '?bb +'`\"", "Run a "B("bb command")}, {{'s'}, ("read -n1 -p 'Sort "B("(a)")"lphabetic "B("(s)")"ize "B("(m)")"odification " B("(c)")"creation "B("(a)")"access "B("(r)")"andom "B("(p)")"ermissions:\033[0m ' sort " "&& bb \"+sort:+$sort\""), B("Sort")" by..."}, {{'#'}, "bb \"+col:`bb '?Set columns: '`\"", "Set "B("columns")}, {{'.'}, "bb +dotfiles", "Toggle "B("dotfiles")}, {{'g', KEY_HOME}, "+move:0", "Go to "B("first")" file"}, {{'G', KEY_END}, "+move:100%n", "Go to "B("last")" file"}, {{KEY_F5, KEY_CTRL_R}, "+refresh", B("Refresh")}, {{KEY_CTRL_A}, "+select:*", B("Select all")" files in current directory"}, {{KEY_PGDN}, "+scroll:+100%", B("Page down")}, {{KEY_PGUP}, "+scroll:-100%", B("Page up")}, {{KEY_CTRL_D}, "+scroll:+50%", B("Half page down")}, {{KEY_CTRL_U}, "+scroll:-50%", B("Half page up")}, {{KEY_MOUSE_WHEEL_DOWN}, "+scroll:+3", B("Scroll down")}, {{KEY_MOUSE_WHEEL_UP}, "+scroll:-3", B("Scroll up")}, {{0}}, // Array must be 0-terminated }; #ifdef __APPLE__ #pragma clang diagnostic pop #endif // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1