diff options
| -rw-r--r-- | bb.c | 188 | ||||
| -rw-r--r-- | config.h | 34 | ||||
| -rw-r--r-- | keys.h | 9 |
3 files changed, 169 insertions, 62 deletions
@@ -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; @@ -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}, }; @@ -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 |
