From 88fd9c416be0f5fe1e5fd48ba7c27d4d1e25261c Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 24 Feb 2020 03:39:44 -0800 Subject: Moved bbstartup into a script, renamed helper/ -> scripts/, and added bbshutdown script. Also tweaked some of the precedence. --- Makefile | 4 ++-- bb.1 | 2 +- bb.c | 70 +++++++++++++++++++++++++++++++----------------------- bb.h | 15 +++--------- bbcmd.1 | 2 +- bbstartup.sh | 16 ------------- helpers/bbask | 31 ------------------------ helpers/bbcmd | 11 --------- helpers/bbconfirm | 9 ------- helpers/bbpause | 4 ---- helpers/bbpick | 39 ------------------------------ helpers/bbtargets | 25 ------------------- helpers/bbunscroll | 5 ---- scripts/bbask | 31 ++++++++++++++++++++++++ scripts/bbcmd | 11 +++++++++ scripts/bbconfirm | 9 +++++++ scripts/bbpause | 4 ++++ scripts/bbpick | 39 ++++++++++++++++++++++++++++++ scripts/bbshutdown | 3 +++ scripts/bbstartup | 15 ++++++++++++ scripts/bbtargets | 25 +++++++++++++++++++ scripts/bbunscroll | 5 ++++ 22 files changed, 189 insertions(+), 186 deletions(-) delete mode 100755 bbstartup.sh delete mode 100755 helpers/bbask delete mode 100755 helpers/bbcmd delete mode 100755 helpers/bbconfirm delete mode 100755 helpers/bbpause delete mode 100755 helpers/bbpick delete mode 100755 helpers/bbtargets delete mode 100755 helpers/bbunscroll create mode 100755 scripts/bbask create mode 100755 scripts/bbcmd create mode 100755 scripts/bbconfirm create mode 100755 scripts/bbpause create mode 100755 scripts/bbpick create mode 100755 scripts/bbshutdown create mode 100755 scripts/bbstartup create mode 100755 scripts/bbtargets create mode 100755 scripts/bbunscroll diff --git a/Makefile b/Makefile index 93f5cfb..7eb39b5 100644 --- a/Makefile +++ b/Makefile @@ -24,8 +24,8 @@ install: $(NAME) fi; \ [ ! "$$prefix" ] && prefix="/usr/local"; \ [ ! "$$sysconfdir" ] && sysconfdir=/etc; \ - mkdir -pv -m 755 "$$prefix/share/man/man1" "$$prefix/bin" "$$sysconfdir/xdg/bb" "$$sysconfdir/xdg/bb/helpers" \ - && cp -rv bbstartup.sh bindings.bb helpers "$$sysconfdir/xdg/bb/" \ + mkdir -pv -m 755 "$$prefix/share/man/man1" "$$prefix/bin" "$$sysconfdir/xdg/bb" \ + && cp -rv bindings.bb scripts/* "$$sysconfdir/xdg/bb/" \ && cp -v bb.1 bbcmd.1 "$$prefix/share/man/man1/" \ && rm -f "$$prefix/bin/$(NAME)" \ && cp -v $(NAME) "$$prefix/bin/" diff --git a/bb.1 b/bb.1 index c474fba..3aca4a0 100644 --- a/bb.1 +++ b/bb.1 @@ -1,6 +1,6 @@ .\" Manpage for bb. .\" Contact bruce@bruce-hill.com to correct errors or typos. -.TH man 1 "23 Feb 2020" "0.25" "bb manual page" +.TH man 1 "23 Feb 2020" "0.26" "bb manual page" .SH NAME bb \- A bitty browser for command line file management .SH SYNOPSIS diff --git a/bb.c b/bb.c index adbc8f5..7320f04 100644 --- a/bb.c +++ b/bb.c @@ -23,13 +23,13 @@ void bb_browse(bb_t *bb, const char *initial_path) { if (populate_files(bb, initial_path)) err("Could not find initial path: \"%s\"", initial_path); - run_script(bb, runstartup); + run_script(bb, "bbstartup"); check_cmdfile(bb); - while (!bb->should_quit) { render(bb); handle_next_key_binding(bb); } + run_script(bb, "bbshutdown"); } /* @@ -580,8 +580,7 @@ void run_bbcmd(bb_t *bb, const char *cmd) if (populate_files(bb, value)) warn("Could not open directory: \"%s\"", value); } else if (matches_cmd(cmd, "columns:")) { // +columns: - strncpy(bb->columns, value, MAX_COLS); - dirty = 1; + set_columns(bb, value); } else if (matches_cmd(cmd, "deselect")) { // +deselect while (bb->selected) set_selected(bb, bb->selected, 0); @@ -656,6 +655,7 @@ void run_bbcmd(bb_t *bb, const char *cmd) if (unlink(filename) == -1) err("Couldn't delete temporary help file: '%s'", filename); } else if (matches_cmd(cmd, "interleave:") || matches_cmd(cmd, "interleave")) { // +interleave set_bool(bb->interleave_dirs); + set_interleave(bb, bb->interleave_dirs); sort_files(bb); } else if (matches_cmd(cmd, "move:")) { // +move: int oldcur, isdelta, n; @@ -935,6 +935,15 @@ int run_script(bb_t *bb, const char *cmd) return status; } +/* + * Set the columns displayed by bb. + */ +void set_columns(bb_t *bb, const char *cols) +{ + strncpy(bb->columns, cols, MAX_COLS); + setenv("BBCOLUMNS", bb->columns, 1); +} + /* * Set bb's file cursor to the given index (and adjust the scroll as necessary) */ @@ -964,6 +973,28 @@ void set_cursor(bb_t *bb, int newcur) } } +/* + * Set the glob pattern(s) used by bb. Patterns are ' ' delimited + */ +void set_globs(bb_t *bb, const char *globs) +{ + free(bb->globpats); + bb->globpats = memcheck(strdup(globs)); + setenv("BBGLOB", bb->globpats, 1); +} + + +/* + * Set whether or not bb should interleave directories and files. + */ +void set_interleave(bb_t *bb, int interleave) +{ + bb->interleave_dirs = interleave; + if (interleave) setenv("BBINTERLEAVE", "interleave", 1); + else unsetenv("BBINTERLEAVE"); + dirty = 1; +} + /* * Set bb's scroll to the given index (and adjust the cursor as necessary) */ @@ -984,17 +1015,6 @@ void set_scroll(bb_t *bb, int newscroll) if (bb->cursor < 0) bb->cursor = 0; } - -/* - * Set the glob pattern(s) used by bb. Patterns are ' ' delimited - */ -void set_globs(bb_t *bb, const char *globs) -{ - free(bb->globpats); - bb->globpats = memcheck(strdup(globs)); - setenv("BBGLOB", bb->globpats, 1); -} - /* * Select or deselect a file. */ @@ -1034,6 +1054,7 @@ void set_sort(bb_t *bb, const char *sort) size_t len = MIN(MAX_SORT, strlen(sort)); memmove(bb->sort + len, bb->sort, MAX_SORT+1 - len); memmove(bb->sort, sortbuf, len); + setenv("BBSORT", bb->sort, 1); } /* @@ -1204,12 +1225,12 @@ int main(int argc, char *argv[]) setenv("BBPATH", bbpath, 1); } if (getenv("BBPATH")) { - if (asprintf(&newpath, "%s/helpers:%s/bb/helpers:%s", - getenv("BBPATH"), getenv("XDG_CONFIG_HOME"), getenv("PATH")) < 0) + if (asprintf(&newpath, "%s/bb:%s/scripts:%s", + getenv("XDG_CONFIG_HOME"), getenv("BBPATH"), getenv("PATH")) < 0) err("Could not allocate memory for PATH"); } else { - if (asprintf(&newpath, "%s/xdg/bb/helpers:%s/bb/helpers:%s", - getenv("sysconfdir"), getenv("XDG_CONFIG_HOME"), getenv("PATH")) < 0) + if (asprintf(&newpath, "%s/bb:%s/xdg/bb:%s", + getenv("XDG_CONFIG_HOME"), getenv("sysconfdir"), getenv("PATH")) < 0) err("Could not allocate memory for PATH"); } setenv("PATH", newpath, 1); @@ -1285,17 +1306,6 @@ int main(int argc, char *argv[]) fflush(stdout); } - { - char path[PATH_MAX + strlen("/bb/state.sh")]; - sprintf(path, "%s/bb/state.sh", xdg_data_home); - FILE *f = fopen(path, "w"); - fprintf(f, "bbcmd glob:'%s'\n", bb.globpats); - fprintf(f, "bbcmd sort:'%s'\n", bb.sort); - fprintf(f, "bbcmd columns:'%s'\n", bb.columns); - if (bb.interleave_dirs) fprintf(f, "bbcmd interleave\n"); - fclose(f); - } - if (print_dir) printf("%s\n", bb.path); diff --git a/bb.h b/bb.h index 479943f..3e1a270 100644 --- a/bb.h +++ b/bb.h @@ -26,7 +26,7 @@ #include "bterm.h" // Macros: -#define BB_VERSION "0.25.0" +#define BB_VERSION "0.26.0" #ifndef PATH_MAX #define PATH_MAX 4096 @@ -203,8 +203,10 @@ static void run_bbcmd(bb_t *bb, const char *cmd); static void render(bb_t *bb); static void restore_term(const struct termios *term); static int run_script(bb_t *bb, const char *cmd); +static void set_columns(bb_t *bb, const char *cols); static void set_cursor(bb_t *bb, int i); static void set_globs(bb_t *bb, const char *globs); +static void set_interleave(bb_t *bb, int interleave); static void set_selected(bb_t *bb, entry_t *e, int selected); static void set_scroll(bb_t *bb, int i); static void set_sort(bb_t *bb, const char *sort); @@ -243,15 +245,4 @@ static const struct termios default_termios = { static const char *description_str = "bb - an itty bitty console TUI file browser\n"; static const char *usage_str = "Usage: bb (-h/--help | -v/--version | -s | -d | -0 | +command)* [[--] directory]\n"; -static const char *runstartup = -"if [ \"$BBPATH\" ]; then\n" -" . \"$BBPATH/bbstartup.sh\"\n" -"else\n" -" for path in \"$XDG_CONFIG_HOME/bb\" \"$sysconfdir/xdg/bb\"; do\n" -" [ -e \"$path/bbstartup.sh\" ] || continue\n" -" . \"$path/bbstartup.sh\"\n" -" break\n" -" done\n" -"fi\n"; - // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1 diff --git a/bbcmd.1 b/bbcmd.1 index 06794de..ed7249b 100644 --- a/bbcmd.1 +++ b/bbcmd.1 @@ -1,6 +1,6 @@ .\" Manpage for bbcmd. .\" Contact bruce@bruce-hill.com to correct errors or typos. -.TH man 1 "23 Feb 2020" "0.25" "bbcmd manual page" +.TH man 1 "23 Feb 2020" "0.26" "bbcmd manual page" .de TPx . TP 4n diff --git a/bbstartup.sh b/bbstartup.sh deleted file mode 100755 index a64394e..0000000 --- a/bbstartup.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -# This file contains the script that is run when bb launches -# See API.md for details on bb's command API. - -[ ! -d "$XDG_DATA_HOME/bb" ] && mkdir -p "$XDG_DATA_HOME/bb" - -# Load key bindings -if [ "$BBPATH" ]; then - cat "$BBPATH/bindings.bb" "$XDG_CONFIG_HOME/bb/bindings.bb" -else - cat "$sysconfdir/xdg/bb/bindings.bb" "$XDG_CONFIG_HOME/bb/bindings.bb" -fi 2>/dev/null | awk '/^#/ {next} /^[^ ]/ {printf "\0bind:"} {print $0} END {printf "\0"}' >> "$BBCMD" - -if [ -e "$XDG_DATA_HOME/bb/state.sh" ]; then - . "$XDG_DATA_HOME/bb/state.sh" -fi diff --git a/helpers/bbask b/helpers/bbask deleted file mode 100755 index ad446ec..0000000 --- a/helpers/bbask +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# A simple user-input asker. Result is output to stdout. -# Usage: ask [-1] [prompt [initial query]] -if [ "$1" = '-1' ]; then - # Get one character of input - tput civis >/dev/tty; - printf '\033[1m%s\033[0m' "$2" >/dev/tty; - stty -icanon -echo >/dev/tty 2>/dev/tty; - if [ "$(uname)" = "Darwin" ]; then - read -n 1 REPLY /dev/tty; - echo $REPLY - else - dd bs=1 count=1 2>/dev/null /dev/tty 2>/dev/tty - tput cvvis >/dev/tty -else - # Get a line of input - if command -v ask >/dev/null; then - ask --history=bb.hist --prompt="$(printf '%s\033[?25h' "$1")" --query="$2" - else - printf "\033[1m%s\033[0m" "$1" >/dev/tty - tput cvvis >/dev/tty - if [ "$(uname)" = "Darwin" ]; then - read -e REPLY /dev/tty - else - read REPLY /dev/tty - fi - echo $REPLY - fi -fi diff --git a/helpers/bbcmd b/helpers/bbcmd deleted file mode 100755 index fdc4e78..0000000 --- a/helpers/bbcmd +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -if [ $# -eq 0 ]; then cat >> $BBCMD; exit; fi -for arg; do - shift - if expr "$arg" : '^[^:]*:$' >/dev/null; then - if [ $# -gt 0 ]; then printf "$arg%s\\0" "$@" >> $BBCMD - else sed "s/\([^\\x00]\+\)/$arg\1/g" >> $BBCMD; fi - exit - fi - printf "%s\\0" "$arg" >> $BBCMD -done diff --git a/helpers/bbconfirm b/helpers/bbconfirm deleted file mode 100755 index cae1153..0000000 --- a/helpers/bbconfirm +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -# Ask for user confirmation -set -e -if command -v ask >/dev/null; then - ask -n "$(printf "$1Is that okay?\033[?25h")" -else - reply="$(bbask -1 "$(printf "$1\033[0;1mIs that okay? [y/N] ")")" - [ "$reply" != 'y' ] -fi diff --git a/helpers/bbpause b/helpers/bbpause deleted file mode 100755 index 6604fbd..0000000 --- a/helpers/bbpause +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -# Pause before continuing -printf '\033[0;2m Press any key to continue...\033[0m' >/dev/tty -bbask -1 >/dev/null diff --git a/helpers/bbpick b/helpers/bbpick deleted file mode 100755 index 3316484..0000000 --- a/helpers/bbpick +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh -# Pick from the provided input -if [ -z "$PICKER" ]; then - if command -v fzf >/dev/null; then - PICKER=fzf - elif command -v fzy >/dev/null; then - PICKER=fzy - elif command -v ask >/dev/null; then - PICKER=ask - elif command -v dmenu >/dev/null; then - PICKER=dmenu - elif command -v pick >/dev/null; then - PICKER=pick - fi -fi - -case "$PICKER" in - fzf) - printf '\033[3A\033[?25h' >/dev/tty - fzf --read0 --height=4 --prompt="$(printf "$1")" - ;; - fzy) - printf '\033[3A\033[?25h' >/dev/tty - tr '\0' '\n' | fzy --lines=3 --prompt="$(printf "\033[1m$1\033[0m")" - ;; - ask) - ask --read0 --prompt="$(printf "$1\033[?25h")" - ;; - dmenu) - tr '\0' '\n' | dmenu -i -l 10 -p "$(printf "$1")" - ;; - pick) - printf '\033[?25h' >/dev/tty - tr '\0' '\n' | pick - ;; - *) - query="$(bbask "$1")" && grep -i -m1 "$(echo "$query" | sed 's;.;[^/&]*[&];g')" - ;; -esac diff --git a/helpers/bbtargets b/helpers/bbtargets deleted file mode 100755 index 1862ca0..0000000 --- a/helpers/bbtargets +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# If the user is doing something ambiguous, like selecting a bunch of files, -# moving the cursor off of those files, then doing an action, this will ask -# what they mean to target, then output either 'cursor' or 'selected'. -# Usage: targets "$BBCURSOR" "$@" -cursor="$1" -shift -if [ $# -gt 0 ]; then - for f in "$@"; do - if [ "$f" = "$cursor" ]; then - intended='Selected files' - break - fi - done -else - intended='Cursor file' -fi - -[ -z "$intended" ] && intended="$(printf '%s\0' 'Cursor file' 'Selected files' 'Both' | bbpick 'Which do you want to delete? ')" - -case "$intended" in - Cursor*) echo cursor ;; - Selected*) echo selected ;; - Both) echo both ;; -esac diff --git a/helpers/bbunscroll b/helpers/bbunscroll deleted file mode 100755 index 15102c4..0000000 --- a/helpers/bbunscroll +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -# Display text from the current line upward (instead of downward) -input="$(cat)" -printf "\\033[$(echo "$input" | wc -l)A\\033[J" >/dev/tty -echo "$input" diff --git a/scripts/bbask b/scripts/bbask new file mode 100755 index 0000000..ad446ec --- /dev/null +++ b/scripts/bbask @@ -0,0 +1,31 @@ +#!/bin/sh +# A simple user-input asker. Result is output to stdout. +# Usage: ask [-1] [prompt [initial query]] +if [ "$1" = '-1' ]; then + # Get one character of input + tput civis >/dev/tty; + printf '\033[1m%s\033[0m' "$2" >/dev/tty; + stty -icanon -echo >/dev/tty 2>/dev/tty; + if [ "$(uname)" = "Darwin" ]; then + read -n 1 REPLY /dev/tty; + echo $REPLY + else + dd bs=1 count=1 2>/dev/null /dev/tty 2>/dev/tty + tput cvvis >/dev/tty +else + # Get a line of input + if command -v ask >/dev/null; then + ask --history=bb.hist --prompt="$(printf '%s\033[?25h' "$1")" --query="$2" + else + printf "\033[1m%s\033[0m" "$1" >/dev/tty + tput cvvis >/dev/tty + if [ "$(uname)" = "Darwin" ]; then + read -e REPLY /dev/tty + else + read REPLY /dev/tty + fi + echo $REPLY + fi +fi diff --git a/scripts/bbcmd b/scripts/bbcmd new file mode 100755 index 0000000..fdc4e78 --- /dev/null +++ b/scripts/bbcmd @@ -0,0 +1,11 @@ +#!/bin/sh +if [ $# -eq 0 ]; then cat >> $BBCMD; exit; fi +for arg; do + shift + if expr "$arg" : '^[^:]*:$' >/dev/null; then + if [ $# -gt 0 ]; then printf "$arg%s\\0" "$@" >> $BBCMD + else sed "s/\([^\\x00]\+\)/$arg\1/g" >> $BBCMD; fi + exit + fi + printf "%s\\0" "$arg" >> $BBCMD +done diff --git a/scripts/bbconfirm b/scripts/bbconfirm new file mode 100755 index 0000000..cae1153 --- /dev/null +++ b/scripts/bbconfirm @@ -0,0 +1,9 @@ +#!/bin/sh +# Ask for user confirmation +set -e +if command -v ask >/dev/null; then + ask -n "$(printf "$1Is that okay?\033[?25h")" +else + reply="$(bbask -1 "$(printf "$1\033[0;1mIs that okay? [y/N] ")")" + [ "$reply" != 'y' ] +fi diff --git a/scripts/bbpause b/scripts/bbpause new file mode 100755 index 0000000..6604fbd --- /dev/null +++ b/scripts/bbpause @@ -0,0 +1,4 @@ +#!/bin/sh +# Pause before continuing +printf '\033[0;2m Press any key to continue...\033[0m' >/dev/tty +bbask -1 >/dev/null diff --git a/scripts/bbpick b/scripts/bbpick new file mode 100755 index 0000000..3316484 --- /dev/null +++ b/scripts/bbpick @@ -0,0 +1,39 @@ +#!/bin/sh +# Pick from the provided input +if [ -z "$PICKER" ]; then + if command -v fzf >/dev/null; then + PICKER=fzf + elif command -v fzy >/dev/null; then + PICKER=fzy + elif command -v ask >/dev/null; then + PICKER=ask + elif command -v dmenu >/dev/null; then + PICKER=dmenu + elif command -v pick >/dev/null; then + PICKER=pick + fi +fi + +case "$PICKER" in + fzf) + printf '\033[3A\033[?25h' >/dev/tty + fzf --read0 --height=4 --prompt="$(printf "$1")" + ;; + fzy) + printf '\033[3A\033[?25h' >/dev/tty + tr '\0' '\n' | fzy --lines=3 --prompt="$(printf "\033[1m$1\033[0m")" + ;; + ask) + ask --read0 --prompt="$(printf "$1\033[?25h")" + ;; + dmenu) + tr '\0' '\n' | dmenu -i -l 10 -p "$(printf "$1")" + ;; + pick) + printf '\033[?25h' >/dev/tty + tr '\0' '\n' | pick + ;; + *) + query="$(bbask "$1")" && grep -i -m1 "$(echo "$query" | sed 's;.;[^/&]*[&];g')" + ;; +esac diff --git a/scripts/bbshutdown b/scripts/bbshutdown new file mode 100755 index 0000000..368fd2f --- /dev/null +++ b/scripts/bbshutdown @@ -0,0 +1,3 @@ +#!/bin/sh +# This file gets run when `bb` shuts down. +echo "bbcmd glob:'$BBGLOB' sort:'$BBSORT' columns:'$BBCOLUMNS' $BBINTERLEAVE" > "$XDG_DATA_HOME"/bb/settings.sh diff --git a/scripts/bbstartup b/scripts/bbstartup new file mode 100755 index 0000000..40de50b --- /dev/null +++ b/scripts/bbstartup @@ -0,0 +1,15 @@ +#!/bin/sh +# This file contains the script that is run when bb launches + +[ ! -d "$XDG_DATA_HOME/bb" ] && mkdir -p "$XDG_DATA_HOME/bb" + +# Load key bindings +if [ "$BBPATH" ]; then + cat "$BBPATH/bindings.bb" "$XDG_CONFIG_HOME/bb/bindings.bb" +else + cat "$sysconfdir/xdg/bb/bindings.bb" "$XDG_CONFIG_HOME/bb/bindings.bb" +fi 2>/dev/null | awk '/^#/ {next} /^[^ ]/ {printf "\0bind:"} {print $0} END {printf "\0"}' >> "$BBCMD" + +if [ -e "$XDG_DATA_HOME/bb/settings.sh" ]; then + . "$XDG_DATA_HOME/bb/settings.sh" +fi diff --git a/scripts/bbtargets b/scripts/bbtargets new file mode 100755 index 0000000..1862ca0 --- /dev/null +++ b/scripts/bbtargets @@ -0,0 +1,25 @@ +#!/bin/sh +# If the user is doing something ambiguous, like selecting a bunch of files, +# moving the cursor off of those files, then doing an action, this will ask +# what they mean to target, then output either 'cursor' or 'selected'. +# Usage: targets "$BBCURSOR" "$@" +cursor="$1" +shift +if [ $# -gt 0 ]; then + for f in "$@"; do + if [ "$f" = "$cursor" ]; then + intended='Selected files' + break + fi + done +else + intended='Cursor file' +fi + +[ -z "$intended" ] && intended="$(printf '%s\0' 'Cursor file' 'Selected files' 'Both' | bbpick 'Which do you want to delete? ')" + +case "$intended" in + Cursor*) echo cursor ;; + Selected*) echo selected ;; + Both) echo both ;; +esac diff --git a/scripts/bbunscroll b/scripts/bbunscroll new file mode 100755 index 0000000..15102c4 --- /dev/null +++ b/scripts/bbunscroll @@ -0,0 +1,5 @@ +#!/bin/sh +# Display text from the current line upward (instead of downward) +input="$(cat)" +printf "\\033[$(echo "$input" | wc -l)A\\033[J" >/dev/tty +echo "$input" -- cgit v1.2.3