summaryrefslogtreecommitdiffstats
path: root/blkshowr.c
diff options
context:
space:
mode:
Diffstat (limited to 'blkshowr.c')
-rw-r--r--blkshowr.c653
1 files changed, 607 insertions, 46 deletions
diff --git a/blkshowr.c b/blkshowr.c
index bbb0ea0..4ca0724 100644
--- a/blkshowr.c
+++ b/blkshowr.c
@@ -20,6 +20,12 @@ static void configure_terminal(void);
static void restore_terminal(void);
+enum component {
+ BLOCK_SELECTOR,
+ BLOCK_DISPLAY,
+ NCOMPONENTS
+};
+
static size_t blksize = 4ul << 10;
static off_t *blocks = NULL;
static size_t blocks_size = 0u;
@@ -27,8 +33,8 @@ static size_t nblocks = 0u;
static int max_block_len;
static volatile sig_atomic_t term_resized = 0;
-static struct termios term_attributes_stdin;
-static int term_attributes_stdin_saved = 0;
+static struct termios term_attributes;
+static int term_attributes_saved = 0;
static int term_entered_submode_stdout = 0;
static int ttyfd = -1;
@@ -37,44 +43,580 @@ static size_t term_height;
static int exiting = 0;
static int interrupt_deferred = 0;
+static size_t selected_block = 0u;
+static size_t first_visible_block = 0u;
+static size_t first_visible_line = 0u;
+static size_t line_count = 0u;
+static size_t *line_map = NULL;
+static size_t line_map_size = 0u;
+static enum component active_focus = BLOCK_SELECTOR;
+static int textfd;
+static const char *path;
+static off_t current_block_off = -1;
+static unsigned char *current_block_text = NULL;
+static size_t current_block_text_size = 0u;
+static size_t current_block_text_len = 0u;
+static size_t display_width = 0u;
+static int display_as_text = 0;
+
+static int limited_block_drawing;
+static const char *const scroll_blocks8[] = {" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇"};
+static const char *const scroll_blocks2[] = {scroll_blocks8[0], scroll_blocks8[4]};
+static const char *const scroll_blocks3[] = {" ", "\xf0\x9f\xac\xad", "\xf0\x9f\xac\xb9"}; /* emacs has broken support for these, its the block equivalents of "⠤" and "⠶" */
+static const char *const scroll_blocks1_3[] = {"\xf0\x9f\xac\xad", "\xf0\x9f\xac\x8b", "\xf0\x9f\xac\x82"}; /* emacs has broken support for these, its the block equivalents of "⠤", "⠒", and "⠉" */
+
+
+#define S(X)\
+ X"0", X"1", X"2", X"3", X"4", X"5", X"6", X"7",\
+ X"8", X"9", X"A", X"B", X"C", X"D", X"E", X"F"
+#if defined(__GNUC__)
+__attribute__((__nonstring__))
+#endif
+static const char hex[256][2] = {
+ S("0"), S("1"), S("2"), S("3"), S("4"), S("5"), S("6"), S("7"),
+ S("8"), S("9"), S("A"), S("B"), S("C"), S("D"), S("E"), S("F")
+};
+#undef S
+
+
+#define PRINT(...) dprintf(ttyfd, __VA_ARGS__)
+
static void
do_redraw(void)
{
- dprintf(ttyfd, "\033[H\033[2J");
+ size_t last_visible_block = first_visible_block + term_height - 2u;
+ size_t blocks_top, blocks_bottom;
+ int block_pane_width = MAX(max_block_len, (int)sizeof("Block:") - 1) + 1;
+ size_t i, j, end, vis_end;
+ size_t new_display_width;
+ size_t right_pad;
+ size_t text_top, text_bottom;
+
+ if (current_block_off != blocks[selected_block]) {
+ off_t off;
+ ssize_t r;
+ if (current_block_text_size < blksize) {
+ current_block_text = erealloc(current_block_text, blksize);
+ current_block_text_size = blksize;
+ }
+ off = current_block_off = blocks[selected_block];
+ off *= (off_t)blksize;
+ for (i = 0u; i < blksize;) {
+ r = pread(textfd, &current_block_text[i], blksize - i, off);
+ if (r <= 0) {
+ if (!r)
+ break;
+ if (errno == EINTR) {
+ interrupt_deferred = 1;
+ continue;
+ }
+ eprintf("pread %s %zu %ji:", path, blksize - i, (intmax_t)off);
+ }
+ off += (off_t)r;
+ i += (size_t)r;
+ }
+ current_block_text_len = i;
+ }
+
+ new_display_width = term_width;
+ new_display_width -= MIN(new_display_width, (size_t)block_pane_width);
+ new_display_width -= MIN(new_display_width, 2u); /* scrollbar for block list */
+ new_display_width -= MIN(new_display_width, 3u); /* scrollbar for display incl. spacing */
+ right_pad = new_display_width;
+ new_display_width /= 4u;
+ if (!display_as_text) {
+ if (first_visible_line && new_display_width && new_display_width != display_width) {
+ first_visible_line *= display_width;
+ first_visible_line /= new_display_width;
+ }
+ if (line_count == 0u && new_display_width) {
+ line_count = current_block_text_len / new_display_width;
+ line_count += current_block_text_len % new_display_width ? 1u : 0u;
+ }
+ right_pad -= new_display_width * 4u;
+ }
+ display_width = new_display_width;
+
+ if (display_as_text && !line_count) {;
+ for (i = 0u; i + 1u < current_block_text_len; i++)
+ if (current_block_text[i] == '\n')
+ line_count += 1u;
+ if (current_block_text_len)
+ line_count += 1u;
+ if (line_map_size < line_count) {
+ line_map_size = line_count;
+ line_map = ereallocarray(line_map, line_map_size, sizeof(*line_map));
+ line_map[0u] = 0u;
+ }
+ for (i = 0u, j = 1u; j < line_count; i++)
+ if (current_block_text[i] == '\n')
+ line_map[j++] = i + 1u;
+ }
+
+ /* TODO what if terminal is too small? */
+
+ /* TODO make size stable */
+ blocks_top = first_visible_block * (term_height - 2u) / nblocks;
+ blocks_bottom = (last_visible_block + 1u) * (term_height - 2u) / nblocks;
+ if (blocks_bottom == blocks_top)
+ blocks_bottom += 1u;
+
+ /* TODO make size stable */
+ if (line_count) {
+ size_t last_visible_line = first_visible_line + term_height - 2u;
+ last_visible_line = MIN(last_visible_line, line_count) - 1u;
+ text_top = first_visible_line * (term_height - 2u) / line_count;
+ text_bottom = (last_visible_line + 1u) * (term_height - 2u) / line_count;
+ if (text_bottom == text_top)
+ text_bottom += 1u;
+ }
+
+ PRINT("\033[H");
+
+ PRINT("\033[7;1m%-*s\033[m\n", (int)term_width, "Block:");
+ /* TODO add caption for display area */
+
+ /* TODO draw breaks if display_width is too large */
+ for (i = 0u; i + 2u < term_height; i++) {
+ j = i + first_visible_block;
+ if (j == selected_block && active_focus == BLOCK_SELECTOR)
+ PRINT("\033[7;1;34m%-*ji\033[m", block_pane_width, (intmax_t)blocks[j]);
+ else if (j == selected_block)
+ PRINT("\033[34m%-*ji\033[m", block_pane_width, (intmax_t)blocks[j]);
+ else if (j < nblocks)
+ PRINT("%-*ji", block_pane_width, (intmax_t)blocks[j]);
+ else
+ PRINT("%*s", block_pane_width, "");
+
+ /* TODO need to fix colour support for less capable terminals */
+ /* TODO make more granular */
+ if (i < blocks_top || i >= blocks_bottom)
+ PRINT("\033[100m%s\033[m", " ");
+ else
+ PRINT("\033[107m%s\033[m", " ");
+ PRINT("\033[m");
+
+ if (display_as_text) {
+ int truncated = 1;
+ size_t cols = 0;
+ if (i + first_visible_line >= line_count) {
+ PRINT("\033[1;30m~\033[m");
+ cols += 1u;
+ truncated = 0;
+ goto end_of_line;
+ }
+ j = line_map[i + first_visible_line];
+ for (; j < current_block_text_len && cols < right_pad; j++) {
+ unsigned char c = current_block_text[j];
+ const char *ctext = NULL;
+ char buf[8];
+ switch (c) {
+ case '\a': PRINT("\033[36m"); ctext = "\\a"; break;
+ case '\b': PRINT("\033[36m"); ctext = "\\b"; break;
+ case '\033': PRINT("\033[36m"); ctext = "\\e"; break;
+ case '\r': PRINT("\033[36m"); ctext = "\\r"; break;
+ case '\v': PRINT("\033[36m"); ctext = "\\v"; break;
+ case '\f': PRINT("\033[36m"); ctext = "^L"; break;
+ case 0x7Fu: PRINT("\033[36m"); ctext = "^?"; break;
+ case ' ': PRINT("\033[90m.\033[m"); break;
+ case '\t':
+ PRINT("\033[90m→");
+ memset(buf, ' ', 7u);
+ buf[7u - cols % 8u] = '\0';
+ cols += 1u;
+ ctext = buf;
+ break;
+ case '\n':
+ PRINT("\033[90m\\");
+ cols += 1u;
+ if (cols < right_pad) {
+ PRINT("n");
+ cols += 1u;
+ }
+ PRINT("\033[m");
+ truncated = 0;
+ goto end_of_line;
+ default:
+ if (c & 0x80u) {
+ /* TODO add support for UTF-8 */
+ PRINT("\033[31m");
+ ctext = buf;
+ buf[0u] = '\\';
+ buf[1u] = 'x';
+ buf[2u] = hex[c][0];
+ buf[3u] = hex[c][1];
+ buf[4u] = '\0';
+ } else {
+ if (c < (unsigned char)' ') {
+ PRINT("\033[36m");
+ ctext = buf;
+ buf[0u] = '^';
+ buf[1u] = (char)(c + '@');
+ buf[2u] = '\0';
+ } else {
+ PRINT("%c", (char)c);
+ }
+ }
+ break;
+ }
+ if (ctext) {
+ size_t len = strlen(ctext);
+ int n = (int)MIN(len, right_pad - cols);
+ PRINT("%.*s\033[m", n, ctext);
+ cols += (size_t)n;
+ } else {
+ cols += 1u;
+ }
+ }
+ if (j == current_block_text_len)
+ truncated = 0;
+
+ end_of_line:
+ if (right_pad - cols)
+ PRINT("%*s", (int)(right_pad - cols), "");
+ if (truncated)
+ PRINT("\033[1;33m$");
+ else
+ PRINT(" ");
+ goto next;
+ }
+
+ j = (i + first_visible_line) * display_width;
+ vis_end = j + display_width;
+ end = MIN(vis_end, current_block_text_len);
+ for (; j < end; j++) {
+ unsigned char c = current_block_text[j];
+ switch (c) {
+ case '\a': PRINT("\033[35ma\033[m"); break;
+ case '\b': PRINT("\033[35mb\033[m"); break;
+ case '\033': PRINT("\033[35me\033[m"); break;
+ case '\f': PRINT("\033[35mf\033[m"); break;
+ case '\n': PRINT("\033[1;35mn\033[m"); break;
+ case '\r': PRINT("\033[35mr\033[m"); break;
+ case '\t': PRINT("\033[35mt\033[m"); break;
+ case '\v': PRINT("\033[35mv\033[m"); break;
+ case ' ': PRINT("\033[35m.\033[m"); break;
+ case 0x7Fu: PRINT("\033[36m?\033[m"); break;
+ default:
+ if (c & 0x80u) {
+ c &= 0x7Fu;
+ if (c == 0x7Fu)
+ PRINT("\033[32m?\033[m");
+ else if (c == (unsigned char)' ')
+ PRINT("\033[32m.\033[m");
+ else if (c < (unsigned char)' ')
+ PRINT("\033[32m%c\033[m", (char)(c + '@'));
+ else
+ PRINT("\033[33m%c\033[m", (char)c);
+ } else {
+ if (c < (unsigned char)' ')
+ PRINT("\033[36m%c\033[m", (char)(c + '@'));
+ else
+ PRINT("%c", (char)c);
+ }
+ break;
+ }
+ }
+ if (end != vis_end)
+ PRINT("%*s", (int)(vis_end - end), "");
+
+ j = (i + first_visible_line) * display_width;
+ for (; j < end; j++) {
+ unsigned char c = current_block_text[j];
+ switch (c) {
+ case '\n':
+ PRINT("\033[1;35m");
+ break;
+ case '\a':
+ case '\b':
+ case '\033':
+ case '\f':
+ case '\r':
+ case '\t':
+ case '\v':
+ case ' ':
+ PRINT("\033[35m");
+ break;
+ case 0x7Fu:
+ PRINT("\033[36m");
+ break;
+ default:
+ if (c & 0x80u) {
+ if (c == 0xFFu || c <= (unsigned char)' ' + 0x80u)
+ PRINT("\033[32m");
+ else
+ PRINT("\033[33m");
+ } else {
+ if (c < (unsigned char)' ')
+ PRINT("\033[36m");
+ }
+ break;
+ }
+ PRINT(" %.2s\033[m", hex[c]);
+ }
+ if (end != vis_end || right_pad)
+ PRINT("%*s", (int)((vis_end - end) * 3u + right_pad), "");
+
+ PRINT(" ");
+ next:
+ /* TODO need to fix colour support for less capable terminals */
+ /* TODO make more granular */
+ if (line_count == 0u)
+ PRINT("\033[100m%s\033[m", " ");
+ else if (i < text_top || i >= text_bottom)
+ PRINT("\033[100m%s\033[m", " ");
+ else if (active_focus == BLOCK_DISPLAY)
+ PRINT("\033[104m%s\033[m", " ");
+ else
+ PRINT("\033[107m%s\033[m", " ");
+
+ PRINT("\033[K\n");
+ }
+
+ PRINT("\033[7;1m%*s\033[m\033[H", (int)term_width, "");
+}
+
+
+static int
+ensure_selected_block_visible(void)
+{
+ if (selected_block < first_visible_block) {
+ first_visible_block = selected_block;
+ return 1;
+ } else if (term_height < 3u) {
+ first_visible_block = selected_block;
+ return 0;
+ } else if (selected_block - first_visible_block > term_height - 3u) {
+ first_visible_block = selected_block - (term_height - 3u);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+static int
+handle_keyboard_input_global(union libterminput_input *input)
+{
+ if (input->type != LIBTERMINPUT_KEYPRESS)
+ return 0;
+
+ if (IS_CTRL_KEY(input, 'Z')) {
+ restore_terminal();
+ raise(SIGTSTP);
+ configure_terminal();
+ redraw:
+ interrupt_deferred = 1;
+ term_resized = 1;
+
+ } else if (IS_CTRL_KEY(input, 'L')) {
+ goto redraw;
+
+ } else if (IS_CTRL_KEY(input, 'C') ||
+ IS_CTRL_KEY(input, 'Q')) {
+ exiting = 1;
+
+ } else if (IS_KEY(input, 't')) {
+ /* TODO need a horizontal display offset */
+ display_as_text ^= 1;
+ line_count = 0u;
+ do_redraw();
+
+ } else if (input->keypress.key == LIBTERMINPUT_TAB) {
+ if (input->keypress.mods & LIBTERMINPUT_SHIFT)
+ goto backtab;
+ active_focus += 1;
+ active_focus %= NCOMPONENTS;
+ do_redraw();
+
+ } else if (input->keypress.key == LIBTERMINPUT_BACKTAB) {
+ backtab:
+ active_focus -= 1;
+ if (active_focus < 0)
+ active_focus += NCOMPONENTS;
+ do_redraw();
+
+ } else {
+ return 0;
+ }
+
+ /* TODO delete key should unlist a block */
+ /* TODO should be able to add prior/next block */
+ /* TODO should be able to save blocks to file */
+
+ return 1;
+}
+
+
+static void
+handle_keyboard_input_to_block_selector(union libterminput_input *input)
+{
+ if (input->type != LIBTERMINPUT_KEYPRESS)
+ return;
+
+ /* TODO optimise redraw to only affected areas */
+ /* TODO defer redraw until all repeations have been processed */
+
+ if (input->keypress.key == LIBTERMINPUT_UP) {
+ if (selected_block > 0u) {
+ first_visible_line = 0u;
+ line_count = 0u;
+ selected_block -= 1u;
+ ensure_selected_block_visible();
+ do_redraw();
+ }
+
+ } else if (input->keypress.key == LIBTERMINPUT_DOWN) {
+ if (selected_block < nblocks - 1u) {
+ first_visible_line = 0u;
+ line_count = 0u;
+ selected_block += 1u;
+ ensure_selected_block_visible();
+ do_redraw();
+ }
+
+ } else if (input->keypress.key == LIBTERMINPUT_HOME) {
+ if (selected_block > 0u) {
+ first_visible_line = 0u;
+ line_count = 0u;
+ selected_block = 0u;
+ ensure_selected_block_visible();
+ do_redraw();
+ }
+
+ } else if (input->keypress.key == LIBTERMINPUT_END) {
+ if (selected_block < nblocks - 1u) {
+ first_visible_line = 0u;
+ line_count = 0u;
+ selected_block = nblocks - 1u;
+ ensure_selected_block_visible();
+ do_redraw();
+ }
- /* TODO draw everything */
+ } else if (input->keypress.key == LIBTERMINPUT_PRIOR) {
+ if (selected_block > 0u && term_height > 2u) {
+ first_visible_line = 0u;
+ line_count = 0u;
+ if (selected_block != first_visible_block) {
+ selected_block = first_visible_block;
+ do_redraw();
+ } else {
+ if (selected_block > term_height - 2u)
+ selected_block -= term_height - 2u;
+ else
+ selected_block = 0u;
+ ensure_selected_block_visible();
+ do_redraw();
+ }
+ }
+
+ } else if (input->keypress.key == LIBTERMINPUT_NEXT) {
+ if (selected_block < nblocks - 1u && term_height > 2u) {
+ size_t last = first_visible_block + (term_height - 3u);
+ first_visible_line = 0u;
+ line_count = 0u;
+ if (selected_block != last) {
+ selected_block = last;
+ do_redraw();
+ } else {
+ if (term_height - 2u > nblocks - 1u - selected_block)
+ selected_block = nblocks - 1u;
+ else
+ selected_block += term_height - 2u;
+ ensure_selected_block_visible();
+ do_redraw();
+ }
+ }
+ }
}
static void
-handle_keyboard_input(union libterminput_input *input)
+handle_keyboard_input_to_block_display(union libterminput_input *input)
{
- if (input->type == LIBTERMINPUT_KEYPRESS) {
- if (IS_CTRL_KEY(input, 'Z')) {
- restore_terminal();
- raise(SIGTSTP);
- configure_terminal();
- redraw:
- interrupt_deferred = 1;
- term_resized = 1;
- } else if (IS_CTRL_KEY(input, 'L')) {
- goto redraw;
- } else if (IS_CTRL_KEY(input, 'Q')) {
- exiting = 1;
+ if (input->type != LIBTERMINPUT_KEYPRESS)
+ return;
+
+ /* TODO optimise redraw to only affected areas */
+ /* TODO defer redraw until all repeations have been processed */
+
+ if (input->keypress.key == LIBTERMINPUT_UP) {
+ if (first_visible_line > 0u) {
+ first_visible_line -= 1u;
+ do_redraw();
+ }
+
+ } else if (input->keypress.key == LIBTERMINPUT_DOWN) {
+ if (line_count > first_visible_line && term_height > 2u) {
+ if (term_height - 2u < line_count - first_visible_line) {
+ first_visible_line += 1;
+ do_redraw();
+ }
+ }
+
+ } else if (input->keypress.key == LIBTERMINPUT_HOME) {
+ if (first_visible_line != 0u) {
+ first_visible_line = 0u;
+ do_redraw();
+ }
+
+ } else if (input->keypress.key == LIBTERMINPUT_END) {
+ if (line_count && term_height > 2u && line_count > term_height - 1u) {
+ if (first_visible_line != line_count - (term_height - 2u)) {
+ first_visible_line = line_count - (term_height - 2u);
+ do_redraw();
+ }
+ }
+
+ } else if (input->keypress.key == LIBTERMINPUT_PRIOR) {
+ if (first_visible_line != 0u && term_height > 2u) {
+ if (first_visible_line < term_height - 2u)
+ first_visible_line = 0u;
+ else
+ first_visible_line -= term_height - 2u;
+ do_redraw();
+ }
+
+ } else if (input->keypress.key == LIBTERMINPUT_NEXT) {
+ if (term_height > 2u) {
+ size_t prev = first_visible_line;
+ first_visible_line += term_height - 2u;
+ if (first_visible_line + term_height - 2u > line_count) {
+ if (line_count > term_height - 2u)
+ first_visible_line = line_count - (term_height - 2u);
+ else
+ first_visible_line = 0u;
+ }
+ if (first_visible_line != prev)
+ do_redraw();
}
}
}
static void
+handle_keyboard_input(union libterminput_input *input)
+{
+ if (handle_keyboard_input_global(input))
+ return;
+
+ if (active_focus == BLOCK_SELECTOR)
+ handle_keyboard_input_to_block_selector(input);
+ else if (active_focus == BLOCK_DISPLAY)
+ handle_keyboard_input_to_block_display(input);
+}
+
+
+static void
enter_subterminal(void)
{
- dprintf(ttyfd,
- "\033[?1049h" /* enter subterminal */
- "\033[?25l" /* hide cursor */
- "\033[H\033[2J" /* clear terminal */
- );
+ if (dprintf(ttyfd,
+ "\033[?1049h" /* enter subterminal */
+ "\033[?25l" /* hide cursor */
+ "\033[H\033[2J" /* clear terminal */
+ ) < 0)
+ eprintf("dprintf /dev/tty:");
term_entered_submode_stdout = 1;
}
@@ -96,17 +638,17 @@ exit_subterminal(void)
static void
set_term_attributes(void)
{
- struct termios new_term_attributes_stdin;
+ struct termios new_term_attributes;
- if (tcgetattr(ttyfd, &term_attributes_stdin))
+ if (tcgetattr(ttyfd, &term_attributes))
eprintf("tcgetattr /dev/tty:");
- term_attributes_stdin_saved = 1;
+ term_attributes_saved = 1;
- memcpy(&new_term_attributes_stdin, &term_attributes_stdin, sizeof(term_attributes_stdin));
- new_term_attributes_stdin.c_iflag &= (tcflag_t)~(IXON | IXANY | IXOFF);
- new_term_attributes_stdin.c_lflag &= (tcflag_t)~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+ memcpy(&new_term_attributes, &term_attributes, sizeof(term_attributes));
+ new_term_attributes.c_iflag &= (tcflag_t)~(IXON | IXANY | IXOFF);
+ new_term_attributes.c_lflag &= (tcflag_t)~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
- if (tcsetattr(ttyfd, TCSANOW, &new_term_attributes_stdin))
+ if (tcsetattr(ttyfd, TCSANOW, &new_term_attributes))
weprintf("tcsetattr /dev/tty TCSANOW:");
}
@@ -114,9 +656,9 @@ set_term_attributes(void)
static void
restore_term_attributes(void)
{
- if (term_attributes_stdin_saved) {
- term_attributes_stdin_saved = 0;
- if (tcsetattr(ttyfd, TCSAFLUSH, &term_attributes_stdin))
+ if (term_attributes_saved) {
+ term_attributes_saved = 0;
+ if (tcsetattr(ttyfd, TCSAFLUSH, &term_attributes))
weprintf("tcsetattr /dev/tty TCSAFLUSH:");
}
}
@@ -142,6 +684,8 @@ static void
cleanup(void)
{
restore_terminal();
+ close(ttyfd);
+ ttyfd = -1;
}
@@ -264,8 +808,10 @@ read_block_list(int fd, const char *fname)
if (r <= 0) {
if (!r)
break;
- if (errno == EINTR)
+ if (errno == EINTR) {
+ interrupt_deferred = 1;
continue;
+ }
eprintf("read %s:", fname);
}
n = (size_t)r;
@@ -276,6 +822,7 @@ read_block_list(int fd, const char *fname)
continue;
have_v = 0;
add_to_block_list(v);
+ v = 0;
} else if ('0' <= buf[i] && buf[i] <= '9') {
have_v = 1;
d = (off_t)(buf[i] - '0');
@@ -288,7 +835,7 @@ read_block_list(int fd, const char *fname)
}
}
}
- if (!have_v)
+ if (have_v)
add_to_block_list(v);
if (!nblocks)
goto inval;
@@ -307,8 +854,8 @@ main(int argc, char *argv[])
{
struct libterminput_state input_ctx;
union libterminput_input input;
- const char *path, *listpath;
- int fd, listfd;
+ const char *listpath, *env;
+ int listfd;
ARGBEGIN {
case 'b':
@@ -332,9 +879,9 @@ main(int argc, char *argv[])
usage();
/* Open terminal and ensure process is running in the foreground */
- ttyfd = open("/dev/tty", O_RDONLY);
+ ttyfd = open("/dev/tty", O_RDWR);
if (ttyfd < 0)
- eprintf("open /dev/tty O_RDONLY:");
+ eprintf("open /dev/tty O_RDWR:");
if (getpgrp() != tcgetpgrp(ttyfd))
eprintf("process not running in the foreground");
@@ -347,12 +894,12 @@ main(int argc, char *argv[])
}
/* Open file to display */
- fd = open(path, O_RDONLY);
- if (fd < 0)
+ textfd = open(path, O_RDONLY);
+ if (textfd < 0)
eprintf("open %s O_RDONLY", path);
/* Advise the kernel about the access pattern */
- posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM);
+ posix_fadvise(textfd, 0, 0, POSIX_FADV_RANDOM);
/* Set up cleanup on exit */
atexit(&cleanup);
@@ -361,15 +908,27 @@ main(int argc, char *argv[])
/* Read block list */
read_block_list(listfd, listpath);
close(listfd);
- max_block_len = snprintf("%ji", (uintmax_t)blocks[nblocks - 1u]);
+ max_block_len = snprintf(NULL, 0u, "%ji", (intmax_t)blocks[nblocks - 1u]);
if (max_block_len < 1)
- eprintf("snprintf %%ji:")
+ eprintf("snprintf %%ji:");
+
+ /* Configure UI */
+ env = getenv("TERM");
+ limited_block_drawing = (!env || !*env || !strcasecmp(env, "linux"));
/* UI loop */
update_term_size();
subscribe_term_resize();
configure_terminal();
memset(&input_ctx, 0, sizeof(input_ctx));
+ while (libterminput_init(&input_ctx, ttyfd)) {
+ if (errno == EINTR) {
+ interrupt_deferred = 1;
+ continue;
+ }
+ eprintf("libterminput_init /dev/tty:");
+ }
+ do_redraw();
do {
if (interrupt_deferred) {
interrupt_deferred = 0;
@@ -391,12 +950,14 @@ main(int argc, char *argv[])
if (errno == EINTR)
interrupt_deferred = 1;
else
- eprintf("libterminput <stdin>:");
+ eprintf("libterminput_read /dev/tty:");
break;
}
} while (!exiting);
+ libterminput_destroy(&input_ctx);
- close(fd);
- close(ttyfd);
+ close(textfd);
+ free(current_block_text);
+ free(line_map);
return 0;
}