Simplified the make flags for fuzzy finding and asking. Cleaned up the
readme a bit.
This commit is contained in:
parent
15e5de72f7
commit
792a39500c
17
Makefile
17
Makefile
@ -4,7 +4,6 @@ CC=gcc
|
||||
CFLAGS=-O0 -std=gnu99 -D_XOPEN_SOURCE=500 -D_GNU_SOURCE -D_POSIX_C_SOURCE=200809L
|
||||
CWARN= -Wall -Wpedantic -Wno-unknown-pragmas -fsanitize=address -fno-omit-frame-pointer
|
||||
G=-g
|
||||
PICKER=
|
||||
|
||||
ifeq ($(shell uname),Darwin)
|
||||
CFLAGS += -D_DARWIN_C_SOURCE
|
||||
@ -12,20 +11,20 @@ CWARN += -Weverything -Wno-missing-field-initializers -Wno-padded\
|
||||
-Wno-missing-noreturn -Wno-cast-qual
|
||||
endif
|
||||
|
||||
ifneq (, $(shell which ask))
|
||||
ifeq (, $(ASKECHO)$(ASK))
|
||||
CFLAGS += -D'ASKECHO(prompt,initial)="ask --prompt=\"" prompt "\" --query=\"" initial "\""'
|
||||
ifeq ($(PICKER),fzy)
|
||||
CFLAGS += -D'PICK(prompt, initial)=" { printf \"\\033[3A\" >/dev/tty; fzy --lines=3 --prompt=\"" prompt "\" --query=\"" initial "\"; } "'
|
||||
endif
|
||||
ifeq (, $(PICKER))
|
||||
PICKER=ask
|
||||
ifeq ($(PICKER),fzf)
|
||||
CFLAGS += -D'PICK(prompt, initial)=" { printf \"\\033[3A\" >/dev/tty; fzf --height=4 --prompt=\"" prompt "\" --query=\"" initial "\"; } "'
|
||||
endif
|
||||
ifeq ($(PICKER),ask)
|
||||
CFLAGS += -D'PICK(prompt, initial)=" ask --prompt=\"" prompt "\" --query=\"" initial "\" "'
|
||||
endif
|
||||
|
||||
ifneq (, $(PICKER))
|
||||
CFLAGS += -D'PICK(prompt, initial)="$(PICKER) --prompt=\"" prompt "\" --query=\"" initial "\""'
|
||||
ifneq (, $(USE_ASK))
|
||||
CFLAGS += -D'USE_ASK=1'
|
||||
endif
|
||||
|
||||
|
||||
all: $(NAME)
|
||||
|
||||
clean:
|
||||
|
99
README.md
99
README.md
@ -30,7 +30,47 @@ create a new file, `N` to create a new directory, `:` to run a command with the
|
||||
selected files in `$@`, and `|` to pipe files to a command. Pressing `Ctrl-c`
|
||||
will cause `bb` to exit with a failure status and without printing anything.
|
||||
|
||||
## Using bb to Change Directory
|
||||
# bb's Philosophy
|
||||
The core idea behind `bb` is that `bb` is a file **browser**, not a file
|
||||
**manager**, which means `bb` uses shell scripts to perform all modifications
|
||||
to the filesystem (passing selected files as arguments), rather than
|
||||
reinventing the wheel by hard-coding operations like `rm`, `mv`, `cp`, `touch`,
|
||||
and so on. Shell scripts can be bound to keypresses in config.h (the user's
|
||||
version of [the defaults in config.def.h](config.def.h)). For example, `D` is
|
||||
bound to `rm -rf "$@"`, which means selecting `file_foo` and `dir_baz`, then
|
||||
pressing `D` will cause `bb` to run the shell command `rm -rf file_foo dir_baz`.
|
||||
|
||||
## Customizing bb
|
||||
`bb` comes with a bunch of pre-defined bindings for basic actions in
|
||||
[config.def.h](config.def.h) (within `bb`, press `?` to see descriptions of the
|
||||
bindings), but it's very easy to add new bindings for whatever custom scripts
|
||||
you want to run, just add a new entry in `bindings` in config.h with the form
|
||||
`{{keys...}, "<shell command>", "<description>"}` The description is shown when
|
||||
pressing `?` within `bb`.
|
||||
|
||||
### User Input in Scripts
|
||||
If you need user input in a binding, you can use the `ASK(var, prompt,
|
||||
initial)` and `ASKECHO(prompt, initial)` macros, which internally use the
|
||||
`read` shell function (`initial` is discarded) or the `ask` tool, if `USE_ASK`
|
||||
is set to 1. This is used in a few key bindings by default, including `n` and
|
||||
`:`.
|
||||
|
||||
### Fuzzy Finding
|
||||
To select from a list of options with a fuzzy finder in a binding, you can use
|
||||
the `PICK` macro. During the `make` process, you can use `PICKER=fzy`,
|
||||
`PICKER=fzf`, or `PICKER=ask` to choose which fuzzy finder program `bb` will
|
||||
use (and provide some default arguments). This is used in the `/` and `Ctrl-f`
|
||||
key bindings by default.
|
||||
|
||||
### API
|
||||
`bb` also exposes an API that allows shell scripts to modify `bb`'s internal
|
||||
state. To do this, call `bb +<your command>` from within `bb`. For example, by
|
||||
default, `j` is bound to `bb '+move:+1'`, which has the effect of moving `bb`'s
|
||||
cursor down one item. More details about the API can be found in [the config
|
||||
file](config.def.h).
|
||||
|
||||
## FAQ
|
||||
### Using bb to Change Directory
|
||||
Applications cannot change the shell's working directory on their own, but you
|
||||
can define a shell function that uses the shell's builtin `cd` function on the
|
||||
output of `bb -d` (print directory on exit). For bash (sh, zsh, etc.), you can
|
||||
@ -47,7 +87,7 @@ For [fish](https://fishshell.com/) (v3.0.0+), you can put this in your
|
||||
In both versions, `|| pwd` means the directory will not change if `bb` exits
|
||||
with failure (e.g. by pressing `Ctrl-c`).
|
||||
|
||||
## Launching bb with a Keyboard Shortcut
|
||||
### Launching bb with a Keyboard Shortcut
|
||||
Using a keyboard shortcut to launch `bb` from the shell is something that is
|
||||
handled by your shell. Here are some examples for binding `Ctrl-b` to launch
|
||||
`bb` and change directory to `bb`'s directory (using the `bcd` function defined
|
||||
@ -59,58 +99,5 @@ For fish, put this in your `~/.config/fish/functions/fish_user_key_bindings.fish
|
||||
|
||||
bind \cB 'bcd; commandline -f repaint'
|
||||
|
||||
# bb's Philosophy
|
||||
The core idea behind `bb` is that `bb` is a file **browser**, not a file
|
||||
**manager**, which means `bb` uses shell scripts to perform all modifications
|
||||
to the filesystem (passing selected files as arguments), rather than
|
||||
reinventing the wheel by hard-coding operations like `rm`, `mv`, `cp`, `touch`,
|
||||
and so on. Shell scripts can be bound to keypresses in config.h (the user's
|
||||
version of [the defaults in config.def.h](config.def.h)). For example, `D` is
|
||||
bound to `rm -rf "$@"`, which means selecting `file_foo` and `dir_baz`, then
|
||||
pressing `D` will cause `bb` to run the shell command `rm -rf file_foo dir_baz`.
|
||||
|
||||
`bb` comes with a bunch of pre-defined bindings for basic actions in
|
||||
[config.def.h](config.def.h) (within `bb`, press `?` to see descriptions of the
|
||||
bindings), but it's very easy to add new bindings for whatever custom scripts
|
||||
you want to run, just add a new entry in `bindings` in config.h with the form
|
||||
`{{keys...}, "<shell command>", "<description>"}` The description is shown when
|
||||
pressing `?` within `bb`.
|
||||
|
||||
## User Input in Scripts
|
||||
If you need user input in a script, you can just use the `read` shell function
|
||||
like so: `read -p "Archive: " name && zip "$name" "$@"` However, `read` doesn't
|
||||
support a lot of functionality (e.g. using the arrow keys), so I would recommnd
|
||||
using [ask](https://bitbucket.org/spilt/ask) instead. If you have `ask`
|
||||
isntalled, making `bb` will automatically detect it and the default key
|
||||
bindings will use it instead of `read`.
|
||||
|
||||
## 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
|
||||
essentially all they do is write ANSI escape sequences to the terminal. `bb`
|
||||
does all of that by itself, just using basic calls to `write()`, with no
|
||||
external libraries beyond the C standard library. Since `bb` only has to
|
||||
support the terminal functionality that it uses itself, `bb`'s entire source
|
||||
code is less than half the size of the source code for an extremely compact
|
||||
library like termbox, and less than *half a percent* of the size of the source
|
||||
code for ncurses. I hope anyone checking out this project can see it as a great
|
||||
example of how you can build a full TUI without ncurses or any external
|
||||
libraries as long as you're willing to hand-write a few escape sequences.
|
||||
|
||||
|
||||
## Hacking
|
||||
|
||||
If you want to customize `bb`, you can add or change the key bindings by
|
||||
editing `config.h` and recompiling. In [suckless](https://suckless.org/) style,
|
||||
customizing means editing source code, and compilation is extremely fast.
|
||||
Key character constants are in `keys.h` and the rest of the code is in `bb.c`.
|
||||
|
||||
## License
|
||||
|
||||
# License
|
||||
`bb` is released under the MIT license. See the `LICENSE` file for full details.
|
||||
|
23
config.def.h
23
config.def.h
@ -100,23 +100,18 @@ typedef struct {
|
||||
#define B(s) "\033[1m" s "\033[22m"
|
||||
|
||||
// Macros for getting user input:
|
||||
#ifndef ASK
|
||||
#ifdef ASKECHO
|
||||
#ifdef USE_ASK
|
||||
#define ASKECHO(prompt, initial) "ask --prompt=\"" prompt "\" --query=\"" initial "\""
|
||||
#define ASK(var, prompt, initial) var "=\"$(" ASKECHO(prompt, initial) ")\""
|
||||
#else
|
||||
#define ASK(var, prompt, initial) "read -p \"" prompt "\" " var " </dev/tty >/dev/tty"
|
||||
#endif
|
||||
#define ASK(var, prompt, initial) "read -ep \"" prompt "\" " var " </dev/tty >/dev/tty"
|
||||
#define ASKECHO(prompt, initial) "read -ep \"" prompt "\" </dev/tty >/dev/tty && echo \"$REPLY\""
|
||||
#endif
|
||||
|
||||
#ifndef ASKECHO
|
||||
#define ASKECHO(prompt, initial) ASK("REPLY", prompt, initial) " && echo \"$REPLY\""
|
||||
#endif
|
||||
|
||||
// Get user input to choose an option (piped in). If you want to use
|
||||
// a fuzzy finder like fzy or fzf, then this should be something like:
|
||||
// "fzy --prompt=\"" prompt "\" --query=\"" initial "\""
|
||||
// Macros for picking from a list of options:
|
||||
#ifndef PICK
|
||||
#define PICK(prompt, initial) "grep -i -m1 \"^$(" ASKECHO(prompt, initial) " | sed 's/./[^&]*[&]/g')\""
|
||||
#define PICK(prompt, initial) " { printf '\\033[A' >/dev/tty; awk '{print length, $1}' | sort -n | cut -d' ' -f2- | "\
|
||||
"grep -i -m1 \"^$(" ASKECHO(prompt, initial) " | sed 's/./[^&]*[&]/g')\"; } "
|
||||
#endif
|
||||
|
||||
// Display a spinning indicator if command takes longer than 10ms:
|
||||
@ -194,7 +189,7 @@ binding_t bindings[] = {
|
||||
{{KEY_ESC}, "+deselect:*", B("Clear")" selection"},
|
||||
{{'e'}, "$EDITOR \"$@\" || "PAUSE, B("Edit")" file in $EDITOR"},
|
||||
{{KEY_CTRL_F}, "bb \"+g:`find | "PICK("Find: ", "")"`\"", B("Search")" for file"},
|
||||
{{'/'}, "bb \"+g:`ls -pa | "PICK("Pick: ", "")"`\"", B("Pick")" file"},
|
||||
{{'/'}, "bb \"+g:`ls -A | "PICK("Pick: ", "")"`\"", B("Pick")" file"},
|
||||
{{'d', KEY_DELETE}, "rm -rfi \"$@\" && bb '+deselect:*' +r ||" PAUSE, B("Delete")" files"},
|
||||
{{'D'}, SPIN("rm -rf \"$@\"")" && bb '+deselect:*' +r ||" PAUSE, B("Delete")" files (without confirmation)"},
|
||||
{{'M'}, SPIN("mv -i \"$@\" .")" && bb '+deselect:*' +r && for f; do bb \"+sel:`pwd`/`basename \"$f\"`\"; done || "PAUSE,
|
||||
@ -245,7 +240,7 @@ binding_t bindings[] = {
|
||||
"&& bb \"+sort:+$sort\" +refresh"),
|
||||
B("Sort")" by..."},
|
||||
{{'#'}, "bb \"+col:`"ASKECHO("Set columns: ", "")"`\"", "Set "B("columns")},
|
||||
{{'.'}, "bb +dotfiles", "Toggle "B("dotfiles")},
|
||||
{{'.'}, "+dotfiles", "Toggle "B("dotfiles")},
|
||||
{{'g', KEY_HOME}, "+move:0", "Go to "B("first")" file"},
|
||||
{{'G', KEY_END}, "+move:100%n", "Go to "B("last")" file"},
|
||||
{{KEY_F5, KEY_CTRL_R}, "+refresh", B("Refresh")},
|
||||
|
Loading…
Reference in New Issue
Block a user