Updated docs and added some refresh consistency
This commit is contained in:
parent
7c3a23bbee
commit
f3b052d47c
10
README.md
10
README.md
@ -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
40
bb.c
@ -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);
|
||||
|
82
config.def.h
82
config.def.h
@ -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
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user