Replaced marks system with something a little more elegant using

symbolic links in ~/.config/bb/marks/. The new version is a little more
flexible (arbitrary mark names), persistent across bb sessions, and uses
a bit less code.
This commit is contained in:
Bruce Hill 2019-09-12 18:41:15 -07:00
parent 88514eda09
commit e1e34bc6ed
2 changed files with 33 additions and 60 deletions

76
bb.c
View File

@ -101,10 +101,10 @@ typedef struct bb_s {
entry_t **files; entry_t **files;
entry_t *firstselected; entry_t *firstselected;
char path[PATH_MAX]; char path[PATH_MAX];
char prev_path[PATH_MAX];
int nfiles; int nfiles;
int scroll, cursor; int scroll, cursor;
char *marks[128]; // Mapping from key to directory
char sort[MAX_SORT+1]; char sort[MAX_SORT+1];
char columns[MAX_COLS+1]; char columns[MAX_COLS+1];
unsigned int dirty : 1; unsigned int dirty : 1;
@ -856,11 +856,9 @@ int cd_to(bb_t *bb, const char *path)
strcpy(prev, bb->path); strcpy(prev, bb->path);
if (strcmp(path, "<selection>") == 0) { if (strcmp(path, "<selection>") == 0) {
strcpy(pbuf, path); strcpy(pbuf, path);
if (bb->marks['-']) free(bb->marks['-']);
bb->marks['-'] = memcheck(strdup(bb->path));
} else if (strcmp(path, "..") == 0 && strcmp(bb->path, "<selection>") == 0) { } else if (strcmp(path, "..") == 0 && strcmp(bb->path, "<selection>") == 0) {
if (!bb->marks['-']) return -1; if (!bb->prev_path[0]) return -1;
strcpy(pbuf, bb->marks['-']); strcpy(pbuf, bb->prev_path);
if (chdir(pbuf)) return -1; if (chdir(pbuf)) return -1;
} else { } else {
normalize_path(bb->path, path, pbuf, 1); normalize_path(bb->path, path, pbuf, 1);
@ -870,8 +868,8 @@ int cd_to(bb_t *bb, const char *path)
} }
if (strcmp(bb->path, "<selection>") != 0) { if (strcmp(bb->path, "<selection>") != 0) {
if (bb->marks['-']) free(bb->marks['-']); strcpy(bb->prev_path, prev);
bb->marks['-'] = memcheck(strdup(bb->path)); setenv("BBPREVPATH", bb->prev_path, 1);
} }
strcpy(bb->path, pbuf); strcpy(bb->path, pbuf);
@ -1083,52 +1081,24 @@ bb_result_t process_cmd(bb_t *bb, const char *cmd)
sort_files(bb); sort_files(bb);
return BB_OK; return BB_OK;
} }
case 'j': { // +jump: case 'm': { // +move:
int oldcur, isdelta, n;
move:
if (!value) return BB_INVALID; if (!value) return BB_INVALID;
bb->dirty = 1; if (!bb->nfiles) return BB_INVALID;
char key = value[0]; oldcur = bb->cursor;
if (bb->marks[(int)key]) { isdelta = value[0] == '-' || value[0] == '+';
value = bb->marks[(int)key]; n = (int)strtol(value, &value, 10);
if (!value) return BB_INVALID; if (*value == '%')
if (cd_to(bb, value)) return BB_INVALID; n = (n * (value[1] == 'n' ? bb->nfiles : termheight)) / 100;
return BB_OK; if (isdelta) set_cursor(bb, bb->cursor + n);
} else set_cursor(bb, n);
return BB_INVALID; if (cmd[0] == 's') { // +spread:
} int sel = IS_SELECTED(bb->files[oldcur]);
case 'm': { // +move:, +mark: for (int i = bb->cursor; i != oldcur; i += (oldcur > i ? 1 : -1))
switch (cmd[1]) { set_selected(bb, bb->files[i], sel);
case 'a': { // +mark:
if (!value) return BB_INVALID;
char key = value[0];
if (key < 0) return BB_INVALID;
value = strchr(value, '=');
if (!value) value = bb->path;
else ++value;
if (bb->marks[(int)key])
free(bb->marks[(int)key]);
bb->marks[(int)key] = memcheck(strdup(value));
return BB_OK;
}
default: { // +move:
int oldcur, isdelta, n;
move:
if (!value) return BB_INVALID;
if (!bb->nfiles) return BB_INVALID;
oldcur = bb->cursor;
isdelta = value[0] == '-' || value[0] == '+';
n = (int)strtol(value, &value, 10);
if (*value == '%')
n = (n * (value[1] == 'n' ? bb->nfiles : termheight)) / 100;
if (isdelta) set_cursor(bb, bb->cursor + n);
else set_cursor(bb, n);
if (cmd[0] == 's') { // +spread:
int sel = IS_SELECTED(bb->files[oldcur]);
for (int i = bb->cursor; i != oldcur; i += (oldcur > i ? 1 : -1))
set_selected(bb, bb->files[i], sel);
}
return BB_OK;
}
} }
return BB_OK;
} }
case 'q': // +quit case 'q': // +quit
bb->should_quit = 1; bb->should_quit = 1;
@ -1189,7 +1159,6 @@ void bb_browse(bb_t *bb, const char *path)
int lastwidth = termwidth, lastheight = termheight; int lastwidth = termwidth, lastheight = termheight;
int check_cmds = 1; int check_cmds = 1;
bb->marks['-'] = memcheck(strdup(path));
cd_to(bb, path); cd_to(bb, path);
bb->scroll = 0; bb->scroll = 0;
bb->cursor = 0; bb->cursor = 0;
@ -1505,6 +1474,7 @@ int main(int argc, char *argv[])
strcat(curdir, "/"); strcat(curdir, "/");
normalize_path(curdir, initial_path, path, 1); normalize_path(curdir, initial_path, path, 1);
if (chdir(path)) err("Not a valid path: %s\n", path); if (chdir(path)) err("Not a valid path: %s\n", path);
setenv("BBINITIALPATH", path, 1);
bb_t *bb = memcheck(calloc(1, sizeof(bb_t))); bb_t *bb = memcheck(calloc(1, sizeof(bb_t)));
bb->columns[0] = COL_NAME; bb->columns[0] = COL_NAME;
@ -1539,8 +1509,6 @@ int main(int argc, char *argv[])
try_free_entry(e); try_free_entry(e);
} }
bb->firstselected = NULL; bb->firstselected = NULL;
for (int m = 0; m < 128; m++)
if (bb->marks[m]) free(bb->marks[m]);
free(bb); free(bb);
if (cmdfilename) free(cmdfilename); if (cmdfilename) free(cmdfilename);

View File

@ -34,8 +34,6 @@
dotfiles:[01] Whether dotfiles are visible dotfiles:[01] Whether dotfiles are visible
goto:<filename> Move the cursor to <filename> (changing directory if needed) goto:<filename> Move the cursor to <filename> (changing directory if needed)
interleave:[01] Whether or not directories should be interleaved with files in the display interleave:[01] Whether or not directories should be interleaved with files in the display
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 move:<num*> Move the cursor a numeric amount
quit Quit bb quit Quit bb
refresh Refresh the file listing refresh Refresh the file listing
@ -149,8 +147,11 @@ const column_t columns[128] = {
// This is a list of commands that runs when `bb` launches: // This is a list of commands that runs when `bb` launches:
const char *startupcmds[] = { const char *startupcmds[] = {
// Set some default marks: // Set some default marks:
"+mark:0", "+mark:~=~", "+mark:h=~", "+mark:/=/", "+mark:c=~/.config", "mkdir -p ~/.config/bb/marks",
"+mark:l=~/.local", "+mark:s=<selection>", "ln -sfT ~ ~/.config/bb/marks/home",
"ln -sfT / ~/.config/bb/marks/root",
"ln -sfT ~/.config ~/.config/bb/marks/config",
"ln -sfT ~/.local ~/.config/bb/marks/local",
// Default column and sorting options: // Default column and sorting options:
"+sort:+n", "+col:*smpn", "+..", "+sort:+n", "+col:*smpn", "+..",
NULL, // NULL-terminated array NULL, // NULL-terminated array
@ -207,8 +208,12 @@ binding_t bindings[] = {
{{':'}, "sh -c \"$(" ASKECHO(":", "") ")\" -- \"$@\"; " PAUSE "; bb +refresh", {{':'}, "sh -c \"$(" ASKECHO(":", "") ")\" -- \"$@\"; " PAUSE "; bb +refresh",
B("Run")" a command"}, B("Run")" a command"},
{{'>'}, "tput rmcup >/dev/tty; $SHELL; bb +r", "Open a "B("shell")}, {{'>'}, "tput rmcup >/dev/tty; $SHELL; bb +r", "Open a "B("shell")},
{{'m'}, "read -n1 -p 'Mark: ' m && bb \"+mark:$m;$PWD\"", "Set "B("mark")}, {{'\''}, "bb +cd:\"$(readlink -f ~/.config/bb/marks/\"$(ls ~/.config/bb/marks | " PICK("Jump to: ", "") ")\")\"",
{{'\''}, "read -n1 -p 'Jump: ' j && bb \"+jump:$j\"", B("Jump")" to mark"}, B("Jump")" to a directory"},
{{'-'}, "test $BBPREVPATH && bb +cd:\"$BBPREVPATH\"", "Go to "B("previous")" directory"},
{{';'}, "bb +cd:'<selection>'", "Go to "B("previous")" directory"},
{{'0'}, "bb +cd:\"$BBINITIALPATH\"", "Go to "B("initial")" directory"},
{{'m'}, "ln -s \"$PWD\" ~/.config/bb/marks/\"$("ASKECHO("Mark: ", "")")\"", B("Mark")" this directory"},
{{'r'}, {{'r'},
"bb +refresh; " "bb +refresh; "
"for f; do " "for f; do "