Updated docs and added some refresh consistency

This commit is contained in:
Bruce Hill 2019-05-25 21:47:30 -07:00
parent 7c3a23bbee
commit f3b052d47c
3 changed files with 101 additions and 31 deletions

View File

@ -2,7 +2,7 @@
`bb` (bitty browser) is a TUI console file browser that is:
- Extremely lightweight (currently around 1.4K lines of code)
- Extremely lightweight (under 2k lines of code)
- Highly interoperable with unix pipelines
- Highly customizable and hackable
- Without any build dependencies other than the C standard library (no ncurses)
@ -25,6 +25,12 @@ some complicated one-time task, you can just hit `>` to drop to a shell and run
commands with the selected files available in `$@` (or use `|` to run a quick
one-liner command that gets the selected files piped as input).
## API
`bb` also exposes an API so that programs can modify `bb`'s internal state.
For example, by default, `f` is bound to `bb "+goto:$(fzf)"`, which has the
effect of moving `bb`'s cursor to whatever `fzf` (a fuzzy finder) prints out.
More details about the API can be found in [the config file](config.def.h).
## Zero Dependencies
There's a lot of TUI libraries out there like ncurses and termbox, but
@ -47,7 +53,7 @@ libraries as long as you're willing to hand-write a few escape sequences.
Just run `bb` to launch the file browser. Press `?` for a full list of
available key bindings. In short: `h`/`j`/`k`/`l` or arrow keys for navigation,
`q` to quit, <space> to toggle selection, `d` to delete, `c` to copy, `m` to
`q` to quit, `<space>` to toggle selection, `d` to delete, `c` to copy, `M` to
move, `r` to rename, `n` to create a new file, `N` to create a new directory,
and `|` to pipe files to a command.

40
bb.c
View File

@ -537,8 +537,11 @@ int compare_files(void *r, const void *v1, const void *v2)
if ('0' <= c1 && c1 <= '9' && '0' <= c2 && c2 <= '9') {
long n1 = strtol(p1, (char**)&p1, 10);
long n2 = strtol(p2, (char**)&p2, 10);
diff = ((p1 - f1->d_name) - (p2 - f2->d_name)) || (n1 - n2);
if (diff) return diff*sign;
diff = (int)(p1 - f1->d_name) - (int)(p2 - f2->d_name);
if (diff != 0)
return diff*sign;
if (n1 != n2)
return (n1 > n2 ? 1 : -1)*sign;
} else if (diff) {
return diff*sign;
} else {
@ -682,16 +685,17 @@ void populate_files(bb_state_t *s, const char *path)
free(s->files);
s->files = NULL;
}
int old_cursor = s->cursor;
int old_scroll = s->scroll;
s->nfiles = 0;
s->cursor = 0;
if (path == NULL)
return;
if (strcmp(path, s->path) != 0) {
s->scroll = 0;
int samedir = strcmp(path, s->path) == 0;
if (!samedir)
strcpy(s->path, path);
}
// Hash inode -> entry_t with linear probing
int nselected = 0;
@ -776,15 +780,22 @@ void populate_files(bb_state_t *s, const char *path)
free(selecthash);
if (s->nfiles == 0) err("No files found (not even '..')");
if (old_inode) {
for (int i = 0; i < s->nfiles; i++) {
if (s->files[i]->d_ino == old_inode) {
set_cursor(s, i);
break;
sort_files(s);
if (samedir) {
if (old_inode) {
for (int i = 0; i < s->nfiles; i++) {
if (s->files[i]->d_ino == old_inode) {
set_scroll(s, old_scroll);
set_cursor(s, i);
return;
}
}
}
set_cursor(s, old_cursor);
set_scroll(s, old_scroll);
} else {
set_cursor(s, 0);
}
sort_files(s);
}
void sort_files(bb_state_t *state)
@ -825,9 +836,10 @@ execute_cmd(bb_state_t *state, const char *cmd)
char *value = strchr(cmd, ':');
if (value) ++value;
switch (cmd[0]) {
case 'r': // refresh
case 'r': { // refresh
populate_files(state, state->path);
return BB_REFRESH;
}
case 'q': // quit
return BB_QUIT;
case 's': // sort:, select:, scroll:, spread:
@ -1323,6 +1335,7 @@ int main(int argc, char *argv[])
FILE *cmdfile = NULL;
if (initial_path) {
has_initial_path:
cmdfilename = memcheck(strdup(CMDFILE_FORMAT));
if (!mktemp(cmdfilename)) err("Couldn't create tmpfile\n");
cmdfile = fopen(cmdfilename, "a");
@ -1337,7 +1350,8 @@ int main(int argc, char *argv[])
} else if (cmd_args > 0) {
char *parent_bbcmd = getenv("BBCMD");
if (!parent_bbcmd || parent_bbcmd[0] == '\0') {
err("Couldn't find command file\n");
initial_path = ".";
goto has_initial_path;
}
cmdfile = fopen(parent_bbcmd, "a");
if (!cmdfile) err("Couldn't open cmdfile: '%s'\n", parent_bbcmd);

View File

@ -1,5 +1,54 @@
/*
* User-defined key bindings.
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"
@ -18,28 +67,29 @@ typedef struct {
int flags;
} binding_t;
// These commands will run at startup (before command-line arguments)
extern const char *startupcmds[];
const char *startupcmds[] = {
"+mark:0",
"+mark:~;~",
"+mark:h;~",
"+mark:/;/",
"+mark:c;~/.config",
//////////////////////////////////////////////
// User-defined startup commands can go here
//////////////////////////////////////////////
// Set some default marks:
"+mark:0", "+mark:~;~", "+mark:h;~", "+mark:/;/", "+mark:c;~/.config",
"+mark:l;~/.local",
"+columns:smpn",
"+sort:n",
NULL,
// Default column and sorting options:
"+columns:smpn", "+sort:n",
NULL, // NULL-terminated array
};
extern binding_t bindings[];
binding_t bindings[] = {
////////////////////////////////////////////////////////////////////////
// User-defined custom scripts go here
//////////////////////////////////////////////////////////////////////////
// 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}, "", "Figure out what key does"},
{{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"},
@ -70,8 +120,8 @@ else xdg-open \"$BBCURSOR\"; fi",
{{'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", "New file", SHOW_CURSOR},
{{'N'}, "read -p 'New dir: ' name && mkdir \"$name\"; bb +r", "New folder", SHOW_CURSOR},
{{'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",
@ -108,5 +158,5 @@ else xdg-open \"$BBCURSOR\"; fi",
{{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},
{0}, // Array must be 0-terminated
};