aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bb.c248
-rw-r--r--config.def.h31
2 files changed, 138 insertions, 141 deletions
diff --git a/bb.c b/bb.c
index b6ba926..b2490c1 100644
--- a/bb.c
+++ b/bb.c
@@ -100,7 +100,7 @@ typedef struct bb_s {
char path[PATH_MAX];
int nfiles;
int scroll, cursor;
- options_t options, initialopts;
+ options_t options;
char *marks[128]; // Mapping from key to directory
} bb_t;
@@ -377,7 +377,7 @@ void render(bb_t *bb, int lazy)
fputs("│\033[K", tty_out);
x += 1;
}
- int k = bb->options.aligns[col] == 'l' ? 0 : (bb->options.aligns[col] == 'r' ? 2 : 1);
+ int k = bb->options.aligns[col] == 'c' ? 1 : (bb->options.aligns[col] == 'r' ? 2 : 0);
const char *indicator = " ";
char *found;
if ((found = strchr(bb->options.sort, bb->options.columns[col])))
@@ -437,7 +437,7 @@ void render(bb_t *bb, int lazy)
fputs(color, tty_out);
x += 1;
}
- int k = bb->options.aligns[col] == 'l' ? 0 : (bb->options.aligns[col] == 'r' ? 2 : 1);
+ int k = bb->options.aligns[col] == 'c' ? 1 : (bb->options.aligns[col] == 'r' ? 2 : 0);
switch (bb->options.columns[col]) {
case '*':
move_cursor(tty_out, x + MAX(0, (k*(bb->options.colwidths[col] - colselw))/2), y);
@@ -875,104 +875,61 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd)
{
char *value = strchr(cmd, ':');
if (value) ++value;
+#define set_bool(target) do { if (!value || value[0] == '~') { target = !target; } else { target = value[0] == '1'; } } while (0)
switch (cmd[0]) {
- case 'r': { // +refresh
+ case '.': { // +..:, +.:
+ if (cmd[1] == '.') // +..:
+ set_bool(bb->options.show_dotdot);
+ else // +.:
+ set_bool(bb->options.show_dot);
populate_files(bb, bb->path);
return BB_REFRESH;
}
- case 'q': // +quit
- return BB_QUIT;
- case 's': // +select:, +scroll:, +spread:
+ case 'a': { // +align:
+ if (!value) return BB_INVALID;
+ strncpy(bb->options.aligns, value, MAX_COLS);
+ return BB_REFRESH;
+ }
+ case 'c': { // +cd:, +columns:
switch (cmd[1]) {
- case 'c': { // scroll:
+ case 'd': { // +cd:
+ char pbuf[PATH_MAX];
+ cd:
if (!value) return BB_INVALID;
- // TODO: figure out the best version of this
- int isdelta = value[0] == '+' || value[0] == '-';
- int n = (int)strtol(value, &value, 10);
- if (*value == '%')
- n = (n * (value[1] == 'n' ? bb->nfiles : termheight)) / 100;
- if (isdelta)
- set_scroll(bb, bb->scroll + n);
- else
- set_scroll(bb, n);
- return BB_NOP;
- }
-
- case 'p': // +spread:
- goto move;
-
- case '\0': case 'e': // +select:
- if (!value) value = bb->files[bb->cursor]->name;
- if (strcmp(value, "*") == 0) {
- for (int i = 0; i < bb->nfiles; i++)
- select_file(bb, bb->files[i]);
- } else {
- int f = find_file(bb, value);
- if (f >= 0) select_file(bb, bb->files[f]);
- // TODO: support selecting files in other directories
+ if (value[0] == '~') {
+ char *home;
+ if (!(home = getenv("HOME")))
+ return BB_INVALID;
+ strcpy(pbuf, home);
+ strcat(pbuf, value+1);
+ value = pbuf;
+ }
+ char *rpbuf = realpath(value, NULL);
+ if (!rpbuf) return BB_INVALID;
+ if (strcmp(rpbuf, bb->path) == 0) {
+ free(rpbuf);
+ return BB_NOP;
+ }
+ if (chdir(rpbuf)) {
+ free(rpbuf);
+ return BB_INVALID;
}
+ char *oldpath = memcheck(strdup(bb->path));
+ populate_files(bb, rpbuf);
+ free(rpbuf);
+ if (strcmp(value, "..") == 0) {
+ int f = find_file(bb, oldpath);
+ if (f >= 0) set_cursor(bb, f);
+ }
+ free(oldpath);
return BB_REFRESH;
- }
- case 'c': { // +cd:
- char pbuf[PATH_MAX];
- cd:
- if (!value) return BB_INVALID;
- if (value[0] == '~') {
- char *home;
- if (!(home = getenv("HOME")))
- return BB_INVALID;
- strcpy(pbuf, home);
- strcat(pbuf, value+1);
- value = pbuf;
- }
- char *rpbuf = realpath(value, NULL);
- if (!rpbuf) return BB_INVALID;
- if (strcmp(rpbuf, bb->path) == 0) {
- free(rpbuf);
- return BB_NOP;
- }
- if (chdir(rpbuf)) {
- free(rpbuf);
- return BB_INVALID;
- }
- char *oldpath = memcheck(strdup(bb->path));
- populate_files(bb, rpbuf);
- free(rpbuf);
- if (strcmp(value, "..") == 0) {
- int f = find_file(bb, oldpath);
- if (f >= 0) set_cursor(bb, f);
- }
- free(oldpath);
- return BB_REFRESH;
- }
- case 't': { // +toggle:
- if (!value) value = bb->files[bb->cursor]->name;
- int f = find_file(bb, value);
- if (f < 0) return BB_INVALID;
- toggle_file(bb, bb->files[f]);
- return f == bb->cursor ? BB_NOP : BB_REFRESH;
- }
- case 'o': { // +options:
- if (!value) return BB_INVALID;
- char *cmdscratch = memcheck(strdup(value));
- char *v, *nextv = cmdscratch;
- while ((v = strsep(&nextv, " ")) != NULL) {
- if (!*v) continue;
- char *k;
- if ((k = strsep(&v, "=")) == NULL)
- v = "1";
-#define matches(s) (strncmp(k, (s), strlen(k)) == 0)
- if (matches("..")) {
- bb->options.show_dotdot = v[0] == '1';
- } else if (matches(".*")) {
- bb->options.show_dotfiles = v[0] == '1';
- } else if (matches(".")) {
- bb->options.show_dot = v[0] == '1';
- } else if (matches("columns") || matches("cols")) {
- strncpy(bb->options.columns, v, MAX_COLS);
- for (int i = 0; i < v[i] && i < MAX_COLS; i++) {
+ }
+ case 'o': { // +columns:
+ if (!value) return BB_INVALID;
+ strncpy(bb->options.columns, value, MAX_COLS);
+ for (int i = 0; i < value[i] && i < MAX_COLS; i++) {
int *colw = &bb->options.colwidths[i];
- switch (v[i]) {
+ switch (value[i]) {
case 'c': case 'm': case 'a': *colw = coldatew; break;
case 's': *colw = colsizew; break;
case 'p': *colw = colpermw; break;
@@ -982,30 +939,32 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd)
case '/': *colw = coldirw; break;
}
}
- } else if (matches("sort")) {
- set_sort(bb, v);
- } else if (matches("aligns")) {
- strncpy(bb->options.aligns, v, MAX_COLS);
- } else {
+ return BB_REFRESH;
}
-#undef matches
}
- free(cmdscratch);
- populate_files(bb, bb->path);
- return BB_REFRESH;
+ return BB_INVALID;
}
- case 'd': // +deselect:
- if (!value) value = bb->files[bb->cursor]->name;
- if (strcmp(value, "*") == 0) {
- clear_selection(bb);
- return BB_REFRESH;
- } else {
- int f = find_file(bb, value);
- if (f < 0) return BB_INVALID;
- select_file(bb, bb->files[f]);
- return f == bb->cursor ? BB_NOP : BB_REFRESH;
+ case 'd': { // +deselect:, +dotfiles:
+ switch (cmd[1]) {
+ case 'e': { // +deselect:
+ if (!value) value = bb->files[bb->cursor]->name;
+ if (strcmp(value, "*") == 0) {
+ clear_selection(bb);
+ return BB_REFRESH;
+ } else {
+ int f = find_file(bb, value);
+ if (f < 0) return BB_INVALID;
+ select_file(bb, bb->files[f]);
+ return f == bb->cursor ? BB_NOP : BB_REFRESH;
+ }
+ }
+ case 'o': { // +dotfiles:
+ set_bool(bb->options.show_dotfiles);
+ populate_files(bb, bb->path);
+ return BB_REFRESH;
+ }
}
-
+ }
case 'g': { // +goto:
if (!value) return BB_INVALID;
int f = find_file(bb, value);
@@ -1027,6 +986,15 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd)
}
return BB_REFRESH;
}
+ case 'j': { // +jump:
+ if (!value) return BB_INVALID;
+ char key = value[0];
+ if (bb->marks[(int)key]) {
+ value = bb->marks[(int)key];
+ goto cd;
+ }
+ return BB_INVALID;
+ }
case 'm': { // +move:, +mark:
switch (cmd[1]) {
case 'a': { // +mark:
@@ -1065,14 +1033,55 @@ bb_result_t execute_cmd(bb_t *bb, const char *cmd)
}
}
}
- case 'j': { // +jump:
- if (!value) return BB_INVALID;
- char key = value[0];
- if (bb->marks[(int)key]) {
- value = bb->marks[(int)key];
- goto cd;
+ case 'q': // +quit
+ return BB_QUIT;
+ case 'r': { // +refresh
+ populate_files(bb, bb->path);
+ return BB_REFRESH;
+ }
+ case 's': // +scroll:, +select:, +sort:, +spread:
+ switch (cmd[1]) {
+ case 'c': { // scroll:
+ if (!value) return BB_INVALID;
+ // TODO: figure out the best version of this
+ int isdelta = value[0] == '+' || value[0] == '-';
+ int n = (int)strtol(value, &value, 10);
+ if (*value == '%')
+ n = (n * (value[1] == 'n' ? bb->nfiles : termheight)) / 100;
+ if (isdelta)
+ set_scroll(bb, bb->scroll + n);
+ else
+ set_scroll(bb, n);
+ return BB_NOP;
+ }
+
+ case '\0': case 'e': // +select:
+ if (!value) value = bb->files[bb->cursor]->name;
+ if (strcmp(value, "*") == 0) {
+ for (int i = 0; i < bb->nfiles; i++)
+ select_file(bb, bb->files[i]);
+ } else {
+ int f = find_file(bb, value);
+ if (f >= 0) select_file(bb, bb->files[f]);
+ // TODO: support selecting files in other directories
+ }
+ return BB_REFRESH;
+
+ case 'o': // +sort:
+ if (!value) return BB_INVALID;
+ set_sort(bb, value);
+ qsort_r(bb->files, (size_t)bb->nfiles, sizeof(entry_t*), bb, compare_files);
+ return BB_REFRESH;
+
+ case 'p': // +spread:
+ goto move;
}
- return BB_INVALID;
+ case 't': { // +toggle:
+ if (!value) value = bb->files[bb->cursor]->name;
+ int f = find_file(bb, value);
+ if (f < 0) return BB_INVALID;
+ toggle_file(bb, bb->files[f]);
+ return f == bb->cursor ? BB_NOP : BB_REFRESH;
}
default: err("UNKNOWN COMMAND: '%s'", cmd); break;
}
@@ -1105,7 +1114,6 @@ void bb_browse(bb_t *bb, const char *path)
check_cmds = 1;
}
}
- memcpy(&bb->initialopts, &bb->options, sizeof(bb->initialopts));
init_term();
fputs(T_ON(T_ALT_SCREEN), tty_out);
diff --git a/config.def.h b/config.def.h
index a3f077c..796141a 100644
--- a/config.def.h
+++ b/config.def.h
@@ -21,34 +21,25 @@
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):
+ .:(0|1|~) Whether to show "." in each directory
+ ..:(0|1|~) Whether to show ".." in each directory
+ align:<col-aligns> Direction of column text alignment ('r' for right, 'c' for center, and 'l' for left)
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
+ dotfiles:(0|1|~) 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
- option:(<k>=<v>)+ Set space-separated options (see below)
quit Quit bb
refresh Refresh the file listing
scroll:<num*> Scroll the view a numeric amount
select:<filename> Select <filename>
+ sort:([+-]method)+ List of sortings (if equal on one, move to the next)
spread:<num*> Spread the selection state at the cursor
toggle:<filename> Toggle the selection status of <filename>
- Currently supported options:
- 'sort': a list of things to sort by.
- '.': dotfiles visibility (bit 1: "..", bit 2: ".", bit 3: .whatever)
- 'i': interleave files and directories (boolean), when false, directories are always at the top
- '0'-'9': what to put in each of the (maximum of 10) columns (one of: [nscmap])
- 'A'-'J': how wide to make each column (A -> column 0, etc.). 0 means
- minimum width, 1+ means divide the free space proportionally among all
- nonzero columns
- The postfix operator '=' assigns an option to the following character
- value, and '%'(+/-)n increments or decrements the value and takes the value
- modulo n, and no postfix operator restores the initial value.
-
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.
@@ -108,7 +99,7 @@ const char *startupcmds[] = {
"+mark:0", "+mark:~=~", "+mark:h=~", "+mark:/=/", "+mark:c=~/.config",
"+mark:l=~/.local",
// Default column and sorting options:
- "+opt:sort=+/+n col=*smpn aligns=ccccl",
+ "+sort:+/+n", "+col:*smpn", "+..",
NULL, // NULL-terminated array
};
@@ -190,15 +181,13 @@ done)/*ENDQUOTE*/, "Regex rename files", AT_CURSOR},
"Regex select files"},
{{'J'}, "+spread:+1", "Spread selection down"},
{{'K'}, "+spread:-1", "Spread selection up"},
- {{'o'}, "bb \"+opts:`bb '?Options: '`\"", "Set bb options"},
+ {{'b'}, "bb \"+`bb '?bb +'`\"", "Run a bb command"},
{{'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 \"+opt:s=$sort\"", "Sort by..."},
- {{'#'}, "cols=`bb '?Set columns: '` && bb '+opt:ABCDEFGHIJ=0' && "
- "bb \"+opt:`echo \"$cols \" | fold -w1 | sed 10q | nl -v0 -s= -w1 | paste -sd '\\0' -`\"",
- "Set columns"},
- {{'.'}, "bb '+opt:.%8' +refresh", "Toggle dotfiles"},
+ "&& bb \"+sort:+$sort\"", "Sort by..."},
+ {{'#'}, "bb \"+col:`bb '?Set columns: '`\"", "Set columns"},
+ {{'.'}, "bb +dotfiles", "Toggle dotfiles"},
{{'g', KEY_HOME}, "+move:0", "Go to first file"},
{{'G', KEY_END}, "+move:100%n", "Go to last file"},
{{KEY_ESC}, "+deselect:*", "Clear selection"},