iomenu.c: horizontal mode with -l 0 - iomenu - interactive terminal-based selection menu
(HTM) git clone git://bitreich.org/iomenu git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/iomenu
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Tags
(DIR) README
(DIR) LICENSE
---
(DIR) commit 695c25f7dc0613e9aa3e9057b333ec22c0e580f9
(DIR) parent 5ac10691e817e4bfb903449a99614a1184d03a7e
(HTM) Author: Josuah Demangeon <josuah.demangeon@gandi.net>
Date: Sun, 3 Sep 2017 20:09:12 +0200
iomenu.c: horizontal mode with -l 0
Diffstat:
M iomenu.c | 215 +++++++++++++++++++------------
1 file changed, 135 insertions(+), 80 deletions(-)
---
(DIR) diff --git a/iomenu.c b/iomenu.c
@@ -14,6 +14,7 @@
#include "utf8.h"
#define CONTINUE 2 /* as opposed to EXIT_SUCCESS and EXIT_FAILURE */
+#define MARGIN 30 /* space for the input before the horizontal list */
#define CTL(char) (char ^ 0x40)
#define ALT(char) (char + 0x80)
@@ -53,6 +54,34 @@ die(const char *s)
}
static void
+read_lines(void)
+{
+ int size = 0;
+ size_t len;
+
+ do {
+ if (linec >= size) {
+ size += BUFSIZ;
+ linev = realloc(linev, sizeof (char **) * size);
+ matchv = realloc(matchv, sizeof (char **) * size);
+ if (!linev || !matchv)
+ die("realloc");
+ }
+
+ linev[linec] = malloc(LINE_MAX + 1);
+ if (!(fgets(linev[linec], LINE_MAX, stdin))) {
+ free(linev[linec]);
+ break;
+ }
+
+ len = strlen(linev[linec]);
+ if (len > 0 && linec[linev][len - 1] == '\n')
+ linev[linec][len - 1] = '\0';
+
+ } while (++linec, ++matchc);
+}
+
+static void
set_terminal(void)
{
struct termios new;
@@ -83,48 +112,73 @@ reset_terminal(void)
/* reset cursor position */
fputs("\033[u", stderr);
- /* set terminal back to normal mode */
tcsetattr(ttyfd, TCSANOW, &termios);
}
-static void
-read_lines(void)
+static size_t
+str_width(char *s)
{
- int size = 0;
- size_t len;
+ int width = 0;
- do {
- if (linec >= size) {
- size += BUFSIZ;
- linev = realloc(linev, sizeof (char **) * size);
- matchv = realloc(matchv, sizeof (char **) * size);
- if (!linev || !matchv)
- die("realloc");
- }
+ while (*s) {
+ if (*s++ == '\t')
+ width += (width + 7) % 8;
+ else
+ width++;
+ }
- linev[linec] = malloc(LINE_MAX + 1);
- if (!(fgets(linev[linec], LINE_MAX, stdin))) {
- free(linev[linec]);
- break;
- }
+ return width;
+}
- len = strlen(linev[linec]);
- if (len > 0 && linec[linev][len - 1] == '\n')
- linev[linec][len - 1] = '\0';
+static int
+prev_page(int pos, int cols)
+{
+ int col;
- } while (++linec, ++matchc);
+ pos -= pos > 0 ? 1 : 0;
+ for (col = 0; pos > 0; pos--)
+ if ((col += str_width(matchv[pos]) + 2) > cols)
+ return pos + 1;
+ return pos;
}
-static size_t
-string_width(char *s)
+static int
+next_page(int pos, int cols)
{
- int width = 0;
+ int col;
- while (*s)
- if (*s++ == '\t')
- width += (width + 7) % 8;
+ for (col = 0; pos < matchc; pos++)
+ if ((col += str_width(matchv[pos]) + 2) > cols)
+ return pos;
+ return pos;
+}
- return width;
+static void
+move(signed int sign)
+{
+ int i;
+
+ for (i = current + sign; 0 <= i && i < matchc; i += sign) {
+ if (!opt['#'] || matchv[i][0] != '#') {
+ current = i;
+ break;
+ }
+ }
+}
+
+static void
+move_page(signed int sign)
+{
+ int i = current - current % rows + rows * sign;
+
+ if (!opt['l'])
+ return;
+
+ if (0 > i || i > matchc)
+ return;
+
+ current = i - 1;
+ move(+1);
}
static char *
@@ -149,10 +203,10 @@ format(char *str, int cols)
*fmt++ = *str++;
col++;
- } else {
- *fmt++ = '?';
- col++;
- str++;
+ } else {
+ *fmt++ = '?';
+ col++;
+ str++;
}
}
*fmt = '\0';
@@ -165,22 +219,51 @@ print_lines(void)
{
int printed = 0, i = current - current % rows;
- while (printed < rows && i < matchc) {
+ for (; printed < rows && i < matchc; i++, printed++) {
+ fprintf(stderr,
+ opt['#'] && matchv[i][0] == '#' ?
+ "\n\033[1m\033[K %s\033[m" :
+ i == current ?
+ "\n\033[47;30m\033[K %s\033[m" :
+ "\n\033[K %s",
+ format(matchv[i], ws.ws_col - 1)
+ );
+ }
+
+ while (printed++ < rows)
+ fputs("\n\033[K", stderr);
+}
- char *s = format(matchv[i], ws.ws_col - 1);
+static void
+print_segments(void)
+{
+ int i;
- if (opt['#'] && matchv[i][0] == '#')
- fprintf(stderr, "\n\033[1m\033[K %s\033[m", s);
- else if (i == current)
- fprintf(stderr, "\n\033[30;47m\033[K %s\033[m", s);
- else
- fprintf(stderr, "\n\033[K %s", s);
+ if (current < offset) {
+ next = offset;
+ offset = prev_page(offset, ws.ws_col - MARGIN - 4);
- i++; printed++;
+ } else if (current >= next) {
+ offset = next;
+ next = next_page(offset, ws.ws_col - MARGIN - 4);
}
- while (printed++ < rows)
- fputs("\n\033[K", stderr);
+ fprintf(stderr, "\r\033[K\033[%dC", MARGIN);
+ fputs(offset > 0 ? "< " : " ", stderr);
+
+ for (i = offset; i < next && i < matchc; i++) {
+ fprintf(stderr,
+ opt['#'] && matchv[i][0] == '#' ? "\033[1m %s \033[m" :
+ i == current ? "\033[7m %s \033[m" :
+ " %s ",
+ format(matchv[i], ws.ws_col - 1)
+ );
+ }
+
+ if (next < matchc)
+ fprintf(stderr, "\033[%dC\b>", ws.ws_col - MARGIN);
+
+ fputc('\r', stderr);
}
static void
@@ -188,10 +271,12 @@ print_screen(void)
{
int cols = ws.ws_col - 1;
- fputs("\r\033[K", stderr);
-
- print_lines();
- fprintf(stderr, "\033[%dA\r", rows);
+ if (opt['l'] > 0) {
+ print_lines();
+ fprintf(stderr, "\033[%dA\r", rows);
+ } else {
+ print_segments();
+ }
if (*prompt) {
format(prompt, cols - 2);
@@ -219,34 +304,6 @@ match_line(char *line, char **tokv, int tokc)
}
static void
-move(signed int sign)
-{
- int i;
-
- for (i = current + sign; 0 <= i && i < matchc; i += sign) {
- if (!opt['#'] || matchv[i][0] != '#') {
- current = i;
- break;
- }
- }
-}
-
-static void
-move_page(signed int sign)
-{
- int i = current - current % rows + rows * sign;
-
- if (!opt['l'])
- return;
-
- if (0 > i || i > matchc)
- return;
-
- current = i - 1;
- move(+1);
-}
-
-static void
filter(void)
{
char **tokv = NULL, *s, buffer[sizeof (input)];
@@ -333,10 +390,8 @@ print_selection(void)
}
static int
-key(void)
+key(int key)
{
- int key = fgetc(stdin);
-
top:
switch (key) {
@@ -485,7 +540,7 @@ main(int argc, char *argv[])
sigwinch();
input[0] = '\0';
- while ((exit_code = key()) == CONTINUE)
+ while ((exit_code = key(fgetc(stdin))) == CONTINUE)
print_screen();
print_screen();