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