isingle file implementation - iomenu - interactive terminal-based selection menu Err bitreich.org 70 hgit clone git://bitreich.org/iomenu git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/iomenu URL:git://bitreich.org/iomenu git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/iomenu bitreich.org 70 1Log /scm/iomenu/log.gph bitreich.org 70 1Files /scm/iomenu/files.gph bitreich.org 70 1Refs /scm/iomenu/refs.gph bitreich.org 70 1Tags /scm/iomenu/tag bitreich.org 70 1README /scm/iomenu/file/README.gph bitreich.org 70 1LICENSE /scm/iomenu/file/LICENSE.gph bitreich.org 70 i--- Err bitreich.org 70 1commit 35d50bc1a88b26d1f57219a9f3f7b1a907c57498 /scm/iomenu/commit/35d50bc1a88b26d1f57219a9f3f7b1a907c57498.gph bitreich.org 70 1parent 60947ffd7f79328a77d58ca78da7ff46c602fd1f /scm/iomenu/commit/60947ffd7f79328a77d58ca78da7ff46c602fd1f.gph bitreich.org 70 hAuthor: Josuah Demangeonā  ā µ URL:mailto:mail@josuah.net bitreich.org 70 iDate: Thu, 16 Mar 2017 18:34:21 +0100 Err bitreich.org 70 i Err bitreich.org 70 isingle file implementation Err bitreich.org 70 i Err bitreich.org 70 iDiffstat: Err bitreich.org 70 i M Makefile | 2 -- Err bitreich.org 70 i D TODO | 8 -------- Err bitreich.org 70 i D buffer.c | 119 ------------------------------- Err bitreich.org 70 i D draw.c | 158 ------------------------------- Err bitreich.org 70 i D input.c | 221 ------------------------------- Err bitreich.org 70 i D iomenu.1 | 78 ------------------------------- Err bitreich.org 70 i M iomenu.c | 522 ++++++++++++++++++++++++++++++- Err bitreich.org 70 i D iomenu.h | 61 ------------------------------- Err bitreich.org 70 i Err bitreich.org 70 i8 files changed, 516 insertions(+), 653 deletions(-) Err bitreich.org 70 i--- Err bitreich.org 70 1diff --git a/Makefile b/Makefile /scm/iomenu/file/Makefile.gph bitreich.org 70 i@@ -3,8 +3,6 @@ OBJ = ${SRC:.c=.o} Err bitreich.org 70 i Err bitreich.org 70 i all: clean iomenu Err bitreich.org 70 i Err bitreich.org 70 i-iomenu: buffer.c draw.c input.c Err bitreich.org 70 i- Err bitreich.org 70 i clean: Err bitreich.org 70 i rm -f iomenu ${OBJ} Err bitreich.org 70 i Err bitreich.org 70 1diff --git a/TODO b/TODO /scm/iomenu/file/TODO.gph bitreich.org 70 i@@ -1,8 +0,0 @@ Err bitreich.org 70 i-- Check return values for every function that may fail. Err bitreich.org 70 i- Err bitreich.org 70 i-- Add support for a default input string (when I will need it or if Err bitreich.org 70 i- someone ask for it). Err bitreich.org 70 i- Err bitreich.org 70 i-- Fix the input shifting the line count by 1. Err bitreich.org 70 i- Err bitreich.org 70 i-- Case insensitive match. Err bitreich.org 70 1diff --git a/buffer.c b/buffer.c /scm/iomenu/file/buffer.c.gph bitreich.org 70 i@@ -1,119 +0,0 @@ Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i- Err bitreich.org 70 i-#include "iomenu.h" Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Fill the buffer apropriately with the lines Err bitreich.org 70 i- */ Err bitreich.org 70 i-void Err bitreich.org 70 i-fill_buffer(void) Err bitreich.org 70 i-{ Err bitreich.org 70 i- extern Line **buffer; Err bitreich.org 70 i- Err bitreich.org 70 i- char s[LINE_SIZE]; Err bitreich.org 70 i- size_t size = 1; Err bitreich.org 70 i- Err bitreich.org 70 i- buffer = malloc(sizeof(Line) * 2 << 4); Err bitreich.org 70 i- Err bitreich.org 70 i- input[0] = '\0'; Err bitreich.org 70 i- total = matching = 1; Err bitreich.org 70 i- Err bitreich.org 70 i- /* read the file into an array of lines */ Err bitreich.org 70 i- for (; fgets(s, LINE_SIZE, stdin); total++, matching++) { Err bitreich.org 70 i- if (total > size) { Err bitreich.org 70 i- size *= 2; Err bitreich.org 70 i- if (!realloc(buffer, size * sizeof(Line))) Err bitreich.org 70 i- die("realloc"); Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- buffer[total]->text[strlen(s) - 1] = '\0'; Err bitreich.org 70 i- buffer[total]->match = 1; /* empty input match everything */ Err bitreich.org 70 i- } Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-void Err bitreich.org 70 i-free_buffer(Line **buffer) Err bitreich.org 70 i-{ Err bitreich.org 70 i- Line *next = NULL; Err bitreich.org 70 i- Err bitreich.org 70 i- for (; total > 0; total--) Err bitreich.org 70 i- free(buffer[total - 1]->text); Err bitreich.org 70 i- Err bitreich.org 70 i- free(buffer); Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * If inc is 1, it will only check already matching lines. Err bitreich.org 70 i- * If inc is 0, it will only check non-matching lines. Err bitreich.org 70 i- */ Err bitreich.org 70 i-void Err bitreich.org 70 i-filter_lines(int inc) Err bitreich.org 70 i-{ Err bitreich.org 70 i- char **tokv = NULL; Err bitreich.org 70 i- char *s, buf[sizeof(input)]; Err bitreich.org 70 i- size_t n = 0, tokc = 0; Err bitreich.org 70 i- Err bitreich.org 70 i- /* tokenize input from space characters, this comes from dmenu */ Err bitreich.org 70 i- strcpy(buf, input); Err bitreich.org 70 i- for (s = strtok(buf, " "); s; s = strtok(NULL, " ")) { Err bitreich.org 70 i- if (++tokc > n && !(tokv = realloc(tokv, ++n * sizeof(*tokv)))) Err bitreich.org 70 i- die("realloc"); Err bitreich.org 70 i- Err bitreich.org 70 i- tokv[tokc - 1] = s; Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- /* match lines */ Err bitreich.org 70 i- matching = 0; Err bitreich.org 70 i- for (int i = 0; i < total; i++) { Err bitreich.org 70 i- Err bitreich.org 70 i- if (input[0] && strcmp(input, buffer[i]->text) == 0) { Err bitreich.org 70 i- buffer[i]->match = 1; Err bitreich.org 70 i- Err bitreich.org 70 i- } else if ((inc && buffer[i]->match) || (!inc && !buffer[i]->match)) { Err bitreich.org 70 i- buffer[i]->match = match_line(buffer[i], tokv, tokc); Err bitreich.org 70 i- matching += buffer[i]->match; Err bitreich.org 70 i- } Err bitreich.org 70 i- } Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Return whecher the line matches every string from tokv. Err bitreich.org 70 i- */ Err bitreich.org 70 i-int Err bitreich.org 70 i-match_line(Line *line, char **tokv, size_t tokc) Err bitreich.org 70 i-{ Err bitreich.org 70 i- for (int i = 0; i < tokc; i++) Err bitreich.org 70 i- if (!!strstr(buffer[i]->text, tokv[i])) Err bitreich.org 70 i- return 0; Err bitreich.org 70 i- Err bitreich.org 70 i- return 1; Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Seek the previous matching line, or NULL if none matches. Err bitreich.org 70 i- */ Err bitreich.org 70 i-Line * Err bitreich.org 70 i-matching_prev(int pos) Err bitreich.org 70 i-{ Err bitreich.org 70 i- for (; pos > 0 && !buffer[pos]->match; pos--); Err bitreich.org 70 i- return buffer[pos]; Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Seek the next matching line, or NULL if none matches. Err bitreich.org 70 i- */ Err bitreich.org 70 i-Line * Err bitreich.org 70 i-matching_next(int pos) Err bitreich.org 70 i-{ Err bitreich.org 70 i- for (; pos < total && !buffer[pos]->match; pos++); Err bitreich.org 70 i- return buffer[pos]; Err bitreich.org 70 i-} Err bitreich.org 70 1diff --git a/draw.c b/draw.c /scm/iomenu/file/draw.c.gph bitreich.org 70 i@@ -1,158 +0,0 @@ Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i- Err bitreich.org 70 i-#include "iomenu.h" Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Print a line to stderr. Err bitreich.org 70 i- */ Err bitreich.org 70 i-void Err bitreich.org 70 i-draw_line(Line *line, const int cols) Err bitreich.org 70 i-{ Err bitreich.org 70 i- char output[LINE_SIZE] = "\033[K"; Err bitreich.org 70 i- int n = 0; Err bitreich.org 70 i- Err bitreich.org 70 i- if (opt_line_numbers) { Err bitreich.org 70 i- strcat(output, buffer[current] ? "\033[1;37m" : "\033[1;30m"); Err bitreich.org 70 i- sprintf(output + strlen(output), "%7d\033[m ", line->number); Err bitreich.org 70 i- } else { Err bitreich.org 70 i- strcat(output, buffer[current] ? "\033[1;31m > " : " "); Err bitreich.org 70 i- } Err bitreich.org 70 i- n += 8; Err bitreich.org 70 i- Err bitreich.org 70 i- /* highlight buffer[current] line */ Err bitreich.org 70 i- if (buffer[current]) Err bitreich.org 70 i- strcat(output, "\033[1;33m"); Err bitreich.org 70 i- Err bitreich.org 70 i- /* content */ Err bitreich.org 70 i- strncat(output, line->content, cols - n); Err bitreich.org 70 i- n += strlen(line->content); Err bitreich.org 70 i- Err bitreich.org 70 i- /* MAX with '1' as \033[0C still move 1 to the right */ Err bitreich.org 70 i- sprintf(output + strlen(output), "\033[%dC", Err bitreich.org 70 i- MAX(1, 40 - n)); Err bitreich.org 70 i- n += MAX(1, 40 - n); Err bitreich.org 70 i- strcat(output, "\033[m\n"); Err bitreich.org 70 i- Err bitreich.org 70 i- fputs(output, stderr); Err bitreich.org 70 i- Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Print all the lines from an array of pointer to lines. Err bitreich.org 70 i- * Err bitreich.org 70 i- * The total number oflines printed shall not excess 'count'. Err bitreich.org 70 i- */ Err bitreich.org 70 i-void Err bitreich.org 70 i-draw_lines( int count, int cols) Err bitreich.org 70 i-{ Err bitreich.org 70 i- Line *line = buffer[current]; Err bitreich.org 70 i- int i = 0; Err bitreich.org 70 i- int j = 0; Err bitreich.org 70 i- Err bitreich.org 70 i- /* seek back from buffer[current] line to the first line to print */ Err bitreich.org 70 i- while (line && i < count - OFFSET) { Err bitreich.org 70 i- i = line->matches ? i + 1 : i; Err bitreich.org 70 i- line = line->prev; Err bitreich.org 70 i- } Err bitreich.org 70 i- line = line ? line : first; Err bitreich.org 70 i- Err bitreich.org 70 i- /* print up to count lines that match the input */ Err bitreich.org 70 i- while (line && j < count) { Err bitreich.org 70 i- if (line->matches) { Err bitreich.org 70 i- draw_line(line, line == buffer[current], cols); Err bitreich.org 70 i- j++; Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- line = line->next; Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- /* continue up to the end of the screen clearing it */ Err bitreich.org 70 i- for (; j < count; j++) Err bitreich.org 70 i- fputs("\r\033[K\n", stderr); Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Update the screen interface and print all candidates. Err bitreich.org 70 i- * Err bitreich.org 70 i- * This also has to clear the previous lines. Err bitreich.org 70 i- */ Err bitreich.org 70 i-void Err bitreich.org 70 i-draw_screen( int tty_fd) Err bitreich.org 70 i-{ Err bitreich.org 70 i- struct winsize w; Err bitreich.org 70 i- int count; Err bitreich.org 70 i- Err bitreich.org 70 i- if (ioctl(tty_fd, TIOCGWINSZ, &w) < 0) Err bitreich.org 70 i- die("could not get terminal size"); Err bitreich.org 70 i- Err bitreich.org 70 i- count = MIN(opt_lines, w.ws_row - 2); Err bitreich.org 70 i- Err bitreich.org 70 i- fputs("\n", stderr); Err bitreich.org 70 i- draw_lines(count, w.ws_col); Err bitreich.org 70 i- Err bitreich.org 70 i- /* go up to the prompt position and update it */ Err bitreich.org 70 i- fprintf(stderr, "\033[%dA", count + 1); Err bitreich.org 70 i- draw_prompt(w.ws_col); Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-void Err bitreich.org 70 i-draw_clear(int lines) Err bitreich.org 70 i-{ Err bitreich.org 70 i- int i; Err bitreich.org 70 i- Err bitreich.org 70 i- for (i = 0; i < lines + 1; i++) Err bitreich.org 70 i- fputs("\r\033[K\n", stderr); Err bitreich.org 70 i- fprintf(stderr, "\033[%dA", lines + 1); Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Print the prompt, before the input, with the number of candidates that Err bitreich.org 70 i- * match. Err bitreich.org 70 i- */ Err bitreich.org 70 i-void Err bitreich.org 70 i-draw_prompt(int cols) Err bitreich.org 70 i-{ Err bitreich.org 70 i- size_t i; Err bitreich.org 70 i- int matching = matching; Err bitreich.org 70 i- int total = total; Err bitreich.org 70 i- Err bitreich.org 70 i- /* for the '/' separator between the numbers */ Err bitreich.org 70 i- cols--; Err bitreich.org 70 i- Err bitreich.org 70 i- /* number of digits */ Err bitreich.org 70 i- for (i = matching; i; i /= 10, cols--); Err bitreich.org 70 i- for (i = total; i; i /= 10, cols--); Err bitreich.org 70 i- cols -= !matching ? 1 : 0; /* 0 also has one digit*/ Err bitreich.org 70 i- Err bitreich.org 70 i- /* actual prompt */ Err bitreich.org 70 i- fprintf(stderr, "\r%-6s\033[K\033[1m>\033[m ", opt_prompt); Err bitreich.org 70 i- cols -= 2 + MAX(strlen(opt_prompt), 6); Err bitreich.org 70 i- Err bitreich.org 70 i- /* input without overflowing terminal width */ Err bitreich.org 70 i- for (i = 0; i < strlen(input) && cols > 0; cols--, i++) Err bitreich.org 70 i- fputc(input[i], stderr); Err bitreich.org 70 i- Err bitreich.org 70 i- /* save the cursor position at the end of the input */ Err bitreich.org 70 i- fputs("\033[s", stderr); Err bitreich.org 70 i- Err bitreich.org 70 i- /* grey */ Err bitreich.org 70 i- fputs("\033[1;30m", stderr); Err bitreich.org 70 i- Err bitreich.org 70 i- /* go to the end of the line */ Err bitreich.org 70 i- fprintf(stderr, "\033[%dC", cols); Err bitreich.org 70 i- Err bitreich.org 70 i- /* total match and line count at the end of the line */ Err bitreich.org 70 i- fprintf(stderr, "%d/%d", matching, total); Err bitreich.org 70 i- Err bitreich.org 70 i- /* restore cursor position at the end of the input */ Err bitreich.org 70 i- fputs("\033[m\033[u", stderr); Err bitreich.org 70 i- Err bitreich.org 70 i-} Err bitreich.org 70 1diff --git a/input.c b/input.c /scm/iomenu/file/input.c.gph bitreich.org 70 i@@ -1,221 +0,0 @@ Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i- Err bitreich.org 70 i-#include "iomenu.h" Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Listen for the user input and call the appropriate functions. Err bitreich.org 70 i- */ Err bitreich.org 70 i-int Err bitreich.org 70 i-input_get(int tty_fd) Err bitreich.org 70 i-{ Err bitreich.org 70 i- FILE *tty_fp = fopen("/dev/tty", "r"); Err bitreich.org 70 i- int exit_code; Err bitreich.org 70 i- Err bitreich.org 70 i- /* receive one character at a time from the terminal */ Err bitreich.org 70 i- struct termios termio_old = set_terminal(tty_fd); Err bitreich.org 70 i- Err bitreich.org 70 i- while ((exit_code = input_key(tty_fp)) == CONTINUE) Err bitreich.org 70 i- draw_screen(tty_fd); Err bitreich.org 70 i- Err bitreich.org 70 i- /* resets the terminal to the previous state. */ Err bitreich.org 70 i- tcsetattr(tty_fd, TCSANOW, &termio_old); Err bitreich.org 70 i- Err bitreich.org 70 i- fclose(tty_fp); Err bitreich.org 70 i- Err bitreich.org 70 i- return exit_code; Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Perform action associated with key Err bitreich.org 70 i- */ Err bitreich.org 70 i-int Err bitreich.org 70 i-input_key(FILE *tty_fp) Err bitreich.org 70 i-{ Err bitreich.org 70 i- extern char *input; Err bitreich.org 70 i- Err bitreich.org 70 i- char key = fgetc(tty_fp); Err bitreich.org 70 i- Err bitreich.org 70 i- if (key == '\n') { Err bitreich.org 70 i- action_print_selection(0); Err bitreich.org 70 i- return EXIT_SUCCESS; Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- switch (key) { Err bitreich.org 70 i- Err bitreich.org 70 i- case CONTROL('C'): Err bitreich.org 70 i- draw_clear(opt_lines); Err bitreich.org 70 i- return EXIT_FAILURE; Err bitreich.org 70 i- Err bitreich.org 70 i- case CONTROL('U'): Err bitreich.org 70 i- input[0] = '\0'; Err bitreich.org 70 i- current = 0; Err bitreich.org 70 i- filter_lines(0); Err bitreich.org 70 i- action_jump(1); Err bitreich.org 70 i- action_jump(-1); Err bitreich.org 70 i- break; Err bitreich.org 70 i- Err bitreich.org 70 i- case CONTROL('W'): Err bitreich.org 70 i- action_remove_word_input(); Err bitreich.org 70 i- filter_lines(0); Err bitreich.org 70 i- break; Err bitreich.org 70 i- Err bitreich.org 70 i- case 127: Err bitreich.org 70 i- case CONTROL('H'): /* backspace */ Err bitreich.org 70 i- input[strlen(input) - 1] = '\0'; Err bitreich.org 70 i- filter_lines(0); Err bitreich.org 70 i- action_jump(0); Err bitreich.org 70 i- break; Err bitreich.org 70 i- Err bitreich.org 70 i- case CONTROL('N'): Err bitreich.org 70 i- action_jump(1); Err bitreich.org 70 i- break; Err bitreich.org 70 i- Err bitreich.org 70 i- case CONTROL('P'): Err bitreich.org 70 i- action_jump(-1); Err bitreich.org 70 i- break; Err bitreich.org 70 i- Err bitreich.org 70 i- case CONTROL('I'): /* tab */ Err bitreich.org 70 i- strcpy(input, buffer[current]->text); Err bitreich.org 70 i- filter_lines(1); Err bitreich.org 70 i- break; Err bitreich.org 70 i- Err bitreich.org 70 i- case CONTROL('J'): Err bitreich.org 70 i- case CONTROL('M'): /* enter */ Err bitreich.org 70 i- action_print_selection(0); Err bitreich.org 70 i- return EXIT_SUCCESS; Err bitreich.org 70 i- Err bitreich.org 70 i- case CONTROL('@'): /* ctrl + space */ Err bitreich.org 70 i- action_print_selection(1); Err bitreich.org 70 i- return EXIT_SUCCESS; Err bitreich.org 70 i- Err bitreich.org 70 i- case CONTROL('['): /* escape */ Err bitreich.org 70 i- switch (fgetc(tty_fp)) { Err bitreich.org 70 i- Err bitreich.org 70 i- case 'O': /* arrow keys */ Err bitreich.org 70 i- switch (fgetc(tty_fp)) { Err bitreich.org 70 i- Err bitreich.org 70 i- case 'A': /* up */ Err bitreich.org 70 i- action_jump(-1); Err bitreich.org 70 i- break; Err bitreich.org 70 i- Err bitreich.org 70 i- case 'B': /* Down */ Err bitreich.org 70 i- action_jump(1); Err bitreich.org 70 i- break; Err bitreich.org 70 i- } Err bitreich.org 70 i- break; Err bitreich.org 70 i- Err bitreich.org 70 i- case '[': /* page control */ Err bitreich.org 70 i- key = fgetc(tty_fp); Err bitreich.org 70 i- switch(fgetc(tty_fp)) { Err bitreich.org 70 i- Err bitreich.org 70 i- case '~': Err bitreich.org 70 i- switch (key) { Err bitreich.org 70 i- Err bitreich.org 70 i- case '5': /* page up */ Err bitreich.org 70 i- action_jump(-10); Err bitreich.org 70 i- break; Err bitreich.org 70 i- Err bitreich.org 70 i- case '6': /* page down */ Err bitreich.org 70 i- action_jump(10); Err bitreich.org 70 i- break; Err bitreich.org 70 i- } Err bitreich.org 70 i- break; Err bitreich.org 70 i- } Err bitreich.org 70 i- break; Err bitreich.org 70 i- } Err bitreich.org 70 i- break; Err bitreich.org 70 i- Err bitreich.org 70 i- default: Err bitreich.org 70 i- action_add_character(key); Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- return CONTINUE; Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Set the buffer[current] line to next/previous/any matching line. Err bitreich.org 70 i- */ Err bitreich.org 70 i-void Err bitreich.org 70 i-action_jump(int direction) Err bitreich.org 70 i-{ Err bitreich.org 70 i- Line * line = buffer[current]; Err bitreich.org 70 i- Line * result = line; Err bitreich.org 70 i- Err bitreich.org 70 i- if (direction == 0 && !buffer[current]->match) { Err bitreich.org 70 i- line = matching_next(current); Err bitreich.org 70 i- line = line ? line : matching_prev(current); Err bitreich.org 70 i- result = line ? line : result; Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- for (; direction < 0 && line; direction++) { Err bitreich.org 70 i- line = matching_prev(line); Err bitreich.org 70 i- result = line ? line : result; Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- for (; direction > 0 && line; direction--) { Err bitreich.org 70 i- line = matching_next(line); Err bitreich.org 70 i- result = line ? line : result; Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- buffer[current] = result; Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Remove the last word from the buffer's input Err bitreich.org 70 i- */ Err bitreich.org 70 i-void Err bitreich.org 70 i-action_remove_word_input() Err bitreich.org 70 i-{ Err bitreich.org 70 i- size_t len = strlen(input) - 1; Err bitreich.org 70 i- Err bitreich.org 70 i- for (int i = len; i >= 0 && isspace(input[i]); i--) Err bitreich.org 70 i- input[i] = '\0'; Err bitreich.org 70 i- Err bitreich.org 70 i- len = strlen(input) - 1; Err bitreich.org 70 i- for (int i = len; i >= 0 && !isspace(input[i]); i--) Err bitreich.org 70 i- input[i] = '\0'; Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Add a character to the buffer input and filter lines again. Err bitreich.org 70 i- */ Err bitreich.org 70 i-void Err bitreich.org 70 i-action_add_character(char key) Err bitreich.org 70 i-{ Err bitreich.org 70 i- size_t len = strlen(input); Err bitreich.org 70 i- Err bitreich.org 70 i- if (isprint(key)) { Err bitreich.org 70 i- input[len] = key; Err bitreich.org 70 i- input[len + 1] = '\0'; Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- filter_lines(1); Err bitreich.org 70 i- Err bitreich.org 70 i- action_jump(0); Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/* Err bitreich.org 70 i- * Send the selection to stdout. Err bitreich.org 70 i- */ Err bitreich.org 70 i-void Err bitreich.org 70 i-action_print_selection(int return_input) Err bitreich.org 70 i-{ Err bitreich.org 70 i- fputs("\r\033[K", stderr); Err bitreich.org 70 i- Err bitreich.org 70 i- if (return_input || !matching) { Err bitreich.org 70 i- puts(input); Err bitreich.org 70 i- Err bitreich.org 70 i- } else if (matching > 0) { Err bitreich.org 70 i- puts(buffer[current]->text); Err bitreich.org 70 i- } Err bitreich.org 70 i-} Err bitreich.org 70 1diff --git a/iomenu.1 b/iomenu.1 /scm/iomenu/file/iomenu.1.gph bitreich.org 70 i@@ -1,78 +0,0 @@ Err bitreich.org 70 i-.Dd Mars 16 2016 Err bitreich.org 70 i-.Dt IOMENU 1 Err bitreich.org 70 i-.Os Err bitreich.org 70 i-. Err bitreich.org 70 i-.Sh NAME Err bitreich.org 70 i-. Err bitreich.org 70 i-.Nm iomenu Err bitreich.org 70 i-.Op Fl nNHksl Err bitreich.org 70 i-. Err bitreich.org 70 i-.Sh DESCRIPTION Err bitreich.org 70 i-. Err bitreich.org 70 i-The Err bitreich.org 70 i-.Nm Err bitreich.org 70 i-utility filters lines form stdin interactively with the keyboard, and print Err bitreich.org 70 i-the selected line to stdout. Err bitreich.org 70 i-.Pp Err bitreich.org 70 i-Lower case switches are for the interface, uppercase switches are for Err bitreich.org 70 i-input/output. Err bitreich.org 70 i-.Bl -tag Err bitreich.org 70 i-.It Fl n Err bitreich.org 70 i-Display line numbers in interface. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Fl N Err bitreich.org 70 i-Return the line number rather than the match. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Fl H Err bitreich.org 70 i-Return the current header that the selection belongs to in addition to the Err bitreich.org 70 i-match, delimited by a tab. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Fl k Cm key Err bitreich.org 70 i-Key to use to validate current selection in addition to Enter. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Fl s Cm separator Err bitreich.org 70 i-Character separating the content from the comments. Every character after Err bitreich.org 70 i-the separator will be considered as comment and will be grayed and aligned Err bitreich.org 70 i-in the interface. Err bitreich.org 70 i-.Pp Err bitreich.org 70 i-If a separator is at the beginning of a line (without leading space), the Err bitreich.org 70 i-line is considered as a section header, and it will always be displayed Err bitreich.org 70 i-regardless if it matches or not. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Fl l Cm lines Err bitreich.org 70 i-Number of lines to display at once. Default is 30. Err bitreich.org 70 i-.El Err bitreich.org 70 i-. Err bitreich.org 70 i-. Err bitreich.org 70 i-.Sh KEYBINDINGS Err bitreich.org 70 i-. Err bitreich.org 70 i-.Bl -tag Err bitreich.org 70 i-.It Cm ^M, ^J, Enter Err bitreich.org 70 i-Print the matched line to stdout and exit. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Cm ^@, ^Space Err bitreich.org 70 i-Print the content of the input rather than the matched line to stdout and exit. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Cm ^P / ^N, Up / Down Err bitreich.org 70 i-Navigate to the previous / next line. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Cm PageUp / PageDown Err bitreich.org 70 i-Navigate 10 lines up / down. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Cm ^I, Tab Err bitreich.org 70 i-Set input to the currently highlighted candidate, then cycle through candidate Err bitreich.org 70 i-list. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Cm ^H, Backspace Err bitreich.org 70 i-Delete one char backward, but if there is no char Err bitreich.org 70 i-backward, it should return an error code of 1. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Cm ^C Err bitreich.org 70 i-Cancel, and make filter return the error code of 1. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Cm ^W Err bitreich.org 70 i-Deletes the last entered word. Err bitreich.org 70 i-. Err bitreich.org 70 i-.It Cm ^U Err bitreich.org 70 i-Deletes the entire input and jump to the first line. Err bitreich.org 70 i-.El Err bitreich.org 70 1diff --git a/iomenu.c b/iomenu.c /scm/iomenu/file/iomenu.c.gph bitreich.org 70 i@@ -1,8 +1,3 @@ Err bitreich.org 70 i-opt_line_numbers = 0; Err bitreich.org 70 i-opt_print_number = 0; Err bitreich.org 70 i-opt_lines = 30; Err bitreich.org 70 i-opt_prompt = ""; Err bitreich.org 70 i- Err bitreich.org 70 i #include Err bitreich.org 70 i #include Err bitreich.org 70 i #include Err bitreich.org 70 i@@ -13,7 +8,522 @@ opt_prompt = ""; Err bitreich.org 70 i Err bitreich.org 70 i #include Err bitreich.org 70 i Err bitreich.org 70 i-#include "iomenu.h" Err bitreich.org 70 i+ Err bitreich.org 70 i+/*--- constants --------------------------------------------------------------*/ Err bitreich.org 70 i+ Err bitreich.org 70 i+#define LINE_SIZE 1024 Err bitreich.org 70 i+#define OFFSET 5 Err bitreich.org 70 i+#define CONTINUE 2 /* as opposed to EXIT_SUCCESS and EXIT_FAILURE */ Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/*--- macros -----------------------------------------------------------------*/ Err bitreich.org 70 i+ Err bitreich.org 70 i+#define CONTROL(char) (char ^ 0x40) Err bitreich.org 70 i+#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) Err bitreich.org 70 i+#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/*--- structures -------------------------------------------------------------*/ Err bitreich.org 70 i+ Err bitreich.org 70 i+typedef struct Line { Err bitreich.org 70 i+ char *text; /* sent as output and matched by input */ Err bitreich.org 70 i+ int match; /* whether it matches buffer's input */ Err bitreich.org 70 i+} Line; Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/*--- variables --------------------------------------------------------------*/ Err bitreich.org 70 i+ Err bitreich.org 70 i+Line **buffer; Err bitreich.org 70 i+int current, matching, total; Err bitreich.org 70 i+int opt_lines; Err bitreich.org 70 i+char *opt_prompt, *input; Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/*--- functions --------------------------------------------------------------*/ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Fill the buffer apropriately with the lines Err bitreich.org 70 i+ */ Err bitreich.org 70 i+void Err bitreich.org 70 i+fill_buffer(void) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ extern Line **buffer; Err bitreich.org 70 i+ Err bitreich.org 70 i+ char s[LINE_SIZE]; Err bitreich.org 70 i+ size_t size = 1; Err bitreich.org 70 i+ Err bitreich.org 70 i+ buffer = malloc(sizeof(Line) * 2 << 4); Err bitreich.org 70 i+ Err bitreich.org 70 i+ input[0] = '\0'; Err bitreich.org 70 i+ total = matching = 1; Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* read the file into an array of lines */ Err bitreich.org 70 i+ for (; fgets(s, LINE_SIZE, stdin); total++, matching++) { Err bitreich.org 70 i+ if (total > size) { Err bitreich.org 70 i+ size *= 2; Err bitreich.org 70 i+ if (!realloc(buffer, size * sizeof(Line))) Err bitreich.org 70 i+ die("realloc"); Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ buffer[total]->text[strlen(s) - 1] = '\0'; Err bitreich.org 70 i+ buffer[total]->match = 1; /* empty input match everything */ Err bitreich.org 70 i+ } Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+free_buffer(Line **buffer) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ Line *next = NULL; Err bitreich.org 70 i+ Err bitreich.org 70 i+ for (; total > 0; total--) Err bitreich.org 70 i+ free(buffer[total - 1]->text); Err bitreich.org 70 i+ Err bitreich.org 70 i+ free(buffer); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * If inc is 1, it will only check already matching lines. Err bitreich.org 70 i+ * If inc is 0, it will only check non-matching lines. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+void Err bitreich.org 70 i+filter_lines(int inc) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ char **tokv = NULL; Err bitreich.org 70 i+ char *s, buf[sizeof(input)]; Err bitreich.org 70 i+ size_t n = 0, tokc = 0; Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* tokenize input from space characters, this comes from dmenu */ Err bitreich.org 70 i+ strcpy(buf, input); Err bitreich.org 70 i+ for (s = strtok(buf, " "); s; s = strtok(NULL, " ")) { Err bitreich.org 70 i+ if (++tokc > n && !(tokv = realloc(tokv, ++n * sizeof(*tokv)))) Err bitreich.org 70 i+ die("realloc"); Err bitreich.org 70 i+ Err bitreich.org 70 i+ tokv[tokc - 1] = s; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* match lines */ Err bitreich.org 70 i+ matching = 0; Err bitreich.org 70 i+ for (int i = 0; i < total; i++) { Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (input[0] && strcmp(input, buffer[i]->text) == 0) { Err bitreich.org 70 i+ buffer[i]->match = 1; Err bitreich.org 70 i+ Err bitreich.org 70 i+ } else if ((inc && buffer[i]->match) || (!inc && !buffer[i]->match)) { Err bitreich.org 70 i+ buffer[i]->match = match_line(buffer[i], tokv, tokc); Err bitreich.org 70 i+ matching += buffer[i]->match; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ } Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Return whecher the line matches every string from tokv. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+int Err bitreich.org 70 i+match_line(Line *line, char **tokv, size_t tokc) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ for (int i = 0; i < tokc; i++) Err bitreich.org 70 i+ if (!!strstr(buffer[i]->text, tokv[i])) Err bitreich.org 70 i+ return 0; Err bitreich.org 70 i+ Err bitreich.org 70 i+ return 1; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Seek the previous matching line, or NULL if none matches. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+Line * Err bitreich.org 70 i+matching_prev(int pos) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ for (; pos > 0 && !buffer[pos]->match; pos--); Err bitreich.org 70 i+ return buffer[pos]; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Seek the next matching line, or NULL if none matches. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+Line * Err bitreich.org 70 i+matching_next(int pos) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ for (; pos < total && !buffer[pos]->match; pos++); Err bitreich.org 70 i+ return buffer[pos]; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Print a line to stderr. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+void Err bitreich.org 70 i+draw_line(Line *line, const int cols) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ char output[LINE_SIZE] = "\033[K"; Err bitreich.org 70 i+ int n = 0; Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (opt_line_numbers) { Err bitreich.org 70 i+ strcat(output, buffer[current] ? "\033[1;37m" : "\033[1;30m"); Err bitreich.org 70 i+ sprintf(output + strlen(output), "%7d\033[m ", line->number); Err bitreich.org 70 i+ } else { Err bitreich.org 70 i+ strcat(output, buffer[current] ? "\033[1;31m > " : " "); Err bitreich.org 70 i+ } Err bitreich.org 70 i+ n += 8; Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* highlight buffer[current] line */ Err bitreich.org 70 i+ if (buffer[current]) Err bitreich.org 70 i+ strcat(output, "\033[1;33m"); Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* content */ Err bitreich.org 70 i+ strncat(output, line->content, cols - n); Err bitreich.org 70 i+ n += strlen(line->content); Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* MAX with '1' as \033[0C still move 1 to the right */ Err bitreich.org 70 i+ sprintf(output + strlen(output), "\033[%dC", Err bitreich.org 70 i+ MAX(1, 40 - n)); Err bitreich.org 70 i+ n += MAX(1, 40 - n); Err bitreich.org 70 i+ strcat(output, "\033[m\n"); Err bitreich.org 70 i+ Err bitreich.org 70 i+ fputs(output, stderr); Err bitreich.org 70 i+ Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Print all the lines from an array of pointer to lines. Err bitreich.org 70 i+ * Err bitreich.org 70 i+ * The total number oflines printed shall not excess 'count'. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+void Err bitreich.org 70 i+draw_lines( int count, int cols) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ Line *line = buffer[current]; Err bitreich.org 70 i+ int i = 0; Err bitreich.org 70 i+ int j = 0; Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* seek back from buffer[current] line to the first line to print */ Err bitreich.org 70 i+ while (line && i < count - OFFSET) { Err bitreich.org 70 i+ i = line->matches ? i + 1 : i; Err bitreich.org 70 i+ line = line->prev; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ line = line ? line : first; Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* print up to count lines that match the input */ Err bitreich.org 70 i+ while (line && j < count) { Err bitreich.org 70 i+ if (line->matches) { Err bitreich.org 70 i+ draw_line(line, line == buffer[current], cols); Err bitreich.org 70 i+ j++; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ line = line->next; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* continue up to the end of the screen clearing it */ Err bitreich.org 70 i+ for (; j < count; j++) Err bitreich.org 70 i+ fputs("\r\033[K\n", stderr); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Update the screen interface and print all candidates. Err bitreich.org 70 i+ * Err bitreich.org 70 i+ * This also has to clear the previous lines. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+void Err bitreich.org 70 i+draw_screen( int tty_fd) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ struct winsize w; Err bitreich.org 70 i+ int count; Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (ioctl(tty_fd, TIOCGWINSZ, &w) < 0) Err bitreich.org 70 i+ die("could not get terminal size"); Err bitreich.org 70 i+ Err bitreich.org 70 i+ count = MIN(opt_lines, w.ws_row - 2); Err bitreich.org 70 i+ Err bitreich.org 70 i+ fputs("\n", stderr); Err bitreich.org 70 i+ draw_lines(count, w.ws_col); Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* go up to the prompt position and update it */ Err bitreich.org 70 i+ fprintf(stderr, "\033[%dA", count + 1); Err bitreich.org 70 i+ draw_prompt(w.ws_col); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+draw_clear(int lines) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ int i; Err bitreich.org 70 i+ Err bitreich.org 70 i+ for (i = 0; i < lines + 1; i++) Err bitreich.org 70 i+ fputs("\r\033[K\n", stderr); Err bitreich.org 70 i+ fprintf(stderr, "\033[%dA", lines + 1); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Print the prompt, before the input, with the number of candidates that Err bitreich.org 70 i+ * match. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+void Err bitreich.org 70 i+draw_prompt(int cols) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ size_t i; Err bitreich.org 70 i+ int matching = matching; Err bitreich.org 70 i+ int total = total; Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* for the '/' separator between the numbers */ Err bitreich.org 70 i+ cols--; Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* number of digits */ Err bitreich.org 70 i+ for (i = matching; i; i /= 10, cols--); Err bitreich.org 70 i+ for (i = total; i; i /= 10, cols--); Err bitreich.org 70 i+ cols -= !matching ? 1 : 0; /* 0 also has one digit*/ Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* actual prompt */ Err bitreich.org 70 i+ fprintf(stderr, "\r%-6s\033[K\033[1m>\033[m ", opt_prompt); Err bitreich.org 70 i+ cols -= 2 + MAX(strlen(opt_prompt), 6); Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* input without overflowing terminal width */ Err bitreich.org 70 i+ for (i = 0; i < strlen(input) && cols > 0; cols--, i++) Err bitreich.org 70 i+ fputc(input[i], stderr); Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* save the cursor position at the end of the input */ Err bitreich.org 70 i+ fputs("\033[s", stderr); Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* grey */ Err bitreich.org 70 i+ fputs("\033[1;30m", stderr); Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* go to the end of the line */ Err bitreich.org 70 i+ fprintf(stderr, "\033[%dC", cols); Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* total match and line count at the end of the line */ Err bitreich.org 70 i+ fprintf(stderr, "%d/%d", matching, total); Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* restore cursor position at the end of the input */ Err bitreich.org 70 i+ fputs("\033[m\033[u", stderr); Err bitreich.org 70 i+ Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Listen for the user input and call the appropriate functions. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+int Err bitreich.org 70 i+input_get(int tty_fd) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ FILE *tty_fp = fopen("/dev/tty", "r"); Err bitreich.org 70 i+ int exit_code; Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* receive one character at a time from the terminal */ Err bitreich.org 70 i+ struct termios termio_old = set_terminal(tty_fd); Err bitreich.org 70 i+ Err bitreich.org 70 i+ while ((exit_code = input_key(tty_fp)) == CONTINUE) Err bitreich.org 70 i+ draw_screen(tty_fd); Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* resets the terminal to the previous state. */ Err bitreich.org 70 i+ tcsetattr(tty_fd, TCSANOW, &termio_old); Err bitreich.org 70 i+ Err bitreich.org 70 i+ fclose(tty_fp); Err bitreich.org 70 i+ Err bitreich.org 70 i+ return exit_code; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Perform action associated with key Err bitreich.org 70 i+ */ Err bitreich.org 70 i+int Err bitreich.org 70 i+input_key(FILE *tty_fp) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ extern char *input; Err bitreich.org 70 i+ Err bitreich.org 70 i+ char key = fgetc(tty_fp); Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (key == '\n') { Err bitreich.org 70 i+ action_print_selection(0); Err bitreich.org 70 i+ return EXIT_SUCCESS; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ switch (key) { Err bitreich.org 70 i+ Err bitreich.org 70 i+ case CONTROL('C'): Err bitreich.org 70 i+ draw_clear(opt_lines); Err bitreich.org 70 i+ return EXIT_FAILURE; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case CONTROL('U'): Err bitreich.org 70 i+ input[0] = '\0'; Err bitreich.org 70 i+ current = 0; Err bitreich.org 70 i+ filter_lines(0); Err bitreich.org 70 i+ action_jump(1); Err bitreich.org 70 i+ action_jump(-1); Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case CONTROL('W'): Err bitreich.org 70 i+ action_remove_word_input(); Err bitreich.org 70 i+ filter_lines(0); Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case 127: Err bitreich.org 70 i+ case CONTROL('H'): /* backspace */ Err bitreich.org 70 i+ input[strlen(input) - 1] = '\0'; Err bitreich.org 70 i+ filter_lines(0); Err bitreich.org 70 i+ action_jump(0); Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case CONTROL('N'): Err bitreich.org 70 i+ action_jump(1); Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case CONTROL('P'): Err bitreich.org 70 i+ action_jump(-1); Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case CONTROL('I'): /* tab */ Err bitreich.org 70 i+ strcpy(input, buffer[current]->text); Err bitreich.org 70 i+ filter_lines(1); Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case CONTROL('J'): Err bitreich.org 70 i+ case CONTROL('M'): /* enter */ Err bitreich.org 70 i+ action_print_selection(0); Err bitreich.org 70 i+ return EXIT_SUCCESS; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case CONTROL('@'): /* ctrl + space */ Err bitreich.org 70 i+ action_print_selection(1); Err bitreich.org 70 i+ return EXIT_SUCCESS; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case CONTROL('['): /* escape */ Err bitreich.org 70 i+ switch (fgetc(tty_fp)) { Err bitreich.org 70 i+ Err bitreich.org 70 i+ case 'O': /* arrow keys */ Err bitreich.org 70 i+ switch (fgetc(tty_fp)) { Err bitreich.org 70 i+ Err bitreich.org 70 i+ case 'A': /* up */ Err bitreich.org 70 i+ action_jump(-1); Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case 'B': /* Down */ Err bitreich.org 70 i+ action_jump(1); Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case '[': /* page control */ Err bitreich.org 70 i+ key = fgetc(tty_fp); Err bitreich.org 70 i+ switch(fgetc(tty_fp)) { Err bitreich.org 70 i+ Err bitreich.org 70 i+ case '~': Err bitreich.org 70 i+ switch (key) { Err bitreich.org 70 i+ Err bitreich.org 70 i+ case '5': /* page up */ Err bitreich.org 70 i+ action_jump(-10); Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ Err bitreich.org 70 i+ case '6': /* page down */ Err bitreich.org 70 i+ action_jump(10); Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ Err bitreich.org 70 i+ default: Err bitreich.org 70 i+ action_add_character(key); Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ return CONTINUE; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Set the buffer[current] line to next/previous/any matching line. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+void Err bitreich.org 70 i+action_jump(int direction) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ Line * line = buffer[current]; Err bitreich.org 70 i+ Line * result = line; Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (direction == 0 && !buffer[current]->match) { Err bitreich.org 70 i+ line = matching_next(current); Err bitreich.org 70 i+ line = line ? line : matching_prev(current); Err bitreich.org 70 i+ result = line ? line : result; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ for (; direction < 0 && line; direction++) { Err bitreich.org 70 i+ line = matching_prev(line); Err bitreich.org 70 i+ result = line ? line : result; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ for (; direction > 0 && line; direction--) { Err bitreich.org 70 i+ line = matching_next(line); Err bitreich.org 70 i+ result = line ? line : result; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ buffer[current] = result; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Remove the last word from the buffer's input Err bitreich.org 70 i+ */ Err bitreich.org 70 i+void Err bitreich.org 70 i+action_remove_word_input() Err bitreich.org 70 i+{ Err bitreich.org 70 i+ size_t len = strlen(input) - 1; Err bitreich.org 70 i+ Err bitreich.org 70 i+ for (int i = len; i >= 0 && isspace(input[i]); i--) Err bitreich.org 70 i+ input[i] = '\0'; Err bitreich.org 70 i+ Err bitreich.org 70 i+ len = strlen(input) - 1; Err bitreich.org 70 i+ for (int i = len; i >= 0 && !isspace(input[i]); i--) Err bitreich.org 70 i+ input[i] = '\0'; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Add a character to the buffer input and filter lines again. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+void Err bitreich.org 70 i+action_add_character(char key) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ size_t len = strlen(input); Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (isprint(key)) { Err bitreich.org 70 i+ input[len] = key; Err bitreich.org 70 i+ input[len + 1] = '\0'; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ filter_lines(1); Err bitreich.org 70 i+ Err bitreich.org 70 i+ action_jump(0); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * Send the selection to stdout. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+void Err bitreich.org 70 i+action_print_selection(int return_input) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ fputs("\r\033[K", stderr); Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (return_input || !matching) { Err bitreich.org 70 i+ puts(input); Err bitreich.org 70 i+ Err bitreich.org 70 i+ } else if (matching > 0) { Err bitreich.org 70 i+ puts(buffer[current]->text); Err bitreich.org 70 i+ } Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+opt_line_numbers = 0; Err bitreich.org 70 i+opt_print_number = 0; Err bitreich.org 70 i+opt_lines = 30; Err bitreich.org 70 i+opt_prompt = ""; Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i /* Err bitreich.org 70 1diff --git a/iomenu.h b/iomenu.h /scm/iomenu/file/iomenu.h.gph bitreich.org 70 i@@ -1,61 +0,0 @@ Err bitreich.org 70 i-/*--- constants --------------------------------------------------------------*/ Err bitreich.org 70 i- Err bitreich.org 70 i-#define LINE_SIZE 1024 Err bitreich.org 70 i-#define OFFSET 5 Err bitreich.org 70 i-#define CONTINUE 2 /* as opposed to EXIT_SUCCESS and EXIT_FAILURE */ Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/*--- macros -----------------------------------------------------------------*/ Err bitreich.org 70 i- Err bitreich.org 70 i-#define CONTROL(char) (char ^ 0x40) Err bitreich.org 70 i-#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) Err bitreich.org 70 i-#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/*--- structures -------------------------------------------------------------*/ Err bitreich.org 70 i- Err bitreich.org 70 i-typedef struct Line { Err bitreich.org 70 i- char *text; /* sent as output and matched by input */ Err bitreich.org 70 i- int match; /* whether it matches buffer's input */ Err bitreich.org 70 i-} Line; Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/*--- variables --------------------------------------------------------------*/ Err bitreich.org 70 i- Err bitreich.org 70 i-Line **buffer; Err bitreich.org 70 i-int current, matching, total; Err bitreich.org 70 i-int opt_lines; Err bitreich.org 70 i-char *opt_prompt, *input; Err bitreich.org 70 i- Err bitreich.org 70 i- Err bitreich.org 70 i-/*--- functions --------------------------------------------------------------*/ Err bitreich.org 70 i- Err bitreich.org 70 i-/* iomenu */ Err bitreich.org 70 i-void die(const char *); Err bitreich.org 70 i-struct termios set_terminal(int); Err bitreich.org 70 i-void usage(void); Err bitreich.org 70 i- Err bitreich.org 70 i-/* buffer */ Err bitreich.org 70 i-void fill_buffer(void); Err bitreich.org 70 i-void free_buffer(); Err bitreich.org 70 i-Line * add_line(int, char *, char *, Line *); Err bitreich.org 70 i-Line * new_line(char *, char *); Err bitreich.org 70 i-Line * matching_next(int); Err bitreich.org 70 i-Line * matching_prev(int); Err bitreich.org 70 i-int match_line(Line *, char **, size_t); Err bitreich.org 70 i-void filter_lines(int); Err bitreich.org 70 i- Err bitreich.org 70 i-/* draw */ Err bitreich.org 70 i-void draw_screen(int); Err bitreich.org 70 i-void draw_clear(int); Err bitreich.org 70 i-void draw_line(Line *, int); Err bitreich.org 70 i-void draw_lines(int, int); Err bitreich.org 70 i-void draw_prompt(int); Err bitreich.org 70 i- Err bitreich.org 70 i-/* input */ Err bitreich.org 70 i-int input_get(int); Err bitreich.org 70 i-int input_key(FILE *); Err bitreich.org 70 i-void action_jump(int); Err bitreich.org 70 i-void action_print_selection(int); Err bitreich.org 70 i-void action_remove_word_input(); Err bitreich.org 70 i-void action_add_character(char); Err bitreich.org 70 .