From d10e9cbc236a7e74981ba0d62bcf91ef729b4f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Rolim?= Date: Thu, 7 Jan 2021 15:47:16 -0300 Subject: [PATCH] Initial commit. Single file with the whole implementation. Keypad interaction is still murky; how exactly do I read a backspace or Ctrl+W command? --- .gitignore | 4 ++ LICENSE | 13 +++++ Makefile | 9 +++ browser.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 browser.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b54e006 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +* +!*.c +!*.h +!Makefile diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..977b60d --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2021 Érico Nogueira + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6400ea2 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +SRC = browser.c +EXE = browser +CFLAGS = -Wall -Wextra +LDLIBS = -lcurses + +all: $(EXE) + +clean: + rm -f $(EXE) diff --git a/browser.c b/browser.c new file mode 100644 index 0000000..2311479 --- /dev/null +++ b/browser.c @@ -0,0 +1,165 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include + +#include + +enum my_keycodes { + MY_CTRLW = 7000, +}; + +static void endwin_void(void) +{ + endwin(); +} + +static void finish(int sig) +{ + (void)sig; + quick_exit(1); +} + +struct str_array { + const char **v; + bool *m; + size_t n, c; +}; + +static void add_entry(struct str_array *a, const char *s) +{ + if (a->n == a->c) { + if (a->c == 0) a->c = 32; + else a->c *= 2; + a->v = realloc(a->v, sizeof(*a->v) * a->c); + a->m = realloc(a->m, sizeof(*a->m) * a->c); + if (!a->v || !a->m) { + perror("realloc"); + exit(1); + } + } + + a->v[a->n] = s; + a->m[a->n] = false; + a->n++; +} + +static inline const char *get_entry(const struct str_array *a, size_t i) +{ + return a->v[i]; +} + +static inline const char *get_entry_match(const struct str_array *a, size_t i) +{ + return a->m[i] ? a->v[i] : NULL; +} + +static void filter_entries(struct str_array *a, const char *s) +{ + for (size_t i = 0; i < a->n; i++) { + a->m[i] = strstr(a->v[i], s); + } +} + +static void print_entries(const struct str_array *a) +{ + for (size_t i = 0; i < a->n; i++) { + printf("entry %zu: %s\n", i, get_entry(a, i)); + } +} + +int main() +{ + signal(SIGINT, finish); + atexit(endwin_void); + at_quick_exit(endwin_void); + + char delim = '\n'; + + struct str_array entries = { 0 }; + + char *line = NULL; + size_t tmp = 0; + { + ssize_t n; + while ((n = getdelim(&line, &tmp, delim, stdin)) >= 0) { + if (line[n-1] == '\n') line[n-1] = 0; + add_entry(&entries, line); + + line = NULL; + tmp = 0; + } + if (dup2(STDERR_FILENO, STDIN_FILENO) != STDIN_FILENO) { + perror("dup2"); + exit(1); + } + } + + initscr(); + nonl(); + cbreak(); + noecho(); + + if (has_colors()) { + start_color(); + init_pair(1, COLOR_GREEN, COLOR_BLACK); + // red,green,yellow,blue,cyan,magenta,white + } + attrset(COLOR_PAIR(1)); + + WINDOW *list = newwin(LINES - 1, 0, 0, 0); + WINDOW *prompt = newwin(1, 0, LINES - 1, 0); + if (!list || !prompt) { + perror("newwin"); + exit(1); + } + keypad(prompt, TRUE); + keypad(list, TRUE); + + for (size_t i = 0; i < entries.n; i++) { + mvwaddstr(list, i, 0, get_entry(&entries, i)); + } + wrefresh(list); + + mvwaddstr(prompt, 0, 0, "> "); + wrefresh(prompt); + + char name[1024] = { 0 }; + size_t n = 0; + while (n < sizeof name) { + int c = wgetch(prompt); + switch (c) { + case KEY_BACKSPACE: + case 127: + name[n] = 0; + if (n) n--; + break; + case KEY_DL: + name[0] = 0; + n = 0; + break; + default: + name[n] = c; + n++; + break; + } + werase(prompt); + mvwaddstr(prompt, 0, 0, "> "); + waddstr(prompt, name); + wrefresh(prompt); + filter_entries(&entries, name); + + werase(list); + int line = 0; + for (size_t i = 0; i < entries.n; i++) { + const char *e = get_entry_match(&entries, i); + if (e) mvwaddstr(list, line++, 0, e); + } + wrefresh(list); + } + + return 0; +}