diff --git a/src/pcrepp.hh b/src/pcrepp.hh index 9ec7ce8e..f94c5f51 100644 --- a/src/pcrepp.hh +++ b/src/pcrepp.hh @@ -191,6 +191,22 @@ public: iter->length()); }; + void reset(const char *str, size_t off = 0, size_t len = -1) { + this->pi_string = str; + this->pi_offset = off; + this->pi_next_offset = off; + if (this->pi_length == (size_t)-1) { + this->pi_length = strlen(str); + } + else { + this->pi_length = len; + } + } + + void reset(const std::string &str, size_t off = 0) { + this->reset(str.c_str(), off, str.length()); + } + size_t pi_offset; size_t pi_next_offset; size_t pi_length; diff --git a/src/textview_curses.cc b/src/textview_curses.cc index 7385f264..18e52eb0 100644 --- a/src/textview_curses.cc +++ b/src/textview_curses.cc @@ -32,6 +32,7 @@ #include #include +#include "pcrepp.hh" #include "lnav_util.hh" #include "data_parser.hh" #include "textview_curses.hh" @@ -55,111 +56,92 @@ public: void scrub_value(string &str, string_attrs_t &sa) { - vector range_queue; + view_colors &vc = view_colors::singleton(); vector > attr_queue; - int rc, matches[60]; + pcre_context_static<60> context; + vector range_queue; + pcre_input pi(str); - do { - rc = pcre_exec(this->as_pcre, - NULL, - str.c_str(), - str.size(), - 0, - 0, - matches, - 60); - if (rc > 0) { - int c_start = matches[0]; - int c_end = matches[1]; - struct line_range lr; - bool has_attrs = false; - int attrs = 0; - int lpc; + while (this->as_regex.match(context, pi)) { + pcre_context::capture_t *caps = context.all(); + struct line_range lr; + bool has_attrs = false; + int attrs = 0; + int bg = 0; + int fg = 0; + int lpc; - switch (str[matches[4]]) { - case 'm': - for (lpc = matches[2]; - lpc != (int)string::npos && lpc < matches[3]; ) { - int ansi_code = 0; + switch (pi.get_substr_start(&caps[2])[0]) { + case 'm': + for (lpc = caps[1].c_begin; + lpc != (int)string::npos && lpc < caps[1].c_end; ) { + int ansi_code = 0; - if (sscanf(&(str[lpc]), "%d", &ansi_code) == 1) { - switch (ansi_code) { - case 1: - attrs |= A_BOLD; - break; - - case 2: - attrs |= A_DIM; - break; - - case 4: - attrs |= A_UNDERLINE; - break; - - case 7: - attrs |= A_REVERSE; - break; - - case 31: - attrs |= COLOR_PAIR(view_colors::VC_RED); - break; - - case 32: - attrs |= COLOR_PAIR(view_colors::VC_GREEN); - break; - - case 33: - attrs |= COLOR_PAIR(view_colors::VC_YELLOW); - break; - - case 34: - attrs |= COLOR_PAIR(view_colors::VC_BLUE); - break; - - case 35: - attrs |= COLOR_PAIR(view_colors::VC_MAGENTA); - break; - - case 36: - attrs |= COLOR_PAIR(view_colors::VC_CYAN); - break; - - case 37: - attrs |= COLOR_PAIR(view_colors::VC_WHITE); - break; - } + if (sscanf(&(str[lpc]), "%d", &ansi_code) == 1) { + if (90 <= ansi_code && ansi_code <= 97) { + ansi_code -= 60; + attrs |= A_STANDOUT; } - lpc = str.find(";", lpc); - if (lpc != (int)string::npos) { - lpc += 1; + if (30 <= ansi_code && ansi_code <= 37) { + fg = ansi_code - 30; + } + if (40 <= ansi_code && ansi_code <= 47) { + bg = ansi_code - 40; + } + switch (ansi_code) { + case 1: + attrs |= A_BOLD; + break; + + case 2: + attrs |= A_DIM; + break; + + case 4: + attrs |= A_UNDERLINE; + break; + + case 7: + attrs |= A_REVERSE; + break; } } - has_attrs = true; - break; + lpc = str.find(";", lpc); + if (lpc != (int)string::npos) { + lpc += 1; + } + } + if (fg != 0 || bg != 0) { + attrs |= vc.ansi_color_pair(fg, bg); + } + has_attrs = true; + break; - case 'C': + case 'C': { int spaces = 0; - if (sscanf(&(str[matches[2]]), "%d", &spaces) == 1) { - str.insert(c_end, spaces, ' '); + if (sscanf(&(str[caps[1].c_begin]), "%d", &spaces) == 1) { + str.insert(caps[0].c_end, spaces, ' '); } } break; - } - str.erase(str.begin() + c_start, str.begin() + c_end); - - if (has_attrs) { - if (!range_queue.empty()) { - range_queue.back().lr_end = c_start; - } - lr.lr_start = c_start; - lr.lr_end = -1; - range_queue.push_back(lr); - attr_queue.push_back(make_string_attr("style", attrs)); - } } - } while (rc > 0); + str.erase(str.begin() + caps[0].c_begin, + str.begin() + caps[0].c_end); + + if (has_attrs) { + if (!range_queue.empty()) { + range_queue.back().lr_end = caps[0].c_begin; + } + lr.lr_start = caps[0].c_begin; + lr.lr_end = -1; + range_queue.push_back(lr); + attr_queue.push_back(make_string_attr("style", attrs)); + } + + pi.reset(str); + } for (size_t lpc = 0; lpc < range_queue.size(); lpc++) { sa[range_queue[lpc]].insert(attr_queue[lpc]); @@ -167,26 +149,11 @@ public: }; private: - pcre *build_pcre(const char *pattern) /* XXX refactor me */ - { - const char *errptr; - pcre * retval; - int eoff; - - retval = pcre_compile(pattern, 0, &errptr, &eoff, NULL); - if (retval == NULL) { - throw errptr; - } - - return retval; - }; - ansi_scrubber() - { - this->as_pcre = this->build_pcre("\x1b\\[([\\d=;]*)([a-zA-Z])"); + : as_regex("\x1b\\[([\\d=;]*)([a-zA-Z])") { }; - pcre *as_pcre; + pcrepp as_regex; }; textview_curses::textview_curses() diff --git a/src/view_curses.cc b/src/view_curses.cc index 87cbc466..ad11bc78 100644 --- a/src/view_curses.cc +++ b/src/view_curses.cc @@ -237,6 +237,17 @@ view_colors::view_colors() void view_colors::init(void) { if (has_colors()) { + static int ansi_colors_to_curses[] = { + COLOR_BLACK, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + }; + start_color(); /* use_default_colors(); */ @@ -262,6 +273,14 @@ void view_colors::init(void) init_pair(VC_GRAY, COLOR_BLACK, COLOR_BLACK); + for (int fg = 0; fg < 8; fg++) { + for (int bg = 0; bg < 8; bg++) { + init_pair(ansi_color_pair_index(fg, bg), + ansi_colors_to_curses[fg], + ansi_colors_to_curses[bg]); + } + } + for (int lpc = 0; lpc < 8; lpc++) { short gradient_value = (1000 / 8) * lpc; diff --git a/src/view_curses.hh b/src/view_curses.hh index 44825d4f..8d74e710 100644 --- a/src/view_curses.hh +++ b/src/view_curses.hh @@ -414,9 +414,20 @@ public: VC_GRAY, + VC_ANSI_START, + VC_ANSI_END = VC_ANSI_START + (8 * 8), + VC_GRADIENT_START, }; + static inline int ansi_color_pair_index(int fg, int bg) { + return VC_ANSI_START + ((fg * 8) + bg); + }; + + int ansi_color_pair(int fg, int bg) { + return COLOR_PAIR(ansi_color_pair_index(fg, bg)); + }; + private: /** The number of colors used for highlighting. */ diff --git a/test/Makefile.am b/test/Makefile.am index e9567eff..78ea4f81 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -156,6 +156,7 @@ dist_noinst_SCRIPTS = \ test_vt52_curses.sh dist_noinst_DATA = \ + ansi-colors.0.in \ datafile_simple.0 \ datafile_simple.1 \ datafile_simple.2 \ diff --git a/test/Makefile.in b/test/Makefile.in index d874e281..297d569c 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -721,6 +721,7 @@ dist_noinst_SCRIPTS = \ test_vt52_curses.sh dist_noinst_DATA = \ + ansi-colors.0.in \ datafile_simple.0 \ datafile_simple.1 \ datafile_simple.2 \ diff --git a/test/ansi-colors.0.in b/test/ansi-colors.0.in new file mode 100644 index 00000000..8c2573dc --- /dev/null +++ b/test/ansi-colors.0.in @@ -0,0 +1,22 @@ +Basic ANSI colors (eight-color, or dim) + + black  black  red  green  yellow  blue  magenta cyan  white  +bold black  black  red  green  yellow  blue  magenta cyan  white  + red  black  red  green  yellow  blue  magenta cyan  white  +bold red  black  red  green  yellow  blue  magenta cyan  white  + green  black  red  green  yellow  blue  magenta cyan  white  +bold green  black  red  green  yellow  blue  magenta cyan  white  + yellow  black  red  green  yellow  blue  magenta cyan  white  +bold yellow  black  red  green  yellow  blue  magenta cyan  white  + blue  black  red  green  yellow  blue  magenta cyan  white  +bold blue  black  red  green  yellow  blue  magenta cyan  white  + magenta  black  red  green  yellow  blue  magenta cyan  white  +bold magenta  black  red  green  yellow  blue  magenta cyan  white  + cyan  black  red  green  yellow  blue  magenta cyan  white  +bold cyan  black  red  green  yellow  blue  magenta cyan  white  + white  black  red  green  yellow  blue  magenta cyan  white  +bold white  black  red  green  yellow  blue  magenta cyan  white  + +Attributes: bold dark italic underline blink concealed +  testing  testing  testing  testing  testing  testing  +