From 68932004a8eb935f18732913ca904e466f320753 Mon Sep 17 00:00:00 2001 From: Mark Nudelman Date: Mon, 10 Oct 2022 12:31:36 -0700 Subject: [PATCH 11/48] lesstest: handle colored text with less -R. --- lesstest/display.c | 33 ++++++++++++--------- lesstest/lt_screen.c | 68 ++++++++++++++++++++++++++------------------ lesstest/lt_types.h | 6 ++++ lesstest/runtest | 3 +- 4 files changed, 68 insertions(+), 42 deletions(-) diff --git a/lesstest/display.c b/lesstest/display.c index 5c9355e..a7e1954 100644 --- a/lesstest/display.c +++ b/lesstest/display.c @@ -5,8 +5,6 @@ extern TermInfo terminfo; static void display_attr(Attr attr) { static Attr prev_attr = 0; - if (attr == prev_attr) - return; if (prev_attr & ATTR_STANDOUT) printf("%s", terminfo.exit_standout); if (prev_attr & ATTR_BLINK) @@ -26,8 +24,11 @@ static void display_attr(Attr attr) { prev_attr = attr; } -static void display_color(Color fg_color, Color bg_color) { -printf("{%x/%x}", fg_color, bg_color); +static void display_color(Color color) { + if (color == NULL_COLOR) + printf("\33[m"); + else + printf("\33[%dm", color); } void display_screen(const byte* img, int imglen, int screen_width, int screen_height, int move_cursor) { @@ -36,22 +37,28 @@ void display_screen(const byte* img, int imglen, int screen_width, int screen_he int cursor_x = 0; int cursor_y = 0; int literal = 0; + Attr curr_attr = 0; + Color curr_color = NULL_COLOR; while (imglen-- > 0) { wchar ch = load_wchar(&img); if (!literal) { - if (ch == '\\') { + switch (ch) { + case '\\': literal = 1; continue; - } else if (ch == '@') { - Attr attr = *img++; - display_attr(attr); + case LTS_CHAR_ATTR: + curr_attr = *img++; + display_attr(curr_attr); + if (curr_color != NULL_COLOR) + display_color(curr_color); continue; - } else if (ch == '$') { - Color fg_color = *img++; - Color bg_color = *img++; - display_color(fg_color, bg_color); + case LTS_CHAR_COLOR: + curr_color = *img++; + display_color(curr_color); + if (curr_attr != 0) + display_attr(curr_attr); continue; - } else if (ch == '#') { + case LTS_CHAR_CURSOR: cursor_x = x; cursor_y = y; continue; diff --git a/lesstest/lt_screen.c b/lesstest/lt_screen.c index 3574320..6b1fde4 100644 --- a/lesstest/lt_screen.c +++ b/lesstest/lt_screen.c @@ -9,7 +9,7 @@ static const char version[] = "lt_screen|v=1"; int usage(void) { - fprintf(stderr, "usage: lt_screen\n"); + fprintf(stderr, "usage: lt_screen [-w width] [-h height] [-qv]\n"); return 0; } @@ -20,8 +20,7 @@ int usage(void) { typedef struct ScreenChar { wchar ch; Attr attr; - Color fg_color; - Color bg_color; + Color color; } ScreenChar; typedef struct ScreenState { @@ -31,8 +30,7 @@ typedef struct ScreenState { int cx; int cy; Attr curr_attr; - Color curr_fg_color; - Color curr_bg_color; + Color curr_color; int param_top; int params[MAX_PARAMS+1]; int in_esc; @@ -53,7 +51,7 @@ static void screen_init(void) { screen.cy = 0; screen.in_esc = 0; screen.curr_attr = 0; - screen.curr_fg_color = screen.curr_bg_color = 0; + screen.curr_color = NULL_COLOR; screen.param_top = -1; screen.params[0] = 0; } @@ -74,7 +72,7 @@ static void param_push(int v) { static int param_pop(void){ if (screen.param_top < 0) - return 0; // missing param is assumed to be 0 + return -1; // missing param return screen.params[screen.param_top--]; } @@ -107,17 +105,16 @@ static int screen_incr(int* px, int* py) { return 1; } -static void screen_char_set(int x, int y, wchar ch, Attr attr, Color fg_color, Color bg_color) { +static void screen_char_set(int x, int y, wchar ch, Attr attr, Color color) { ScreenChar* sc = screen_char(x, y); sc->ch = ch; sc->attr = attr; - sc->fg_color = fg_color; - sc->bg_color = bg_color; + sc->color = color; } static int screen_clear(int x, int y, int count) { while (count-- > 0) { - screen_char_set(x, y, '_', 0, 0, 0); + screen_char_set(x, y, '_', 0, NULL_COLOR); screen_incr(&x, &y); } return 1; @@ -125,28 +122,25 @@ static int screen_clear(int x, int y, int count) { static int screen_read(int x, int y, int count) { //write(ttyout, "$|", 2); - int attr = 0; - int fg_color = 0; - int bg_color = 0; + Attr attr = 0; + int color = NULL_COLOR; while (count-- > 0) { byte buf[32]; byte* bufp = buf; ScreenChar* sc = screen_char(x, y); if (sc->attr != attr) { attr = sc->attr; - *bufp++ = '@'; + *bufp++ = LTS_CHAR_ATTR; *bufp++ = attr; } - if (sc->fg_color != fg_color || sc->bg_color != bg_color) { - fg_color = sc->fg_color; - bg_color = sc->bg_color; - *bufp++ = '$'; - *bufp++ = fg_color; - *bufp++ = bg_color; + if (sc->color != color) { + color = sc->color; + *bufp++ = LTS_CHAR_COLOR; + *bufp++ = color; } if (x == screen.cx && y == screen.cy) - *bufp++ = '#'; - if (sc->ch == '@' || sc->ch == '$' || sc->ch == '\\' || sc->ch == '#') + *bufp++ = LTS_CHAR_CURSOR; + if (sc->ch == '\\' || sc->ch == LTS_CHAR_ATTR || sc->ch == LTS_CHAR_COLOR || sc->ch == LTS_CHAR_CURSOR) *bufp++ = '\\'; store_wchar(&bufp, sc->ch); write(ttyout, buf, bufp-buf); @@ -189,12 +183,20 @@ static int screen_rscroll(void) { static int screen_set_attr(int attr) { screen.curr_attr |= attr; - return 0; + if (verbose) fprintf(stderr, "[%d,%d] set_attr(%d)=%d\n", screen.cx, screen.cy, attr, screen.curr_attr); + return 1; } static int screen_clear_attr(int attr) { screen.curr_attr &= ~attr; - return 0; + if (verbose) fprintf(stderr, "[%d,%d] clr_attr(%d)=%d\n", screen.cx, screen.cy, attr, screen.curr_attr); + return 1; +} + +static int screen_set_color(int color) { + screen.curr_color = (color >= 0) ? color : NULL_COLOR; + if (verbose) fprintf(stderr, "[%d,%d] set_color(%d)=%d\n", screen.cx, screen.cy, color, screen.curr_color); + return 1; } // ------------------------------------------------------------------ @@ -223,10 +225,15 @@ static int exec_esc(wchar ch) { count = param_pop(); y = param_pop(); x = param_pop(); + if (x < 0) x = 0; + if (y < 0) y = 0; + if (count < 0) count = 0; return screen_read(x, y, count); case 'j': // jump cursor to (N1,N2) y = param_pop(); x = param_pop(); + if (x < 0) x = 0; + if (y < 0) y = 0; return screen_move(x, y); case 'g': // visual bell return 0; @@ -256,6 +263,8 @@ static int exec_esc(wchar ch) { return screen_clear_attr(ATTR_BLINK); case 'E': // exit bold/blink return screen_clear_attr(ATTR_BOLD|ATTR_BLINK); + case 'm': // set color + return screen_set_color(param_pop()); case '?': // print version string write(ttyout, version, strlen(version)); return 1; @@ -266,10 +275,10 @@ static int exec_esc(wchar ch) { static int add_char(wchar ch) { //if (verbose) fprintf(stderr, "add (%c) %lx at %d,%d\n", (char)ch, (long)ch, screen.cx, screen.cy); - screen_char_set(screen.cx, screen.cy, ch, screen.curr_attr, screen.curr_fg_color, screen.curr_bg_color); + screen_char_set(screen.cx, screen.cy, ch, screen.curr_attr, screen.curr_color); int fits = screen_incr(&screen.cx, &screen.cy); if (fits && is_wide_char(ch)) { - screen_char_set(screen.cx, screen.cy, 0, 0, 0, 0); + screen_char_set(screen.cx, screen.cy, 0, 0, NULL_COLOR); fits = screen_incr(&screen.cx, &screen.cy); } if (!fits) { // Wrap at bottom of screen = scroll @@ -284,9 +293,12 @@ static int process_char(wchar ch) { int ok = 1; if (screen.in_esc) { if (ch >= '0' && ch <= '9') { - param_push(10 * param_pop() + ch - '0'); + int d = (screen.param_top < 0) ? 0 : screen.params[screen.param_top--]; + param_push(10 * d + ch - '0'); } else if (ch == ';') { param_push(0); + } else if (ch == '[') { + ; // ANSI sequence } else { screen.in_esc = 0; ok = exec_esc(ch); diff --git a/lesstest/lt_types.h b/lesstest/lt_types.h index 2b3c1bc..3f98376 100644 --- a/lesstest/lt_types.h +++ b/lesstest/lt_types.h @@ -5,6 +5,8 @@ typedef unsigned char byte; typedef unsigned char Attr; typedef unsigned char Color; +#define NULL_COLOR ((Color)0xff) + #define ATTR_BOLD (1<<0) #define ATTR_UNDERLINE (1<<1) #define ATTR_STANDOUT (1<<2) @@ -18,6 +20,10 @@ typedef unsigned char Color; #define RUN_OK 0 #define RUN_ERR 1 +#define LTS_CHAR_ATTR '@' +#define LTS_CHAR_COLOR '$' +#define LTS_CHAR_CURSOR '#' + #define is_ascii(ch) ((ch) >= ' ' && (ch) < 0x7f) #define pr_ascii(ch) (is_ascii(ch) ? ((char)ch) : '.') diff --git a/lesstest/runtest b/lesstest/runtest index fe7fcab..2a39047 100755 --- a/lesstest/runtest +++ b/lesstest/runtest @@ -59,7 +59,8 @@ sub run { print "ERR cannot open $file\n"; return 1; } - print "TEST $file\n"; + my ($basename) = $file =~ m|^.*/([^/]+)$|; + print "TEST $basename\n"; my $cmd = "$lesstest $lt_opts -s '$lt_screen' -t '$file' '$less'"; my $err = system $cmd; if ($err) { -- 2.27.0