1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
/*
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:
<list of keys to bind>
<program to run>
<description> (for the help menu)
<flags> (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 (short) name of the file under the cursor
$BBFULLCURSOR: the full path 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):
cd:<path> Navigate to <path>
columns:<columns> Change which columns are visible, and in what order
deselect:<filename> Deselect <filename>
dots[:yes|:no] Toggle whether dotfiles are visible
goto:<filename> Move the cursor to <filename> (changing directory if needed)
jump:<key> Jump to the mark associated with <key>
mark:<key>[;<path>] Associate <key> with <path> (or current dir, if blank)
move:<num*> Move the cursor a numeric amount
quit Quit bb
refresh Refresh the file listing
scroll:<num*> Scroll the view a numeric amount
select:<filename> Select <filename>
sort:<method> Change the sorting method (uppercase means reverse)
spread:<num*> Spread the selection state at the cursor
toggle:<filename> Toggle the selection status of <filename>
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 "keys.h"
#define PIPE_SELECTION_TO " printf '%s\\n' \"$@\" | "
#define PAUSE " read -n1 -p '\033[2m...press any key to continue...\033[0m\033[?25l'"
#define NORMAL_TERM (1<<0)
#define SHOW_CURSOR (1<<1)
#define MAX_REBINDINGS 8
typedef struct {
int keys[MAX_REBINDINGS+1];
const char *command;
const char *description;
int flags;
} binding_t;
// These commands will run at startup (before command-line arguments)
extern const char *startupcmds[];
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",
// Default column and sorting options:
"+columns:smpn", "+sort:n",
NULL, // NULL-terminated array
};
extern binding_t bindings[];
binding_t bindings[] = {
//////////////////////////////////////////////////////////////////////////
// User-defined custom scripts can go here
// Please note that these are sh scripts, not bash scripts, so bash-isms
// won't work unless you make your script use `bash -c "<your script>"`
//////////////////////////////////////////////////////////////////////////
{{'?'}, "bb -b | less -r", "Show the help menu", NORMAL_TERM},
{{KEY_CTRL_H}, "<placeholder>", "Figure out what key does"},
{{'q', 'Q'}, "bb +q", "Quit"},
{{'k', KEY_ARROW_UP}, "+m:-1", "Move up"},
{{'j', KEY_ARROW_DOWN}, "+m:+1", "Move down"},
{{'h', KEY_ARROW_LEFT}, "bb \"+cd:..\"", "Go up a folder"},
{{'l', KEY_ARROW_RIGHT}, "test -d \"$BBCURSOR\" && bb \"+cd:$BBCURSOR\"", "Enter a folder"},
{{' ','v','V'}, "bb \"+t:$BBCURSOR\"", "Toggle selection"},
{{'e'}, "$EDITOR \"$@\"", "Edit file in $EDITOR", NORMAL_TERM},
{{'\r', KEY_MOUSE_DOUBLE_LEFT},
#ifdef __APPLE__
"if test -d \"$BBCURSOR\"; then bb \"+cd:$BBCURSOR\";\n\
elif test -x \"$BBCURSOR\"; then \"$BBCURSOR\";\n\
read -n1 -p '\n\033[2m...press any key to continue...\033[0m';\n\
elif file -bI \"$BBCURSOR\" | grep '^\\(text/\\|inode/empty\\)' >/dev/null; then $EDITOR \"$BBCURSOR\";\n\
else open \"$BBCURSOR\"; fi",
#else
"if test -d \"$BBCURSOR\"; then bb \"+cd:$BBCURSOR\";\n\
elif test -x \"$BBCURSOR\"; then \"$BBCURSOR\";\n\
read -n1 -p '\n\033[2m...press any key to continue...\033[0m';\n\
elif file -bi \"$BBCURSOR\" | grep '^\\(text/\\|inode/empty\\)' >/dev/null; then $EDITOR \"$BBCURSOR\";\n\
else xdg-open \"$BBCURSOR\"; fi",
#endif
"Open file", NORMAL_TERM},
{{'f'}, "bb \"+g:`fzf`\"", "Fuzzy search for file", NORMAL_TERM},
{{'/'}, "bb \"+g:`ls -a|fzf`\"", "Fuzzy select file", NORMAL_TERM},
{{'L'}, PIPE_SELECTION_TO "less", "List all selected files", NORMAL_TERM},
{{'d', KEY_DELETE}, "rm -rfi \"$@\"; bb '+d:*' +r", "Delete files", SHOW_CURSOR},
{{'D'}, "rm -rf \"$@\"; bb '+d:*' +r", "Delete files without confirmation"},
{{'M'}, "mv -i \"$@\" .; bb '+d:*' +r", "Move files to current folder", SHOW_CURSOR},
{{'c'}, "cp -i \"$@\" .; bb +r", "Copy files to current folder", SHOW_CURSOR},
{{'C'}, "for f; do cp \"$f\" \"$f.copy\"; done; bb +r", "Clone files"},
{{'n'}, "read -p 'New file: ' name && touch \"$name\"; bb +r \"+goto:$name\"", "New file", SHOW_CURSOR},
{{'N'}, "read -p 'New dir: ' name && mkdir \"$name\"; bb +r \"+goto:$name\"", "New folder", SHOW_CURSOR},
{{'|'}, "read -p '| ' cmd && " PIPE_SELECTION_TO "sh -c \"$cmd\" && " PAUSE "; bb +r",
"Pipe selected files to a command", SHOW_CURSOR},
{{':'}, "read -p ': ' cmd && sh -c \"$cmd\" -- \"$@\"; " PAUSE "; bb +r",
"Run a command", SHOW_CURSOR},
{{'>'}, "sh", "Open a shell", NORMAL_TERM},
{{'m'}, "read -n1 -p 'Mark: ' m && bb \"+mark:$m;$PWD\"", "Set mark", SHOW_CURSOR},
{{'\''}, "read -n1 -p 'Jump: ' j && bb \"+jump:$j\"", "Jump to mark", SHOW_CURSOR},
{{'r'}, "for f; do read -p \"Rename $f: \" renamed && mv \"$f\" \"$renamed\"; done; "
"bb '+d:*' +r",
"Rename files", SHOW_CURSOR},
{{'R'}, "read -p 'Rename pattern: ' patt && "
"for f; do mv -i \"$f\" \"`echo \"$f\" | sed \"$patt\"`\"; done &&" PAUSE,
"Regex rename files", SHOW_CURSOR},
// TODO debug:
{{'P'}, "read -p 'Select pattern: ' patt && "
"for f; do echo \"$f\" | grep \"$patt\" >/dev/null 2>/dev/null && bb \"+sel:$f\"; done",
"Regex select files"},
{{'J'}, "bb '+spread:+1'", "Spread selection down"},
{{'K'}, "bb '+spread:-1'", "Spread selection up"},
{{'s'}, "read -n1 -p 'Sort \033[1m(a)\033[22mlphabetic "
"\033[1m(s)\033[22mize \033[1m(m)\033[22modification \033[1m(c)\033[22mcreation "
"\033[1m(a)\033[22maccess \033[1m(r)\033[22mandom \033[1m(p)\033[22mermissions:\033[0m ' sort "
"&& bb \"+sort:$sort\"", "Sort by..."},
{{'#'}, "read -p 'Set columns: ' cols && bb \"+cols:$cols\"", "Set columns"},
{{'.'}, "bb +dots", "Toggle dotfiles"},
{{'g', KEY_HOME}, "bb +m:0", "Go to first file"},
{{'G', KEY_END}, "bb +m:100%n", "Go to last file"},
{{KEY_ESC}, "bb '+d:*'", "Clear selection"},
{{KEY_F5, KEY_CTRL_R}, "bb +r", "Refresh"},
{{KEY_CTRL_A}, "bb '+select:*'", "Select all files in current folder"},
{{KEY_PGDN}, "bb '+scroll:+100%'", "Page down"},
{{KEY_PGUP}, "bb '+scroll:-100%'", "Page up"},
{{KEY_CTRL_D}, "bb '+scroll:+50%'", "Half page down"},
{{KEY_CTRL_U}, "bb '+scroll:-50%'", "Half page up"},
{{KEY_MOUSE_WHEEL_DOWN}, "bb '+scroll:+3'", "Scroll down"},
{{KEY_MOUSE_WHEEL_UP}, "bb '+scroll:-3'", "Scroll up"},
{0}, // Array must be 0-terminated
};
|