Handle piped in input, handle resizing better, overall improvements.

This commit is contained in:
Bruce Hill 2019-01-03 20:49:47 -08:00
parent e815927766
commit 991cace0a3

108
ascii.c
View File

@ -29,6 +29,7 @@
#include <curses.h>
#include <ncurses.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -101,10 +102,10 @@ static inline void shift(int dy, int dx) {
move(y+dy, x+dx);
}
#define printwattrs(_attrs,fmt, ...) \
#define printwattrs(_attrs, ...) \
{ char _buf[COL_WIDTH+1];\
chtype _bufch[COL_WIDTH+1];\
sprintf(_buf, fmt, __VA_ARGS__);\
sprintf(_buf, __VA_ARGS__);\
for (int i = 0; i == 0 || _buf[i-1]; i++) _bufch[i] = _buf[i] | _attrs;\
addchstr(_bufch);\
shift(0, strlen(_buf));}
@ -138,42 +139,50 @@ static inline void draw_entry(int i, int scrollx, int attrs)
// Redraw the parts of the ASCII table necessary for the selected item
static void redraw(int selected)
{
static int last_selected = -1, last_scrollx = -1;
static int last_selected = -1, last_scrollx = -1, last_W = -1, last_H = -1;
int selectedx = (selected / (H-1)) * COL_WIDTH;
int scrollx = (selectedx + COL_WIDTH < W) ? 0 : (((selectedx + COL_WIDTH) - W)/COL_WIDTH+1)*COL_WIDTH;
if (selected == last_selected) return;
if (last_selected == -1 || last_scrollx != scrollx) {
if (last_selected == -1 || last_scrollx != scrollx || last_W != W || last_H != H) {
// Redraw everything
erase();
for (int i = 0; i < 128; i++) {
draw_entry(i, scrollx, i == selected ? A_REVERSE : 0);
}
last_scrollx = scrollx;
} else {
last_H = H;
last_W = W;
} else if (selected != last_selected) {
draw_entry(selected, scrollx, A_REVERSE);
draw_entry(last_selected, scrollx, 0);
}
refresh();
last_selected = selected;
}
void draw_output(char *buf, int size)
void draw_output(char *start, char *stop)
{
attron(OUTPUT_LABEL_COLORS);
mvprintw(H-1, 0, " Output:");
attroff(OUTPUT_LABEL_COLORS);
for (int i = 0; i < size; i++) {
char c = buf[i];
if (' ' <= c && c <= '~') { // printable range
printwattrs(OUTPUT_CHAR_COLORS, "%c", c);
addch(' ');
attroff(OUTPUT_LABEL_COLORS);
for (char *c = start; c < stop; c++) {
if (' ' <= *c && *c <= '~') { // printable range
printwattrs(OUTPUT_CHAR_COLORS, "%c", *c);
} else {
printwattrs(OUTPUT_ESCAPE_COLORS, "\\x%02X", c);
printwattrs(OUTPUT_ESCAPE_COLORS, "\\x%02X", *c);
}
}
int y, x;
getyx(stdscr, y, x);
// Clear to end of line
for (int x2 = x; x2 < W; x2++) mvaddch(y, x2, ' ');
move(y, x);
}
int main(int argc, char *argv[])
{
// If any command line args, treat them as numbers
// and print them as ASCII characters
if (argc >= 2) {
for (int i = 1; i < argc; i++) {
putc(atoi(argv[i]), stdout);
@ -181,17 +190,23 @@ int main(int argc, char *argv[])
return 0;
}
size_t buf_size = 256, buf_i = 0;
char *outbuf = calloc(buf_size, sizeof(char));
SCREEN *screen = newterm(NULL, stderr, stdin);
char* term_type = getenv("TERM");
if (term_type == NULL || *term_type == '\0') {
term_type = "unknown";
}
FILE* term_in = fopen("/dev/tty", "r");
if (term_in == NULL) {
perror("fopen(/dev/tty)");
exit(EXIT_FAILURE);
}
SCREEN *screen = newterm(term_type, stdout, term_in);
set_term(screen);
set_escdelay(5);
W = getmaxx(stdscr);
H = getmaxy(stdscr);
noecho();
keypad(stdscr, 1);
curs_set(0);
curs_set(2);
start_color();
DECIMAL_COLORS = new_colorpair(COLOR_YELLOW, COLOR_BLACK) | A_BOLD;
HEX_COLORS = new_colorpair(COLOR_GREEN, COLOR_BLACK) | A_BOLD;
@ -201,11 +216,41 @@ int main(int argc, char *argv[])
OUTPUT_ESCAPE_COLORS = new_colorpair(COLOR_RED, COLOR_WHITE) | A_BOLD;
OUTPUT_LABEL_COLORS = new_colorpair(COLOR_BLACK, COLOR_YELLOW);
size_t chunk = 256;
size_t buf_size = chunk, buf_i = 0;
char *outbuf = calloc(buf_size, sizeof(char));
{ // Read stdin if anything was piped in
struct pollfd desc;
desc.fd = STDIN_FILENO;
desc.events = POLLIN;
int ret = poll(&desc, 1, 50);
if (ret > 0) {
for (size_t consumed; (consumed = fread(&outbuf[buf_i], 1, chunk, stdin));
buf_i += consumed) {
if (consumed == chunk) {
chunk *= 2;
buf_size += chunk;
outbuf = realloc(outbuf, buf_size);
}
}
}
}
int selected = 0;
while (1) {
// Bar at the bottom of the screen showing the output text
redraw(selected);
draw_output(outbuf, buf_i);
// Bar at the bottom of the screen showing the output text:
// left-truncate output so the end of it fits on screen:
char *visible = &outbuf[buf_i];
for (int space = W-strlen(" Output: ")-1-5; space > 0 && visible > outbuf; visible--) {
int chlen = (' ' <= *visible && *visible <= '~') ? 1 : 4; // printable range
if (chlen > space) break;
else space -= chlen;
}
draw_output(visible, &outbuf[buf_i]);
refresh();
next_input:;
int key = getch();
switch (key) {
case 'j': case KEY_DOWN:
@ -233,9 +278,21 @@ int main(int argc, char *argv[])
break;
case KEY_RESIZE:
// To prevent wasted work, wait until 200ms has elapsed
// with no additional resizes before doing anything
timeout(0);
do {
// Wait 200ms
usleep(2e5);
// Peek if there's another resize event
int k = getch();
if (k == KEY_RESIZE) continue;
if (k > 0) ungetch(k);
} while (0);
// Back to blocking input
timeout(-1);
W = getmaxx(stdscr);
H = getmaxy(stdscr);
clear();
break;
case KEY_ENTER: case '\n':
@ -246,10 +303,19 @@ int main(int argc, char *argv[])
}
break;
case KEY_BACKSPACE: case KEY_DC: case 127:
if (buf_i > 0) {
outbuf[buf_i] = 'X';
buf_i--;
}
break;
case 'q': case 'Q': case KEY_CANCEL: case KEY_CLOSE: case KEY_EXIT: case 27:
endwin();
write(1, outbuf, buf_i);
return 0;
default: goto next_input;
}
if (selected < 0) selected = 0;
if (selected >= 128) selected = 127;