aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2019-05-22 00:25:25 -0700
committerBruce Hill <bruce@bruce-hill.com>2019-05-22 00:25:25 -0700
commit075525603907717663e22f424d40ac6a74b806db (patch)
tree7868f8a58b0d94a18ab7c191cce6c50a53364e30
parentb7b6b6cc74a477a3745d06bce64e284e5b2dd880 (diff)
Added dynamically generated help, fixed some ctrl-c stuff.
-rw-r--r--bb.c188
-rw-r--r--config.h34
-rw-r--r--keys.h9
3 files changed, 169 insertions, 62 deletions
diff --git a/bb.c b/bb.c
index 27c3461..7670743 100644
--- a/bb.c
+++ b/bb.c
@@ -5,6 +5,7 @@
*/
#include <dirent.h>
#include <fcntl.h>
+#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -71,6 +72,11 @@ static void update_term_size(void)
height = sz.ws_row;
}
+static void do_nothing(int _)
+{
+ // Used as SIGINT handler
+}
+
static void init_term()
{
termfd = open("/dev/tty", O_RDWR);
@@ -175,7 +181,7 @@ static void render(bb_state_t *state)
term_move(0,1);
{ // Column labels
- char buf[] = "\e[32m Size Date Bits Name\e[0m";
+ char buf[] = "\e[32m Size Date Perm Name\e[0m";
buf[8] = state->sortmethod == SORT_SIZE ? (state->sort_reverse ? '-' : '+') : ' ';
buf[21] = state->sortmethod == SORT_DATE ? (state->sort_reverse ? '-' : '+') : ' ';
buf[36] = state->sortmethod == SORT_BITS ? (state->sort_reverse ? '-' : '+') : ' ';
@@ -260,10 +266,15 @@ static void render(bb_state_t *state)
writez(termfd, " \e[0m"); // Reset color and attributes
}
- term_move(0, height - 1);
+ static const char *help = "Press '?' to see key bindings ";
char buf[32] = {0};
- int len = snprintf(buf, sizeof(buf), "%lu selected", state->nselected);
- write(termfd, buf, len);
+ int len = snprintf(buf, sizeof(buf), " %lu selected", state->nselected);
+ if (strlen(help) + len < width + 1) {
+ term_move(0, height - 1);
+ write(termfd, buf, len);
+ }
+ term_move(MAX(0, width - strlen(help)), height - 1);
+ writez(termfd, help);
}
static int compare_alpha(void *r, const void *v1, const void *v2)
@@ -292,7 +303,7 @@ static int compare_alpha(void *r, const void *v1, const void *v2)
return (*p1 - *p2)*sign;
}
-static int compare_bits(void *r, const void *v1, const void *v2)
+static int compare_perm(void *r, const void *v1, const void *v2)
{
int sign = *((int *)r) ? -1 : 1;
const entry_t *f1 = *((const entry_t**)v1), *f2 = *((const entry_t**)v2);
@@ -468,9 +479,13 @@ static void explore(char *path, int print_dir, int print_selection)
cmp = compare_alpha;
if (state.sortmethod == SORT_SIZE) cmp = compare_size;
if (state.sortmethod == SORT_DATE) cmp = compare_date;
- if (state.sortmethod == SORT_BITS) cmp = compare_bits;
+ if (state.sortmethod == SORT_BITS) cmp = compare_perm;
qsort_r(&state.files[1], state.nfiles-1, sizeof(entry_t*), &state.sort_reverse, cmp);
+ // Put the cursor on the first *real* file if one exists
+ if (state.nfiles > 1)
+ ++state.cursor;
+
if (to_select[0]) {
for (int i = 0; i < state.nfiles; i++) {
if (strcmp(to_select, state.files[i]->d_name) == 0) {
@@ -498,13 +513,13 @@ static void explore(char *path, int print_dir, int print_selection)
dt_ms += 1e-6*(double)(clicktime.tv_nsec - state.lastclick.tv_nsec);
state.lastclick = clicktime;
if (mouse_y == 1) {
- // Size Date Bits Name
+ // Size Date Perm Name
if (mouse_x <= 8)
goto sort_size;
else if (mouse_x <= 30)
goto sort_date;
else if (mouse_x <= 35)
- goto sort_bits;
+ goto sort_perm;
else
goto sort_alpha;
} else if (mouse_y >= 2 && state.scroll + (mouse_y - 2) < state.nfiles) {
@@ -694,44 +709,61 @@ static void explore(char *path, int print_dir, int print_selection)
picked = 0;
goto open_file;
- case 'a':
- sort_alpha:
- if (state.sortmethod == SORT_ALPHA)
- state.sort_reverse ^= 1;
- else {
- state.sortmethod = SORT_ALPHA;
- state.sort_reverse = 0;
- }
- goto sort_files;
+ case 's':
+ // Change sorting method:
+ term_move(0, height-1);
+ writez(termfd, "\e[K\e[1mSort by (a)lphabetic (s)ize (t)ime (p)ermissions:\e[0m \e[?25h");
+ try_sort_again:
+ switch (term_getkey(termfd, &mouse_x, &mouse_y)) {
+ case 'a': case 'A':
+ sort_alpha:
+ if (state.sortmethod == SORT_ALPHA)
+ state.sort_reverse ^= 1;
+ else {
+ state.sortmethod = SORT_ALPHA;
+ state.sort_reverse = 0;
+ }
+ break;
- case 'b':
- sort_bits:
- if (state.sortmethod == SORT_BITS)
- state.sort_reverse ^= 1;
- else {
- state.sortmethod = SORT_BITS;
- state.sort_reverse = 0;
- }
- goto sort_files;
+ case 'p': case 'P':
+ sort_perm:
+ if (state.sortmethod == SORT_BITS)
+ state.sort_reverse ^= 1;
+ else {
+ state.sortmethod = SORT_BITS;
+ state.sort_reverse = 0;
+ }
+ break;
- case 's':
- sort_size:
- if (state.sortmethod == SORT_SIZE)
- state.sort_reverse ^= 1;
- else {
- state.sortmethod = SORT_SIZE;
- state.sort_reverse = 0;
- }
- goto sort_files;
+ case 's': case 'S':
+ sort_size:
+ if (state.sortmethod == SORT_SIZE)
+ state.sort_reverse ^= 1;
+ else {
+ state.sortmethod = SORT_SIZE;
+ state.sort_reverse = 0;
+ }
+ break;
- case 't':
- sort_date:
- if (state.sortmethod == SORT_DATE)
- state.sort_reverse ^= 1;
- else {
- state.sortmethod = SORT_DATE;
- state.sort_reverse = 0;
+ case 't': case 'T':
+ sort_date:
+ if (state.sortmethod == SORT_DATE)
+ state.sort_reverse ^= 1;
+ else {
+ state.sortmethod = SORT_DATE;
+ state.sort_reverse = 0;
+ }
+ break;
+
+ case -1:
+ goto try_sort_again;
+
+ default:
+ writez(termfd, "\e[?25l");
+ goto redraw;
}
+ // Hide cursor again
+ writez(termfd, "\e[?25l");
goto sort_files;
case '.':
@@ -810,21 +842,64 @@ static void explore(char *path, int print_dir, int print_selection)
goto tail_call;
}
- default:
+ case '?': {
+ close_term();
+ int fd;
+ pid_t child = run_cmd(NULL, &fd, "less -r");
+
+ writez(fd, "\n \e[33;1mKey Bindings:\e[0m\n");
for (int i = 0; bindings[i].key; i++) {
+ if (bindings[i].key > 0) continue;
+ writez(fd, "\e[1m");
+ char *tab = strchr(bindings[i].command, '\t');
+ const char *spaces = " ";
+ write(fd, spaces, 16 - (tab - bindings[i].command));
+ write(fd, bindings[i].command, tab - bindings[i].command);
+ write(fd, " ", 1);
+ writez(fd, tab + 1);
+ writez(fd, "\e[0m\n");
+ }
+ writez(fd, "\n \e[33;1mScript Key Bindings:\e[0m\n");
+ for (int i = 0; bindings[i].key; i++) {
+ if (bindings[i].key <= 0) continue;
+ writez(fd, "\e[1m");
+ char buf[] = " X \e[0m";
+ *strchr(buf, 'X') = bindings[i].key;
+ writez(fd, buf);
+ writez(fd, bindings[i].command);
+ writez(fd, "\e[0m\n");
+ }
+ writez(fd, "\n");
+
+ close(fd);
+ waitpid(child, NULL, 0);
+ init_term();
+ goto redraw;
+ }
+
+ case -1:
+ goto skip_redraw;
+
+ default:
+ // Search user-defined key bindings from config.h:
+ for (int i = 0; bindings[i].key > 0; i++) {
if (key == bindings[i].key) {
term_move(0, height-1);
- if (!(bindings[i].flags & ONSCREEN))
+ struct termios cur_tios;
+ if (!(bindings[i].flags & ONSCREEN)) {
close_term();
- else {
- // Show cursor:
+ } else {
+ tcgetattr(termfd, &cur_tios);
+ struct termios tios;
+ memcpy(&tios, &orig_termios, sizeof(tios));
+ tcsetattr(termfd, TCSAFLUSH, &tios);
+ // Show cursor
writez(termfd, "\e[?25h");
- tcsetattr(termfd, TCSAFLUSH, &orig_termios);
- close(termfd);
}
int scriptinfd;
pid_t child;
+ sig_t old_handler = signal(SIGINT, do_nothing);
child = run_cmd(NULL, &scriptinfd, bindings[i].command);
if (!(bindings[i].flags & NO_FILES)) {
if (state.nselected > 0) {
@@ -835,7 +910,15 @@ static void explore(char *path, int print_dir, int print_selection)
}
close(scriptinfd);
waitpid(child, NULL, 0);
- init_term();
+ signal(SIGINT, old_handler);
+
+ if (!(bindings[i].flags & ONSCREEN)) {
+ init_term();
+ } else {
+ tcsetattr(termfd, TCSAFLUSH, &cur_tios);
+ // hide cursor
+ writez(termfd, "\e[?25l");
+ }
if (bindings[i].flags & CLEAR_SELECTION)
clear_selection(&state);
@@ -848,13 +931,6 @@ static void explore(char *path, int print_dir, int print_selection)
goto redraw;
}
}
- if (key != -1) {
- term_move(0,height-1);
- writez(termfd, "\e[K");
- char buf[64] = {0};
- sprintf(buf, "unknown: %x", key);
- writez(termfd, buf);
- }
goto skip_redraw;
}
goto skip_redraw;
diff --git a/config.h b/config.h
index 146696d..7659983 100644
--- a/config.h
+++ b/config.h
@@ -1,8 +1,9 @@
/*
* User-defined key bindings.
*/
+#include "keys.h"
+
#define PROG_FUZZY "fzf"
-#define PROG_DELETE "rm -rf"
#define SCROLLOFF 5
#define NO_FILES (1<<0)
@@ -18,18 +19,39 @@ struct {
const char *command;
int flags;
} bindings[] = {
- {'?', "less"},
+ // User-defined custom scripts go here:
+ {'L', "less"},
{'D', "xargs rm -rf" DEVNULL, CLEAR_SELECTION | REFRESH | ONSCREEN},
{'d', "xargs -I @ sh -c 'rm -rfi @ </dev/tty'", CLEAR_SELECTION | REFRESH | ONSCREEN},
- {'+', "xargs -n1 -I @ cp @ @.copy" DEVNULL, REFRESH | ONSCREEN},
+ {'c', "xargs -n1 -I @ cp @ @.copy" DEVNULL, REFRESH | ONSCREEN},
{'m', "xargs -I @ mv -i @ . </dev/tty" DEVNULL, CLEAR_SELECTION | REFRESH | ONSCREEN},
{'p', "xargs -I @ cp -i @ . </dev/tty" DEVNULL, CLEAR_SELECTION | REFRESH | ONSCREEN},
{'n', "touch \"`printf '\\033[33;1mNew file:\\033[0m ' >/dev/tty && head -n1 /dev/tty`\"", ONSCREEN | REFRESH | NO_FILES},
{'|', "sh -c \"`printf '> ' >/dev/tty && head -n1 /dev/tty`\"", REFRESH},
{'>', "sh -c \"`printf '> ' >/dev/tty && head -n1 /dev/tty`\"", NO_FILES | REFRESH},
- {'r', "xargs -I @ -n1 sh -c 'mv \"@\" \"`printf \"\e[1mRename \e[0;33m%%s\e[0m: \" \"@\" >&2 && head -n1 </dev/tty`\"'",
- REFRESH | CLEAR_SELECTION | ONSCREEN},
- {'r', "xargs -I @ -n1 sh -c 'mv \"@\" \"`printf \"\\033[1mRename \\033[0;33m%%s\\033[0m: \" \"@\" >&2 && head -n1 </dev/tty`\"'",
+ {'r', "xargs -I @ -n1 sh -c 'mv \"@\" \"`printf \"\e[1mRename \e[1;33m%%s\e[0m: \" \"@\" >&2 && head -n1 </dev/tty`\"'",
REFRESH | CLEAR_SELECTION | ONSCREEN},
+
+ // Hard-coded behaviors (these are just placeholders for the help):
+ {-1, "?\t\e[0;34mOpen help menu\e[0m"},
+ {-1, "h,Left\t\e[0;34mNavigate up a directory\e[0m"},
+ {-1, "j,Down\t\e[0;34mMove cursor down\e[0m"},
+ {-1, "k,Up\t\e[0;34mMove cursor up\e[0m"},
+ {-1, "l,Right,Enter\t\e[0;34mOpen file/dir\e[0m"},
+ {-1, "Space\t\e[0;34mToggle selection\e[0m"},
+ {-1, "J\t\e[0;34mMove selection state down\e[0m"},
+ {-1, "K\t\e[0;34mMove selection state up\e[0m"},
+ {-1, "q,Q\t\e[0;34mQuit\e[0m"},
+ {-1, "g,Home\t\e[0;34mGo to first item\e[0m"},
+ {-1, "G,End\t\e[0;34mGo to last item\e[0m"},
+ {-1, "s\t\e[0;34mChange sorting\e[0m"},
+ {-1, "f,/\t\e[0;34mFuzzy find\e[0m"},
+ {-1, "Escape\t\e[0;34mClear selection\e[0m"},
+ {-1, "F5,Ctrl-R\t\e[0;34mRefresh\e[0m"},
+ {-1, "Ctrl-A\t\e[0;34mSelect all\e[0m"},
+ {-1, "Ctrl-C\t\e[0;34mAbort and exit\e[0m"},
+ {-1, "PgDn,Ctrl-D\t\e[0;34mPage down\e[0m"},
+ {-1, "PgUp,Ctrl-U\t\e[0;34mPage up\e[0m"},
+ {-1, "Ctrl-Z\t\e[0;34mSuspend\e[0m"},
{0},
};
diff --git a/keys.h b/keys.h
index b4731f9..fc1e8b2 100644
--- a/keys.h
+++ b/keys.h
@@ -1,3 +1,10 @@
+/*
+ * Definitions of some key character constants
+ */
+
+#ifndef KEYS_DEFINED
+#define KEYS_DEFINED
+
#define KEY_F1 (0xFFFF-0)
#define KEY_F2 (0xFFFF-1)
#define KEY_F3 (0xFFFF-2)
@@ -189,3 +196,5 @@ int term_getkey(int fd, int *mouse_x, int *mouse_y)
}
return -1;
}
+
+#endif