aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--bb.c205
-rw-r--r--config.h36
-rw-r--r--keys.h65
4 files changed, 175 insertions, 133 deletions
diff --git a/Makefile b/Makefile
index a121074..04c0586 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ all: $(NAME)
clean:
rm $(NAME)
-$(NAME): $(NAME).c
+$(NAME): $(NAME).c keys.h config.h
$(CC) $(NAME).c $(LIBS) $(CFLAGS) -o $(NAME)
test: $(NAME)
diff --git a/bb.c b/bb.c
index f222ee4..56234ca 100644
--- a/bb.c
+++ b/bb.c
@@ -18,6 +18,7 @@
#include <time.h>
#include <unistd.h>
+#include "config.h"
#include "keys.h"
#define MAX(a,b) ((a) < (b) ? (b) : (a))
@@ -26,7 +27,6 @@
#define writez(fd, str) write(fd, str, strlen(str))
#define IS_SELECTED(p) ((p)->atme)
-static const int SCROLLOFF = 5;
static struct termios orig_termios;
static int termfd;
@@ -348,64 +348,6 @@ static void write_selection(int fd, entry_t *firstselected)
}
}
-static int term_get_event()
-{
- char c;
- if (read(termfd, &c, 1) != 1)
- return -1;
-
- if (c != '\x1b')
- return c;
-
- // Actual escape key:
- if (read(termfd, &c, 1) != 1)
- return KEY_ESC;
-
- switch (c) {
- case '[':
- if (read(termfd, &c, 1) != 1)
- return -1;
- switch (c) {
- case 'H': return KEY_HOME;
- case 'F': return KEY_END;
- case '<': // Mouse clicks
- {
- int buttons = 0, x = 0, y = 0;
- char buf;
- while (read(termfd, &buf, 1) == 1 && '0' <= buf && buf <= '9')
- buttons = buttons * 10 + (buf - '0');
- if (buf != ';') return -1;
- while (read(termfd, &buf, 1) == 1 && '0' <= buf && buf <= '9')
- x = x * 10 + (buf - '0');
- if (buf != ';') return -1;
- while (read(termfd, &buf, 1) == 1 && '0' <= buf && buf <= '9')
- y = y * 10 + (buf - '0');
- if (buf != 'm' && buf != 'M') return -1;
-
- mouse_x = x - 1, mouse_y = y - 1;
-
- if (buf == 'm')
- return KEY_MOUSE_RELEASE;
- switch (buttons) {
- case 64: return KEY_MOUSE_WHEEL_UP;
- case 65: return KEY_MOUSE_WHEEL_DOWN;
- case 0: return KEY_MOUSE_LEFT;
- case 1: return KEY_MOUSE_RIGHT;
- case 2: return KEY_MOUSE_MIDDLE;
- default: return -1;
- }
- }
- break;
- default:
- break;
- }
- return -1;
- default:
- return -1;
- }
- return -1;
-}
-
static char *input(const char *prompt, const char *starter)
{
size_t len = 0, capacity = MAX(100, starter ? strlen(starter)+1 : 0);
@@ -426,7 +368,7 @@ static char *input(const char *prompt, const char *starter)
write(termfd, reply, len);
skip_redraw:;
- int c = term_get_event();
+ int c = term_getkey(termfd, &mouse_x, &mouse_y);
switch (c) {
case KEY_BACKSPACE: case KEY_BACKSPACE2:
if (len > 0) {
@@ -468,6 +410,20 @@ static char *input(const char *prompt, const char *starter)
return reply;
}
+static void clear_selection(bb_state_t *state)
+{
+ entry_t **tofree = calloc(state->nselected, sizeof(entry_t*));
+ int i = 0;
+ for (entry_t *e = state->firstselected; e; e = e->next) {
+ if (!e->visible) tofree[i++] = e;
+ *e->atme = NULL;
+ e->atme = NULL;
+ }
+ while (i) free(tofree[--i]);
+ free(tofree);
+ state->nselected = 0;
+}
+
static void explore(char *path, int print_dir, int print_selection)
{
char *tmp = path;
@@ -591,7 +547,7 @@ static void explore(char *path, int print_dir, int print_selection)
render(&state);
skip_redraw:
scrolloff = MIN(SCROLLOFF, (height-4)/2);
- int key = term_get_event();
+ int key = term_getkey(termfd, &mouse_x, &mouse_y);
switch (key) {
case KEY_MOUSE_LEFT: {
struct timespec clicktime;
@@ -723,22 +679,11 @@ static void explore(char *path, int print_dir, int print_selection)
}
goto redraw;
- case KEY_ESC: {
- entry_t **tofree = calloc(state.nselected, sizeof(entry_t*));
- int i = 0;
- for (entry_t *e = state.firstselected; e; e = e->next) {
- if (!e->visible) tofree[i++] = e;
- *e->atme = NULL;
- e->atme = NULL;
- }
- if (state.firstselected) err("???");
- while (i) free(tofree[--i]);
- free(tofree);
- state.nselected = 0;
+ case KEY_ESC:
+ clear_selection(&state);
goto redraw;
- }
- case 'j':
+ case 'j': case KEY_ARROW_DOWN:
if (state.cursor >= state.nfiles - 1)
goto skip_redraw;
++state.cursor;
@@ -747,7 +692,7 @@ static void explore(char *path, int print_dir, int print_selection)
}
goto redraw;
- case 'k':
+ case 'k': case KEY_ARROW_UP:
if (state.cursor <= 0)
goto skip_redraw;
--state.cursor;
@@ -786,7 +731,7 @@ static void explore(char *path, int print_dir, int print_selection)
}
goto skip_redraw;
- case 'h':
+ case 'h': case KEY_ARROW_LEFT:
picked = 0;
goto open_file;
@@ -834,7 +779,7 @@ static void explore(char *path, int print_dir, int print_selection)
state.showhidden ^= 1;
goto tail_call;
- case 'l': case '\r':
+ case 'l': case '\r': case KEY_ARROW_RIGHT:
picked = state.cursor;
open_file: {
if (state.files[picked]->d_isdir) {
@@ -868,60 +813,13 @@ static void explore(char *path, int print_dir, int print_selection)
break;
}
- case 'm':
- if (state.nselected) {
- int fd;
- run_cmd(NULL, &fd, "xargs -I {} mv {} .");
- write_selection(fd, state.firstselected);
- close(fd);
- }
- break;
-
- case 'D': {
- int fd;
- run_cmd(NULL, &fd, "xargs rm -rf");
- if (state.nselected > 0) {
- write_selection(fd, state.firstselected);
- for (entry_t *e = state.firstselected; e; e = e->next) {
- e->next = NULL;
- *(e->atme) = NULL;
- e->atme = NULL;
- if (!e->visible) free(e);
- }
- state.nselected = 0;
- } else {
- writez(fd, state.files[state.cursor]->d_fullname);
- write(fd, "\n", 1);
- }
- close(fd);
- goto tail_call;
- }
-
- case 'p':
- if (state.nselected) {
- int fd;
- run_cmd(NULL, &fd, "xargs -I {} cp {} .");
- write_selection(fd, state.firstselected);
- close(fd);
- } else if (strcmp(state.files[state.cursor]->d_name, "..") != 0) {
- run_cmd(NULL, NULL, "cp %s %s.copy", state.files[state.cursor]->d_name);
- }
- goto tail_call;
-
- case 'n': {
- char *name = input("new file: ", "foo");
- if (!name) goto redraw;
- run_cmd(NULL, NULL, "touch %s", name);
- goto tail_call;
- }
-
case 'f': case '/': {
close_term();
int fd;
if (state.showhidden)
- run_cmd(&fd, NULL, "find | cut -d/ -f2- | fzf");
+ run_cmd(&fd, NULL, "find | cut -d/ -f2- | " PROG_FUZZY);
else
- run_cmd(&fd, NULL, "find -not -name '\\.*' -not -path '*/\\.*' | cut -d/ -f2- | fzf");
+ run_cmd(&fd, NULL, "find -not -name '\\.*' -not -path '*/\\.*' | cut -d/ -f2- | " PROG_FUZZY);
int len = 0, space = MAX_PATH, consumed;
while ((consumed = read(fd, &to_select[len], space)) > 0) {
if (consumed < 0) err("Error reading selection");
@@ -953,6 +851,7 @@ static void explore(char *path, int print_dir, int print_selection)
goto tail_call;
}
+ /*
case '|': {
char *cmd = input("> ", NULL);
if (!cmd)
@@ -970,16 +869,58 @@ static void explore(char *path, int print_dir, int print_selection)
}
close(fd);
waitpid(child, NULL, 0);
-
- printf("\npress any key to continue...\n");
- fflush(stdout);
- getchar();
-
init_term();
goto tail_call;
}
+ */
default:
+ for (int i = 0; bindings[i].key; i++) {
+ if (key == bindings[i].key) {
+ if (!(bindings[i].flags & SILENT))
+ close_term();
+
+ int fd;
+ pid_t child;
+ if (bindings[i].flags & PROMPT) {
+ char *txt = input(bindings[i].prompt, NULL);
+ if (!txt) goto redraw;
+ child = run_cmd(NULL, &fd, bindings[i].command, txt);
+ free(txt);
+ } else {
+ child = run_cmd(NULL, &fd, bindings[i].command);
+ }
+
+ if (!(bindings[i].flags & NO_FILES)) {
+ if (state.nselected > 0) {
+ write_selection(fd, state.firstselected);
+ } else if (strcmp(state.files[state.cursor]->d_name, "..") != 0) {
+ write(fd, state.files[state.cursor]->d_name, state.files[state.cursor]->d_namlen);
+ }
+ }
+
+ close(fd);
+ waitpid(child, NULL, 0);
+
+ if (!(bindings[i].flags & SILENT))
+ init_term();
+
+ if (bindings[i].flags & CLEAR_SELECTION)
+ clear_selection(&state);
+
+ if (bindings[i].flags & REFRESH)
+ goto tail_call;
+
+ 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
new file mode 100644
index 0000000..109d318
--- /dev/null
+++ b/config.h
@@ -0,0 +1,36 @@
+/*
+ * User-defined key bindings.
+ */
+#define PROG_FUZZY "fzf"
+#define PROG_DELETE "rm -rf"
+#define SCROLLOFF 5
+
+#define NO_FILES (1<<0)
+#define PROMPT (1<<1)
+#define CD_TO_RESULT (1<<2)
+#define REFRESH (1<<3)
+#define CLEAR_SELECTION (1<<4)
+#define SILENT (1<<5)
+
+#define DEVNULL " >/dev/null 2>/dev/null"
+
+struct {
+ int key;
+ const char *command;
+ int flags;
+ const char *prompt;
+} bindings[] = {
+ {'?', "less"},
+ {'D', "xargs rm -rf" DEVNULL, CLEAR_SELECTION | REFRESH | SILENT},
+ {'d', "xargs -I @ sh -c 'rm -rfi @ </dev/tty'", CLEAR_SELECTION | REFRESH},
+ {'+', "xargs -n1 -I @ cp @ @.copy" DEVNULL, REFRESH | SILENT},
+ {'m', "xargs -I @ mv @ ." DEVNULL, CLEAR_SELECTION | REFRESH | SILENT},
+ {'p', "xargs -I @ cp @ ." DEVNULL, CLEAR_SELECTION | REFRESH | SILENT},
+ {'n', "touch %s", SILENT | PROMPT | REFRESH | NO_FILES, "New file: "},
+ {'|', "sh -c \"`read -p '> ' </dev/tty`\"", 0},//, PROMPT, "> "},
+ //{'|', "%s", PROMPT, "> "},
+ {'>', "%s", PROMPT | NO_FILES, "> "},
+ {'r', "xargs -I @ -n1 sh -c 'mv \"@\" \"`printf \"\\033[1mRename \\033[0;33m%%s\\033[0m: \" \"@\" >&2 && head -n1 </dev/tty`\"'",
+ REFRESH | CLEAR_SELECTION},
+ {0},
+};
diff --git a/keys.h b/keys.h
index e1b3e23..78b918b 100644
--- a/keys.h
+++ b/keys.h
@@ -73,3 +73,68 @@
#define KEY_SPACE 0x20
#define KEY_BACKSPACE2 0x7F
#define KEY_CTRL_8 0x7F /* clash with 'BACKSPACE2' */
+
+
+int term_getkey(int fd, int *mouse_x, int *mouse_y)
+{
+ char c;
+ if (read(fd, &c, 1) != 1)
+ return -1;
+
+ if (c == '\x1b')
+ goto escape;
+
+ return c;
+
+ escape:
+ // Actual escape key:
+ if (read(fd, &c, 1) != 1)
+ return KEY_ESC;
+
+ switch (c) {
+ case '[': goto CSI;
+ default: return -1;
+ }
+
+ CSI:
+ if (read(fd, &c, 1) != 1)
+ return -1;
+
+ switch (c) {
+ case 'H': return KEY_HOME;
+ case 'F': return KEY_END;
+ case 'A': return KEY_ARROW_UP;
+ case 'B': return KEY_ARROW_DOWN;
+ case 'C': return KEY_ARROW_RIGHT;
+ case 'D': return KEY_ARROW_LEFT;
+ case '<': { // Mouse clicks
+ int buttons = 0, x = 0, y = 0;
+ char buf;
+ while (read(fd, &buf, 1) == 1 && '0' <= buf && buf <= '9')
+ buttons = buttons * 10 + (buf - '0');
+ if (buf != ';') return -1;
+ while (read(fd, &buf, 1) == 1 && '0' <= buf && buf <= '9')
+ x = x * 10 + (buf - '0');
+ if (buf != ';') return -1;
+ while (read(fd, &buf, 1) == 1 && '0' <= buf && buf <= '9')
+ y = y * 10 + (buf - '0');
+ if (buf != 'm' && buf != 'M') return -1;
+
+ *mouse_x = x - 1, *mouse_y = y - 1;
+
+ if (buf == 'm')
+ return KEY_MOUSE_RELEASE;
+ switch (buttons) {
+ case 64: return KEY_MOUSE_WHEEL_UP;
+ case 65: return KEY_MOUSE_WHEEL_DOWN;
+ case 0: return KEY_MOUSE_LEFT;
+ case 1: return KEY_MOUSE_RIGHT;
+ case 2: return KEY_MOUSE_MIDDLE;
+ default: return -1;
+ }
+ break;
+ }
+ }
+
+ return -1;
+}