From 8ef581177ca4e2cb46ade2ff6d46bb532608ee81 Mon Sep 17 00:00:00 2001 From: Timothy Stack Date: Wed, 27 Jul 2022 21:49:14 -0700 Subject: [PATCH] [line_buffer] add some performance counters for tracking SQL perf Also, check for keyboard input during SQL execution so we can cancel. Fixes #894 --- NEWS | 4 + docs/schemas/config-v1.schema.json | 5 + src/base/ansi_scrubber.cc | 28 +- src/base/attr_line.cc | 14 +- src/base/intern_string.hh | 62 +- src/base/is_utf8.cc | 8 +- src/base/is_utf8.hh | 7 +- src/base/itertools.hh | 12 + src/base/lnav.console.cc | 25 +- src/base/snippet_highlighters.cc | 31 +- src/base/string_attr_type.cc | 2 +- src/base/string_attr_type.hh | 38 +- src/breadcrumb_curses.cc | 4 +- src/column_namer.cc | 8 +- src/column_namer.hh | 2 +- src/command_executor.cc | 56 +- src/db_sub_source.cc | 30 +- src/db_sub_source.hh | 2 +- src/field_overlay_source.cc | 22 +- src/files_sub_source.cc | 4 +- src/filter_status_source.cc | 5 +- src/filter_sub_source.cc | 38 +- src/formats/logfmt/logfmt.parser.cc | 117 +- src/highlighter.cc | 28 +- src/highlighter.hh | 13 +- src/hist_source.hh | 12 +- src/hotkeys.cc | 25 +- src/json-extension-functions.cc | 9 +- src/line_buffer.cc | 54 +- src/line_buffer.hh | 27 + src/listview_curses.cc | 18 +- src/lnav.cc | 36 +- src/lnav_commands.cc | 32 +- src/lnav_config.cc | 4 + src/lnav_util.cc | 1 + src/log_format.cc | 34 +- src/log_format_impls.cc | 11 +- src/log_search_table.cc | 4 +- src/log_vtab_impl.cc | 13 +- src/log_vtab_impl.hh | 3 + src/logfile.cc | 28 + src/logfile.hh | 2 + src/logfile_sub_source.cc | 9 +- src/md2attr_line.cc | 28 +- src/md4cpp.cc | 15 + src/pcrepp/pcrepp.hh | 13 +- src/plain_text_source.cc | 3 +- src/readline_callbacks.cc | 4 +- src/readline_curses.cc | 6 +- src/readline_highlighters.cc | 17 +- src/shared_buffer.hh | 2 +- src/spectro_source.cc | 4 +- src/sql_util.cc | 2 +- src/statusview_curses.cc | 24 +- src/string-extension-functions.cc | 5 +- src/styling.hh | 1 + src/textfile_sub_source.cc | 28 +- src/textview_curses.cc | 13 +- src/themes/default-theme.json | 1 - src/themes/grayscale.json | 1 - src/themes/monocai.json | 5 +- src/themes/night-owl.json | 1 - src/view_curses.cc | 1004 ++++++----------- src/view_curses.hh | 60 +- src/view_helpers.hh | 1 + src/views_vtab.cc | 3 +- src/vtab_module.hh | 22 +- src/vtab_module_json.hh | 4 +- src/yajlpp/yajlpp.cc | 4 +- test/Makefile.am | 1 + test/drive_mvwattrline.cc | 17 +- test/drive_view_colors.cc | 10 +- test/expected/expected.am | 2 + ...0943ef715598c7554b85de8502454e41bb9e28.out | 4 +- ...fabc25374ff47c47931f63b1d697061b816a28.out | 2 +- ...d326da92d1cacda63501cd1a3077381a18e8f2.out | 2 +- ...dd62995fdefc8318053af05a32416eccfa79fc.out | 2 +- ...2c0a90ce333365ff7354375f2c609bc27135c8.err | 2 +- ...670dfa1ae7ac5a074baa642068c6d26ac8e096.err | 2 +- ...2feef079a51410e1f8661bfe92da1c3277f665.err | 2 +- ...c1fb9affbfac609ebf1cc5556aafb1ecd223c1.err | 2 +- ...f0fc1a154b0d79b4f6e846f283426be498040f.err | 2 +- ...862ec9c8f261a8507d237eb673c7ddfaafd898.err | 2 +- ...872aadda29b9a824361a2c711d62ec1c75d40f.err | 0 ...872aadda29b9a824361a2c711d62ec1c75d40f.out | 74 ++ test/test_ansi_scrubber.cc | 9 +- test/test_text_file.sh | 4 + test/tui-captures/tui_echo.0 | 200 ++-- test/tui-captures/tui_help.0 | 161 ++- test/xpath_tui.0 | 512 ++++----- 90 files changed, 1597 insertions(+), 1573 deletions(-) create mode 100644 test/expected/test_text_file.sh_ac872aadda29b9a824361a2c711d62ec1c75d40f.err create mode 100644 test/expected/test_text_file.sh_ac872aadda29b9a824361a2c711d62ec1c75d40f.out diff --git a/NEWS b/NEWS index 84103266..1095a81b 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,8 @@ lnav v0.11.0: that range. You can then press TAB to focus on the detail view and scroll around. * Add initial support for pcap(3) files using tshark(1). + * SQL statement execution can now be canceled by pressing CTRL+] + (same as canceling out of a prompt). * To make it possible to automate some operations, there is now an "lnav_events" table that is updated when internal events occur within lnav (e.g. opening a file, format is detected). You @@ -105,6 +107,8 @@ lnav v0.11.0: * Fix a crash related to long lines that are word wrapped. * Multiple SQL statements in a SQL block of a script are now executed instead of just the first one. + * In cases where there were many different colors on screen, some + text would be colored incorrectly. lnav v0.10.1: Features: diff --git a/docs/schemas/config-v1.schema.json b/docs/schemas/config-v1.schema.json index 4e5c2977..c2b0fb40 100644 --- a/docs/schemas/config-v1.schema.json +++ b/docs/schemas/config-v1.schema.json @@ -269,6 +269,11 @@ "title": "/ui/theme-defs//styles/ok", "$ref": "#/definitions/style" }, + "info": { + "description": "Styling for informational messages", + "title": "/ui/theme-defs//styles/info", + "$ref": "#/definitions/style" + }, "warning": { "description": "Styling for warning messages", "title": "/ui/theme-defs//styles/warning", diff --git a/src/base/ansi_scrubber.cc b/src/base/ansi_scrubber.cc index 65f40bdb..a14010e3 100644 --- a/src/base/ansi_scrubber.cc +++ b/src/base/ansi_scrubber.cc @@ -50,7 +50,7 @@ void scrub_ansi_string(std::string& str, string_attrs_t& sa) { pcre_context_static<60> context; - pcrepp& regex = ansi_regex(); + auto& regex = ansi_regex(); pcre_input pi(str); replace(str.begin(), str.end(), '\0', ' '); @@ -58,9 +58,7 @@ scrub_ansi_string(std::string& str, string_attrs_t& sa) pcre_context::capture_t* caps = context.all(); struct line_range lr; bool has_attrs = false; - attr_t attrs = 0; - auto bg = nonstd::optional(); - auto fg = nonstd::optional(); + text_attrs attrs; auto role = nonstd::optional(); size_t lpc; @@ -74,29 +72,29 @@ scrub_ansi_string(std::string& str, string_attrs_t& sa) if (sscanf(&(str[lpc]), "%d", &ansi_code) == 1) { if (90 <= ansi_code && ansi_code <= 97) { ansi_code -= 60; - attrs |= A_STANDOUT; + attrs.ta_attrs |= A_STANDOUT; } if (30 <= ansi_code && ansi_code <= 37) { - fg = ansi_code - 30; + attrs.ta_fg_color = ansi_code - 30; } if (40 <= ansi_code && ansi_code <= 47) { - bg = ansi_code - 40; + attrs.ta_bg_color = ansi_code - 40; } switch (ansi_code) { case 1: - attrs |= A_BOLD; + attrs.ta_attrs |= A_BOLD; break; case 2: - attrs |= A_DIM; + attrs.ta_attrs |= A_DIM; break; case 4: - attrs |= A_UNDERLINE; + attrs.ta_attrs |= A_UNDERLINE; break; case 7: - attrs |= A_REVERSE; + attrs.ta_attrs |= A_REVERSE; break; } } @@ -160,17 +158,11 @@ scrub_ansi_string(std::string& str, string_attrs_t& sa) } lr.lr_start = caps[0].c_begin; lr.lr_end = -1; - if (attrs) { + if (attrs.ta_attrs || attrs.ta_fg_color || attrs.ta_bg_color) { sa.emplace_back(lr, VC_STYLE.value(attrs)); } role | [&lr, &sa](role_t r) { sa.emplace_back(lr, VC_ROLE.value(r)); }; - fg | [&lr, &sa](int color) { - sa.emplace_back(lr, VC_FOREGROUND.value(color)); - }; - bg | [&lr, &sa](int color) { - sa.emplace_back(lr, VC_BACKGROUND.value(color)); - }; } pi.reset(str); diff --git a/src/base/attr_line.cc b/src/base/attr_line.cc index dec130ab..bec25cf3 100644 --- a/src/base/attr_line.cc +++ b/src/base/attr_line.cc @@ -101,7 +101,7 @@ consume(const string_fragment text) pcre_input pi(text); pcre_context_static<30> pc; - if (WORD_RE.match(pc, pi)) { + if (WORD_RE.match(pc, pi, PCRE_NO_UTF8_CHECK)) { auto split_res = text.split_n(pc.all()->length()).value(); return word{split_res.first, split_res.second}; @@ -113,7 +113,7 @@ consume(const string_fragment text) return space{split_res.first, split_res.second}; } - if (SPACE_RE.match(pc, pi)) { + if (SPACE_RE.match(pc, pi, PCRE_NO_UTF8_CHECK)) { auto split_res = text.split_n(pc.all()->length()).value(); return space{split_res.first, split_res.second}; @@ -195,8 +195,8 @@ attr_line_t::insert(size_t index, const ssize_t usable_width = tws->tws_width - tws->tws_indent; - auto text_to_wrap - = string_fragment{this->al_string.data(), (int) starting_line_index}; + auto text_to_wrap = string_fragment::from_str_range( + this->al_string, starting_line_index, this->al_string.length()); string_fragment last_word; ssize_t line_ch_count = 0; auto needs_indent = false; @@ -225,7 +225,8 @@ attr_line_t::insert(size_t index, text_to_wrap = chunk.match( [&](text_stream::word word) { - auto ch_count = word.w_word.utf8_length().unwrap(); + auto ch_count + = word.w_word.utf8_length().unwrapOr(word.w_word.length()); if ((line_ch_count + ch_count) > usable_width && find_string_attr_containing(this->al_attrs, @@ -272,7 +273,8 @@ attr_line_t::insert(size_t index, } if (line_ch_count > 0) { - auto ch_count = space.s_value.utf8_length().unwrap(); + auto ch_count = space.s_value.utf8_length().unwrapOr( + space.s_value.length()); if ((line_ch_count + ch_count) > usable_width && find_string_attr_containing(this->al_attrs, diff --git a/src/base/intern_string.hh b/src/base/intern_string.hh index 4e2020f3..8562b30a 100644 --- a/src/base/intern_string.hh +++ b/src/base/intern_string.hh @@ -47,15 +47,71 @@ struct string_fragment { using iterator = const char*; + static string_fragment from_c_str(const char* str) + { + return string_fragment{str, 0, (int) strlen(str)}; + } + + template + static string_fragment from_const(const T (&str)[N]) + { + return string_fragment{str, 0, (int) N - 1}; + } + + static string_fragment from_str(const std::string& str) + { + return string_fragment{str.c_str(), 0, (int) str.size()}; + } + + static string_fragment from_substr(const std::string& str, + size_t offset, + size_t length) + { + return string_fragment{ + str.c_str(), (int) offset, (int) (offset + length)}; + } + + static string_fragment from_str_range(const std::string& str, + size_t begin, + size_t end) + { + return string_fragment{str.c_str(), (int) begin, (int) end}; + } + + static string_fragment from_bytes(const char* bytes, size_t len) + { + return string_fragment{bytes, 0, (int) len}; + } + + static string_fragment from_bytes(const unsigned char* bytes, size_t len) + { + return string_fragment{(const char*) bytes, 0, (int) len}; + } + + static string_fragment from_memory_buffer(const fmt::memory_buffer& buf) + { + return string_fragment{buf.data(), 0, (int) buf.size()}; + } + + static string_fragment from_byte_range(const char* bytes, + size_t begin, + size_t end) + { + return string_fragment{bytes, (int) begin, (int) end}; + } + explicit string_fragment(const char* str = "", int begin = 0, int end = -1) - : sf_string(str), sf_begin(begin), - sf_end(end == -1 ? strlen(str) : end){}; + : sf_string(str), sf_begin(begin), sf_end(end == -1 ? strlen(str) : end) + { + } explicit string_fragment(const unsigned char* str, int begin = 0, int end = -1) : sf_string((const char*) str), sf_begin(begin), - sf_end(end == -1 ? strlen((const char*) str) : end){}; + sf_end(end == -1 ? strlen((const char*) str) : end) + { + } string_fragment(const std::string& str) : sf_string(str.c_str()), sf_begin(0), sf_end(str.length()) diff --git a/src/base/is_utf8.cc b/src/base/is_utf8.cc index e861e175..1b77d01a 100644 --- a/src/base/is_utf8.cc +++ b/src/base/is_utf8.cc @@ -60,14 +60,18 @@ error. */ ssize_t -is_utf8(unsigned char* str, size_t len, const char** message, int* faulty_bytes) +is_utf8(const unsigned char* str, + size_t len, + const char** message, + int* faulty_bytes, + nonstd::optional terminator) { size_t i = 0; *message = nullptr; *faulty_bytes = 0; while (i < len) { - if (str[i] == '\n') { + if (terminator && str[i] == terminator.value()) { *message = nullptr; return i; } diff --git a/src/base/is_utf8.hh b/src/base/is_utf8.hh index 2e39cdc7..bb157f0b 100644 --- a/src/base/is_utf8.hh +++ b/src/base/is_utf8.hh @@ -31,9 +31,12 @@ #include #include -ssize_t is_utf8(unsigned char* str, +#include "optional.hpp" + +ssize_t is_utf8(const unsigned char* str, size_t len, const char** message, - int* faulty_bytes); + int* faulty_bytes, + nonstd::optional terminator = nonstd::nullopt); #endif /* _IS_UTF8_H */ diff --git a/src/base/itertools.hh b/src/base/itertools.hh index 070448b5..058ceb81 100644 --- a/src/base/itertools.hh +++ b/src/base/itertools.hh @@ -588,6 +588,18 @@ operator|(nonstd::optional in, lnav::func::invoke(eacher.fe_func, in.value()); } +template::value, int> = 0> +void +operator|(std::vector>& in, + const lnav::itertools::details::for_eacher& eacher) +{ + for (auto& elem : in) { + lnav::func::invoke(eacher.fe_func, *elem); + } +} + template::value, int> = 0> diff --git a/src/base/lnav.console.cc b/src/base/lnav.console.cc index d3fff707..3ff5ee0e 100644 --- a/src/base/lnav.console.cc +++ b/src/base/lnav.console.cc @@ -110,7 +110,7 @@ user_message::to_attr_line(std::set flags) const retval.append(lnav::roles::ok("\u2714 ")); break; case level::info: - retval.append(lnav::roles::status("\u24d8 info")).append(": "); + retval.append("\u24d8 info"_info).append(": "); break; case level::warning: retval.append(lnav::roles::warning("\u26a0 warning")) @@ -293,15 +293,31 @@ println(FILE* file, const attr_line_t& al) fg_style = fmt::fg(color_opt.value()); } } else if (attr.sa_type == &VC_STYLE) { - auto saw = string_attr_wrapper(&attr); + auto saw = string_attr_wrapper(&attr); auto style = saw.get(); - if (style & A_REVERSE) { + if (style.ta_attrs & A_REVERSE) { line_style |= fmt::emphasis::reverse; } - if (style & A_BOLD) { + if (style.ta_attrs & A_BOLD) { line_style |= fmt::emphasis::bold; } + if (style.ta_fg_color) { + auto color_opt = curses_color_to_terminal_color( + style.ta_fg_color.value()); + + if (color_opt) { + fg_style = fmt::fg(color_opt.value()); + } + } + if (style.ta_bg_color) { + auto color_opt = curses_color_to_terminal_color( + style.ta_bg_color.value()); + + if (color_opt) { + line_style |= fmt::bg(color_opt.value()); + } + } } else if (attr.sa_type == &SA_LEVEL) { auto level = static_cast( attr.sa_value.get()); @@ -341,6 +357,7 @@ println(FILE* file, const attr_line_t& al) line_style |= fmt::emphasis::bold | fmt::fg(fmt::terminal_color::green); break; + case role_t::VCR_INFO: case role_t::VCR_STATUS: line_style |= fmt::emphasis::bold | fmt::fg(fmt::terminal_color::magenta); diff --git a/src/base/snippet_highlighters.cc b/src/base/snippet_highlighters.cc index 8f2da629..de632aa9 100644 --- a/src/base/snippet_highlighters.cc +++ b/src/base/snippet_highlighters.cc @@ -68,7 +68,7 @@ find_matching_bracket( } else if (line[lpc] == left && is_bracket(line, lpc, is_lit)) { if (depth == 0) { alb.overlay_attr_for_char( - lpc, VC_STYLE.value(A_BOLD | A_REVERSE)); + lpc, VC_STYLE.value(text_attrs{A_BOLD | A_REVERSE})); alb.overlay_attr_for_char(lpc, VC_ROLE.value(role_t::VCR_OK)); break; @@ -85,7 +85,7 @@ find_matching_bracket( } else if (line[lpc] == right && is_bracket(line, lpc, is_lit)) { if (depth == 0) { alb.overlay_attr_for_char( - lpc, VC_STYLE.value(A_BOLD | A_REVERSE)); + lpc, VC_STYLE.value(text_attrs{A_BOLD | A_REVERSE})); alb.overlay_attr_for_char(lpc, VC_ROLE.value(role_t::VCR_OK)); break; @@ -110,7 +110,8 @@ find_matching_bracket( depth -= 1; } else { auto lr = line_range(is_lit ? lpc - 1 : lpc, lpc + 1); - alb.overlay_attr(lr, VC_STYLE.value(A_BOLD | A_REVERSE)); + alb.overlay_attr( + lr, VC_STYLE.value(text_attrs{A_BOLD | A_REVERSE})); alb.overlay_attr(lr, VC_ROLE.value(role_t::VCR_ERROR)); } } @@ -120,7 +121,7 @@ find_matching_bracket( auto lr = line_range(is_lit ? first_left.value() - 1 : first_left.value(), first_left.value() + 1); - alb.overlay_attr(lr, VC_STYLE.value(A_BOLD | A_REVERSE)); + alb.overlay_attr(lr, VC_STYLE.value(text_attrs{A_BOLD | A_REVERSE})); alb.overlay_attr(lr, VC_ROLE.value(role_t::VCR_ERROR)); } } @@ -189,7 +190,8 @@ regex_highlighter(attr_line_t& al, int x, line_range sub) if (lpc == sub.lr_start || (lpc - sub.lr_start) == 0) { alb.overlay_attr_for_char( - lpc, VC_STYLE.value(A_BOLD | A_REVERSE)); + lpc, + VC_STYLE.value(text_attrs{A_BOLD | A_REVERSE})); alb.overlay_attr_for_char( lpc, VC_ROLE.value(role_t::VCR_ERROR)); } else if (line[lpc - 1] == '(') { @@ -220,10 +222,11 @@ regex_highlighter(attr_line_t& al, int x, line_range sub) case '>': { static const pcrepp CAP_RE(R"(\(\?\<\w+$)"); - auto sf = string_fragment{ - line.c_str(), sub.lr_start, (int) lpc}; - auto capture_start = sf.find_left_boundary( - lpc - sub.lr_start - 1, string_fragment::tag1{'('}); + auto capture_start + = string_fragment::from_str_range( + line, sub.lr_start, lpc) + .find_left_boundary(lpc - sub.lr_start - 1, + string_fragment::tag1{'('}); pcre_context_static<30> pc; pcre_input pi(capture_start); @@ -280,8 +283,9 @@ regex_highlighter(attr_line_t& al, int x, line_range sub) VC_ROLE.value(role_t::VCR_SYMBOL)); break; case ' ': - alb.overlay_attr(line_range(lpc - 1, lpc + 1), - VC_STYLE.value(A_BOLD | A_REVERSE)); + alb.overlay_attr( + line_range(lpc - 1, lpc + 1), + VC_STYLE.value(text_attrs{A_BOLD | A_REVERSE})); alb.overlay_attr(line_range(lpc - 1, lpc + 1), VC_ROLE.value(role_t::VCR_ERROR)); break; @@ -296,8 +300,9 @@ regex_highlighter(attr_line_t& al, int x, line_range sub) alb.overlay_attr(line_range(lpc - 1, lpc + 3), VC_ROLE.value(role_t::VCR_RE_SPECIAL)); } else { - alb.overlay_attr(line_range(lpc - 1, lpc + 1), - VC_STYLE.value(A_BOLD | A_REVERSE)); + alb.overlay_attr( + line_range(lpc - 1, lpc + 1), + VC_STYLE.value(text_attrs{A_BOLD | A_REVERSE})); alb.overlay_attr(line_range(lpc - 1, lpc + 1), VC_ROLE.value(role_t::VCR_ERROR)); } diff --git a/src/base/string_attr_type.cc b/src/base/string_attr_type.cc index b56c5883..99c7ea66 100644 --- a/src/base/string_attr_type.cc +++ b/src/base/string_attr_type.cc @@ -43,7 +43,7 @@ string_attr_type SA_LEVEL("level"); string_attr_type VC_ROLE("role"); string_attr_type VC_ROLE_FG("role-fg"); -string_attr_type VC_STYLE("style"); +string_attr_type VC_STYLE("style"); string_attr_type VC_GRAPHIC("graphic"); string_attr_type VC_FOREGROUND("foreground"); string_attr_type VC_BACKGROUND("background"); diff --git a/src/base/string_attr_type.hh b/src/base/string_attr_type.hh index a4ef93df..bbc3aeb6 100644 --- a/src/base/string_attr_type.hh +++ b/src/base/string_attr_type.hh @@ -49,6 +49,7 @@ enum class role_t : int32_t { VCR_IDENTIFIER, VCR_SEARCH, /*< A search hit. */ VCR_OK, + VCR_INFO, VCR_ERROR, /*< An error message. */ VCR_WARNING, /*< A warning message. */ VCR_ALT_ROW, /*< Highlight for alternating rows in a list */ @@ -127,8 +128,29 @@ enum class role_t : int32_t { VCR__MAX }; +struct text_attrs { + bool empty() const + { + return this->ta_attrs == 0 && !this->ta_fg_color && !this->ta_bg_color; + } + + text_attrs operator|(const text_attrs& other) const + { + return text_attrs{ + this->ta_attrs | other.ta_attrs, + this->ta_fg_color ? this->ta_fg_color : other.ta_fg_color, + this->ta_bg_color ? this->ta_bg_color : other.ta_bg_color, + }; + } + + int32_t ta_attrs{0}; + nonstd::optional ta_fg_color; + nonstd::optional ta_bg_color; +}; + using string_attr_value = mapbox::util::variant, @@ -183,7 +205,7 @@ extern string_attr_type SA_LEVEL; extern string_attr_type VC_ROLE; extern string_attr_type VC_ROLE_FG; -extern string_attr_type VC_STYLE; +extern string_attr_type VC_STYLE; extern string_attr_type VC_GRAPHIC; extern string_attr_type VC_FOREGROUND; extern string_attr_type VC_BACKGROUND; @@ -455,6 +477,13 @@ h6(S str) namespace literals { +inline std::pair operator"" _info( + const char* str, std::size_t len) +{ + return std::make_pair(std::string(str, len), + VC_ROLE.template value(role_t::VCR_INFO)); +} + inline std::pair operator"" _symbol( const char* str, std::size_t len) { @@ -483,6 +512,13 @@ inline std::pair operator"" _comment( VC_ROLE.template value(role_t::VCR_COMMENT)); } +inline std::pair operator"" _hotkey( + const char* str, std::size_t len) +{ + return std::make_pair(std::string(str, len), + VC_ROLE.template value(role_t::VCR_STATUS_HOTKEY)); +} + inline std::pair operator"" _h1(const char* str, std::size_t len) { diff --git a/src/breadcrumb_curses.cc b/src/breadcrumb_curses.cc index 1c0c8aa4..eb05d4d2 100644 --- a/src/breadcrumb_curses.cc +++ b/src/breadcrumb_curses.cc @@ -90,7 +90,7 @@ breadcrumb_curses::do_update() - crumb.c_display_value.length()), (int) crumbs_line.length(), }, - VC_STYLE.template value(A_REVERSE)); + VC_STYLE.template value(text_attrs{A_REVERSE})); } crumb_index += 1; crumbs_line.append("\u276d"_breadcrumb); @@ -385,7 +385,7 @@ breadcrumb_curses::search_overlay_source::list_value_for_overlay( | lnav::itertools::unwrap_or( breadcrumb::crumb::expected_input_t::exact); - value_out.with_attr_for_all(VC_STYLE.value(A_UNDERLINE)); + value_out.with_attr_for_all(VC_STYLE.value(text_attrs{A_UNDERLINE})); if (!parent->bc_current_search.empty()) { value_out = parent->bc_current_search; diff --git a/src/column_namer.cc b/src/column_namer.cc index c17009de..ba2d8729 100644 --- a/src/column_namer.cc +++ b/src/column_namer.cc @@ -38,7 +38,7 @@ #include "config.h" #include "sql_util.hh" -const char* column_namer::BUILTIN_COL = "col"; +const char column_namer::BUILTIN_COL[] = "col"; column_namer::column_namer(language lang) : cn_language(lang) {} @@ -79,7 +79,7 @@ column_namer::add_column(const string_fragment& in_name) int num = 0; if (in_name.empty()) { - base_name = string_fragment{BUILTIN_COL}; + base_name = string_fragment::from_const(BUILTIN_COL); } else { base_name = in_name; } @@ -90,7 +90,7 @@ column_namer::add_column(const string_fragment& in_name) num = ++counter_iter->second; fmt::format_to( std::back_inserter(buf), FMT_STRING("{}_{}"), base_name, num); - retval = string_fragment{buf.data(), 0, (int) buf.size()}; + retval = string_fragment::from_memory_buffer(buf); } while (this->existing_name(retval)) { @@ -103,7 +103,7 @@ column_namer::add_column(const string_fragment& in_name) "column name already exists: %.*s", retval.length(), retval.data()); fmt::format_to( std::back_inserter(buf), FMT_STRING("{}_{}"), base_name, num); - retval = string_fragment{buf.data(), 0, (int) buf.size()}; + retval = string_fragment::from_memory_buffer(buf); num += 1; } diff --git a/src/column_namer.hh b/src/column_namer.hh index 120db55e..a98d9efd 100644 --- a/src/column_namer.hh +++ b/src/column_namer.hh @@ -52,7 +52,7 @@ public: string_fragment add_column(const string_fragment& in_name); - static const char* BUILTIN_COL; + static const char BUILTIN_COL[]; ArenaAlloc::Alloc cn_alloc; language cn_language; diff --git a/src/command_executor.cc b/src/command_executor.cc index 28e818f5..ff71de3b 100644 --- a/src/command_executor.cc +++ b/src/command_executor.cc @@ -34,6 +34,7 @@ #include "base/ansi_scrubber.hh" #include "base/fs_util.hh" #include "base/injector.hh" +#include "base/itertools.hh" #include "base/string_util.hh" #include "bound_tags.hh" #include "config.h" @@ -51,6 +52,8 @@ #include "vtab_module.hh" #include "yajlpp/json_ptr.hh" +using namespace lnav::roles::literals; + exec_context INIT_EXEC_CONTEXT; static const std::string MSG_FORMAT_STMT = R"( @@ -123,10 +126,36 @@ sql_progress(const struct log_cursor& lc) } if (ui_periodic_timer::singleton().time_to_update(sql_counter)) { + struct timeval current_time = {0, 0}; + int ch; + + while ((ch = getch()) != ERR) { + if (current_time.tv_sec == 0) { + gettimeofday(¤t_time, nullptr); + } + lnav_data.ld_user_message_source.clear(); + + alerter::singleton().new_input(ch); + + lnav_data.ld_input_dispatcher.new_input(current_time, ch); + + lnav_data.ld_view_stack.top() | [ch](auto tc) { + lnav_data.ld_key_repeat_history.update(ch, tc->get_top()); + }; + + if (!lnav_data.ld_looping) { + // No reason to keep processing input after the + // user has quit. The view stack will also be + // empty, which will cause issues. + break; + } + } + lnav_data.ld_bottom_source.update_loading(off, total); lnav_data.ld_top_source.update_time(); lnav_data.ld_status[LNS_TOP].do_update(); lnav_data.ld_status[LNS_BOTTOM].do_update(); + lnav_data.ld_rl_view->do_update(); refresh(); } @@ -316,6 +345,9 @@ execute_sql(exec_context& ec, const std::string& sql, std::string& alt_msg) log_info("Executing SQL: %s", sql.c_str()); + auto old_mode = lnav_data.ld_mode; + lnav_data.ld_mode = ln_mode_t::BUSY; + auto mode_fin = finally([old_mode]() { lnav_data.ld_mode = old_mode; }); lnav_data.ld_bottom_source.grep_error(""); if (startswith(stmt_str, ".")) { @@ -400,7 +432,15 @@ execute_sql(exec_context& ec, const std::string& sql, std::string& alt_msg) auto bound_values = TRY(bind_sql_parameters(ec, stmt.in())); if (lnav_data.ld_rl_view != nullptr) { - lnav_data.ld_rl_view->set_value("Executing query: " + sql + " ..."); + if (lnav_data.ld_rl_view) { + lnav_data.ld_rl_view->set_attr_value( + lnav::console::user_message::info( + attr_line_t("executing SQL statement, press ") + .append("CTRL+]"_hotkey) + .append(" to cancel")) + .to_attr_line()); + lnav_data.ld_rl_view->do_update(); + } } ec.ec_sql_callback(ec, stmt.in()); @@ -473,6 +513,8 @@ execute_sql(exec_context& ec, const std::string& sql, std::string& alt_msg) lnav_data.ld_views[LNV_DB].reload_data(); lnav_data.ld_views[LNV_DB].set_left(0); + lnav_data.ld_active_files.fc_files + | lnav::itertools::for_each(&logfile::dump_stats); if (!ec.ec_accumulator->empty()) { retval = ec.ec_accumulator->get_string(); } else if (!dls.dls_rows.empty()) { @@ -853,8 +895,8 @@ sql_callback(exec_context& ec, sqlite3_stmt* stmt) return 0; } - stacked_bar_chart& chart = dls.dls_chart; - view_colors& vc = view_colors::singleton(); + auto& chart = dls.dls_chart; + auto& vc = view_colors::singleton(); int ncols = sqlite3_column_count(stmt); int row_number; int lpc, retval = 0; @@ -875,7 +917,7 @@ sql_callback(exec_context& ec, sqlite3_stmt* stmt) dls.push_header(colname, type, graphable); if (graphable) { - int attrs = vc.attrs_for_ident(colname); + auto attrs = vc.attrs_for_ident(colname); chart.with_attrs_for_ident(colname, attrs); } } @@ -898,11 +940,9 @@ sql_callback(exec_context& ec, sqlite3_stmt* stmt) value = null_value_t{}; break; default: - value = string_fragment{ + value = string_fragment::from_bytes( sqlite3_value_text(raw_value), - 0, - sqlite3_value_bytes(raw_value), - }; + sqlite3_value_bytes(raw_value)); break; } dls.push_column(value); diff --git a/src/db_sub_source.cc b/src/db_sub_source.cc index bb5f4b84..caa0b15e 100644 --- a/src/db_sub_source.cc +++ b/src/db_sub_source.cc @@ -37,7 +37,7 @@ #include "config.h" #include "yajlpp/json_ptr.hh" -const char* db_label_source::NULL_STR = ""; +const char db_label_source::NULL_STR[] = ""; constexpr size_t MAX_COLUMN_WIDTH = 120; constexpr size_t MAX_JSON_WIDTH = 16 * 1024; @@ -93,7 +93,7 @@ db_label_source::text_attrs_for_line(textview_curses& tc, } for (size_t lpc = 0; lpc < this->dls_headers.size() - 1; lpc++) { if (row % 2 == 0) { - sa.emplace_back(lr2, VC_STYLE.value(A_BOLD)); + sa.emplace_back(lr2, VC_STYLE.value(text_attrs{A_BOLD})); } lr.lr_start += this->dls_cell_width[lpc]; lr.lr_end = lr.lr_start + 1; @@ -166,7 +166,7 @@ db_label_source::push_column(const scoped_value_t& sv) double num_value = 0.0; auto col_sf = sv.match( - [](const std::string& str) { return string_fragment{str}; }, + [](const std::string& str) { return string_fragment::from_str(str); }, [this](const string_fragment& sf) { return sf.to_owned(*this->dls_allocator); }, @@ -174,17 +174,17 @@ db_label_source::push_column(const scoped_value_t& sv) fmt::memory_buffer buf; fmt::format_to(std::back_inserter(buf), FMT_STRING("{}"), i); - return string_fragment{buf.data(), 0, (int) buf.size()}.to_owned( + return string_fragment::from_memory_buffer(buf).to_owned( *this->dls_allocator); }, [this](double d) { fmt::memory_buffer buf; fmt::format_to(std::back_inserter(buf), FMT_STRING("{}"), d); - return string_fragment{buf.data(), 0, (int) buf.size()}.to_owned( + return string_fragment::from_memory_buffer(buf).to_owned( *this->dls_allocator); }, - [](null_value_t) { return string_fragment{NULL_STR}; }); + [](null_value_t) { return string_fragment::from_const(NULL_STR); }); if (index == this->dls_time_column_index) { date_time_scanner dts; @@ -332,7 +332,7 @@ db_overlay_source::list_overlay_count(const listview_curses& lv) sa.emplace_back(lr, VC_GRAPHIC.value(ACS_LTEE)); lr.lr_start = 3 + jpw_value.wt_ptr.size() + 3; lr.lr_end = -1; - sa.emplace_back(lr, VC_STYLE.value(A_BOLD)); + sa.emplace_back(lr, VC_STYLE.value(text_attrs{A_BOLD})); double num_value = 0.0; @@ -340,7 +340,7 @@ db_overlay_source::list_overlay_count(const listview_curses& lv) && sscanf(jpw_value.wt_value.c_str(), "%lf", &num_value) == 1) { - int attrs = vc.attrs_for_ident(jpw_value.wt_ptr); + auto attrs = vc.attrs_for_ident(jpw_value.wt_ptr); chart.add_value(jpw_value.wt_ptr, num_value); chart.with_attrs_for_ident(jpw_value.wt_ptr, attrs); @@ -423,17 +423,19 @@ db_overlay_source::list_value_for_overlay(const listview_curses& lv, struct line_range header_range(line_len_before, line.length()); - int attrs - = vc.attrs_for_ident(dls->dls_headers[lpc].hm_name) | A_REVERSE; - if (!this->dos_labels->dls_headers[lpc].hm_graphable) { - attrs = A_UNDERLINE; + text_attrs attrs; + if (this->dos_labels->dls_headers[lpc].hm_graphable) { + attrs = vc.attrs_for_ident(dls->dls_headers[lpc].hm_name) + | text_attrs{A_REVERSE}; + } else { + attrs.ta_attrs = A_UNDERLINE; } - sa.emplace_back(header_range, VC_STYLE.value(attrs)); + sa.emplace_back(header_range, VC_STYLE.value(text_attrs{attrs})); } struct line_range lr(0); - sa.emplace_back(lr, VC_STYLE.value(A_BOLD | A_UNDERLINE)); + sa.emplace_back(lr, VC_STYLE.value(text_attrs{A_BOLD | A_UNDERLINE})); return true; } else if (this->dos_active && y >= 2 && ((size_t) y) < (this->dos_lines.size() + 2)) diff --git a/src/db_sub_source.hh b/src/db_sub_source.hh index 41aad261..659e531a 100644 --- a/src/db_sub_source.hh +++ b/src/db_sub_source.hh @@ -123,7 +123,7 @@ public: std::unique_ptr> dls_allocator{ std::make_unique>(64 * 1024)}; - static const char* NULL_STR; + static const char NULL_STR[]; }; class db_overlay_source : public list_overlay_source { diff --git a/src/field_overlay_source.cc b/src/field_overlay_source.cc index 0aba62f7..c5fdac72 100644 --- a/src/field_overlay_source.cc +++ b/src/field_overlay_source.cc @@ -131,7 +131,7 @@ field_overlay_source::build_field_lines(const listview_curses& lv) time_str.append(curr_timestamp); time_lr.lr_end = time_str.length(); time_line.with_attr( - string_attr(time_lr, VC_STYLE.value(A_BOLD))); + string_attr(time_lr, VC_STYLE.value(text_attrs{A_BOLD}))); time_str.append(" -- "); time_lr.lr_start = time_str.length(); time_str.append(humanize::time::point::from_tv(ll->get_timeval()) @@ -139,7 +139,7 @@ field_overlay_source::build_field_lines(const listview_curses& lv) .as_precise_time_ago()); time_lr.lr_end = time_str.length(); time_line.with_attr( - string_attr(time_lr, VC_STYLE.value(A_BOLD))); + string_attr(time_lr, VC_STYLE.value(text_attrs{A_BOLD}))); struct line_range time_range = find_string_attr_range( this->fos_log_helper.ldh_line_attrs, &logline::L_TIMESTAMP); @@ -181,7 +181,7 @@ field_overlay_source::build_field_lines(const listview_curses& lv) humanize::time::duration::from_tv(diff_tv).to_string()); time_lr.lr_end = time_str.length(); time_line.with_attr( - string_attr(time_lr, VC_STYLE.value(A_BOLD))); + string_attr(time_lr, VC_STYLE.value(text_attrs{A_BOLD}))); } } @@ -282,10 +282,10 @@ field_overlay_source::build_field_lines(const listview_curses& lv) if (curr_format != last_format) { this->fos_lines.emplace_back(" Known message fields for table " + format_name + ":"); - this->fos_lines.back().with_attr(string_attr( - line_range(32, 32 + format_name.length()), - VC_STYLE.value(vc.attrs_for_ident(format_name) - | A_BOLD))); + this->fos_lines.back().with_attr( + string_attr(line_range(32, 32 + format_name.length()), + VC_STYLE.value(vc.attrs_for_ident(format_name) + | text_attrs{A_BOLD}))); last_format = curr_format; } @@ -344,8 +344,8 @@ field_overlay_source::build_field_lines(const listview_curses& lv) - 9 + 3, ' ') .append(" = ") - .append(string_fragment{ - (const char*) js.js_content.in(), 0, (int) js.js_len}); + .append( + string_fragment::from_bytes(js.js_content.in(), js.js_len)); this->fos_lines.emplace_back(al); this->add_key_line_attrs(this->fos_known_key_size); } @@ -406,7 +406,7 @@ field_overlay_source::build_field_lines(const listview_curses& lv) auto& disc_str = al.get_string(); al.with_attr(string_attr(line_range(disc_str.length(), -1), - VC_STYLE.value(A_BOLD))); + VC_STYLE.value(text_attrs{A_BOLD}))); disc_str.append(this->fos_log_helper.ldh_msg_format); } @@ -488,7 +488,7 @@ field_overlay_source::add_key_line_attrs(int key_size, bool last_line) lr.lr_start = 3 + key_size + 3; lr.lr_end = -1; - sa.emplace_back(lr, VC_STYLE.value(A_BOLD)); + sa.emplace_back(lr, VC_STYLE.value(text_attrs{A_BOLD})); } bool diff --git a/src/files_sub_source.cc b/src/files_sub_source.cc index 3c8b9607..48a3f56e 100644 --- a/src/files_sub_source.cc +++ b/src/files_sub_source.cc @@ -334,7 +334,7 @@ files_sub_source::text_attrs_for_line(textview_curses& tc, } if (line == fc.fc_other_files.size() - 1) { value_out.emplace_back(line_range{0, -1}, - VC_STYLE.value(A_UNDERLINE)); + VC_STYLE.value(text_attrs{A_UNDERLINE})); } return; } @@ -366,7 +366,7 @@ files_sub_source::text_attrs_for_line(textview_curses& tc, (int) filename_width + 3 + 4, (int) filename_width + 3 + 10, }; - value_out.emplace_back(lr, VC_STYLE.value(A_BOLD)); + value_out.emplace_back(lr, VC_STYLE.value(text_attrs{A_BOLD})); lr.lr_start = this->fss_last_line_len; lr.lr_end = -1; diff --git a/src/filter_status_source.cc b/src/filter_status_source.cc index 1b3b0451..79786425 100644 --- a/src/filter_status_source.cc +++ b/src/filter_status_source.cc @@ -210,10 +210,9 @@ filter_status_source::update_filtered(text_sub_source* tss) if (tss->get_filtered_count() == this->bss_last_filtered_count) { if (timer.fade_diff(this->bss_filter_counter) == 0) { - this->tss_fields[TSF_FILTERED].set_role( - role_t::VCR_STATUS); + this->tss_fields[TSF_FILTERED].set_role(role_t::VCR_STATUS); al.with_attr(string_attr(line_range{0, -1}, - VC_STYLE.value(A_BOLD))); + VC_STYLE.value(text_attrs{A_BOLD}))); } } else { this->tss_fields[TSF_FILTERED].set_role( diff --git a/src/filter_sub_source.cc b/src/filter_sub_source.cc index f570c7c9..6ce518c6 100644 --- a/src/filter_sub_source.cc +++ b/src/filter_sub_source.cc @@ -298,9 +298,9 @@ filter_sub_source::text_value_for_line(textview_curses& tc, std::string& value_out, text_sub_source::line_flags_t flags) { - textview_curses* top_view = *lnav_data.ld_view_stack.top(); - text_sub_source* tss = top_view->get_sub_source(); - filter_stack& fs = tss->get_filters(); + auto* top_view = *lnav_data.ld_view_stack.top(); + auto* tss = top_view->get_sub_source(); + auto& fs = tss->get_filters(); auto tf = *(fs.begin() + line); value_out = " "; @@ -357,19 +357,21 @@ filter_sub_source::text_attrs_for_line(textview_curses& tc, value_out.emplace_back(lr, VC_FOREGROUND.value(COLOR_GREEN)); } + if (selected) { + value_out.emplace_back(line_range{0, -1}, + VC_ROLE.value(role_t::VCR_FOCUSED)); + } + role_t fg_role = tf->get_type() == text_filter::INCLUDE ? role_t::VCR_OK : role_t::VCR_ERROR; value_out.emplace_back(line_range{4, 7}, VC_ROLE.value(fg_role)); - value_out.emplace_back(line_range{4, 7}, VC_STYLE.value(A_BOLD)); + value_out.emplace_back(line_range{4, 7}, + VC_STYLE.value(text_attrs{A_BOLD})); - value_out.emplace_back(line_range{8, 17}, VC_STYLE.value(A_BOLD)); + value_out.emplace_back(line_range{8, 17}, + VC_STYLE.value(text_attrs{A_BOLD})); value_out.emplace_back(line_range{23, 24}, VC_GRAPHIC.value(ACS_VLINE)); - if (selected) { - value_out.emplace_back(line_range{0, -1}, - VC_ROLE.value(role_t::VCR_FOCUSED)); - } - attr_line_t content{tf->get_id()}; auto& content_attrs = content.get_attrs(); @@ -436,15 +438,11 @@ filter_sub_source::rl_change(readline_curses* rc) } else { auto& hm = top_view->get_highlights(); highlighter hl(code.release()); - int color; - - if (tf->get_type() == text_filter::EXCLUDE) { - color = COLOR_RED; - } else { - color = COLOR_GREEN; - } - hl.with_attrs(view_colors::ansi_color_pair(COLOR_BLACK, color) - | A_BLINK); + auto role = tf->get_type() == text_filter::EXCLUDE + ? role_t::VCR_DIFF_DELETE + : role_t::VCR_DIFF_ADD; + hl.with_role(role); + hl.with_attrs(text_attrs{A_BLINK | A_REVERSE}); hm[{highlight_source_t::PREVIEW, "preview"}] = hl; top_view->set_needs_update(); @@ -616,7 +614,7 @@ filter_sub_source::rl_display_matches(readline_curses* rc) for (const auto& match : matches) { if (match == current_match) { - al.append(match, VC_STYLE.value(A_REVERSE)); + al.append(match, VC_STYLE.value(text_attrs{A_REVERSE})); selected_line = line; } else { al.append(match); diff --git a/src/formats/logfmt/logfmt.parser.cc b/src/formats/logfmt/logfmt.parser.cc index 6231c09d..47748102 100644 --- a/src/formats/logfmt/logfmt.parser.cc +++ b/src/formats/logfmt/logfmt.parser.cc @@ -21,26 +21,23 @@ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @file logfmt.parser.cc */ -#include "config.h" +#include "logfmt.parser.hh" #include "base/string_util.hh" -#include "logfmt.parser.hh" +#include "config.h" -logfmt::parser::parser(string_fragment sf) - : p_next_input(sf) -{ +logfmt::parser::parser(string_fragment sf) : p_next_input(sf) {} -} - -static bool is_not_eq(char ch) +static bool +is_not_eq(char ch) { return ch != '='; } @@ -68,11 +65,13 @@ struct bare_value_predicate { float_state_t bvp_float_state{float_state_t::INIT}; size_t bvp_index{0}; - bool is_integer() const { + bool is_integer() const + { return this->bvp_int_state == int_state_t::DIGITS; } - bool is_float() const { + bool is_float() const + { switch (this->bvp_float_state) { case float_state_t::DIGITS: case float_state_t::FRACTION_DIGIT: @@ -83,7 +82,8 @@ struct bare_value_predicate { } } - bool operator()(char ch) { + bool operator()(char ch) + { if (ch == ' ') { return false; } @@ -169,7 +169,8 @@ struct bare_value_predicate { } }; -logfmt::parser::step_result logfmt::parser::step() +logfmt::parser::step_result +logfmt::parser::step() { const static auto IS_DQ = string_fragment::tag1{'"'}; @@ -209,48 +210,52 @@ logfmt::parser::step_result logfmt::parser::step() } this->p_next_input = after_quote.value(); - return std::make_pair(key_frag, quoted_value{string_fragment{ - quoted_pair->first.sf_string, - quoted_pair->first.sf_begin - 1, - quoted_pair->first.sf_end + 1 - }}); - } else { - bare_value_predicate bvp; - auto value_pair = value_start.split_while(bvp); - - if (value_pair) { - static const auto TRUE_FRAG = string_fragment{"true"}; - static const auto FALSE_FRAG = string_fragment{"false"}; - - this->p_next_input = value_pair->second; - if (bvp.is_integer()) { - int_value retval; - - strtonum(retval.iv_value, - value_pair->first.data(), - value_pair->first.length()); - retval.iv_str_value = value_pair->first; - - return std::make_pair(key_frag, retval); - } else if (bvp.is_float()) { - char float_copy[value_pair->first.length() + 1]; - float_value retval; - - strncpy(float_copy, value_pair->first.data(), value_pair->first.length()); - float_copy[value_pair->first.length()] = '\0'; - retval.fv_value = strtod(float_copy, nullptr); - retval.fv_str_value = value_pair->first; - - return std::make_pair(key_frag, retval); - } else if (value_pair->first.iequal(TRUE_FRAG)) { - return std::make_pair(key_frag, bool_value{true, value_pair->first}); - } else if (value_pair->first.iequal(FALSE_FRAG)) { - return std::make_pair(key_frag, bool_value{false, value_pair->first}); - } - return std::make_pair(key_frag, unquoted_value{value_pair->first}); - } else { - this->p_next_input = value_start; - return std::make_pair(key_frag, unquoted_value{string_fragment{""}}); + return std::make_pair( + key_frag, + quoted_value{string_fragment{quoted_pair->first.sf_string, + quoted_pair->first.sf_begin - 1, + quoted_pair->first.sf_end + 1}}); + } + + bare_value_predicate bvp; + auto value_pair = value_start.split_while(bvp); + + if (value_pair) { + static const auto TRUE_FRAG = string_fragment::from_const("true"); + static const auto FALSE_FRAG = string_fragment::from_const("false"); + + this->p_next_input = value_pair->second; + if (bvp.is_integer()) { + int_value retval; + + strtonum(retval.iv_value, + value_pair->first.data(), + value_pair->first.length()); + retval.iv_str_value = value_pair->first; + + return std::make_pair(key_frag, retval); + } else if (bvp.is_float()) { + char float_copy[value_pair->first.length() + 1]; + float_value retval; + + strncpy(float_copy, + value_pair->first.data(), + value_pair->first.length()); + float_copy[value_pair->first.length()] = '\0'; + retval.fv_value = strtod(float_copy, nullptr); + retval.fv_str_value = value_pair->first; + + return std::make_pair(key_frag, retval); + } else if (value_pair->first.iequal(TRUE_FRAG)) { + return std::make_pair(key_frag, + bool_value{true, value_pair->first}); + } else if (value_pair->first.iequal(FALSE_FRAG)) { + return std::make_pair(key_frag, + bool_value{false, value_pair->first}); } + return std::make_pair(key_frag, unquoted_value{value_pair->first}); + } else { + this->p_next_input = value_start; + return std::make_pair(key_frag, unquoted_value{string_fragment{}}); } } diff --git a/src/highlighter.cc b/src/highlighter.cc index 5a7e0509..bcaacfea 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -135,27 +135,25 @@ highlighter::annotate(attr_line_t& al, int start) const sa, &VC_STYLE, lr) == sa.end())) { - int attrs = 0; - - if (this->h_attrs != -1) { - attrs = this->h_attrs; - } if (!this->h_fg.empty()) { - sa.emplace_back(lr, - VC_FOREGROUND.value( - vc.match_color(this->h_fg))); + sa.emplace_back( + lr, + VC_FOREGROUND.value( + vc.match_color(this->h_fg) + .value_or(view_colors::MATCH_COLOR_DEFAULT))); } if (!this->h_bg.empty()) { - sa.emplace_back(lr, - VC_BACKGROUND.value( - vc.match_color(this->h_bg))); + sa.emplace_back( + lr, + VC_BACKGROUND.value( + vc.match_color(this->h_bg) + .value_or(view_colors::MATCH_COLOR_DEFAULT))); } if (this->h_role != role_t::VCR_NONE) { - sa.emplace_back(lr, - VC_ROLE.value(this->h_role)); + sa.emplace_back(lr, VC_ROLE.value(this->h_role)); } - if (attrs) { - sa.emplace_back(lr, VC_STYLE.value(attrs)); + if (!this->h_attrs.empty()) { + sa.emplace_back(lr, VC_STYLE.value(this->h_attrs)); } off = matches[1]; diff --git a/src/highlighter.hh b/src/highlighter.hh index 6ba0328f..47274220 100644 --- a/src/highlighter.hh +++ b/src/highlighter.hh @@ -40,7 +40,7 @@ #include "view_curses.hh" struct highlighter { - highlighter() : h_code(nullptr), h_code_extra(nullptr){}; + highlighter() : h_code(nullptr), h_code_extra(nullptr) {} explicit highlighter(pcre* code) : h_code(code) { @@ -77,7 +77,7 @@ struct highlighter { return *this; } - highlighter& with_attrs(int attrs) + highlighter& with_attrs(text_attrs attrs) { this->h_attrs = attrs; @@ -113,12 +113,7 @@ struct highlighter { return *this; } - int get_attrs() const - { - ensure(this->h_attrs != -1); - - return this->h_attrs; - } + text_attrs get_attrs() const { return this->h_attrs; } void annotate(attr_line_t& al, int start) const; @@ -128,7 +123,7 @@ struct highlighter { styling::color_unit h_bg{styling::color_unit::make_empty()}; pcre* h_code; pcre_extra* h_code_extra; - int h_attrs{-1}; + text_attrs h_attrs; std::set h_text_formats; intern_string_t h_format_name; bool h_nestable{true}; diff --git a/src/hist_source.hh b/src/hist_source.hh index efbc71c1..e1d6cf4e 100644 --- a/src/hist_source.hh +++ b/src/hist_source.hh @@ -80,9 +80,9 @@ public: return *this; } - stacked_bar_chart& with_attrs_for_ident(const T& ident, int attrs) + stacked_bar_chart& with_attrs_for_ident(const T& ident, text_attrs attrs) { - struct chart_ident& ci = this->find_ident(ident); + auto& ci = this->find_ident(ident); ci.ci_attrs = attrs; return *this; } @@ -221,8 +221,10 @@ public: } lr.lr_end = left = lr.lr_start + amount; - if (ci.ci_attrs != 0 && !lr.empty()) { - value_out.emplace_back(lr, VC_STYLE.value(ci.ci_attrs | A_REVERSE)); + if (!ci.ci_attrs.empty() && !lr.empty()) { + auto rev_attrs = ci.ci_attrs; + rev_attrs.ta_attrs |= A_REVERSE; + value_out.emplace_back(lr, VC_STYLE.value(rev_attrs)); } } @@ -283,7 +285,7 @@ protected: explicit chart_ident(const T& ident) : ci_ident(ident) {} T ci_ident; - int ci_attrs{0}; + text_attrs ci_attrs; bucket_stats_t ci_stats; }; diff --git a/src/hotkeys.cc b/src/hotkeys.cc index 98776e53..7810f5e1 100644 --- a/src/hotkeys.cc +++ b/src/hotkeys.cc @@ -122,12 +122,27 @@ key_sql_callback(exec_context& ec, sqlite3_stmt* stmt) if (sql_ident_needs_quote(column_name)) { continue; } - if (sqlite3_column_type(stmt, lpc) == SQLITE_NULL) { - continue; - } - vars[column_name] - = std::string((const char*) sqlite3_column_text(stmt, lpc)); + auto* raw_value = sqlite3_column_value(stmt, lpc); + auto value_type = sqlite3_column_type(stmt, lpc); + scoped_value_t value; + switch (value_type) { + case SQLITE_INTEGER: + value = (int64_t) sqlite3_value_int64(raw_value); + break; + case SQLITE_FLOAT: + value = sqlite3_value_double(raw_value); + break; + case SQLITE_NULL: + value = null_value_t{}; + break; + default: + value = string_fragment::from_bytes( + sqlite3_value_text(raw_value), + sqlite3_value_bytes(raw_value)); + break; + } + vars[column_name] = value; } return 0; diff --git a/src/json-extension-functions.cc b/src/json-extension-functions.cc index a64a14fe..794ccf6c 100644 --- a/src/json-extension-functions.cc +++ b/src/json-extension-functions.cc @@ -75,7 +75,7 @@ struct contains_userdata { static int contains_string(void* ctx, const unsigned char* str, size_t len) { - auto sf = string_fragment{(const char*) str, 0, (int) len}; + auto sf = string_fragment::from_bytes(str, len); auto& cu = *((contains_userdata*) ctx); if (cu.cu_depth <= 1 && cu.cu_match_value.get() == sf) { @@ -156,11 +156,8 @@ json_contains(vtab_types::nullable nullable_json_in, switch (sqlite3_value_type(value)) { case SQLITE3_TEXT: cb.yajl_string = contains_string; - cu.cu_match_value = string_fragment{ - (const char*) sqlite3_value_text(value), - 0, - sqlite3_value_bytes(value), - }; + cu.cu_match_value = string_fragment::from_bytes( + sqlite3_value_text(value), sqlite3_value_bytes(value)); break; case SQLITE_INTEGER: cb.yajl_integer = contains_integer; diff --git a/src/line_buffer.cc b/src/line_buffer.cc index 4804ada2..05fb4143 100644 --- a/src/line_buffer.cc +++ b/src/line_buffer.cc @@ -88,15 +88,9 @@ class lock_hack { public: class guard { public: - guard() : g_lock(lock_hack::singleton()) - { - this->g_lock.lock(); - }; + guard() : g_lock(lock_hack::singleton()) { this->g_lock.lock(); } - ~guard() - { - this->g_lock.unlock(); - }; + ~guard() { this->g_lock.unlock(); } private: lock_hack& g_lock; @@ -107,17 +101,11 @@ public: static lock_hack retval; return retval; - }; + } - void lock() - { - lockf(this->lh_fd, F_LOCK, 0); - }; + void lock() { lockf(this->lh_fd, F_LOCK, 0); } - void unlock() - { - lockf(this->lh_fd, F_ULOCK, 0); - }; + void unlock() { lockf(this->lh_fd, F_ULOCK, 0); } private: lock_hack() @@ -128,7 +116,7 @@ private: this->lh_fd = open(lockname, O_CREAT | O_RDWR, 0600); log_perror(fcntl(this->lh_fd, F_SETFD, FD_CLOEXEC)); unlink(lockname); - }; + } auto_fd lh_fd; }; @@ -649,8 +637,11 @@ line_buffer::load_next_buffer() auto before = line_start - this->lb_alt_buffer->begin(); auto remaining = this->lb_alt_buffer.value().size() - before; - auto utf8_end = is_utf8( - (unsigned char*) line_start, remaining, &msg, &faulty_bytes); + auto utf8_end = is_utf8((unsigned char*) line_start, + remaining, + &msg, + &faulty_bytes, + '\n'); if (msg != nullptr) { lf = (char*) memchr(line_start, '\n', remaining); utf8_end = lf - line_start; @@ -722,6 +713,7 @@ line_buffer::fill_range(file_off_t start, ssize_t max_length) this->lb_alt_line_starts.clear(); this->lb_line_is_utf = std::move(this->lb_alt_line_is_utf); this->lb_alt_line_is_utf.clear(); + this->lb_stats.s_used_preloads += 1; } if (this->in_range(start) && this->in_range(start + max_length - 1)) { /* Cache already has the data, nothing to do. */ @@ -755,6 +747,7 @@ line_buffer::fill_range(file_off_t start, ssize_t max_length) #endif auto prom = std::make_shared>(); this->lb_loader_future = prom->get_future(); + this->lb_stats.s_requested_preloads += 1; isc::to().send( [this, prom](auto& ioloop) mutable { prom->set_value(this->load_next_buffer()); @@ -777,6 +770,12 @@ line_buffer::fill_range(file_off_t start, ssize_t max_length) { rc = 0; } else { + this->lb_stats.s_decompressions += 1; + if (this->lb_last_line_offset > 0) { + this->lb_stats.s_hist[(this->lb_file_offset * 10) + / this->lb_last_line_offset] + += 1; + } rc = gi->read(this->lb_buffer.end(), this->lb_file_offset + this->lb_buffer.size(), this->lb_buffer.available()); @@ -852,6 +851,17 @@ line_buffer::fill_range(file_off_t start, ssize_t max_length) #endif else if (this->lb_seekable) { + this->lb_stats.s_preads += 1; + if (this->lb_last_line_offset > 0) { + this->lb_stats.s_hist[(this->lb_file_offset * 10) + / this->lb_last_line_offset] + += 1; + } +#if 0 + log_debug("%d: pread %lld", + this->lb_fd.get(), + this->lb_file_offset + this->lb_buffer.size()); +#endif rc = pread(this->lb_fd, this->lb_buffer.end(), this->lb_buffer.available(), @@ -943,6 +953,7 @@ line_buffer::fill_range(file_off_t start, ssize_t max_length) #endif auto prom = std::make_shared>(); this->lb_loader_future = prom->get_future(); + this->lb_stats.s_requested_preloads += 1; isc::to().send( [this, prom](auto& ioloop) mutable { prom->set_value(this->load_next_buffer()); @@ -1018,7 +1029,8 @@ line_buffer::load_next_line(file_range prev_line) utf8_end = is_utf8((unsigned char*) line_start, retval.li_file_range.fr_size, &msg, - &faulty_bytes); + &faulty_bytes, + '\n'); if (msg != nullptr) { lf = (char*) memchr( line_start, '\n', retval.li_file_range.fr_size); diff --git a/src/line_buffer.hh b/src/line_buffer.hh index 588476a9..bd06e17a 100644 --- a/src/line_buffer.hh +++ b/src/line_buffer.hh @@ -32,6 +32,7 @@ #ifndef line_buffer_hh #define line_buffer_hh +#include #include #include #include @@ -243,6 +244,31 @@ public: void quiesce(); + struct stats { + bool empty() const + { + return this->s_decompressions == 0 && this->s_preads == 0 + && this->s_requested_preloads == 0 + && this->s_used_preloads == 0; + } + + uint32_t s_decompressions{0}; + uint32_t s_preads{0}; + uint32_t s_requested_preloads{0}; + uint32_t s_used_preloads{0}; + std::array s_hist{}; + }; + + struct stats consume_stats() + { + return std::exchange(this->lb_stats, {}); + } + + size_t get_buffer_size() const + { + return this->lb_buffer.size(); + } + private: /** * @param off The file offset to check for in the buffer. @@ -340,6 +366,7 @@ private: std::vector lb_line_starts; std::vector lb_line_is_utf; + stats lb_stats; }; #endif diff --git a/src/listview_curses.cc b/src/listview_curses.cc index 823499fb..665672cc 100644 --- a/src/listview_curses.cc +++ b/src/listview_curses.cc @@ -197,7 +197,7 @@ listview_curses::do_update() struct line_range lr; unsigned long width, wrap_width; int y = this->lv_y, bottom; - attr_t role_attrs = vc.attrs_for_role(this->vc_default_role); + auto role_attrs = vc.attrs_for_role(this->vc_default_role); this->get_dimensions(height, width); @@ -254,9 +254,12 @@ listview_curses::do_update() && lr.lr_start < (int) al.length()); ++row; } else { - wattron(this->lv_window, role_attrs); + wattr_set(this->lv_window, + role_attrs.ta_attrs, + vc.ensure_color_pair(role_attrs.ta_fg_color, + role_attrs.ta_bg_color), + nullptr); mvwhline(this->lv_window, y, this->lv_x, ' ', width); - wattroff(this->lv_window, role_attrs); ++y; } } @@ -283,7 +286,7 @@ listview_curses::do_update() int range_start = 0, range_end; role_t role = this->vc_default_role; role_t bar_role = role_t::VCR_SCROLLBAR; - int attrs; + text_attrs attrs; chtype ch = ACS_VLINE; if (row_count > 0) { @@ -299,9 +302,12 @@ listview_curses::do_update() role = bar_role; } attrs = vc.attrs_for_role(role); - wattron(this->lv_window, attrs); + wattr_set( + this->lv_window, + attrs.ta_attrs, + vc.ensure_color_pair(attrs.ta_fg_color, attrs.ta_bg_color), + nullptr); mvwaddch(this->lv_window, gutter_y, this->lv_x + width - 1, ch); - wattroff(this->lv_window, attrs); } wmove(this->lv_window, this->lv_y + height - 1, this->lv_x); } diff --git a/src/lnav.cc b/src/lnav.cc index 6a42786a..91f18cee 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -82,6 +82,7 @@ #include "base/humanize.time.hh" #include "base/injector.bind.hh" #include "base/isc.hh" +#include "base/itertools.hh" #include "base/lnav.console.hh" #include "base/lnav_log.hh" #include "base/paths.hh" @@ -906,6 +907,14 @@ handle_key(int ch) handle_rl_key(ch); break; + case ln_mode_t::BUSY: + switch (ch) { + case KEY_CTRL_RBRACKET: + log_vtab_data.lvd_looping = false; + break; + } + break; + default: require(0); break; @@ -1133,10 +1142,8 @@ looper() for (const auto& format : log_format::get_root_formats()) { for (auto& hl : format->lf_highlighters) { - if (hl.h_fg.empty()) { - hl.with_attrs(hl.h_attrs - | vc.attrs_for_ident(hl.h_pattern)); - } + hl.with_attrs(hl.h_attrs + | vc.attrs_for_ident(hl.h_pattern)); lnav_data.ld_views[LNV_LOG].get_highlights()[{ highlight_source_t::CONFIGURATION, @@ -1174,7 +1181,7 @@ looper() &lnav_data.ld_bottom_source)); sb.push_back(bind_mem(&bottom_status_source::update_marks, &lnav_data.ld_bottom_source)); - sb.push_back( + vsb.push_back( bind_mem(&term_extra::update_title, injector::get())); vsb.push_back([](listview_curses* lv) { auto* tc = dynamic_cast(lv); @@ -1413,7 +1420,7 @@ UPDATE lnav_views_echo attr_line_t("restored session from ") .append(lnav::roles::number(ago)) .append("; press ") - .append("CTRL-R"_symbol) + .append("CTRL-R"_hotkey) .append(" to reset session")); lnav_data.ld_rl_view->set_attr_value(um.to_attr_line()); } @@ -1621,6 +1628,7 @@ UPDATE lnav_views_echo case ln_mode_t::FILTER: case ln_mode_t::FILES: case ln_mode_t::SPECTRO_DETAILS: + case ln_mode_t::BUSY: if (old_gen == lnav_data.ld_active_files .fc_files_generation) { @@ -1772,7 +1780,8 @@ UPDATE lnav_views_echo } if (session_stage == 1 - && (lnav_data.ld_log_source.text_line_count() > 0 + && (lnav_data.ld_active_files.fc_file_names.empty() + || lnav_data.ld_log_source.text_line_count() > 0 || lnav_data.ld_text_source.text_line_count() > 0 || !lnav_data.ld_active_files.fc_other_files.empty())) { @@ -1791,6 +1800,9 @@ UPDATE lnav_views_echo { log_debug("switching to paging!"); lnav_data.ld_mode = ln_mode_t::PAGING; + lnav_data.ld_active_files.fc_files + | lnav::itertools::for_each( + &logfile::dump_stats); } else { lnav_data.ld_files_view.set_selection(0_vl); } @@ -2071,9 +2083,6 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%' static const std::string DEFAULT_DEBUG_LOG = "/dev/null"; lnav_data.ld_debug_log_name = DEFAULT_DEBUG_LOG; - lnav_data.ld_config_paths.emplace_back("/etc/lnav"); - lnav_data.ld_config_paths.emplace_back(SYSCONFDIR "/lnav"); - lnav_data.ld_config_paths.emplace_back(lnav::paths::dotlnav()); std::vector file_args; std::vector arg_errors; @@ -2228,6 +2237,13 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%' return e.get_exit_code(); } + lnav_data.ld_config_paths.insert(lnav_data.ld_config_paths.begin(), + lnav::paths::dotlnav()); + lnav_data.ld_config_paths.insert(lnav_data.ld_config_paths.begin(), + SYSCONFDIR "/lnav"); + lnav_data.ld_config_paths.insert(lnav_data.ld_config_paths.begin(), + "/etc/lnav"); + if (lnav_data.ld_debug_log_name != DEFAULT_DEBUG_LOG) { lnav_log_level = lnav_log_level_t::TRACE; } diff --git a/src/lnav_commands.cc b/src/lnav_commands.cc index b0d58031..bab2b03d 100644 --- a/src/lnav_commands.cc +++ b/src/lnav_commands.cc @@ -127,7 +127,7 @@ remaining_args_frag(const std::string& cmdline, require(index_in_cmdline != std::string::npos); - return string_fragment{cmdline.c_str(), static_cast(index_in_cmdline)}; + return string_fragment::from_str_range(cmdline, index_in_cmdline, cmdline.size()); } static nonstd::optional @@ -1606,10 +1606,10 @@ com_highlight(exec_context& ec, return Err(um); } else { highlighter hl(code.release()); - attr_t hl_attrs = view_colors::singleton().attrs_for_ident(args[1]); + auto hl_attrs = view_colors::singleton().attrs_for_ident(args[1]); if (ec.ec_dry_run) { - hl_attrs |= A_BLINK; + hl_attrs.ta_attrs |= A_BLINK; } hl.with_attrs(hl_attrs); @@ -1752,22 +1752,17 @@ com_filter(exec_context& ec, } else { auto& hm = tc->get_highlights(); highlighter hl(code.release()); - int color; - - if (args[0] == "filter-out") { - color = COLOR_RED; - } else { - color = COLOR_GREEN; - } - hl.with_attrs(view_colors::ansi_color_pair(COLOR_BLACK, color) - | A_BLINK); + auto role = (args[0] == "filter-out") ? + role_t::VCR_DIFF_DELETE : + role_t::VCR_DIFF_ADD; + hl.with_attrs(text_attrs{A_BLINK}); hm[{highlight_source_t::PREVIEW, "preview"}] = hl; tc->reload_data(); lnav_data.ld_preview_status_source.get_description().set_value( "Matches are highlighted in %s in the text view", - color == COLOR_RED ? "red" : "green"); + role == role_t::VCR_DIFF_DELETE ? "red" : "green"); retval = ""; } @@ -2179,12 +2174,12 @@ com_create_search_table(exec_context& ec, auto tab_name = intern_string::lookup(args[1]); auto lst = std::make_shared(re, tab_name); if (ec.ec_dry_run) { - textview_curses* tc = &lnav_data.ld_views[LNV_LOG]; + auto* tc = &lnav_data.ld_views[LNV_LOG]; auto& hm = tc->get_highlights(); highlighter hl(re.p_code); - hl.with_attrs(view_colors::ansi_color_pair(COLOR_BLACK, COLOR_CYAN) - | A_BLINK); + hl.with_role(role_t::VCR_INFO); + hl.with_attrs(text_attrs{A_BLINK}); hm[{highlight_source_t::PREVIEW, "preview"}] = hl; tc->reload_data(); @@ -2210,7 +2205,7 @@ com_create_search_table(exec_context& ec, errmsg = lnav_data.ld_vtab_manager->register_vtab(lst); if (errmsg.empty()) { custom_search_tables.insert(args[1]); - if (lnav_data.ld_rl_view != NULL) { + if (lnav_data.ld_rl_view != nullptr) { lnav_data.ld_rl_view->add_possibility( ln_mode_t::COMMAND, "search-table", args[1]); } @@ -2556,8 +2551,7 @@ com_open(exec_context& ec, std::string cmdline, std::vector& args) } if (gl->gl_pathc > 10) { al.append(" ... ") - .append(std::to_string(gl->gl_pathc - 10), - VC_STYLE.value(A_BOLD)) + .append(lnav::roles::number(std::to_string(gl->gl_pathc - 10))) .append(" files not shown ..."); } lnav_data.ld_preview_status_source.get_description() diff --git a/src/lnav_config.cc b/src/lnav_config.cc index 5886b716..4328a2c7 100644 --- a/src/lnav_config.cc +++ b/src/lnav_config.cc @@ -515,6 +515,10 @@ static const struct json_path_container theme_styles_handlers = { .with_description("Styling for success messages") .for_child(&lnav_theme::lt_style_ok) .with_children(style_config_handlers), + yajlpp::property_handler("info") + .with_description("Styling for informational messages") + .for_child(&lnav_theme::lt_style_info) + .with_children(style_config_handlers), yajlpp::property_handler("warning") .with_description("Styling for warning messages") .for_child(&lnav_theme::lt_style_warning) diff --git a/src/lnav_util.cc b/src/lnav_util.cc index f41fb2f2..62e72aea 100644 --- a/src/lnav_util.cc +++ b/src/lnav_util.cc @@ -144,6 +144,7 @@ to_json(yajlpp_gen& gen, const attr_line_t& al) }, [&](const intern_string_t& str) { elem_map.gen(str); }, [&](const std::string& str) { elem_map.gen(str); }, + [&](const text_attrs& ta) { elem_map.gen(""); }, [&](const std::shared_ptr& lf) { elem_map.gen(""); }, diff --git a/src/log_format.cc b/src/log_format.cc index b5e3fddf..5661bc08 100644 --- a/src/log_format.cc +++ b/src/log_format.cc @@ -123,8 +123,8 @@ logline_value::logline_value(logline_value_meta lvm, case value_kind_t::VALUE_W3C_QUOTED: case value_kind_t::VALUE_TIMESTAMP: require(origin.lr_end != -1); - this->lv_frag = string_fragment{ - sbr.get_data(), origin.lr_start, origin.lr_end}; + this->lv_frag = string_fragment::from_byte_range( + sbr.get_data(), origin.lr_start, origin.lr_end); break; case value_kind_t::VALUE_NULL: @@ -555,11 +555,9 @@ json_array_end(void* ctx) jlu->jlu_format->jlf_line_values.lvv_values.emplace_back( jlu->jlu_format->get_value_meta(field_name, value_kind_t::VALUE_JSON), - string_fragment{ - jlu->jlu_shared_buffer.get_data(), - (int) jlu->jlu_sub_start, - (int) sub_end, - }); + string_fragment::from_byte_range(jlu->jlu_shared_buffer.get_data(), + jlu->jlu_sub_start, + sub_end)); } return 1; @@ -1324,11 +1322,10 @@ rewrite_json_field(yajlpp_parse_context* ypc, jlu->jlu_format->jlf_line_values.lvv_values.emplace_back( jlu->jlu_format->get_value_meta(body_name, value_kind_t::VALUE_TEXT), - string_fragment{ + string_fragment::from_byte_range( jlu->jlu_shared_buffer.get_data(), str_offset, - str_offset + (int) len, - }); + str_offset + len)); } if (!ypc->is_level(1) && !jlu->jlu_format->has_value_def(field_name)) { return 1; @@ -1337,11 +1334,9 @@ rewrite_json_field(yajlpp_parse_context* ypc, jlu->jlu_format->jlf_line_values.lvv_values.emplace_back( jlu->jlu_format->get_value_meta(field_name, value_kind_t::VALUE_TEXT), - string_fragment{ - jlu->jlu_shared_buffer.get_data(), - str_offset, - str_offset + (int) len, - }); + string_fragment::from_byte_range(jlu->jlu_shared_buffer.get_data(), + str_offset, + str_offset + len)); } else { if (field_name == jlu->jlu_format->elf_body_field) { jlu->jlu_format->jlf_line_values.lvv_values.emplace_back( @@ -2265,7 +2260,8 @@ external_log_format::build(std::vector& errors) const char* errptr; auto fg = styling::color_unit::make_empty(); auto bg = styling::color_unit::make_empty(); - int eoff, attrs = 0; + text_attrs attrs; + int eoff; if (!hd.hd_color.pp_value.empty()) { fg = styling::color_unit::from_str(hd.hd_color.pp_value) @@ -2305,14 +2301,14 @@ external_log_format::build(std::vector& errors) } if (hd.hd_underline) { - attrs |= A_UNDERLINE; + attrs.ta_attrs |= A_UNDERLINE; } if (hd.hd_blink) { - attrs |= A_BLINK; + attrs.ta_attrs |= A_BLINK; } if (hd.hd_pattern != nullptr) { - pcre* code = pcre_compile(hd.hd_pattern->get_pattern().c_str(), + auto* code = pcre_compile(hd.hd_pattern->get_pattern().c_str(), PCRE_CASELESS | PCRE_UTF8, &errptr, &eoff, diff --git a/src/log_format_impls.cc b/src/log_format_impls.cc index 47c1a792..d8a804c3 100644 --- a/src/log_format_impls.cc +++ b/src/log_format_impls.cc @@ -351,7 +351,7 @@ struct separated_string { string_fragment operator*() { - const separated_string& ss = this->i_parent; + const auto& ss = this->i_parent; int end; if (this->i_next_pos < (ss.ss_str + ss.ss_len)) { @@ -359,7 +359,8 @@ struct separated_string { } else { end = this->i_next_pos - ss.ss_str; } - return string_fragment(ss.ss_str, this->i_pos - ss.ss_str, end); + return string_fragment::from_byte_range( + ss.ss_str, this->i_pos - ss.ss_str, end); } bool operator==(const iterator& other) const @@ -1643,8 +1644,7 @@ public: shared_buffer_ref& sbr, scan_batch_context& sbc) override { - auto p = logfmt::parser( - string_fragment{sbr.get_data(), 0, (int) sbr.length()}); + auto p = logfmt::parser(sbr.to_string_fragment()); scan_result_t retval = scan_result_t::SCAN_NO_MATCH; bool done = false; logfmt_pair_handler lph(this->lf_date_time); @@ -1729,8 +1729,7 @@ public: static const auto FIELDS_NAME = intern_string::lookup("fields"); auto& sbr = values.lvv_sbr; - auto p = logfmt::parser( - string_fragment{sbr.get_data(), 0, (int) sbr.length()}); + auto p = logfmt::parser(sbr.to_string_fragment()); bool done = false; while (!done) { diff --git a/src/log_search_table.cc b/src/log_search_table.cc index 32d1a1da..e7e49f03 100644 --- a/src/log_search_table.cc +++ b/src/log_search_table.cc @@ -70,8 +70,8 @@ log_search_table::get_columns_int(std::vector& cols) const std::string colname; int sqlite_type = SQLITE3_TEXT; - colname = cn.add_column( - string_fragment{this->lst_regex.name_for_capture(lpc)}) + colname = cn.add_column(string_fragment::from_c_str( + this->lst_regex.name_for_capture(lpc))) .to_string(); if (this->lst_regex.captures().size() == (size_t) this->lst_regex.get_capture_count()) diff --git a/src/log_vtab_impl.cc b/src/log_vtab_impl.cc index ad8c73a8..a2c20dff 100644 --- a/src/log_vtab_impl.cc +++ b/src/log_vtab_impl.cc @@ -37,6 +37,7 @@ #include "logfile_sub_source.hh" #include "sql_util.hh" #include "vtab_module.hh" +#include "vtab_module_json.hh" #include "yajlpp/json_op.hh" #include "yajlpp/yajlpp_def.hh" @@ -752,11 +753,7 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col) } } - string_fragment sf = gen.to_string_fragment(); - - sqlite3_result_text( - ctx, sf.data(), sf.length(), SQLITE_TRANSIENT); - sqlite3_result_subtype(ctx, JSON_SUBTYPE); + to_sqlite(ctx, json_string(gen)); } break; } @@ -930,8 +927,7 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col) line_hasher.update(sbr.get_data(), sbr.length()) .update(cl) .to_string(outbuf); - auto tab = text_auto_buffer{std::move(outbuf)}; - to_sqlite(ctx, tab); + to_sqlite(ctx, text_auto_buffer{std::move(outbuf)}); } break; } @@ -2046,6 +2042,9 @@ progress_callback(void* ptr) if (log_vtab_data.lvd_progress != nullptr) { retval = log_vtab_data.lvd_progress(log_cursor_latest); } + if (!log_vtab_data.lvd_looping) { + retval = 1; + } return retval; } diff --git a/src/log_vtab_impl.hh b/src/log_vtab_impl.hh index 64ad3ee3..8e82864b 100644 --- a/src/log_vtab_impl.hh +++ b/src/log_vtab_impl.hh @@ -268,6 +268,7 @@ using sql_progress_callback_t = int (*)(const log_cursor&); using sql_progress_finished_callback_t = void (*)(); struct _log_vtab_data { + bool lvd_looping{true}; sql_progress_callback_t lvd_progress; sql_progress_finished_callback_t lvd_finished; source_location lvd_location; @@ -283,6 +284,7 @@ public: source_location loc, const attr_line_t& content) { + log_vtab_data.lvd_looping = true; log_vtab_data.lvd_progress = cb; log_vtab_data.lvd_finished = fcb; log_vtab_data.lvd_location = loc; @@ -294,6 +296,7 @@ public: if (log_vtab_data.lvd_finished) { log_vtab_data.lvd_finished(); } + log_vtab_data.lvd_looping = true; log_vtab_data.lvd_progress = nullptr; log_vtab_data.lvd_finished = nullptr; log_vtab_data.lvd_location = source_location{}; diff --git a/src/logfile.cc b/src/logfile.cc index d2a44e81..30899275 100644 --- a/src/logfile.cc +++ b/src/logfile.cc @@ -962,3 +962,31 @@ logfile::line_for_offset(file_off_t off) const return nonstd::make_optional(iter); } + +void +logfile::dump_stats() +{ + const auto buf_stats = this->lf_line_buffer.consume_stats(); + + if (buf_stats.empty()) { + return; + } + log_info("line buffer stats for file: %s", this->lf_filename.c_str()); + log_info(" file_size=%lld", this->lf_line_buffer.get_file_size()); + log_info(" buffer_size=%ld", this->lf_line_buffer.get_buffer_size()); + log_info(" read_hist=[%4lu %4lu %4lu %4lu %4lu %4lu %4lu %4lu %4lu %4lu]", + buf_stats.s_hist[0], + buf_stats.s_hist[1], + buf_stats.s_hist[2], + buf_stats.s_hist[3], + buf_stats.s_hist[4], + buf_stats.s_hist[5], + buf_stats.s_hist[6], + buf_stats.s_hist[7], + buf_stats.s_hist[8], + buf_stats.s_hist[9]); + log_info(" decompressions=%lu", buf_stats.s_decompressions); + log_info(" preads=%lu", buf_stats.s_preads); + log_info(" requested_preloads=%lu", buf_stats.s_requested_preloads); + log_info(" used_preloads=%lu", buf_stats.s_used_preloads); +} diff --git a/src/logfile.hh b/src/logfile.hh index af08c21d..5704b30d 100644 --- a/src/logfile.hh +++ b/src/logfile.hh @@ -373,6 +373,8 @@ public: void quiesce() { this->lf_line_buffer.quiesce(); } + void dump_stats(); + protected: /** * Process a line from the file. diff --git a/src/logfile_sub_source.cc b/src/logfile_sub_source.cc index 0b4dfbc5..63f70f9e 100644 --- a/src/logfile_sub_source.cc +++ b/src/logfile_sub_source.cc @@ -353,7 +353,7 @@ logfile_sub_source::text_attrs_for_line(textview_curses& lv, logline* next_line = nullptr; struct line_range lr; int time_offset_end = 0; - int attrs = 0; + text_attrs attrs; value_out = this->lss_token_attrs; @@ -365,7 +365,7 @@ logfile_sub_source::text_attrs_for_line(textview_curses& lv, && (day_num(next_line->get_time()) > day_num(this->lss_token_line->get_time()))) { - attrs |= A_UNDERLINE; + attrs.ta_attrs |= A_UNDERLINE; } const auto& line_values = this->lss_token_values; @@ -458,7 +458,8 @@ logfile_sub_source::text_attrs_for_line(textview_curses& lv, vis_line_t(row))) { lr.lr_start = 0; lr.lr_end = 1; - value_out.emplace_back(lr, VC_STYLE.value(A_REVERSE)); + value_out.emplace_back(lr, + VC_STYLE.value(text_attrs{A_REVERSE})); } } } @@ -586,7 +587,7 @@ logfile_sub_source::text_attrs_for_line(textview_curses& lv, } else { color = COLOR_RED; value_out.emplace_back(line_range{0, 1}, - VC_STYLE.value(A_BLINK)); + VC_STYLE.value(text_attrs{A_BLINK})); } } value_out.emplace_back(line_range{0, 1}, diff --git a/src/md2attr_line.cc b/src/md2attr_line.cc index bc64ae7c..8eadbd2b 100644 --- a/src/md2attr_line.cc +++ b/src/md2attr_line.cc @@ -187,11 +187,8 @@ md2attr_line::leave_block(const md4cpp::event_handler::block& bl) this->ml_code_depth -= 1; - auto lang_sf = string_fragment{ - code_detail->lang.text, - 0, - (int) code_detail->lang.size, - }; + auto lang_sf = string_fragment::from_bytes(code_detail->lang.text, + code_detail->lang.size); if (lang_sf == "lnav") { readline_lnav_highlighter(block_text, block_text.length()); } @@ -398,7 +395,7 @@ md2attr_line::leave_span(const md4cpp::event_handler::span& sp) #if defined(A_ITALIC) last_block.with_attr({ lr, - VC_STYLE.value(A_ITALIC), + VC_STYLE.value(text_attrs{(int32_t) A_ITALIC}), }); #endif } else if (sp.is()) { @@ -408,7 +405,7 @@ md2attr_line::leave_span(const md4cpp::event_handler::span& sp) }; last_block.with_attr({ lr, - VC_STYLE.value(A_BOLD), + VC_STYLE.value(text_attrs{A_BOLD}), }); } else if (sp.is()) { auto* a_detail = sp.get(); @@ -464,12 +461,7 @@ md2attr_line::text(MD_TEXTTYPE tt, const string_fragment& sf) pcre_context_static<30> pc; while (REPL_RE.match(pc, pi)) { - auto prev = string_fragment{ - sf.sf_string, - (int) pi.pi_offset, - pc.all()->c_begin, - }; - + auto prev = pi.get_up_to(pc.all()); last_block.append(prev); auto matched = pi.get_string_fragment(pc.all()); @@ -489,11 +481,7 @@ md2attr_line::text(MD_TEXTTYPE tt, const string_fragment& sf) } } - this->ml_blocks.back().append(string_fragment{ - sf.sf_string, - (int) pi.pi_offset, - sf.sf_end, - }); + this->ml_blocks.back().append(sf.substr(pi.pi_offset)); break; } } @@ -514,9 +502,9 @@ md2attr_line::append_url_footnote(std::string href_str) (int) this->ml_span_starts.back(), (int) last_block.length(), }, - VC_STYLE.value(A_UNDERLINE), + VC_STYLE.value(text_attrs{A_UNDERLINE}), }); - if (this->ml_source_path && href_str.find(":") == std::string::npos) { + if (this->ml_source_path && href_str.find(':') == std::string::npos) { auto link_path = ghc::filesystem::absolute( this->ml_source_path.value().parent_path() / href_str); diff --git a/src/md4cpp.cc b/src/md4cpp.cc index e0556a7d..75cb9b51 100644 --- a/src/md4cpp.cc +++ b/src/md4cpp.cc @@ -29,6 +29,7 @@ #include "md4cpp.hh" +#include "base/is_utf8.hh" #include "base/lnav_log.hh" #include "emojis-json.h" #include "xml-entities-json.h" @@ -263,6 +264,20 @@ namespace details { Result parse(const string_fragment& sf, event_handler& eh) { + const char* utf8_errmsg = nullptr; + int utf8_faulty_bytes = 0; + + auto utf8_erroff = is_utf8((unsigned char*) sf.data(), + sf.length(), + &utf8_errmsg, + &utf8_faulty_bytes); + if (utf8_errmsg != nullptr) { + return Err( + fmt::format(FMT_STRING("file has invalid UTF-8 at offset {}: {}"), + utf8_erroff, + utf8_errmsg)); + } + MD_PARSER parser = {0}; auto pu = parse_userdata{eh}; diff --git a/src/pcrepp/pcrepp.hh b/src/pcrepp/pcrepp.hh index 2093c6e1..828e8869 100644 --- a/src/pcrepp/pcrepp.hh +++ b/src/pcrepp/pcrepp.hh @@ -237,11 +237,14 @@ public: string_fragment get_string_fragment(pcre_context::const_iterator iter) const { - return string_fragment{ - this->pi_string, - iter->c_begin, - iter->c_end, - }; + return string_fragment::from_byte_range( + this->pi_string, iter->c_begin, iter->c_end); + } + + string_fragment get_up_to(pcre_context::const_iterator iter) const + { + return string_fragment::from_byte_range( + this->pi_string, this->pi_offset, iter->c_begin); } nonstd::optional get_substr_opt( diff --git a/src/plain_text_source.cc b/src/plain_text_source.cc index 0f0c02ef..9fdd98b0 100644 --- a/src/plain_text_source.cc +++ b/src/plain_text_source.cc @@ -143,7 +143,8 @@ plain_text_source::text_attrs_for_line(textview_curses& tc, if (this->tds_reverse_selection && tc.is_selectable() && tc.get_selection() == line) { - value_out.emplace_back(line_range{0, -1}, VC_STYLE.value(A_REVERSE)); + value_out.emplace_back(line_range{0, -1}, + VC_STYLE.value(text_attrs{A_REVERSE})); } } diff --git a/src/readline_callbacks.cc b/src/readline_callbacks.cc index 452b3248..0e6e2c27 100644 --- a/src/readline_callbacks.cc +++ b/src/readline_callbacks.cc @@ -508,6 +508,7 @@ rl_search_internal(readline_curses* rc, ln_mode_t mode, bool complete = false) case ln_mode_t::EXEC: case ln_mode_t::USER: case ln_mode_t::SPECTRO_DETAILS: + case ln_mode_t::BUSY: return; } @@ -603,6 +604,7 @@ rl_callback_int(readline_curses* rc, bool is_alt) case ln_mode_t::FILTER: case ln_mode_t::FILES: case ln_mode_t::SPECTRO_DETAILS: + case ln_mode_t::BUSY: require(0); break; @@ -830,7 +832,7 @@ rl_display_matches(readline_curses* rc) add_nl = false; } if (match == current_match) { - al.append(match, VC_STYLE.value(A_REVERSE)); + al.append(match, VC_STYLE.value(text_attrs{A_REVERSE})); } else { al.append(match); } diff --git a/src/readline_curses.cc b/src/readline_curses.cc index a28d0158..82804b67 100644 --- a/src/readline_curses.cc +++ b/src/readline_curses.cc @@ -1385,7 +1385,11 @@ readline_curses::do_update() view_colors& vc = view_colors::singleton(); wmove(this->vc_window, this->get_actual_y(), this->vc_left); - wattron(this->vc_window, vc.attrs_for_role(role_t::VCR_TEXT)); + auto attrs = vc.attrs_for_role(role_t::VCR_TEXT); + wattr_set(this->vc_window, + attrs.ta_attrs, + vc.ensure_color_pair(attrs.ta_fg_color, attrs.ta_bg_color), + nullptr); whline(this->vc_window, ' ', this->vc_width); if (time(nullptr) > this->rc_value_expiration) { diff --git a/src/readline_highlighters.cc b/src/readline_highlighters.cc index 0ca6ed4f..b36770d4 100644 --- a/src/readline_highlighters.cc +++ b/src/readline_highlighters.cc @@ -82,7 +82,7 @@ find_matching_bracket( } else if (line[lpc] == left && is_bracket(line, lpc, is_lit)) { if (depth == 0) { alb.overlay_attr_for_char( - lpc, VC_STYLE.value(A_BOLD | A_REVERSE)); + lpc, VC_STYLE.value(text_attrs{A_BOLD | A_REVERSE})); alb.overlay_attr_for_char(lpc, VC_ROLE.value(role_t::VCR_OK)); break; @@ -99,7 +99,7 @@ find_matching_bracket( } else if (line[lpc] == right && is_bracket(line, lpc, is_lit)) { if (depth == 0) { alb.overlay_attr_for_char( - lpc, VC_STYLE.value(A_BOLD | A_REVERSE)); + lpc, VC_STYLE.value(text_attrs{A_BOLD | A_REVERSE})); alb.overlay_attr_for_char(lpc, VC_ROLE.value(role_t::VCR_OK)); break; @@ -124,7 +124,8 @@ find_matching_bracket( depth -= 1; } else { auto lr = line_range(is_lit ? lpc - 1 : lpc, lpc + 1); - alb.overlay_attr(lr, VC_STYLE.value(A_BOLD | A_REVERSE)); + alb.overlay_attr( + lr, VC_STYLE.value(text_attrs{A_BOLD | A_REVERSE})); alb.overlay_attr(lr, VC_ROLE.value(role_t::VCR_ERROR)); } } @@ -134,7 +135,7 @@ find_matching_bracket( auto lr = line_range(is_lit ? first_left.value() - 1 : first_left.value(), first_left.value() + 1); - alb.overlay_attr(lr, VC_STYLE.value(A_BOLD | A_REVERSE)); + alb.overlay_attr(lr, VC_STYLE.value(text_attrs{A_BOLD | A_REVERSE})); alb.overlay_attr(lr, VC_ROLE.value(role_t::VCR_ERROR)); } } @@ -189,7 +190,7 @@ readline_command_highlighter_int(attr_line_t& al, int x, line_range sub) if (COLOR_PREFIXES.match(pc, pi)) { pi.reset(&line[sub.lr_start], 0, sub.length()); if (COLOR_RE.match(pc, pi)) { - pcre_context::capture_t* cap = pc[0]; + auto* cap = pc[0]; auto hash_color = pi.get_substr(cap); styling::color_unit::from_str(hash_color) @@ -278,8 +279,8 @@ readline_sqlite_highlighter_int(attr_line_t& al, int x, line_range sub) if (lr.length() > 1 && al.al_string[lr.lr_end - 1] == '\'') { alb.overlay_attr(lr, VC_ROLE.value(role_t::VCR_STRING)); } else { - alb.overlay_attr_for_char(lr.lr_start, - VC_STYLE.value(A_REVERSE)); + alb.overlay_attr_for_char( + lr.lr_start, VC_STYLE.value(text_attrs{A_REVERSE})); alb.overlay_attr_for_char(lr.lr_start, VC_ROLE.value(role_t::VCR_ERROR)); } @@ -317,7 +318,7 @@ readline_shlex_highlighter_int(attr_line_t& al, int x, line_range sub) case shlex_token_t::ST_ERROR: alb.overlay_attr(line_range(sub.lr_start + cap.c_begin, sub.lr_start + cap.c_end), - VC_STYLE.value(A_REVERSE)); + VC_STYLE.value(text_attrs{A_REVERSE})); alb.overlay_attr(line_range(sub.lr_start + cap.c_begin, sub.lr_start + cap.c_end), VC_ROLE.value(role_t::VCR_ERROR)); diff --git a/src/shared_buffer.hh b/src/shared_buffer.hh index a21db244..5c7526d4 100644 --- a/src/shared_buffer.hh +++ b/src/shared_buffer.hh @@ -123,7 +123,7 @@ public: string_fragment to_string_fragment() const { - return string_fragment{this->sb_data, 0, (int) this->length()}; + return string_fragment::from_bytes(this->sb_data, this->length()); } using narrow_result = std::pair; diff --git a/src/spectro_source.cc b/src/spectro_source.cc index f82e02c7..2ff7a7f1 100644 --- a/src/spectro_source.cc +++ b/src/spectro_source.cc @@ -309,8 +309,8 @@ spectrogram_source::list_value_for_overlay(const listview_curses& lv, } line.append(buf); - value_out.with_attr( - string_attr(line_range(0, -1), VC_STYLE.value(A_UNDERLINE))); + value_out.with_attr(string_attr(line_range(0, -1), + VC_STYLE.value(text_attrs{A_UNDERLINE}))); return true; } diff --git a/src/sql_util.cc b/src/sql_util.cc index b3f20f55..ac40da9f 100644 --- a/src/sql_util.cc +++ b/src/sql_util.cc @@ -693,7 +693,7 @@ annotate_sql_with_error(sqlite3* db, const char* sql, const char* tail) } else { tail = tail_lf; } - retval.append(string_fragment{sql, 0, (int) (tail - sql)}); + retval.append(string_fragment::from_bytes(sql, tail - sql)); } else { retval.append(sql); } diff --git a/src/statusview_curses.cc b/src/statusview_curses.cc index d02c928d..53b6e145 100644 --- a/src/statusview_curses.cc +++ b/src/statusview_curses.cc @@ -63,9 +63,9 @@ status_field::do_cylon() struct line_range lr(std::max(start, 0L), stop); auto& vc = view_colors::singleton(); - sa.emplace_back(lr, - VC_STYLE.value(vc.attrs_for_role(role_t::VCR_ACTIVE_STATUS) - | A_REVERSE)); + auto attrs = vc.attrs_for_role(role_t::VCR_ACTIVE_STATUS); + attrs.ta_attrs |= A_REVERSE; + sa.emplace_back(lr, VC_STYLE.value(attrs)); this->sf_cylon_pos += 1; } @@ -88,7 +88,7 @@ status_field::set_stitch_value(role_t left, void statusview_curses::do_update() { - int top, attrs, field, field_count, left = 0, right; + int top, field, field_count, left = 0, right; auto& vc = view_colors::singleton(); unsigned long width, height; @@ -101,15 +101,14 @@ statusview_curses::do_update() top = this->sc_top < 0 ? height + this->sc_top : this->sc_top; right = width; - attrs = vc.attrs_for_role(this->sc_enabled - ? role_t::VCR_STATUS - : role_t::VCR_INACTIVE_STATUS); + auto attrs = vc.attrs_for_role( + this->sc_enabled ? role_t::VCR_STATUS : role_t::VCR_INACTIVE_STATUS); - wattron(this->sc_window, attrs); + auto pair = vc.ensure_color_pair(attrs.ta_fg_color, attrs.ta_bg_color); + wattr_set(this->sc_window, attrs.ta_attrs, pair, nullptr); wmove(this->sc_window, top, 0); wclrtoeol(this->sc_window); whline(this->sc_window, ' ', width); - wattroff(this->sc_window, attrs); if (this->sc_source != nullptr) { field_count = this->sc_source->statusview_fields(); @@ -125,8 +124,11 @@ statusview_curses::do_update() if (!this->sc_enabled) { for (auto& sa : val.get_attrs()) { if (sa.sa_type == &VC_STYLE) { - sa.sa_value = sa.sa_value.get() - & ~(A_REVERSE | A_COLOR); + auto sa_attrs = sa.sa_value.get(); + sa_attrs.ta_attrs &= ~(A_REVERSE | A_COLOR); + sa_attrs.ta_fg_color = nonstd::nullopt; + sa_attrs.ta_bg_color = nonstd::nullopt; + sa.sa_value = sa_attrs; } else if (sa.sa_type == &VC_ROLE) { if (sa.sa_value.get() == role_t::VCR_ALERT_STATUS) { diff --git a/src/string-extension-functions.cc b/src/string-extension-functions.cc index 14c0398c..d910a877 100644 --- a/src/string-extension-functions.cc +++ b/src/string-extension-functions.cc @@ -59,10 +59,11 @@ find_re(string_fragment re) c.re2 = std::make_shared(re.to_string()); auto pair = cache.insert( - std::make_pair(string_fragment{c.re2->get_pattern()}, c)); + std::make_pair(string_fragment::from_str(c.re2->get_pattern()), c)); for (int lpc = 0; lpc < c.re2->get_capture_count(); lpc++) { - c.cn->add_column(string_fragment{c.re2->name_for_capture(lpc)}); + c.cn->add_column( + string_fragment::from_c_str(c.re2->name_for_capture(lpc))); } iter = pair.first; diff --git a/src/styling.hh b/src/styling.hh index 610ca13d..587bb142 100644 --- a/src/styling.hh +++ b/src/styling.hh @@ -168,6 +168,7 @@ struct lnav_theme { style_config lt_style_text; style_config lt_style_alt_text; style_config lt_style_ok; + style_config lt_style_info; style_config lt_style_error; style_config lt_style_warning; style_config lt_style_popup; diff --git a/src/textfile_sub_source.cc b/src/textfile_sub_source.cc index 6b48ad01..8aa68b76 100644 --- a/src/textfile_sub_source.cc +++ b/src/textfile_sub_source.cc @@ -34,6 +34,8 @@ #include "config.h" #include "md2attr_line.hh" +using namespace lnav::roles::literals; + size_t textfile_sub_source::text_line_count() { @@ -514,20 +516,24 @@ textfile_sub_source::rescan_files( mdal.with_source_path(lf->get_actual_path()); auto parse_res = md4cpp::parse(content_sf, mdal); + + auto& rf = this->tss_rendered_files[lf->get_filename()]; + rf.rf_mtime = st.st_mtime; + rf.rf_file_size = st.st_size; + rf.rf_text_source = std::make_unique(); + rf.rf_text_source->register_view(this->tss_view); if (parse_res.isOk()) { - auto& rf = this->tss_rendered_files[lf->get_filename()]; - rf.rf_mtime = st.st_mtime; - rf.rf_file_size = st.st_size; - rf.rf_text_source - = std::make_unique(); - rf.rf_text_source->register_view(this->tss_view); rf.rf_text_source->replace_with(parse_res.unwrap()); - log_info("successfully rendered markdown file: %s", - lf->get_filename().c_str()); } else { - log_error("unable to parse markdown file: %s -- %s", - lf->get_filename().c_str(), - parse_res.unwrapErr().c_str()); + auto view_content + = lnav::console::user_message::error( + "unable to parse markdown file") + .with_reason(parse_res.unwrapErr()) + .to_attr_line(); + view_content.append("\n").append( + attr_line_t::from_ansi_str(content.c_str())); + + rf.rf_text_source->replace_with(view_content); } } else { log_error("unable to read markdown file: %s -- %s", diff --git a/src/textview_curses.cc b/src/textview_curses.cc index 5fb9fe62..89b5f3ac 100644 --- a/src/textview_curses.cc +++ b/src/textview_curses.cc @@ -197,7 +197,7 @@ textview_curses::reload_config(error_reporter& reporter) const auto& sc = hl_pair.second.hc_style; std::string fg1, bg1, fg_color, bg_color, errmsg; bool invalid = false; - int attrs = 0; + text_attrs attrs; fg1 = sc.sc_color; bg1 = sc.sc_background_color; @@ -229,15 +229,15 @@ textview_curses::reload_config(error_reporter& reporter) } if (sc.sc_bold) { - attrs |= A_BOLD; + attrs.ta_attrs |= A_BOLD; } if (sc.sc_underline) { - attrs |= A_UNDERLINE; + attrs.ta_attrs |= A_UNDERLINE; } this->tc_highlights[{highlight_source_t::THEME, hl_pair.first}] = highlighter(code) .with_pattern(hl_pair.second.hc_regex) - .with_attrs(attrs != 0 ? attrs : -1) + .with_attrs(attrs) .with_color(fg, bg); } } @@ -555,7 +555,7 @@ textview_curses::textview_value_for_row(vis_line_t row, attr_line_t& value_out) || binary_search(user_expr_marks.begin(), user_expr_marks.end(), row)) { sa.emplace_back(line_range{orig_line.lr_start, -1}, - VC_STYLE.value(A_REVERSE)); + VC_STYLE.value(text_attrs{A_REVERSE})); } } @@ -656,8 +656,7 @@ textview_curses::horiz_shift(vis_line_t start, int off_start, std::pair& range_out) { - highlighter& hl - = this->tc_highlights[{highlight_source_t::PREVIEW, "search"}]; + auto& hl = this->tc_highlights[{highlight_source_t::PREVIEW, "search"}]; int prev_hit = -1, next_hit = INT_MAX; for (; start < end; ++start) { diff --git a/src/themes/default-theme.json b/src/themes/default-theme.json index 49adceb8..3920d78c 100644 --- a/src/themes/default-theme.json +++ b/src/themes/default-theme.json @@ -185,7 +185,6 @@ }, "hotkey": { "color": "Purple", - "background-color": "Silver", "underline": true, "bold": true } diff --git a/src/themes/grayscale.json b/src/themes/grayscale.json index a2726b4c..887736a0 100644 --- a/src/themes/grayscale.json +++ b/src/themes/grayscale.json @@ -115,7 +115,6 @@ }, "hotkey": { "color": "#fff", - "background-color": "#353535", "underline": true }, "text": { diff --git a/src/themes/monocai.json b/src/themes/monocai.json index 33d512c8..7e49966d 100644 --- a/src/themes/monocai.json +++ b/src/themes/monocai.json @@ -31,6 +31,10 @@ "color": "$green", "bold": true }, + "info": { + "color": "$magenta", + "bold": true + }, "error": { "color": "$red", "bold": true @@ -215,7 +219,6 @@ }, "hotkey": { "color": "#fff", - "background-color": "#353535", "underline": true }, "text": { diff --git a/src/themes/night-owl.json b/src/themes/night-owl.json index 21ad9b67..7e775e3b 100644 --- a/src/themes/night-owl.json +++ b/src/themes/night-owl.json @@ -183,7 +183,6 @@ }, "hotkey": { "color": "#2d5a80", - "background-color": "#162d40", "bold": true, "underline": true }, diff --git a/src/view_curses.cc b/src/view_curses.cc index 4f36d56b..7d41e3ce 100644 --- a/src/view_curses.cc +++ b/src/view_curses.cc @@ -190,13 +190,13 @@ view_curses::mvwattrline(WINDOW* window, full_line = expanded_line; auto& vc = view_colors::singleton(); - auto text_attrs = vc.attrs_for_role(role_t::VCR_TEXT); - short text_role_fg, text_role_bg; - auto text_color_pair = PAIR_NUMBER(text_attrs); - pair_content(text_color_pair, &text_role_fg, &text_role_bg); + auto text_role_attrs = vc.attrs_for_role(role_t::VCR_TEXT); auto attrs = vc.attrs_for_role(base_role); wmove(window, y, x); - wattron(window, attrs); + wattr_set(window, + attrs.ta_attrs, + vc.ensure_color_pair(attrs.ta_fg_color, attrs.ta_bg_color), + nullptr); if (lr_bytes.lr_start < (int) full_line.size()) { waddnstr( window, &full_line.c_str()[lr_bytes.lr_start], lr_bytes.length()); @@ -204,7 +204,6 @@ view_curses::mvwattrline(WINDOW* window, if (lr_bytes.lr_end > (int) full_line.size()) { whline(window, ' ', lr_bytes.lr_end - (full_line.size() + exp_offset)); } - wattroff(window, attrs); stable_sort(sa.begin(), sa.end()); for (auto iter = sa.begin(); iter != sa.end(); ++iter) { @@ -258,7 +257,8 @@ view_curses::mvwattrline(WINDOW* window, } short attr_fg = iter->sa_value.get(); if (attr_fg == view_colors::MATCH_COLOR_SEMANTIC) { - attr_fg = vc.color_for_ident(al.to_string_fragment(iter)); + attr_fg = vc.color_for_ident(al.to_string_fragment(iter)) + .value_or(view_colors::MATCH_COLOR_DEFAULT); } else if (attr_fg < 8) { attr_fg = vc.ansi_to_theme_color(attr_fg); } @@ -275,7 +275,8 @@ view_curses::mvwattrline(WINDOW* window, } short attr_bg = iter->sa_value.get(); if (attr_bg == view_colors::MATCH_COLOR_SEMANTIC) { - attr_bg = vc.color_for_ident(al.to_string_fragment(iter)); + attr_bg = vc.color_for_ident(al.to_string_fragment(iter)) + .value_or(view_colors::MATCH_COLOR_DEFAULT); } std::fill(bg_color + attr_range.lr_start, bg_color + attr_range.lr_end, @@ -287,79 +288,56 @@ view_curses::mvwattrline(WINDOW* window, if (attr_range.lr_end > attr_range.lr_start) { int awidth = attr_range.length(); nonstd::optional graphic; - short color_pair = 0; if (iter->sa_type == &VC_GRAPHIC) { graphic = iter->sa_value.get(); } else if (iter->sa_type == &VC_STYLE) { - attrs = iter->sa_value.get() & ~A_COLOR; - color_pair = PAIR_NUMBER(iter->sa_value.get()); + attrs = iter->sa_value.get(); } else if (iter->sa_type == &SA_LEVEL) { attrs = vc.vc_level_attrs[iter->sa_value.get()].first; - color_pair = PAIR_NUMBER(attrs); - attrs = attrs & ~A_COLOR; } else if (iter->sa_type == &VC_ROLE) { attrs = vc.attrs_for_role(iter->sa_value.get()); - color_pair = PAIR_NUMBER(attrs); - attrs = attrs & ~A_COLOR; } else if (iter->sa_type == &VC_ROLE_FG) { - short role_fg, role_bg; - attrs = vc.attrs_for_role(iter->sa_value.get()); - color_pair = PAIR_NUMBER(attrs); - pair_content(color_pair, &role_fg, &role_bg); - attrs = attrs & ~A_COLOR; - if (!has_fg) { - memset(fg_color, -1, line_width_chars * sizeof(short)); - } - std::fill(&fg_color[attr_range.lr_start], - &fg_color[attr_range.lr_end], - (short) role_fg); - has_fg = true; - color_pair = 0; + auto role_attrs + = vc.attrs_for_role(iter->sa_value.get()); + attrs.ta_fg_color = role_attrs.ta_fg_color; } - if (graphic || attrs || color_pair > 0) { + if (graphic || !attrs.empty()) { int x_pos = x + attr_range.lr_start; int ch_width = std::min( awidth, (line_width_chars - attr_range.lr_start)); cchar_t row_ch[ch_width + 1]; - if (attrs & (A_LEFT | A_RIGHT)) { - short pair_fg, pair_bg; - - pair_content(color_pair, &pair_fg, &pair_bg); - if (attrs & A_LEFT) { - pair_fg + if (attrs.ta_attrs & (A_LEFT | A_RIGHT)) { + if (attrs.ta_attrs & A_LEFT) { + attrs.ta_fg_color = vc.color_for_ident(al.to_string_fragment(iter)); } - if (attrs & A_RIGHT) { - pair_bg + if (attrs.ta_attrs & A_RIGHT) { + attrs.ta_bg_color = vc.color_for_ident(al.to_string_fragment(iter)); } - color_pair = vc.ensure_color_pair(pair_fg, pair_bg); - - attrs &= ~(A_LEFT | A_RIGHT); + attrs.ta_attrs &= ~(A_LEFT | A_RIGHT); } - if (color_pair > 0) { - short pair_fg, pair_bg; - pair_content(color_pair, &pair_fg, &pair_bg); - - if ((pair_fg == -1 || pair_fg == text_role_fg) - && (pair_bg == -1 || pair_bg == text_role_bg)) - { - color_pair = 0; - } else if (pair_bg == -1 || pair_bg == text_role_bg) { - if (!has_fg) { - memset( - fg_color, -1, line_width_chars * sizeof(short)); - } - std::fill(&fg_color[attr_range.lr_start], - &fg_color[attr_range.lr_end], - (short) pair_fg); - has_fg = true; - color_pair = 0; + if (attrs.ta_fg_color) { + if (!has_fg) { + memset(fg_color, -1, line_width_chars * sizeof(short)); } + std::fill(&fg_color[attr_range.lr_start], + &fg_color[attr_range.lr_end], + attrs.ta_fg_color.value()); + has_fg = true; + } + if (attrs.ta_bg_color) { + if (!has_bg) { + memset(bg_color, -1, line_width_chars * sizeof(short)); + } + std::fill(&bg_color[attr_range.lr_start], + &bg_color[attr_range.lr_end], + attrs.ta_bg_color.value()); + has_bg = true; } mvwin_wchnstr(window, y, x_pos, row_ch, ch_width); @@ -370,20 +348,11 @@ view_curses::mvwattrline(WINDOW* window, row_ch[lpc].chars[0] = graphic.value(); row_ch[lpc].attr |= A_ALTCHARSET; } - if (row_ch[lpc].attr & A_REVERSE && attrs & A_REVERSE) { + if (row_ch[lpc].attr & A_REVERSE + && attrs.ta_attrs & A_REVERSE) { clear_rev = true; } - if (color_pair > 0) { - row_ch[lpc].attr - = attrs | (row_ch[lpc].attr & ~A_COLOR); -#ifdef NCURSES_EXT_COLORS - row_ch[lpc].ext_color = color_pair; -#else - row_ch[lpc].attr |= COLOR_PAIR(color_pair); -#endif - } else { - row_ch[lpc].attr |= attrs; - } + row_ch[lpc].attr |= attrs.ta_attrs; if (clear_rev) { row_ch[lpc].attr &= ~A_REVERSE; } @@ -410,8 +379,11 @@ view_curses::mvwattrline(WINDOW* window, if (fg_color[lpc] == -1 && bg_color[lpc] == -1) { continue; } - +# ifdef NCURSES_EXT_COLORS + auto cur_pair = row_ch[lpc].ext_color; +# else auto cur_pair = PAIR_NUMBER(row_ch[lpc].attr); +# endif short cur_fg, cur_bg; pair_content(cur_pair, &cur_fg, &cur_bg); if (fg_color[lpc] == -1) { @@ -435,6 +407,9 @@ view_curses::mvwattrline(WINDOW* window, #endif } +constexpr short view_colors::MATCH_COLOR_DEFAULT; +constexpr short view_colors::MATCH_COLOR_SEMANTIC; + view_colors& view_colors::singleton() { @@ -515,53 +490,17 @@ view_colors::init() { vc_active_palette = ansi_colors(); if (has_colors()) { - static const int ansi_colors_to_curses[] = { - COLOR_BLACK, - COLOR_RED, - COLOR_GREEN, - COLOR_YELLOW, - COLOR_BLUE, - COLOR_MAGENTA, - COLOR_CYAN, - COLOR_WHITE, - }; - start_color(); if (lnav_config.lc_ui_default_colors) { use_default_colors(); } - for (int fg = 0; fg < 8; fg++) { - for (int bg = 0; bg < 8; bg++) { - if (fg == 0 && bg == 0) { - continue; - } - - if (lnav_config.lc_ui_default_colors - && ansi_colors_to_curses[fg] == COLOR_WHITE - && ansi_colors_to_curses[bg] == COLOR_BLACK) - { - init_pair(ansi_color_pair_index(fg, bg), -1, -1); - } else { - auto curs_bg = ansi_colors_to_curses[bg]; - - if (lnav_config.lc_ui_default_colors - && curs_bg == COLOR_BLACK) { - curs_bg = -1; - } - init_pair(ansi_color_pair_index(fg, bg), - ansi_colors_to_curses[fg], - curs_bg); - } - } - } if (COLORS >= 256) { vc_active_palette = xterm_colors(); } } log_debug("COLOR_PAIRS = %d", COLOR_PAIRS); - singleton().vc_dyn_pairs.set_max_size(COLOR_PAIRS); initialized = true; @@ -574,52 +513,43 @@ view_colors::init() } } -inline attr_t -attr_for_colors(int& pair_base, short fg, short bg) +inline text_attrs +attr_for_colors(nonstd::optional fg, nonstd::optional bg) { - if (fg == -1) { + if (fg && fg.value() == -1) { fg = COLOR_WHITE; } - if (bg == -1) { + if (bg && bg.value() == -1) { bg = COLOR_BLACK; } - if (COLOR_PAIRS <= 64) { - return view_colors::ansi_color_pair(fg, bg); - } else { - if (lnav_config.lc_ui_default_colors) { - if (fg == COLOR_WHITE) { - fg = -1; - } - if (bg == COLOR_BLACK) { - bg = -1; - } - } - } - - require(pair_base < COLOR_PAIRS); - int pair = pair_base; - pair_base += 1; - - if (view_colors::initialized) { - init_pair(pair, fg, bg); + if (lnav_config.lc_ui_default_colors) { + if (fg && fg.value() == COLOR_WHITE) { + fg = -1; + } + if (bg && bg.value() == COLOR_BLACK) { + bg = -1; + } } - auto retval = COLOR_PAIR(pair); + text_attrs retval; - if (fg == view_colors::MATCH_COLOR_SEMANTIC) { - retval |= A_LEFT; + if (fg && fg.value() == view_colors::MATCH_COLOR_SEMANTIC) { + retval.ta_attrs |= A_LEFT; + } else { + retval.ta_fg_color = fg; } - if (bg == view_colors::MATCH_COLOR_SEMANTIC) { - retval |= A_RIGHT; + if (bg && bg.value() == view_colors::MATCH_COLOR_SEMANTIC) { + retval.ta_attrs |= A_RIGHT; + } else { + retval.ta_bg_color = bg; } return retval; } -std::pair -view_colors::to_attrs(int& pair_base, - const lnav_theme& lt, +std::pair +view_colors::to_attrs(const lnav_theme& lt, const style_config& sc, const style_config& fallback_sc, lnav_config_listener::error_reporter& reporter) @@ -631,9 +561,6 @@ view_colors::to_attrs(int& pair_base, fg1 = fallback_sc.sc_color; } bg1 = sc.sc_background_color; - if (bg1.empty()) { - bg1 = fallback_sc.sc_background_color; - } shlex(fg1).eval(fg_color, lt.lt_vars); shlex(bg1).eval(bg_color, lt.lt_vars); @@ -656,17 +583,17 @@ view_colors::to_attrs(int& pair_base, return styling::color_unit::make_empty(); }); - attr_t retval1 = attr_for_colors( - pair_base, this->match_color(fg), this->match_color(bg)); - attr_t retval2 = 0; + text_attrs retval1 + = attr_for_colors(this->match_color(fg), this->match_color(bg)); + text_attrs retval2; if (sc.sc_underline) { - retval1 |= A_UNDERLINE; - retval2 |= A_UNDERLINE; + retval1.ta_attrs |= A_UNDERLINE; + retval2.ta_attrs |= A_UNDERLINE; } if (sc.sc_bold) { - retval1 |= A_BOLD; - retval2 |= A_BOLD; + retval1.ta_attrs |= A_BOLD; + retval2.ta_attrs |= A_BOLD; } return {retval1, retval2}; @@ -676,337 +603,192 @@ void view_colors::init_roles(const lnav_theme& lt, lnav_config_listener::error_reporter& reporter) { - int color_pair_base = VC_ANSI_END + 1; rgb_color fg, bg; std::string err; - if (COLORS == 256) { - const auto& ident_sc = lt.lt_style_identifier; - int ident_bg = (lnav_config.lc_ui_default_colors ? -1 : COLOR_BLACK); + /* Setup the mappings from roles to actual colors. */ + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_TEXT)] + = this->to_attrs(lt, lt.lt_style_text, lt.lt_style_text, reporter); + + for (int ansi_fg = 0; ansi_fg < 8; ansi_fg++) { + for (int ansi_bg = 0; ansi_bg < 8; ansi_bg++) { + if (ansi_fg == 0 && ansi_bg == 0) { + continue; + } - if (!ident_sc.sc_background_color.empty()) { - std::string bg_color; + auto fg_iter = lt.lt_vars.find(COLOR_NAMES[ansi_fg]); + auto bg_iter = lt.lt_vars.find(COLOR_NAMES[ansi_bg]); + auto fg_str = fg_iter == lt.lt_vars.end() ? "" : fg_iter->second; + auto bg_str = bg_iter == lt.lt_vars.end() ? "" : bg_iter->second; - shlex(ident_sc.sc_background_color).eval(bg_color, lt.lt_vars); - auto rgb_bg = rgb_color::from_str(bg_color).unwrapOrElse( + auto rgb_fg = rgb_color::from_str(fg_str).unwrapOrElse( [&](const auto& msg) { - reporter( - &ident_sc.sc_background_color, - lnav::console::user_message::error( - attr_line_t("invalid background color -- ") - .append_quoted(ident_sc.sc_background_color)) - .with_reason(msg)); + reporter(&fg_str, + lnav::console::user_message::error( + attr_line_t("invalid color -- ") + .append_quoted(fg_str)) + .with_reason(msg)); + return rgb_color{}; + }); + auto rgb_bg = rgb_color::from_str(bg_str).unwrapOrElse( + [&](const auto& msg) { + reporter(&bg_str, + lnav::console::user_message::error( + attr_line_t("invalid background color -- ") + .append_quoted(bg_str)) + .with_reason(msg)); return rgb_color{}; }); - ident_bg = vc_active_palette->match_color(lab_color(rgb_bg)); - } - } else { - color_pair_base = VC_ANSI_END + HI_COLOR_COUNT; - } - - /* Setup the mappings from roles to actual colors. */ - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_TEXT)] - = this->to_attrs( - color_pair_base, lt, lt.lt_style_text, lt.lt_style_text, reporter); - { - int pnum = PAIR_NUMBER( - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_TEXT)] - .first); - short text_fg, text_bg; - - pair_content(pnum, &text_fg, &text_bg); - for (int ansi_fg = 0; ansi_fg < 8; ansi_fg++) { - for (int ansi_bg = 0; ansi_bg < 8; ansi_bg++) { - if (ansi_fg == 0 && ansi_bg == 0) { - continue; - } + short fg = vc_active_palette->match_color(lab_color(rgb_fg)); + short bg = vc_active_palette->match_color(lab_color(rgb_bg)); - auto fg_iter = lt.lt_vars.find(COLOR_NAMES[ansi_fg]); - auto bg_iter = lt.lt_vars.find(COLOR_NAMES[ansi_bg]); - auto fg_str = fg_iter == lt.lt_vars.end() ? "" - : fg_iter->second; - auto bg_str = bg_iter == lt.lt_vars.end() ? "" - : bg_iter->second; - - auto rgb_fg = rgb_color::from_str(fg_str).unwrapOrElse( - [&](const auto& msg) { - reporter(&fg_str, - lnav::console::user_message::error( - attr_line_t("invalid color -- ") - .append_quoted(fg_str)) - .with_reason(msg)); - return rgb_color{}; - }); - auto rgb_bg = rgb_color::from_str(bg_str).unwrapOrElse( - [&](const auto& msg) { - reporter(&bg_str, - lnav::console::user_message::error( - attr_line_t("invalid background color -- ") - .append_quoted(bg_str)) - .with_reason(msg)); - return rgb_color{}; - }); - - short fg = vc_active_palette->match_color(lab_color(rgb_fg)); - short bg = vc_active_palette->match_color(lab_color(rgb_bg)); - - if (rgb_fg.empty()) { - fg = ansi_fg; - } - if (rgb_bg.empty()) { - bg = ansi_bg; - } + if (rgb_fg.empty()) { + fg = ansi_fg; + } + if (rgb_bg.empty()) { + bg = ansi_bg; + } - this->vc_ansi_to_theme[ansi_fg] = fg; - if (lnav_config.lc_ui_default_colors && bg == COLOR_BLACK) { - bg = -1; - if (fg == COLOR_WHITE) { - fg = -1; - } + this->vc_ansi_to_theme[ansi_fg] = fg; + if (lnav_config.lc_ui_default_colors && bg == COLOR_BLACK) { + bg = -1; + if (fg == COLOR_WHITE) { + fg = -1; } - init_pair(ansi_color_pair_index(ansi_fg, ansi_bg), fg, bg); } } } + if (lnav_config.lc_ui_dim_text) { - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_TEXT)].first + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_TEXT)] + .first.ta_attrs |= A_DIM; - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_TEXT)] - .second + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_TEXT)] + .second.ta_attrs |= A_DIM; } - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_SEARCH)] - = std::make_pair(A_REVERSE, A_REVERSE); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_IDENTIFIER)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_identifier, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_OK)] + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SEARCH)] + = std::make_pair(text_attrs{A_REVERSE}, text_attrs{A_REVERSE}); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_IDENTIFIER)] = this->to_attrs( - color_pair_base, lt, lt.lt_style_ok, lt.lt_style_text, reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_ERROR)] + lt, lt.lt_style_identifier, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_OK)] + = this->to_attrs(lt, lt.lt_style_ok, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_INFO)] + = this->to_attrs(lt, lt.lt_style_info, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ERROR)] + = this->to_attrs(lt, lt.lt_style_error, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_WARNING)] + = this->to_attrs(lt, lt.lt_style_warning, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ALT_ROW)] + = this->to_attrs(lt, lt.lt_style_alt_text, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_HIDDEN)] + = this->to_attrs(lt, lt.lt_style_hidden, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ADJUSTED_TIME)] = this->to_attrs( - color_pair_base, lt, lt.lt_style_error, lt.lt_style_text, reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_WARNING)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_warning, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_ALT_ROW)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_alt_text, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_HIDDEN)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_hidden, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_ADJUSTED_TIME)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_adjusted_time, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_SKEWED_TIME)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_skewed_time, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_OFFSET_TIME)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_offset_time, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_INVALID_MSG)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_invalid_msg, - lt.lt_style_text, - reporter); + lt, lt.lt_style_adjusted_time, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SKEWED_TIME)] + = this->to_attrs( + lt, lt.lt_style_skewed_time, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_OFFSET_TIME)] + = this->to_attrs( + lt, lt.lt_style_offset_time, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_INVALID_MSG)] + = this->to_attrs( + lt, lt.lt_style_invalid_msg, lt.lt_style_text, reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_STATUS)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_status, - lt.lt_style_status, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_WARN_STATUS)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_warn_status, - lt.lt_style_status, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_ALERT_STATUS)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_alert_status, - lt.lt_style_status, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_ACTIVE_STATUS)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_active_status, - lt.lt_style_status, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_ACTIVE_STATUS2)] - = std::make_pair(this->vc_role_colors[lnav::enums::to_underlying( - role_t::VCR_ACTIVE_STATUS)] - .first - | A_BOLD, - this->vc_role_colors[lnav::enums::to_underlying( - role_t::VCR_ACTIVE_STATUS)] - .second - | A_BOLD); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_STATUS_TITLE)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_status_title, - lt.lt_style_status, - reporter); - this->vc_role_colors[lnav::enums::to_underlying( - role_t::VCR_STATUS_SUBTITLE)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_status_subtitle, - lt.lt_style_status, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_STATUS_INFO)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_status_info, - lt.lt_style_status, - reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STATUS)] + = this->to_attrs(lt, lt.lt_style_status, lt.lt_style_status, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_WARN_STATUS)] + = this->to_attrs( + lt, lt.lt_style_warn_status, lt.lt_style_status, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ALERT_STATUS)] + = this->to_attrs( + lt, lt.lt_style_alert_status, lt.lt_style_status, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ACTIVE_STATUS)] + = this->to_attrs( + lt, lt.lt_style_active_status, lt.lt_style_status, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ACTIVE_STATUS2)] + = std::make_pair(this->vc_role_attrs[lnav::enums::to_underlying( + role_t::VCR_ACTIVE_STATUS)] + .first, + this->vc_role_attrs[lnav::enums::to_underlying( + role_t::VCR_ACTIVE_STATUS)] + .second); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ACTIVE_STATUS2)] + .first.ta_attrs + |= A_BOLD; + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ACTIVE_STATUS2)] + .second.ta_attrs + |= A_BOLD; + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STATUS_TITLE)] + = this->to_attrs( + lt, lt.lt_style_status_title, lt.lt_style_status, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STATUS_SUBTITLE)] + = this->to_attrs( + lt, lt.lt_style_status_subtitle, lt.lt_style_status, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STATUS_INFO)] + = this->to_attrs( + lt, lt.lt_style_status_info, lt.lt_style_status, reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_STATUS_HOTKEY)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_status_hotkey, - lt.lt_style_status, - reporter); - this->vc_role_colors[lnav::enums::to_underlying( + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STATUS_HOTKEY)] + = this->to_attrs( + lt, lt.lt_style_status_hotkey, lt.lt_style_status, reporter); + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_STATUS_TITLE_HOTKEY)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_status_title_hotkey, - lt.lt_style_status, - reporter); - this->vc_role_colors[lnav::enums::to_underlying( + = this->to_attrs( + lt, lt.lt_style_status_title_hotkey, lt.lt_style_status, reporter); + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_STATUS_DISABLED_TITLE)] - = this->to_attrs(color_pair_base, - lt, + = this->to_attrs(lt, lt.lt_style_status_disabled_title, lt.lt_style_status, reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_H1)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_header[0], - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_H2)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_header[1], - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_H3)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_header[2], - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_H4)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_header[3], - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_H5)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_header[4], - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_H6)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_header[5], - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_HR)] + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H1)] + = this->to_attrs(lt, lt.lt_style_header[0], lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H2)] + = this->to_attrs(lt, lt.lt_style_header[1], lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H3)] + = this->to_attrs(lt, lt.lt_style_header[2], lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H4)] + = this->to_attrs(lt, lt.lt_style_header[3], lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H5)] + = this->to_attrs(lt, lt.lt_style_header[4], lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H6)] + = this->to_attrs(lt, lt.lt_style_header[5], lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_HR)] + = this->to_attrs(lt, lt.lt_style_hr, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_HYPERLINK)] + = this->to_attrs(lt, lt.lt_style_hyperlink, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_LIST_GLYPH)] = this->to_attrs( - color_pair_base, lt, lt.lt_style_hr, lt.lt_style_text, reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_HYPERLINK)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_hyperlink, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_LIST_GLYPH)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_list_glyph, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_BREADCRUMB)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_breadcrumb, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_TABLE_BORDER)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_table_border, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_TABLE_HEADER)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_table_header, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_QUOTE_BORDER)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_quote_border, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_QUOTED_TEXT)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_quoted_text, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying( - role_t::VCR_FOOTNOTE_BORDER)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_footnote_border, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_FOOTNOTE_TEXT)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_footnote_text, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_SNIPPET_BORDER)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_snippet_border, - lt.lt_style_text, - reporter); + lt, lt.lt_style_list_glyph, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_BREADCRUMB)] + = this->to_attrs( + lt, lt.lt_style_breadcrumb, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_TABLE_BORDER)] + = this->to_attrs( + lt, lt.lt_style_table_border, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_TABLE_HEADER)] + = this->to_attrs( + lt, lt.lt_style_table_header, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_QUOTE_BORDER)] + = this->to_attrs( + lt, lt.lt_style_quote_border, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_QUOTED_TEXT)] + = this->to_attrs( + lt, lt.lt_style_quoted_text, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_FOOTNOTE_BORDER)] + = this->to_attrs( + lt, lt.lt_style_footnote_border, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_FOOTNOTE_TEXT)] + = this->to_attrs( + lt, lt.lt_style_footnote_text, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SNIPPET_BORDER)] + = this->to_attrs( + lt, lt.lt_style_snippet_border, lt.lt_style_text, reporter); { style_config stitch_sc; @@ -1014,10 +796,9 @@ view_colors::init_roles(const lnav_theme& lt, stitch_sc.sc_color = lt.lt_style_status_subtitle.sc_background_color; stitch_sc.sc_background_color = lt.lt_style_status_title.sc_background_color; - this->vc_role_colors[lnav::enums::to_underlying( + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_STATUS_STITCH_TITLE_TO_SUB)] - = this->to_attrs( - color_pair_base, lt, stitch_sc, lt.lt_style_status, reporter); + = this->to_attrs(lt, stitch_sc, lt.lt_style_status, reporter); } { style_config stitch_sc; @@ -1025,10 +806,9 @@ view_colors::init_roles(const lnav_theme& lt, stitch_sc.sc_color = lt.lt_style_status_title.sc_background_color; stitch_sc.sc_background_color = lt.lt_style_status_subtitle.sc_background_color; - this->vc_role_colors[lnav::enums::to_underlying( + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_STATUS_STITCH_SUB_TO_TITLE)] - = this->to_attrs( - color_pair_base, lt, stitch_sc, lt.lt_style_status, reporter); + = this->to_attrs(lt, stitch_sc, lt.lt_style_status, reporter); } { @@ -1037,20 +817,18 @@ view_colors::init_roles(const lnav_theme& lt, stitch_sc.sc_color = lt.lt_style_status.sc_background_color; stitch_sc.sc_background_color = lt.lt_style_status_subtitle.sc_background_color; - this->vc_role_colors[lnav::enums::to_underlying( + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_STATUS_STITCH_SUB_TO_NORMAL)] - = this->to_attrs( - color_pair_base, lt, stitch_sc, lt.lt_style_status, reporter); + = this->to_attrs(lt, stitch_sc, lt.lt_style_status, reporter); } { style_config stitch_sc; stitch_sc.sc_color = lt.lt_style_status_subtitle.sc_background_color; stitch_sc.sc_background_color = lt.lt_style_status.sc_background_color; - this->vc_role_colors[lnav::enums::to_underlying( + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_STATUS_STITCH_NORMAL_TO_SUB)] - = this->to_attrs( - color_pair_base, lt, stitch_sc, lt.lt_style_status, reporter); + = this->to_attrs(lt, stitch_sc, lt.lt_style_status, reporter); } { @@ -1059,196 +837,111 @@ view_colors::init_roles(const lnav_theme& lt, stitch_sc.sc_color = lt.lt_style_status.sc_background_color; stitch_sc.sc_background_color = lt.lt_style_status_title.sc_background_color; - this->vc_role_colors[lnav::enums::to_underlying( + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_STATUS_STITCH_TITLE_TO_NORMAL)] - = this->to_attrs( - color_pair_base, lt, stitch_sc, lt.lt_style_status, reporter); + = this->to_attrs(lt, stitch_sc, lt.lt_style_status, reporter); } { style_config stitch_sc; stitch_sc.sc_color = lt.lt_style_status_title.sc_background_color; stitch_sc.sc_background_color = lt.lt_style_status.sc_background_color; - this->vc_role_colors[lnav::enums::to_underlying( + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_STATUS_STITCH_NORMAL_TO_TITLE)] - = this->to_attrs( - color_pair_base, lt, stitch_sc, lt.lt_style_status, reporter); + = this->to_attrs(lt, stitch_sc, lt.lt_style_status, reporter); } - this->vc_role_colors[lnav::enums::to_underlying( - role_t::VCR_INACTIVE_STATUS)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_inactive_status, - lt.lt_style_status, - reporter); - this->vc_role_colors[lnav::enums::to_underlying( + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_INACTIVE_STATUS)] + = this->to_attrs( + lt, lt.lt_style_inactive_status, lt.lt_style_status, reporter); + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_INACTIVE_ALERT_STATUS)] - = this->to_attrs(color_pair_base, - lt, + = this->to_attrs(lt, lt.lt_style_inactive_alert_status, lt.lt_style_alert_status, reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_POPUP)] + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_POPUP)] + = this->to_attrs(lt, lt.lt_style_popup, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_FOCUSED)] = this->to_attrs( - color_pair_base, lt, lt.lt_style_popup, lt.lt_style_text, reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_FOCUSED)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_focused, - lt.lt_style_focused, - reporter); - this->vc_role_colors[lnav::enums::to_underlying( + lt, lt.lt_style_focused, lt.lt_style_focused, reporter); + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_DISABLED_FOCUSED)] - = this->to_attrs(color_pair_base, - lt, + = this->to_attrs(lt, lt.lt_style_disabled_focused, lt.lt_style_disabled_focused, reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_COLOR_HINT)] - = std::make_pair(COLOR_PAIR(color_pair_base), - COLOR_PAIR(color_pair_base + 1)); - color_pair_base += 2; - - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_SCROLLBAR)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_scrollbar, - lt.lt_style_status, - reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SCROLLBAR)] + = this->to_attrs( + lt, lt.lt_style_scrollbar, lt.lt_style_status, reporter); { style_config bar_sc; bar_sc.sc_color = lt.lt_style_error.sc_color; bar_sc.sc_background_color = lt.lt_style_scrollbar.sc_background_color; - this->vc_role_colors[lnav::enums::to_underlying( + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_SCROLLBAR_ERROR)] - = this->to_attrs(color_pair_base, - lt, - bar_sc, - lt.lt_style_alert_status, - reporter); + = this->to_attrs(lt, bar_sc, lt.lt_style_alert_status, reporter); } { style_config bar_sc; bar_sc.sc_color = lt.lt_style_warning.sc_color; bar_sc.sc_background_color = lt.lt_style_scrollbar.sc_background_color; - this->vc_role_colors[lnav::enums::to_underlying( + this->vc_role_attrs[lnav::enums::to_underlying( role_t::VCR_SCROLLBAR_WARNING)] - = this->to_attrs( - color_pair_base, lt, bar_sc, lt.lt_style_warn_status, reporter); + = this->to_attrs(lt, bar_sc, lt.lt_style_warn_status, reporter); } - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_QUOTED_CODE)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_quoted_code, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_CODE_BORDER)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_code_border, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_KEYWORD)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_keyword, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_STRING)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_string, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_COMMENT)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_comment, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_DOC_DIRECTIVE)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_doc_directive, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_VARIABLE)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_variable, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_SYMBOL)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_symbol, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_NUMBER)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_number, - lt.lt_style_text, - reporter); - - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_RE_SPECIAL)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_re_special, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_RE_REPEAT)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_re_repeat, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_FILE)] + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_QUOTED_CODE)] = this->to_attrs( - color_pair_base, lt, lt.lt_style_file, lt.lt_style_text, reporter); + lt, lt.lt_style_quoted_code, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_CODE_BORDER)] + = this->to_attrs( + lt, lt.lt_style_code_border, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_KEYWORD)] + = this->to_attrs(lt, lt.lt_style_keyword, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STRING)] + = this->to_attrs(lt, lt.lt_style_string, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_COMMENT)] + = this->to_attrs(lt, lt.lt_style_comment, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_DOC_DIRECTIVE)] + = this->to_attrs( + lt, lt.lt_style_doc_directive, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_VARIABLE)] + = this->to_attrs(lt, lt.lt_style_variable, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SYMBOL)] + = this->to_attrs(lt, lt.lt_style_symbol, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_NUMBER)] + = this->to_attrs(lt, lt.lt_style_number, lt.lt_style_text, reporter); + + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_RE_SPECIAL)] + = this->to_attrs( + lt, lt.lt_style_re_special, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_RE_REPEAT)] + = this->to_attrs(lt, lt.lt_style_re_repeat, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_FILE)] + = this->to_attrs(lt, lt.lt_style_file, lt.lt_style_text, reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_DIFF_DELETE)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_diff_delete, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_DIFF_ADD)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_diff_add, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_DIFF_SECTION)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_diff_section, - lt.lt_style_text, - reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_DIFF_DELETE)] + = this->to_attrs( + lt, lt.lt_style_diff_delete, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_DIFF_ADD)] + = this->to_attrs(lt, lt.lt_style_diff_add, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_DIFF_SECTION)] + = this->to_attrs( + lt, lt.lt_style_diff_section, lt.lt_style_text, reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_LOW_THRESHOLD)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_low_threshold, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_MED_THRESHOLD)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_med_threshold, - lt.lt_style_text, - reporter); - this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_HIGH_THRESHOLD)] - = this->to_attrs(color_pair_base, - lt, - lt.lt_style_high_threshold, - lt.lt_style_text, - reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_LOW_THRESHOLD)] + = this->to_attrs( + lt, lt.lt_style_low_threshold, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_MED_THRESHOLD)] + = this->to_attrs( + lt, lt.lt_style_med_threshold, lt.lt_style_text, reporter); + this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_HIGH_THRESHOLD)] + = this->to_attrs( + lt, lt.lt_style_high_threshold, lt.lt_style_text, reporter); for (auto level = static_cast(LEVEL_UNKNOWN + 1); level < LEVEL__MAX; @@ -1257,22 +950,16 @@ view_colors::init_roles(const lnav_theme& lt, auto level_iter = lt.lt_level_styles.find(level); if (level_iter == lt.lt_level_styles.end()) { - this->vc_level_attrs[level] = this->to_attrs(color_pair_base, - lt, - lt.lt_style_text, - lt.lt_style_text, - reporter); + this->vc_level_attrs[level] = this->to_attrs( + lt, lt.lt_style_text, lt.lt_style_text, reporter); } else { - this->vc_level_attrs[level] = this->to_attrs(color_pair_base, - lt, - level_iter->second, - lt.lt_style_text, - reporter); + this->vc_level_attrs[level] = this->to_attrs( + lt, level_iter->second, lt.lt_style_text, reporter); } } if (initialized && this->vc_color_pair_end == 0) { - this->vc_color_pair_end = color_pair_base + 1; + this->vc_color_pair_end = 1; } this->vc_dyn_pairs.clear(); } @@ -1283,6 +970,13 @@ view_colors::ensure_color_pair(short fg, short bg) require(fg >= -100); require(bg >= -100); + if (fg >= COLOR_BLACK && fg <= COLOR_WHITE) { + fg = this->ansi_to_theme_color(fg); + } + if (bg >= COLOR_BLACK && bg <= COLOR_WHITE) { + bg = this->ansi_to_theme_color(bg); + } + auto index_pair = std::make_pair(fg, bg); auto existing = this->vc_dyn_pairs.get(index_pair); @@ -1292,24 +986,30 @@ view_colors::ensure_color_pair(short fg, short bg) return retval; } - short def_pair = PAIR_NUMBER(this->attrs_for_role(role_t::VCR_TEXT)); - short def_fg, def_bg; - - pair_content(def_pair, &def_fg, &def_bg); - - int new_pair = this->vc_color_pair_end + this->vc_dyn_pairs.size(); - auto retval = PAIR_NUMBER(attr_for_colors( - new_pair, fg == -1 ? def_fg : fg, bg == -1 ? def_bg : bg)); + auto def_attrs = this->attrs_for_role(role_t::VCR_TEXT); + int retval = this->vc_color_pair_end + this->vc_dyn_pairs.size(); + auto attrs + = attr_for_colors(fg == -1 ? def_attrs.ta_fg_color.value_or(-1) : fg, + bg == -1 ? def_attrs.ta_bg_color.value_or(-1) : bg); + init_pair(retval, attrs.ta_fg_color.value(), attrs.ta_bg_color.value()); if (initialized) { - struct dyn_pair dp = {(int) retval}; + struct dyn_pair dp = {retval}; + this->vc_dyn_pairs.set_max_size(256 - this->vc_color_pair_end); this->vc_dyn_pairs.put(index_pair, dp); } return retval; } +int +view_colors::ensure_color_pair(nonstd::optional fg, + nonstd::optional bg) +{ + return this->ensure_color_pair(fg.value_or(-1), bg.value_or(-1)); +} + int view_colors::ensure_color_pair(const styling::color_unit& rgb_fg, const styling::color_unit& rgb_bg) @@ -1320,24 +1020,26 @@ view_colors::ensure_color_pair(const styling::color_unit& rgb_fg, return this->ensure_color_pair(fg, bg); } -short +nonstd::optional view_colors::match_color(const styling::color_unit& color) const { return color.cu_value.match( - [](styling::semantic) { return MATCH_COLOR_SEMANTIC; }, - [](const rgb_color& color) { + [](styling::semantic) -> nonstd::optional { + return MATCH_COLOR_SEMANTIC; + }, + [](const rgb_color& color) -> nonstd::optional { if (color.empty()) { - return MATCH_COLOR_DEFAULT; + return nonstd::nullopt; } return vc_active_palette->match_color(lab_color(color)); }); } -int +nonstd::optional view_colors::color_for_ident(const char* str, size_t len) const { - unsigned long index = crc32(1, (const Bytef*) str, len); + auto index = crc32(1, (const Bytef*) str, len); int retval; if (COLORS >= 256) { @@ -1349,7 +1051,7 @@ view_colors::color_for_ident(const char* str, size_t len) const } } - unsigned long offset = index % HI_COLOR_COUNT; + auto offset = index % HI_COLOR_COUNT; retval = this->vc_highlight_colors[offset]; } else { retval = -1; @@ -1358,25 +1060,19 @@ view_colors::color_for_ident(const char* str, size_t len) const return retval; } -attr_t -view_colors::attrs_for_ident(const char* str, size_t len) +text_attrs +view_colors::attrs_for_ident(const char* str, size_t len) const { auto retval = this->attrs_for_role(role_t::VCR_IDENTIFIER); - if (retval & (A_LEFT | A_RIGHT)) { - auto color_pair = PAIR_NUMBER(retval); - short pair_fg, pair_bg; - - pair_content(color_pair, &pair_fg, &pair_bg); - if (retval & A_LEFT) { - pair_fg = this->color_for_ident(str, len); + if (retval.ta_attrs & (A_LEFT | A_RIGHT)) { + if (retval.ta_attrs & A_LEFT) { + retval.ta_fg_color = this->color_for_ident(str, len); } - if (retval & A_RIGHT) { - pair_bg = this->color_for_ident(str, len); + if (retval.ta_attrs & A_RIGHT) { + retval.ta_bg_color = this->color_for_ident(str, len); } - color_pair = this->ensure_color_pair(pair_fg, pair_bg); - retval &= ~(A_COLOR | A_LEFT | A_RIGHT); - retval |= COLOR_PAIR(color_pair); + retval.ta_attrs &= ~(A_COLOR | A_LEFT | A_RIGHT); } return retval; diff --git a/src/view_curses.hh b/src/view_curses.hh index 0caabb40..6b599e3f 100644 --- a/src/view_curses.hh +++ b/src/view_curses.hh @@ -187,6 +187,11 @@ public: /** @return A reference to the singleton. */ static view_colors& singleton(); + view_colors(const view_colors&) = delete; + view_colors(view_colors&&) = delete; + view_colors& operator=(const view_colors&) = delete; + view_colors& operator=(view_colors&&) = delete; + /** * Performs curses-specific initialization. The other methods can be * called before this method, but the returned attributes cannot be used @@ -201,21 +206,21 @@ public: * @param role The role to retrieve character attributes for. * @return The attributes to use for the given role. */ - attr_t attrs_for_role(role_t role, bool selected = false) const + text_attrs attrs_for_role(role_t role, bool selected = false) const { if (role == role_t::VCR_NONE) { - return 0; + return {}; } require(role > role_t::VCR_NONE); require(role < role_t::VCR__MAX); return selected - ? this->vc_role_colors[lnav::enums::to_underlying(role)].second - : this->vc_role_colors[lnav::enums::to_underlying(role)].first; + ? this->vc_role_attrs[lnav::enums::to_underlying(role)].second + : this->vc_role_attrs[lnav::enums::to_underlying(role)].first; } - attr_t reverse_attrs_for_role(role_t role) const + text_attrs reverse_attrs_for_role(role_t role) const { require(role > role_t::VCR_NONE); require(role < role_t::VCR__MAX); @@ -223,56 +228,45 @@ public: return this->vc_role_reverse_colors[lnav::enums::to_underlying(role)]; } - int color_for_ident(const char* str, size_t len) const; + nonstd::optional color_for_ident(const char* str, size_t len) const; - int color_for_ident(const string_fragment& sf) const + nonstd::optional color_for_ident(const string_fragment& sf) const { return this->color_for_ident(sf.data(), sf.length()); } - attr_t attrs_for_ident(const char* str, size_t len); + text_attrs attrs_for_ident(const char* str, size_t len) const; - attr_t attrs_for_ident(intern_string_t str) + text_attrs attrs_for_ident(intern_string_t str) const { return this->attrs_for_ident(str.get(), str.size()); } - attr_t attrs_for_ident(const std::string& str) + text_attrs attrs_for_ident(const std::string& str) const { return this->attrs_for_ident(str.c_str(), str.length()); } int ensure_color_pair(short fg, short bg); + int ensure_color_pair(nonstd::optional fg, + nonstd::optional bg); + int ensure_color_pair(const styling::color_unit& fg, const styling::color_unit& bg); static constexpr short MATCH_COLOR_DEFAULT = -1; static constexpr short MATCH_COLOR_SEMANTIC = -10; - short match_color(const styling::color_unit& color) const; - - static inline int ansi_color_pair_index(int fg, int bg) - { - return VC_ANSI_START + ((fg * 8) + bg); - } + nonstd::optional match_color(const styling::color_unit& color) const; - static inline attr_t ansi_color_pair(int fg, int bg) - { - return COLOR_PAIR(ansi_color_pair_index(fg, bg)); - } - - static const int VC_ANSI_START = 0; - static const int VC_ANSI_END = VC_ANSI_START + (8 * 8); - - std::pair to_attrs( - int& pair_base, + std::pair to_attrs( const lnav_theme& lt, const style_config& sc, const style_config& fallback_sc, lnav_config_listener::error_reporter& reporter); - std::pair vc_level_attrs[LEVEL__MAX]; + std::pair vc_level_attrs[LEVEL__MAX]; short ansi_to_theme_color(short ansi_fg) const { @@ -291,17 +285,16 @@ private: /** Private constructor that initializes the member fields. */ view_colors(); - view_colors(const view_colors&) = delete; - struct dyn_pair { int dp_color_pair; }; /** Map of role IDs to attribute values. */ - std::pair - vc_role_colors[lnav::enums::to_underlying(role_t::VCR__MAX)]; + std::pair + vc_role_attrs[lnav::enums::to_underlying(role_t::VCR__MAX)]; /** Map of role IDs to reverse-video attribute values. */ - attr_t vc_role_reverse_colors[lnav::enums::to_underlying(role_t::VCR__MAX)]; + text_attrs + vc_role_reverse_colors[lnav::enums::to_underlying(role_t::VCR__MAX)]; short vc_ansi_to_theme[8]; short vc_highlight_colors[HI_COLOR_COUNT]; int vc_color_pair_end{0}; @@ -331,12 +324,11 @@ struct mouse_event { int y = -1) : me_button(button), me_state(state), me_x(x), me_y(y) { - memset(&this->me_time, 0, sizeof(this->me_time)); } mouse_button_t me_button; mouse_button_state_t me_state; - struct timeval me_time; + struct timeval me_time {}; int me_x; int me_y; }; diff --git a/src/view_helpers.hh b/src/view_helpers.hh index 02065027..f7ef1695 100644 --- a/src/view_helpers.hh +++ b/src/view_helpers.hh @@ -71,6 +71,7 @@ enum class ln_mode_t : int { SQL, EXEC, USER, + BUSY, }; extern const char* lnav_view_strings[LNV__MAX + 1]; diff --git a/src/views_vtab.cc b/src/views_vtab.cc index a6330598..68a01921 100644 --- a/src/views_vtab.cc +++ b/src/views_vtab.cc @@ -327,8 +327,7 @@ CREATE TABLE lnav_views ( crumb.c_search_placeholder, std::move(poss)); } - auto ret = top_line_meta_handlers.to_json_string(tlm); - to_sqlite(ctx, ret); + to_sqlite(ctx, top_line_meta_handlers.to_json_string(tlm)); } else { sqlite3_result_null(ctx); } diff --git a/src/vtab_module.hh b/src/vtab_module.hh index 895f16d2..5da3d3e3 100644 --- a/src/vtab_module.hh +++ b/src/vtab_module.hh @@ -159,11 +159,9 @@ template<> struct from_sqlite { inline string_fragment operator()(int argc, sqlite3_value** val, int argi) { - return string_fragment{ - (const unsigned char*) sqlite3_value_blob(val[argi]), - 0, - sqlite3_value_bytes(val[argi]), - }; + return string_fragment::from_bytes( + (const char*) sqlite3_value_blob(val[argi]), + sqlite3_value_bytes(val[argi])); } }; @@ -237,14 +235,14 @@ to_sqlite(sqlite3_context* ctx, const char* str) } inline void -to_sqlite(sqlite3_context* ctx, text_auto_buffer& buf) +to_sqlite(sqlite3_context* ctx, text_auto_buffer buf) { auto pair = buf.inner.release(); sqlite3_result_text(ctx, pair.first, pair.second, free); } inline void -to_sqlite(sqlite3_context* ctx, blob_auto_buffer& buf) +to_sqlite(sqlite3_context* ctx, blob_auto_buffer buf) { auto pair = buf.inner.release(); sqlite3_result_blob(ctx, pair.first, pair.second, free); @@ -306,10 +304,10 @@ to_sqlite(sqlite3_context* ctx, nonstd::optional& val) template inline void -to_sqlite(sqlite3_context* ctx, const nonstd::optional& val) +to_sqlite(sqlite3_context* ctx, nonstd::optional val) { if (val.has_value()) { - to_sqlite(ctx, val.value()); + to_sqlite(ctx, std::move(val.value())); } else { sqlite3_result_null(ctx); } @@ -321,7 +319,7 @@ struct ToSqliteVisitor { template void operator()(T&& t) const { - to_sqlite(this->tsv_context, std::forward(t)); + to_sqlite(this->tsv_context, std::move(t)); } sqlite3_context* tsv_context; @@ -329,7 +327,7 @@ struct ToSqliteVisitor { template void -to_sqlite(sqlite3_context* ctx, mapbox::util::variant& val) +to_sqlite(sqlite3_context* ctx, mapbox::util::variant&& val) { ToSqliteVisitor visitor(ctx); @@ -402,7 +400,7 @@ struct sqlite_func_adapter { try { Return retval = f(from_sqlite()(argc, argv, Idx)...); - to_sqlite(context, retval); + to_sqlite(context, std::move(retval)); } catch (from_sqlite_conversion_error& e) { char buffer[64]; diff --git a/src/vtab_module_json.hh b/src/vtab_module_json.hh index 6e7cd9de..127ed423 100644 --- a/src/vtab_module_json.hh +++ b/src/vtab_module_json.hh @@ -40,7 +40,7 @@ struct flattened_json_string : json_string { }; inline void -to_sqlite(sqlite3_context* ctx, flattened_json_string& val) +to_sqlite(sqlite3_context* ctx, flattened_json_string val) { sqlite3_result_text( ctx, (const char*) val.js_content.release(), val.js_len, free); @@ -48,7 +48,7 @@ to_sqlite(sqlite3_context* ctx, flattened_json_string& val) } inline void -to_sqlite(sqlite3_context* ctx, json_string& val) +to_sqlite(sqlite3_context* ctx, json_string val) { sqlite3_result_text( ctx, (const char*) val.js_content.release(), val.js_len, free); diff --git a/src/yajlpp/yajlpp.cc b/src/yajlpp/yajlpp.cc index 312e1715..6ea6672e 100644 --- a/src/yajlpp/yajlpp.cc +++ b/src/yajlpp/yajlpp.cc @@ -1294,8 +1294,8 @@ yajlpp_parse_context::get_snippet() const if (line_end) { text_len_remaining = (line_end - line_start); } - content.append(string_fragment{ - (const char*) line_start, 0, (int) text_len_remaining}); + content.append( + string_fragment::from_bytes(line_start, text_len_remaining)); } } diff --git a/test/Makefile.am b/test/Makefile.am index e96dc8fb..f3040955 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -460,6 +460,7 @@ DISTCLEANFILES = \ test_pretty_in.* \ tmp \ unreadable.log \ + UTF-8-test.md \ empty \ scripts-empty diff --git a/test/drive_mvwattrline.cc b/test/drive_mvwattrline.cc index 7ceb6036..92269e5a 100644 --- a/test/drive_mvwattrline.cc +++ b/test/drive_mvwattrline.cc @@ -69,44 +69,43 @@ main(int argc, char* argv[]) al.clear() .with_string("\tLeading tab") .with_attr(string_attr(line_range(0, 1), - VC_STYLE.value(A_REVERSE))); + VC_STYLE.value(text_attrs{A_REVERSE}))); view_curses::mvwattrline(win, y++, 0, al, lr); al.clear() .with_string("Tab\twith text") .with_attr(string_attr(line_range(1, 4), - VC_STYLE.value(A_REVERSE))); + VC_STYLE.value(text_attrs{A_REVERSE}))); view_curses::mvwattrline(win, y++, 0, al, lr); al.clear() .with_string("Tab\twith text #2") .with_attr(string_attr(line_range(3, 4), - VC_STYLE.value(A_REVERSE))); + VC_STYLE.value(text_attrs{A_REVERSE}))); view_curses::mvwattrline(win, y++, 0, al, lr); al.clear() .with_string("Two\ttabs\twith text") .with_attr(string_attr(line_range(4, 6), - VC_STYLE.value(A_REVERSE))) + VC_STYLE.value(text_attrs{A_REVERSE}))) .with_attr(string_attr(line_range(9, 13), - VC_STYLE.value(A_REVERSE))); + VC_STYLE.value(text_attrs{A_REVERSE}))); view_curses::mvwattrline(win, y++, 0, al, lr); al.clear() .with_string("Text with mixed attributes.") .with_attr(string_attr( line_range(5, 9), - VC_STYLE.value( - view_colors::ansi_color_pair(COLOR_RED, COLOR_BLACK)))) + VC_STYLE.value(text_attrs{0, COLOR_RED, COLOR_BLACK}))) .with_attr(string_attr(line_range(7, 12), - VC_STYLE.value(A_REVERSE))); + VC_STYLE.value(text_attrs{A_REVERSE}))); view_curses::mvwattrline(win, y++, 0, al, lr); const char* text = u8"Text with unicode ▶ characters"; int offset = strstr(text, "char") - text; al.clear().with_string(text).with_attr( string_attr(line_range(offset, offset + 4), - VC_STYLE.value(A_REVERSE))); + VC_STYLE.value(text_attrs{A_REVERSE}))); view_curses::mvwattrline(win, y++, 0, al, lr); wmove(win, y, 0); diff --git a/test/drive_view_colors.cc b/test/drive_view_colors.cc index 6d55f196..344bafe9 100644 --- a/test/drive_view_colors.cc +++ b/test/drive_view_colors.cc @@ -40,11 +40,11 @@ public: void do_update() override { - view_colors& vc = view_colors::singleton(); + auto& vc = view_colors::singleton(); int lpc; for (lpc = 0; lpc < 16; lpc++) { - int attrs; + text_attrs attrs; char label[64]; attr_line_t al; line_range lr; @@ -64,9 +64,9 @@ public: al = "before <123> after"; al.with_attr({line_range{8, 11}, - VC_STYLE.value((int64_t) view_colors::ansi_color_pair( - COLOR_CYAN, COLOR_BLACK))}); - al.with_attr({line_range{8, 11}, VC_STYLE.value(A_REVERSE)}); + VC_STYLE.value(text_attrs{0, COLOR_CYAN, COLOR_BLACK})}); + al.with_attr( + {line_range{8, 11}, VC_STYLE.value(text_attrs{A_REVERSE})}); test_colors::mvwattrline(this->tc_window, lpc, 0, al, lr); }; diff --git a/test/expected/expected.am b/test/expected/expected.am index 8836eee8..54fdc8fe 100644 --- a/test/expected/expected.am +++ b/test/expected/expected.am @@ -926,6 +926,8 @@ EXPECTED_FILES = \ $(srcdir)/%reldir%/test_text_file.sh_5b51b55dff7332c5bee2c9b797c401c5614d574a.out \ $(srcdir)/%reldir%/test_text_file.sh_87943c6be50d701a03e901f16493314c839af1ab.err \ $(srcdir)/%reldir%/test_text_file.sh_87943c6be50d701a03e901f16493314c839af1ab.out \ + $(srcdir)/%reldir%/test_text_file.sh_ac872aadda29b9a824361a2c711d62ec1c75d40f.err \ + $(srcdir)/%reldir%/test_text_file.sh_ac872aadda29b9a824361a2c711d62ec1c75d40f.out \ $(srcdir)/%reldir%/test_text_file.sh_c2a346ca1da2da4346f1d310212e166767993ce9.err \ $(srcdir)/%reldir%/test_text_file.sh_c2a346ca1da2da4346f1d310212e166767993ce9.out \ $() diff --git a/test/expected/test_cmds.sh_a00943ef715598c7554b85de8502454e41bb9e28.out b/test/expected/test_cmds.sh_a00943ef715598c7554b85de8502454e41bb9e28.out index f84996ae..01761e9b 100644 --- a/test/expected/test_cmds.sh_a00943ef715598c7554b85de8502454e41bb9e28.out +++ b/test/expected/test_cmds.sh_a00943ef715598c7554b85de8502454e41bb9e28.out @@ -1,4 +1,4 @@ - Thu Nov 03 09:20:00  1 normal 2 errors 0 warnings  0 marks + Thu Nov 03 09:20:00  1 normal 2 errors 0 warnings  0 marks  Thu Nov 03 09:45:00  1 normal 0 errors 0 warnings 0 marks - Fri Feb 03 09:20:00  0 normal 1 errors 0 warnings 0 marks + Fri Feb 03 09:20:00  0 normal 1 errors 0 warnings 0 marks  Wed Jan 03 09:20:00  1 normal 0 errors 0 warnings 0 marks diff --git a/test/expected/test_cmds.sh_c7fabc25374ff47c47931f63b1d697061b816a28.out b/test/expected/test_cmds.sh_c7fabc25374ff47c47931f63b1d697061b816a28.out index ed3342c5..2e7404f8 100644 --- a/test/expected/test_cmds.sh_c7fabc25374ff47c47931f63b1d697061b816a28.out +++ b/test/expected/test_cmds.sh_c7fabc25374ff47c47931f63b1d697061b816a28.out @@ -1,2 +1,2 @@ - Sat Nov 03 09:20:00 1 normal 2 errors  0 warnings  1 marks + Sat Nov 03 09:20:00 1 normal 2 errors  0 warnings  1 marks  Sat Nov 03 09:45:00 1 normal 0 errors 0 warnings 0 marks diff --git a/test/expected/test_cmds.sh_ccd326da92d1cacda63501cd1a3077381a18e8f2.out b/test/expected/test_cmds.sh_ccd326da92d1cacda63501cd1a3077381a18e8f2.out index 6532b16e..bc678377 100644 --- a/test/expected/test_cmds.sh_ccd326da92d1cacda63501cd1a3077381a18e8f2.out +++ b/test/expected/test_cmds.sh_ccd326da92d1cacda63501cd1a3077381a18e8f2.out @@ -1 +1 @@ - Sat Nov 03 00:00:00 2 normal 2 errors 0 warnings 0 marks + Sat Nov 03 00:00:00 2 normal 2 errors 0 warnings 0 marks diff --git a/test/expected/test_cmds.sh_dbdd62995fdefc8318053af05a32416eccfa79fc.out b/test/expected/test_cmds.sh_dbdd62995fdefc8318053af05a32416eccfa79fc.out index 5131433b..f3d0606c 100644 --- a/test/expected/test_cmds.sh_dbdd62995fdefc8318053af05a32416eccfa79fc.out +++ b/test/expected/test_cmds.sh_dbdd62995fdefc8318053af05a32416eccfa79fc.out @@ -1 +1 @@ - Sat Nov 03 08:00:00 2 normal 2 errors 0 warnings 0 marks + Sat Nov 03 08:00:00 2 normal 2 errors 0 warnings 0 marks diff --git a/test/expected/test_sql_fs_func.sh_9e2c0a90ce333365ff7354375f2c609bc27135c8.err b/test/expected/test_sql_fs_func.sh_9e2c0a90ce333365ff7354375f2c609bc27135c8.err index 18cae472..b1d8939d 100644 --- a/test/expected/test_sql_fs_func.sh_9e2c0a90ce333365ff7354375f2c609bc27135c8.err +++ b/test/expected/test_sql_fs_func.sh_9e2c0a90ce333365ff7354375f2c609bc27135c8.err @@ -1 +1 @@ -error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to readlink(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":45},{"start":17,"end":21,"type":"role","value":44},{"start":8,"end":22,"type":"role","value":58}]},"reason":{"str":"unable to stat path: non-existent-link -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} +error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to readlink(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":46},{"start":17,"end":21,"type":"role","value":45},{"start":8,"end":22,"type":"role","value":59}]},"reason":{"str":"unable to stat path: non-existent-link -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} diff --git a/test/expected/test_sql_fs_func.sh_cf670dfa1ae7ac5a074baa642068c6d26ac8e096.err b/test/expected/test_sql_fs_func.sh_cf670dfa1ae7ac5a074baa642068c6d26ac8e096.err index 68ee6417..0316795d 100644 --- a/test/expected/test_sql_fs_func.sh_cf670dfa1ae7ac5a074baa642068c6d26ac8e096.err +++ b/test/expected/test_sql_fs_func.sh_cf670dfa1ae7ac5a074baa642068c6d26ac8e096.err @@ -1 +1 @@ -error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to realpath(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":45},{"start":17,"end":21,"type":"role","value":44},{"start":8,"end":22,"type":"role","value":58}]},"reason":{"str":"Could not get real path for non-existent-path -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} +error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to realpath(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":46},{"start":17,"end":21,"type":"role","value":45},{"start":8,"end":22,"type":"role","value":59}]},"reason":{"str":"Could not get real path for non-existent-path -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} diff --git a/test/expected/test_sql_json_func.sh_5f2feef079a51410e1f8661bfe92da1c3277f665.err b/test/expected/test_sql_json_func.sh_5f2feef079a51410e1f8661bfe92da1c3277f665.err index aa519f16..8bf9a3d2 100644 --- a/test/expected/test_sql_json_func.sh_5f2feef079a51410e1f8661bfe92da1c3277f665.err +++ b/test/expected/test_sql_json_func.sh_5f2feef079a51410e1f8661bfe92da1c3277f665.err @@ -1 +1 @@ -error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to json_contains(json, value) failed","attrs":[{"start":8,"end":21,"type":"role","value":45},{"start":22,"end":26,"type":"role","value":44},{"start":28,"end":33,"type":"role","value":44},{"start":8,"end":34,"type":"role","value":58}]},"reason":{"str":"parse error: premature EOF\n [\"hi\", \"bye\", \"solong]\n (right here) ------^","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} +error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to json_contains(json, value) failed","attrs":[{"start":8,"end":21,"type":"role","value":46},{"start":22,"end":26,"type":"role","value":45},{"start":28,"end":33,"type":"role","value":45},{"start":8,"end":34,"type":"role","value":59}]},"reason":{"str":"parse error: premature EOF\n [\"hi\", \"bye\", \"solong]\n (right here) ------^","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} diff --git a/test/expected/test_sql_str_func.sh_80c1fb9affbfac609ebf1cc5556aafb1ecd223c1.err b/test/expected/test_sql_str_func.sh_80c1fb9affbfac609ebf1cc5556aafb1ecd223c1.err index db216654..2d0c060d 100644 --- a/test/expected/test_sql_str_func.sh_80c1fb9affbfac609ebf1cc5556aafb1ecd223c1.err +++ b/test/expected/test_sql_str_func.sh_80c1fb9affbfac609ebf1cc5556aafb1ecd223c1.err @@ -1 +1 @@ -error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to regexp_match(re, str) failed","attrs":[{"start":8,"end":20,"type":"role","value":45},{"start":21,"end":23,"type":"role","value":44},{"start":25,"end":28,"type":"role","value":44},{"start":8,"end":29,"type":"role","value":58}]},"reason":{"str":"regular expression does not have any captures","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} +error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to regexp_match(re, str) failed","attrs":[{"start":8,"end":20,"type":"role","value":46},{"start":21,"end":23,"type":"role","value":45},{"start":25,"end":28,"type":"role","value":45},{"start":8,"end":29,"type":"role","value":59}]},"reason":{"str":"regular expression does not have any captures","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} diff --git a/test/expected/test_sql_time_func.sh_42f0fc1a154b0d79b4f6e846f283426be498040f.err b/test/expected/test_sql_time_func.sh_42f0fc1a154b0d79b4f6e846f283426be498040f.err index fc569fe2..fa2cecdd 100644 --- a/test/expected/test_sql_time_func.sh_42f0fc1a154b0d79b4f6e846f283426be498040f.err +++ b/test/expected/test_sql_time_func.sh_42f0fc1a154b0d79b4f6e846f283426be498040f.err @@ -1 +1 @@ -error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":45},{"start":18,"end":22,"type":"role","value":44},{"start":24,"end":29,"type":"role","value":44},{"start":8,"end":30,"type":"role","value":58}]},"reason":{"str":"unable to parse time slice value: blah -- Unrecognized input","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} +error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":46},{"start":18,"end":22,"type":"role","value":45},{"start":24,"end":29,"type":"role","value":45},{"start":8,"end":30,"type":"role","value":59}]},"reason":{"str":"unable to parse time slice value: blah -- Unrecognized input","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} diff --git a/test/expected/test_sql_time_func.sh_72862ec9c8f261a8507d237eb673c7ddfaafd898.err b/test/expected/test_sql_time_func.sh_72862ec9c8f261a8507d237eb673c7ddfaafd898.err index d672b575..c789e936 100644 --- a/test/expected/test_sql_time_func.sh_72862ec9c8f261a8507d237eb673c7ddfaafd898.err +++ b/test/expected/test_sql_time_func.sh_72862ec9c8f261a8507d237eb673c7ddfaafd898.err @@ -1 +1 @@ -error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":45},{"start":18,"end":22,"type":"role","value":44},{"start":24,"end":29,"type":"role","value":44},{"start":8,"end":30,"type":"role","value":58}]},"reason":{"str":"no time slice value given","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} +error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":46},{"start":18,"end":22,"type":"role","value":45},{"start":24,"end":29,"type":"role","value":45},{"start":8,"end":30,"type":"role","value":59}]},"reason":{"str":"no time slice value given","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} diff --git a/test/expected/test_text_file.sh_ac872aadda29b9a824361a2c711d62ec1c75d40f.err b/test/expected/test_text_file.sh_ac872aadda29b9a824361a2c711d62ec1c75d40f.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_text_file.sh_ac872aadda29b9a824361a2c711d62ec1c75d40f.out b/test/expected/test_text_file.sh_ac872aadda29b9a824361a2c711d62ec1c75d40f.out new file mode 100644 index 00000000..6c9b5ae1 --- /dev/null +++ b/test/expected/test_text_file.sh_ac872aadda29b9a824361a2c711d62ec1c75d40f.out @@ -0,0 +1,74 @@ +✘ error: unable to parse markdown file + reason: file has invalid UTF-8 at offset 4461: Expecting bytes in the following ranges: 00..7F C2..F4. + +UTF-8 decoder capability and stress test +---------------------------------------- + +Markus Kuhn - 2015-08-28 - CC BY 4.0 + +This test file can help you examine, how your UTF-8 decoder handles +various types of correct, malformed, or otherwise interesting UTF-8 +sequences. This file is not meant to be a conformance test. It does +not prescribe any particular outcome. Therefore, there is no way to +"pass" or "fail" this test file, even though the text does suggest a +preferable decoder behaviour at some places. Its aim is, instead, to +help you think about, and test, the behaviour of your UTF-8 decoder on a +systematic collection of unusual inputs. Experience so far suggests +that most first-time authors of UTF-8 decoders find at least one +serious problem in their decoder using this file. + +The test lines below cover boundary conditions, malformed UTF-8 +sequences, as well as correctly encoded UTF-8 sequences of Unicode code +points that should never occur in a correct UTF-8 file. + +According to ISO 10646-1:2000, sections D.7 and 2.3c, a device +receiving UTF-8 shall interpret a "malformed sequence in the same way +that it interprets a character that is outside the adopted subset" and +"characters that are not within the adopted subset shall be indicated +to the user" by a receiving device. One commonly used approach in +UTF-8 decoders is to replace any malformed UTF-8 sequence by a +replacement character (U+FFFD), which looks a bit like an inverted +question mark, or a similar symbol. It might be a good idea to +visually distinguish a malformed UTF-8 sequence from a correctly +encoded Unicode character that is just not available in the current +font but otherwise fully legal, even though ISO 10646-1 doesn't +mandate this. In any case, just ignoring malformed sequences or +unavailable characters does not conform to ISO 10646, will make +debugging more difficult, and can lead to user confusion. + +Please check, whether a malformed UTF-8 sequence is (1) represented at +all, (2) represented by exactly one single replacement character (or +equivalent signal), and (3) the following quotation mark after an +illegal UTF-8 sequence is correctly displayed, i.e. proper +resynchronization takes place immediately after any malformed +sequence. This file says "THE END" in the last line, so if you don't +see that, your decoder crashed somehow before, which should always be +cause for concern. + +All lines in this file are exactly 79 characters long (plus the line +feed). In addition, all lines end with "|", except for the two test +lines 2.1.1 and 2.2.1, which contain non-printable ASCII controls +U+0000 and U+007F. If you display this file with a fixed-width font, +these "|" characters should all line up in column 79 (right margin). +This allows you to test quickly, whether your UTF-8 decoder finds the +correct number of characters in every line, that is whether each +malformed sequences is replaced by a single replacement character. + +Note that, as an alternative to the notion of malformed sequence used +here, it is also a perfectly acceptable (and in some situations even +preferable) solution to represent each individual byte of a malformed +sequence with a replacement character. If you follow this strategy in +your decoder, then please ignore the "|" column. + + +Here come the tests: | + | +1 Some correct UTF-8 text | + | +You should see the Greek word 'kosme': "κόσμε" | + | +2 Boundary condition test cases | + | +2.1 First possible sequence of a certain length | + | +2.1.1 1 byte (U-00000000): " diff --git a/test/test_ansi_scrubber.cc b/test/test_ansi_scrubber.cc index 6676c778..ab94062e 100644 --- a/test/test_ansi_scrubber.cc +++ b/test/test_ansi_scrubber.cc @@ -60,11 +60,12 @@ main(int argc, char* argv[]) assert(sa[0].sa_range.lr_start == 5); assert(sa[0].sa_range.lr_end == 7); - assert(sa[0].sa_type == &VC_BACKGROUND); - assert(sa[0].sa_value.get() == COLOR_BLUE); + assert(sa[0].sa_type == &VC_STYLE); + assert(sa[0].sa_value.get().ta_bg_color.value() == COLOR_BLUE); assert(sa[1].sa_range.lr_start == 7); assert(sa[1].sa_range.lr_end == 12); - assert(sa[1].sa_type == &VC_FOREGROUND); - assert(sa[1].sa_value.get() == COLOR_YELLOW); + assert(sa[1].sa_type == &VC_STYLE); + assert(sa[1].sa_value.get().ta_fg_color.value() + == COLOR_YELLOW); } diff --git a/test/test_text_file.sh b/test/test_text_file.sh index c89c9554..74ff7980 100644 --- a/test/test_text_file.sh +++ b/test/test_text_file.sh @@ -14,3 +14,7 @@ run_cap_test ${lnav_test} -n \ run_cap_test ${lnav_test} -n \ ${top_srcdir}/src/log_level.cc + +cp ${test_dir}/UTF-8-test.txt UTF-8-test.md +run_cap_test ${lnav_test} -n \ + UTF-8-test.md diff --git a/test/tui-captures/tui_echo.0 b/test/tui-captures/tui_echo.0 index f859a265..962b066c 100644 --- a/test/tui-captures/tui_echo.0 +++ b/test/tui-captures/tui_echo.0 @@ -14,13 +14,34 @@ OSC Set window title: LOG S -1 ┋ ┋ A └ normal, normal, normal CSI Erase all -S 1 ┋ Thu Jun 06 1 :: :: LOG ┋ -A └ fg(#c0c0c0), bg(#008080) -S 2 ┋ x┋ -A ···············································································├ normal -A └┛ alt -A ················································································└ normal +S 1 ┋ 2013-06-06T12:13:20 PDT ┋ +A └ bg(#008080) +S 16 ┋ Files :: Text Filters :: Press q to exit ┋ +A └ bg(#000080), bold │ ││ +A ·└ fg(#008080), bg(#000080), underline ││ +A ··└ normal, bg(#000080), bold ││ +A ·······└ normal, fg(#000000), bg(#000080) ││ +A ········└ fg(#000080), bg(#c0c0c0) ││ +A ·········└ fg(#000000), bg(#c0c0c0), bold ││ +A ··········└ fg(#800080), bg(#c0c0c0), underline ││ +A ···········└ normal, fg(#000000), bg(#c0c0c0), bold ││ +A ·······················└ normal, fg(#000000), bg(#c0c0c0) ││ +A ······································································└ bold +A ·······································································└ normal, fg(#000000), bg(#c0c0c0) +S 17 ┋ ┋ +S 23 ┋ L0 0% ?:View Help ┋ +A └ normal, bg(#008080) +S 18 ┋ ┋ +A └ normal, normal +S 1 ┋ Press ENTER to focus on the breadcrumb bar ┋ +A ·····································└ bg(#008080) │ +A ···············································································└ carriage-return +S 2 ┋ LOG ❭ ┋ +A └ fg(#000000), bg(#000080), bold +A ·····└ normal, fg(#008080), bg(#c0c0c0) +A ······└ fg(#000000), bg(#c0c0c0) S 3 ┋ x┋ +A ···············································································├ normal A └┛ alt A ················································································└ normal S 4 ┋ x┋ @@ -59,39 +80,13 @@ A ···································· S 15 ┋ x┋ A └┛ alt A ················································································└ normal -S 16 ┋ x┋ +S 18 ┋ x┋ A └┛ alt A ················································································└ normal -S 17 ┋ lqqqq No log messages; Files: 0; Error rate: 0.00/min; Time span: None qqqqk x┋ -A └----┛ alt │ │ │ │ │ │ │ ││ │││ -A ·······························└ bold │ │ │ │ ││ │││ -A ·································└ normal │ │ │ │ ││ │││ -A ···································└ fg(#800000), bold │ ││ │││ -A ·············································└ normal │ ││ │││ -A ···············································└ bold │ ││ │││ -A ···················································└ normal │ ││ │││ -A ····································································└ bold │││ -A ········································································└ normal│ -A ·········································································├ bold││ -A └----┛ alt -A ··············································································└ normal +S 19 ┋ x┋ A └┛ alt A ················································································└ normal -S 18 ┋ Files :: Text Filters :: Press q to exit ┋ -A └ fg(#c0c0c0), bg(#000080), bold ││ -A ·└ fg(#008080), bg(#000080), underline ││ -A ··└ normal, fg(#c0c0c0), bg(#000080), bold ││ -A ·······└ normal, fg(#c0c0c0), bg(#000080) ││ -A ········└ fg(#000080), bg(#c0c0c0) ││ -A ·········└ fg(#000000), bg(#c0c0c0), bold ││ -A ··········└ fg(#800080), bg(#c0c0c0), underline ││ -A ···········└ normal, fg(#000000), bg(#c0c0c0), bold ││ -A ·······················└ normal, fg(#000000), bg(#c0c0c0) ││ -A ······································································└ bold -A ·······································································└ normal, fg(#000000), bg(#c0c0c0) -S 19 ┋ ┋ S 20 ┋ x┋ -A ···············································································├ normal A └┛ alt A ················································································└ normal S 21 ┋ x┋ @@ -100,59 +95,61 @@ A ···································· S 22 ┋ x┋ A └┛ alt A ················································································└ normal -S 23 ┋ L0 0% ?:View Help ┋ -A └ fg(#000000), bg(#c0c0c0) S 22 ┋ ┋ -A └ normal, normal +A └ normal OSC Set window title: HELP -S 1 ┋ Thu Jun 06 1 :: :: HELP ┋ -A └ fg(#000000), bg(#c0c0c0) │││ │││ -A ················································└ fg(#008080), bg(#c0c0c0) -A ·················································└ fg(#c0c0c0), bg(#008080) -A ··················································└ fg(#000000), bg(#008080) -A ······································································└ fg(#000080), bg(#008080) -A ·······································································└ fg(#008080), bg(#000080) -A ········································································└ fg(#c0c0c0), bg(#000080), bold -S 2 ┋ x┋ -A ···············································································└ normal, fg(#000000), bg(#c0c0c0) -A ················································································└ normal -A └┛ alt -A ················································································└ normal -S 3 ┋ lnav - A fancy log file viewer ┋ -A ··└ fg(#000000), bg(#c0c0c0), normal -A ································└ carriage-return -S 5 ┋DESCRIPTION ┋ -A ···········└ carriage-return -S 6 ┋=========== ┋ -A ···········└ carriage-return -S 8 ┋The log file navigator, lnav, is an enhanced log file viewer that ┋ -A ·································································└ carriage-return -S 9 ┋takes advantage of any semantic information that can be gleaned from ┋ -A ····································································└ carriage-return -S 10 ┋the files being viewed, such as timestamps and log levels. Using this ┋ +S 2 ┋ HELP ❭⋯❭ ┋ +A ·└ fg(#000000), bg(#000080), bold +A ······└ normal, fg(#008080), bg(#c0c0c0) +A ·······└ fg(#000000), bg(#c0c0c0) +A ········└ fg(#008080), bg(#c0c0c0) +S 3 ┋ x┋ +A ···············································································└ normal, fg(#000000) +A ················································································└ normal +A └┛ alt +A ················································································└ normal +S 4 ┋lnav ┋ +A └ fg(#000000), normal, underline +A ····└ carriage-return +S 6 ┋A fancy log file viewer for the terminal. ┋ +A └ normal │ +A ·········································└ carriage-return +S 8 ┋Overview ┋ +A └ underline +A ········└ carriage-return +S 10 ┋The Logfile Navigator, lnav, is an enhanced log file viewer that takes ┋ +A └ normal │ │ │ +A ·······················└ bold │ +A ···························└ normal │ A ······································································└ carriage-return -S 11 ┋extra semantic information, lnav can do things like interleaving ┋ +S 11 ┋advantage of any semantic information that can be gleaned from the ┋ +A ··································································└ carriage-return +S 12 ┋files being viewed, such as timestamps and log levels. Using this ┋ +A ·································································└ carriage-return +S 13 ┋extra semantic information, lnav can do things like interleaving ┋ A ································································└ carriage-return -S 12 ┋messages from different files, generate histograms of messages over ┋ +S 14 ┋messages from different files, generate histograms of messages over ┋ A ···································································└ carriage-return -S 13 ┋time, and providing hotkeys for navigating through the file. It is ┋ -A ···································································└ carriage-return -S 14 ┋hoped that these features will allow the user to quickly and ┋ -A ····························································└ carriage-return -S 15 ┋efficiently zero in on problems. ┋ -A ································└ carriage-return -S 17 ┋ ┋ -A ··············································································└ carriage-return -S 18 ┋OPENING PATHS/URLs x┋ +S 15 ┋time, and providing hotkeys for navigating through the file. It is ┋ +A ··································································└ carriage-return +S 16 ┋hoped that these features will allow the user to quickly and x┋ A └┛ alt A ················································································└ normal -S 19 ┋================== x┋ +S 17 ┋efficiently zero in on problems. x┋ A └┛ alt A ················································································└ normal -S 21 ┋The main arguments to lnav are the files, directories, glob patterns, ┋ -A ·····································································└ carriage-return -S 22 ┋or URLs to be viewed. If no arguments are given, the default syslog ┋ +S 19 ┋Opening Paths/URLs ┋ +A └ underline │ +A ··················└ carriage-return +S 21 ┋The main arguments to lnav are the local/remote files, directories, ┋ +A └ normal │ +A ···································································└ carriage-return +S 22 ┋glob patterns, or URLs to be viewed. If no arguments are given, the ┋ +A ···································································└ carriage-return +S 23 ┋ L0 0% ?:View Help ┋ +A └ fg(#000000), bg(#c0c0c0) S 24 ┋ Press e/E to move forward/backward through error messags ┋ +A ·······················└ normal││ │ A ·····························└ bold │ A ······························└ normal │ A ·······························└ bold │ @@ -167,65 +164,62 @@ A └ normal K 3a CSI Erase Below CSI Erase Below -S 24 ┋ ┋ +S 24 ┋: ┋ A └ normal +A ·└ normal S 23 ┋ Enter an lnav command: (Press CTRL+] to abort) ┋ A ·└ fg(#000000), bg(#c0c0c0) │ │ A ·······························└ bold│ A ·····································└ normal, fg(#000000), bg(#c0c0c0) S 23 ┋ ┋ -A ···································································└ carriage-return -S 24 ┋: ┋ -A └ normal -A ·└ normal -K 65 S 24 ┋ e ┋ +A ·└ normal, normal A ··└ normal -K 63 +K 65 S 24 ┋ c ┋ A ···└ normal -K 68 +K 63 S 24 ┋ h ┋ A ····└ normal -K 6f +K 68 S 24 ┋ o ┋ A ·····└ normal -K 20 +K 6f S 24 ┋ echo ┋ A ·····└ backspace A ····└ backspace A ···└ backspace A ··└ backspace -A ·└ fg(#000080), bold +A ·└ fg(#000080) A ······└ normal, normal -K 68 +K 20 S 24 ┋ h ┋ A ·······└ normal -K 69 +K 68 S 24 ┋ i ┋ A ········└ normal -K 0d +K 69 S 24 ┋ ┋ A ········└ carriage-return CSI Erase Below -S 24 ┋ ┋ +S 24 ┋hi ┋ A └ normal +A ··└ normal +K 0d S 23 ┋ L0 0% ┋ +A ··└ backspace A ·└ fg(#000000), bg(#c0c0c0) S 23 ┋ ?:View Help ┋ -A ···································································└ carriage-return -S 24 ┋✔ hi ┋ -A └ normal, fg(#008000) -A ·└ normal -A ····└ carriage-return -A └ normal +S 24 ┋ ┋ +A ··└ normal, normal K 71 +S 24 ┋ⓘ info: executing SQL statement, press CTRL+] to cancel ┋ +A ··└ carriage-return │ │ │ +A ·······································└ fg(#800080), bold, underline +A ·············································└ normal │ +A ·······················································└ carriage-return +A └ normal OSC Set window title: LOG -S 1 ┋ LOG ┋ -A ···········································································└ fg(#c0c0c0), bg(#000080), bold -A ···············································································└ carriage-return -S 24 ┋ ┋ -A └ normal, normal CSI Erase all CSI Use normal screen buffer CTRL restore cursor diff --git a/test/tui-captures/tui_help.0 b/test/tui-captures/tui_help.0 index 546b7f59..ae13ead6 100644 --- a/test/tui-captures/tui_help.0 +++ b/test/tui-captures/tui_help.0 @@ -14,13 +14,34 @@ OSC Set window title: LOG S -1 ┋ ┋ A └ normal, normal, normal CSI Erase all -S 1 ┋ Thu Jun 06 1 :: :: LOG ┋ -A └ fg(#c0c0c0), bg(#008080) -S 2 ┋ x┋ -A ···············································································├ normal -A └┛ alt -A ················································································└ normal +S 1 ┋ 2013-06-06T12:13:20 PDT ┋ +A └ bg(#008080) +S 16 ┋ Files :: Text Filters :: Press q to exit ┋ +A └ bg(#000080), bold │ ││ +A ·└ fg(#008080), bg(#000080), underline ││ +A ··└ normal, bg(#000080), bold ││ +A ·······└ normal, fg(#000000), bg(#000080) ││ +A ········└ fg(#000080), bg(#c0c0c0) ││ +A ·········└ fg(#000000), bg(#c0c0c0), bold ││ +A ··········└ fg(#800080), bg(#c0c0c0), underline ││ +A ···········└ normal, fg(#000000), bg(#c0c0c0), bold ││ +A ·······················└ normal, fg(#000000), bg(#c0c0c0) ││ +A ······································································└ bold +A ·······································································└ normal, fg(#000000), bg(#c0c0c0) +S 17 ┋ ┋ +S 23 ┋ L0 0% ?:View Help ┋ +A └ normal, bg(#008080) +S 18 ┋ ┋ +A └ normal, normal +S 1 ┋ Press ENTER to focus on the breadcrumb bar ┋ +A ·····································└ bg(#008080) │ +A ···············································································└ carriage-return +S 2 ┋ LOG ❭ ┋ +A └ fg(#000000), bg(#000080), bold +A ·····└ normal, fg(#008080), bg(#c0c0c0) +A ······└ fg(#000000), bg(#c0c0c0) S 3 ┋ x┋ +A ···············································································├ normal A └┛ alt A ················································································└ normal S 4 ┋ x┋ @@ -59,39 +80,13 @@ A ···································· S 15 ┋ x┋ A └┛ alt A ················································································└ normal -S 16 ┋ x┋ +S 18 ┋ x┋ A └┛ alt A ················································································└ normal -S 17 ┋ lqqqq No log messages; Files: 0; Error rate: 0.00/min; Time span: None qqqqk x┋ -A └----┛ alt │ │ │ │ │ │ │ ││ │││ -A ·······························└ bold │ │ │ │ ││ │││ -A ·································└ normal │ │ │ │ ││ │││ -A ···································└ fg(#800000), bold │ ││ │││ -A ·············································└ normal │ ││ │││ -A ···············································└ bold │ ││ │││ -A ···················································└ normal │ ││ │││ -A ····································································└ bold │││ -A ········································································└ normal│ -A ·········································································├ bold││ -A └----┛ alt -A ··············································································└ normal +S 19 ┋ x┋ A └┛ alt A ················································································└ normal -S 18 ┋ Files :: Text Filters :: Press q to exit ┋ -A └ fg(#c0c0c0), bg(#000080), bold ││ -A ·└ fg(#008080), bg(#000080), underline ││ -A ··└ normal, fg(#c0c0c0), bg(#000080), bold ││ -A ·······└ normal, fg(#c0c0c0), bg(#000080) ││ -A ········└ fg(#000080), bg(#c0c0c0) ││ -A ·········└ fg(#000000), bg(#c0c0c0), bold ││ -A ··········└ fg(#800080), bg(#c0c0c0), underline ││ -A ···········└ normal, fg(#000000), bg(#c0c0c0), bold ││ -A ·······················└ normal, fg(#000000), bg(#c0c0c0) ││ -A ······································································└ bold -A ·······································································└ normal, fg(#000000), bg(#c0c0c0) -S 19 ┋ ┋ S 20 ┋ x┋ -A ···············································································├ normal A └┛ alt A ················································································└ normal S 21 ┋ x┋ @@ -100,59 +95,61 @@ A ···································· S 22 ┋ x┋ A └┛ alt A ················································································└ normal -S 23 ┋ L0 0% ?:View Help ┋ -A └ fg(#000000), bg(#c0c0c0) S 22 ┋ ┋ -A └ normal, normal +A └ normal OSC Set window title: HELP -S 1 ┋ Thu Jun 06 1 :: :: HELP ┋ -A └ fg(#000000), bg(#c0c0c0) │││ │││ -A ················································└ fg(#008080), bg(#c0c0c0) -A ·················································└ fg(#c0c0c0), bg(#008080) -A ··················································└ fg(#000000), bg(#008080) -A ······································································└ fg(#000080), bg(#008080) -A ·······································································└ fg(#008080), bg(#000080) -A ········································································└ fg(#c0c0c0), bg(#000080), bold -S 2 ┋ x┋ -A ···············································································└ normal, fg(#000000), bg(#c0c0c0) -A ················································································└ normal -A └┛ alt -A ················································································└ normal -S 3 ┋ lnav - A fancy log file viewer ┋ -A ··└ fg(#000000), bg(#c0c0c0), normal -A ································└ carriage-return -S 5 ┋DESCRIPTION ┋ -A ···········└ carriage-return -S 6 ┋=========== ┋ -A ···········└ carriage-return -S 8 ┋The log file navigator, lnav, is an enhanced log file viewer that ┋ -A ·································································└ carriage-return -S 9 ┋takes advantage of any semantic information that can be gleaned from ┋ -A ····································································└ carriage-return -S 10 ┋the files being viewed, such as timestamps and log levels. Using this ┋ +S 2 ┋ HELP ❭⋯❭ ┋ +A ·└ fg(#000000), bg(#000080), bold +A ······└ normal, fg(#008080), bg(#c0c0c0) +A ·······└ fg(#000000), bg(#c0c0c0) +A ········└ fg(#008080), bg(#c0c0c0) +S 3 ┋ x┋ +A ···············································································└ normal, fg(#000000) +A ················································································└ normal +A └┛ alt +A ················································································└ normal +S 4 ┋lnav ┋ +A └ fg(#000000), normal, underline +A ····└ carriage-return +S 6 ┋A fancy log file viewer for the terminal. ┋ +A └ normal │ +A ·········································└ carriage-return +S 8 ┋Overview ┋ +A └ underline +A ········└ carriage-return +S 10 ┋The Logfile Navigator, lnav, is an enhanced log file viewer that takes ┋ +A └ normal │ │ │ +A ·······················└ bold │ +A ···························└ normal │ A ······································································└ carriage-return -S 11 ┋extra semantic information, lnav can do things like interleaving ┋ +S 11 ┋advantage of any semantic information that can be gleaned from the ┋ +A ··································································└ carriage-return +S 12 ┋files being viewed, such as timestamps and log levels. Using this ┋ +A ·································································└ carriage-return +S 13 ┋extra semantic information, lnav can do things like interleaving ┋ A ································································└ carriage-return -S 12 ┋messages from different files, generate histograms of messages over ┋ -A ···································································└ carriage-return -S 13 ┋time, and providing hotkeys for navigating through the file. It is ┋ +S 14 ┋messages from different files, generate histograms of messages over ┋ A ···································································└ carriage-return -S 14 ┋hoped that these features will allow the user to quickly and ┋ -A ····························································└ carriage-return -S 15 ┋efficiently zero in on problems. ┋ -A ································└ carriage-return -S 17 ┋ ┋ -A ··············································································└ carriage-return -S 18 ┋OPENING PATHS/URLs x┋ +S 15 ┋time, and providing hotkeys for navigating through the file. It is ┋ +A ··································································└ carriage-return +S 16 ┋hoped that these features will allow the user to quickly and x┋ A └┛ alt A ················································································└ normal -S 19 ┋================== x┋ +S 17 ┋efficiently zero in on problems. x┋ A └┛ alt A ················································································└ normal -S 21 ┋The main arguments to lnav are the files, directories, glob patterns, ┋ -A ·····································································└ carriage-return -S 22 ┋or URLs to be viewed. If no arguments are given, the default syslog ┋ +S 19 ┋Opening Paths/URLs ┋ +A └ underline │ +A ··················└ carriage-return +S 21 ┋The main arguments to lnav are the local/remote files, directories, ┋ +A └ normal │ +A ···································································└ carriage-return +S 22 ┋glob patterns, or URLs to be viewed. If no arguments are given, the ┋ +A ···································································└ carriage-return +S 23 ┋ L0 0% ?:View Help ┋ +A └ fg(#000000), bg(#c0c0c0) S 24 ┋ Press e/E to move forward/backward through error messags ┋ +A ·······················└ normal││ │ A ·····························└ bold │ A ······························└ normal │ A ·······························└ bold │ @@ -166,11 +163,13 @@ A ···································· A └ normal K 71 OSC Set window title: LOG -S 1 ┋ LOG ┋ -A ···········································································└ fg(#c0c0c0), bg(#000080), bold -A ···············································································└ carriage-return +S 24 ┋ⓘ info: executing SQL statement, press CTRL+] to cancel ┋ +A ·······································└ fg(#800080), bold, underline +A ·············································└ normal +CSI Erase to Right S 24 ┋ ┋ -A └ normal, normal +A ·······················································└ carriage-return +A └ normal CSI Erase all CSI Use normal screen buffer CTRL restore cursor diff --git a/test/xpath_tui.0 b/test/xpath_tui.0 index 8b46cbbc..feb93ec7 100644 --- a/test/xpath_tui.0 +++ b/test/xpath_tui.0 @@ -14,13 +14,14 @@ OSC Set window title: LOG S -1 ┋ ┋ A └ normal, normal, normal CSI Erase all -S 1 ┋ Thu Jun 06 1 :: :: LOG ┋ -A └ fg(#c0c0c0), bg(#008080) -S 2 ┋ x┋ -A ···············································································├ normal -A └┛ alt -A ················································································└ normal +S 1 ┋ 2013-06-06T12:13:20 PDT Press ENTER to focus on the breadcrumb bar ┋ +A └ bg(#008080) +S 2 ┋ LOG ❭ ┋ +A └ fg(#000000), bg(#000080), bold +A ·····└ normal, fg(#008080), bg(#c0c0c0) +A ······└ fg(#000000), bg(#c0c0c0) S 3 ┋ x┋ +A ···············································································├ normal A └┛ alt A ················································································└ normal S 4 ┋ x┋ @@ -59,284 +60,247 @@ A ···································· S 15 ┋ x┋ A └┛ alt A ················································································└ normal -S 16 ┋ x┋ -A └┛ alt -A ················································································└ normal -S 17 ┋ lqqqq No log messages; Log Files: 0; Text Files: 1; Error rate: 0.00/min; Tix┋ -A └----┛ alt │ │ │ │ │ │ │ │ ││ -A ···································└ bold │ │ │ │ │ │ ││ -A ·····································└ normal │ │ │ │ │ │ ││ -A ···················································└ bold │ │ │ ││ -A ·····················································└ normal │ │ │ ││ -A ·······················································└ fg(#800000), bold ││ -A ·································································└ normal ││ -A ···································································└ bold ││ -A ·······································································└ normal││ -A └┛ alt -A ················································································└ normal -S 18 ┋ Files :: Text Filters :: Press q to exit ┋ -A └ fg(#c0c0c0), bg(#000080), bold ││ +S 16 ┋ Files :: Text Filters :: 0 of 1 enabled Press q to exit ┋ +A └ bg(#000080), bold │ ││ ││ ││ A ·└ fg(#008080), bg(#000080), underline ││ -A ··└ normal, fg(#c0c0c0), bg(#000080), bold ││ -A ·······└ normal, fg(#c0c0c0), bg(#000080) ││ +A ··└ normal, bg(#000080), bold ││ ││ +A ·······└ normal, fg(#000000), bg(#000080) ││ A ········└ fg(#000080), bg(#c0c0c0) ││ A ·········└ fg(#000000), bg(#c0c0c0), bold ││ A ··········└ fg(#800080), bg(#c0c0c0), underline ││ A ···········└ normal, fg(#000000), bg(#c0c0c0), bold ││ A ·······················└ normal, fg(#000000), bg(#c0c0c0) ││ +A ··························└ bold│ ││ +A ···························└ normal, fg(#000000), bg(#c0c0c0) ││ +A ·······························└ bold ││ +A ································└ normal, fg(#000000), bg(#c0c0c0) ││ A ······································································└ bold A ·······································································└ normal, fg(#000000), bg(#c0c0c0) -S 19 ┋ ┋ -S 20 ┋→ ` logfile_xml_msg.0 0.0 B — x┋ -A ··├ fg(#008000), bg(#c0c0c0) │ │ -A └┛ alt │ │ │ -A ···└ fg(#000000), bg(#c0c0c0) │ │ -A ························└ bold│ │ -A ······························└ normal, fg(#000000), bg(#c0c0c0) │ +S 17 ┋ ┋ +S 18 ┋→ ` logfile_xml_msg.0 0.0 B — x┋ +A ··├ fg(#008000), bg(#c0c0c0) │ │ ││ +A └┛ alt │ │ │ ││ +A ···└ fg(#000000), bg(#c0c0c0) │ │ ││ +A ························└ bold│ │ ││ +A ······························└ normal, fg(#000000), bg(#c0c0c0) ││ +A ······································└ fg(#808000), bg(#c0c0c0) ││ +A ···············································································└ normal, fg(#000000) +A ················································································└ normal +A └┛ alt +A ················································································└ normal +S 19 ┋ x┋ +A ···············································································└ fg(#000000) +A ················································································└ normal +A └┛ alt +A ················································································└ normal +S 20 ┋ x┋ +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal S 21 ┋ x┋ -A ···············································································└ fg(#000000), bg(#c0c0c0) +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal S 22 ┋ x┋ -A ···············································································└ fg(#000000), bg(#c0c0c0) +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal S 23 ┋ L0 0% ?:View Help ┋ -A └ fg(#000000), bg(#c0c0c0) +A └ fg(#000000), normal, bg(#008080) S 22 ┋ ┋ A └ normal, normal -S 19 ┋ SPC: Hide ENTER: Jump To ┋ -A ··└ fg(#000000), bg(#c0c0c0), bold -A ·····└ normal, fg(#000000), bg(#c0c0c0) -A ·············└ bold -A ··················└ normal, fg(#000000), bg(#c0c0c0) -S 20 ┋ 64.0 B 2020-12-10 06:56:41.061 — 2020-12-10 06:56:41. ┋ -A ···························└ backspace │ -A ··························└ bold │ +S 18 ┋ 64.0 B 2020-12-10 06:56:41.061 — 2020-12-10 06:56:41. ┋ +A ··························└ fg(#000000), bg(#c0c0c0), bold │ A ······························└ normal, fg(#000000), bg(#c0c0c0) │ A ···············································································└ carriage-return S 22 ┋ ┋ A └ normal, normal -S 20 ┋ 628 ┋ +S 18 ┋ 628 ┋ A ·························└ fg(#000000), bg(#c0c0c0), bold A ····························└ carriage-return S 22 ┋ ┋ A └ normal, normal -OSC Set window title: logfile_xml_msg.0 -S 1 ┋ logfile_xml_msg.0 ┋ -A ·······························└ fg(#c0c0c0), bg(#008080) -S 1 ┋ xml_msg_log ┋ -A ······································································└ carriage-return -S 2 ┋x x ┋ -A └┛ alt│ -A ·└ normal -A ······└ carriage-return -S 3 ┋x ┋ -A └┛ alt │ -A ·└ normal │ -A ··········└ carriage-return -S 4 ┋x ┋ -A └┛ alt │ ││ ││ -A ·└ normal │ ││ ││ -A ··········└ fg(#008080) -A ············└ normal -A ·············└ fg(#008000), bold -A ················└ normal -A ·················└ carriage-return -S 5 ┋x ┋ -A └┛ alt │ -A ·└ normal │ +S 16 ┋ 1 ┋ +A ··························└ fg(#000000), bg(#c0c0c0), bold +S 23 ┋ 25 10 ┋ +A ··└ normal, bg(#008080) A ·············└ carriage-return -S 6 ┋x OK ┋ -A ·└ normal │ -A └┛ alt │ │ -A ·└ normal │ -A ·······└ normal │ -A ··························└ carriage-return -S 7 ┋x ┋ -A └┛ alt │ -A ·└ normal │ -A ··············└ carriage-return -S 8 ┋x ┋ -A └┛ alt │ -A ·└ normal │ -A ···········└ carriage-return -S 9 ┋x x ┋ -A ·└ normal -A └┛ alt ││ -A ·└ normal -A ·······└ normal -A ········└ carriage-return -S 10 ┋x ┋ -A └┛ alt │ -A ·└ normal │ -A ············└ carriage-return -S 11 ┋x x┋ +S 22 ┋ ┋ +A └ normal, normal +S 2 ┋ 2020-12-10T06:56:41.061❭xml_msg_log❭logfile_xml_msg.0[0]❭ ┋ +A ······└ fg(#000000), bg(#c0c0c0) ││ ││ +A ·····························└ fg(#008080), bg(#c0c0c0) ││ +A ······························└ fg(#000000), bg(#c0c0c0) ││ +A ·········································└ fg(#008080), bg(#c0c0c0) +A ··········································└ fg(#000000), bg(#c0c0c0) +A ······························································└ fg(#008080), bg(#c0c0c0) +A ·······························································└ carriage-return +S 3 ┋l[2020-12-10 06:56:41,061] INFO [m:108] Calling 'x' with params: x┋ +A ├ normal │ │ ││ +A └┛ alt │ │ ││ +A ················································└ fg(#008000), bold ││ +A ···················································└ normal ││ +A ···············································································└ fg(#000000) +A ················································································└ normal +A └┛ alt +A ················································································└ normal +S 4 ┋x x┋ +A ├ fg(#000000), normal ││ A └┛ alt ││ A ·└ normal ││ -A ···············································································└ fg(#000000), bg(#c0c0c0) +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal -S 12 ┋x x┋ -A ├ fg(#000000), bg(#c0c0c0) ││ +S 5 ┋x[2020-12-10 06:56:41,092] DEBUG [connect.client:69] Full request text: x┋ +A ├ fg(#000000), normal ││ A └┛ alt ││ -A ·└ normal ││ -A ···············································································└ fg(#000000), bg(#c0c0c0) +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal -S 13 ┋x x x┋ -A ├ fg(#000000), bg(#c0c0c0) ││ -A └┛ alt ││ -A ·└ normal ││ -A ···············································································└ fg(#000000), bg(#c0c0c0) +S 6 ┋x x┋ +A ├ fg(#000000), normal│ ││ │ ││ +A └┛ alt │ ││ ││ ││ │ ││ +A ·······└ fg(#008080)││ ││ │ ││ +A ··············└ normal ││ │ ││ +A ···············└ fg(#008000), bold │ ││ +A ····················└ normal ││ │ ││ +A ·····················└ fg(#008080) │ ││ +A ·····························└ normal │ ││ +A ······························└ fg(#008000), bold ││ +A ··········································└ normal ││ +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal -S 14 ┋x x┋ -A ├ fg(#000000), bg(#c0c0c0) ││ +S 7 ┋x x┋ +A ├ fg(#000000), normal ││ A └┛ alt ││ -A ·└ normal ││ -A ···············································································└ fg(#000000), bg(#c0c0c0) +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal -S 15 ┋x x┋ -A ├ fg(#000000), bg(#c0c0c0) ││ -A └┛ alt ││ -A ·└ normal ││ -A ···············································································└ fg(#000000), bg(#c0c0c0) -A ················································································└ normal +S 8 ┋x ┋ +A ├ fg(#000000), normal +A └┛ alt │ +A ·········└ carriage-return +S 9 ┋x x ┋ +A └┛ alt│ +A ······└ carriage-return +S 10 ┋x ┋ +A └┛ alt │ +A ··········└ carriage-return +S 11 ┋x ┋ +A └┛ alt │ +A ···········└ carriage-return +S 12 ┋x x ┋ +A └┛ alt│ +A ······└ carriage-return +S 13 ┋x ┋ +A └┛ alt │ +A ············└ carriage-return +S 14 ┋x ┋ +A └┛ alt │ ││ ││ +A ············└ fg(#008080) +A ··············└ normal +A ···············└ fg(#008000), bold +A ··················└ normal +A ···················└ carriage-return +S 15 ┋x ┋ +A └┛ alt │ +A ···········└ carriage-return +S 22 ┋ ┋ +A └ normal +CSI set scrolling region 3-20 +S 3 ┋ ┋ +A └ [2M +CSI set scrolling region 1-24 +CSI Erase Below +S 2 ┋ 92 ┋ +A ···························└ fg(#000000), bg(#c0c0c0) +S 2 ┋ 2]❭⋯❭ ┋ +A ······························································└ fg(#008080), bg(#c0c0c0) +A ·······························································└ fg(#000000), bg(#c0c0c0) +A ································································└ fg(#008080), bg(#c0c0c0) +S 3 ┋ x┋ +A ···············································································├ normal A └┛ alt A ················································································└ normal -S 16 ┋ x┋ -A ···············································································└ fg(#000000), bg(#c0c0c0) +S 6 ┋ x┋ +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal -S 17 ┋ Last message: in the future; Files: 1; Error rate: 0.00/min; Time span:x┋ -A ·······└ fg(#000000), bg(#c0c0c0), normal │ │ │ │ │ │ ││ -A ·····················└ bold │ │ │ │ │ │ │ ││ -A ··································└ normal │ │ │ │ │ │ ││ -A ···········································└ bold │ │ │ ││ -A ·············································└ normal │ │ │ ││ -A ···············································└ fg(#800000), bold ││ -A ·························································└ normal ││ -A ···························································└ bold ││ -A ·······························································└ normal ││ -A ···············································································└ fg(#000000), bg(#c0c0c0) +S 7 ┋ x┋ +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal -S 23 ┋ 22 10 ┋ -A ··└ fg(#000000), bg(#c0c0c0) -A ·············└ carriage-return -S 22 ┋ ┋ -A └ normal, normal -CSI Erase Below -S 1 ┋ Thu Jun 06 1 logfile_xml_msg.0:: xml_msg_log:: LOG ┋ -A └ fg(#000000), bg(#c0c0c0) │││ │││ -A ················································└ fg(#008080), bg(#c0c0c0) -A ·················································└ fg(#c0c0c0), bg(#008080) -A ··················································└ fg(#000000), bg(#008080) -A ······································································└ fg(#000080), bg(#008080) -A ·······································································└ fg(#008080), bg(#000080) -A ········································································└ fg(#c0c0c0), bg(#000080), bold -S 2 ┋ [2020-12-10 06:56:41,092] DEBUG [connect.client:69] Full request text: ┋ -A ·└ normal │ -A ················································└ normal -S 3 ┋ x┋ -A ·······└ fg(#008080)││ ││ │ ││ -A ··············└ normal ││ │ ││ -A ···············└ fg(#008000), bold │ ││ -A ····················└ normal ││ │ ││ -A ·····················└ fg(#008080) │ ││ -A ·····························└ normal │ ││ -A ······························└ fg(#008000), bold ││ -A ··········································└ normal ││ -A ···············································································└ fg(#000000), bg(#c0c0c0) +S 8 ┋ x┋ +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal -S 4 ┋ x┋ -A ·└ fg(#000000), bg(#c0c0c0), normal ││ -A ···············································································└ fg(#000000), bg(#c0c0c0) +S 9 ┋ x┋ +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal -S 5 ┋ x┋ -A ···└ fg(#000000), bg(#c0c0c0), normal ││ -A ···············································································└ fg(#000000), bg(#c0c0c0) +S 10 ┋ x┋ +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal -S 6 ┋ x x┋ -A ·····└ fg(#000000), bg(#c0c0c0), normal ││ -A ···············································································└ fg(#000000), bg(#c0c0c0) +S 11 ┋ x┋ +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal -S 7 ┋ x┋ -A ···└ fg(#000000), bg(#c0c0c0), normal ││ -A ···············································································└ fg(#000000), bg(#c0c0c0) +S 12 ┋ x┋ +A ···············································································└ fg(#000000) A ················································································└ normal A └┛ alt A ················································································└ normal -S 8 ┋ x┋ +A ├ fg(#000000), normal ││ +A └┛ alt ││ A └┛ alt A ················································································└ normal -S 11 ┋ request id="1"> ┋ -A ····└ fg(#000000), bg(#c0c0c0), normal -A ············└ fg(#008080) -A ··············└ normal -A ···············└ fg(#008000), bold -A ··················└ normal -S 12 ┋ ┋ -S 13 ┋ x ┋ -S 14 ┋ ┋ -S 15 ┋ x┋ +S 16 ┋x x┋ +A └┛ alt ││ A └┛ alt A ················································································└ normal -S 16 ┋x x┋ +S 17 ┋x x┋ A └┛ alt ││ -A ·└ normal ││ A └┛ alt A ················································································└ normal -S 17 ┋x x┋ +S 18 ┋x x┋ A └┛ alt ││ A ·└ normal ││ A └┛ alt A ················································································└ normal -S 18 ┋x[2020-12-10 06:56:41,099] DEBUG [m:85] Full reply text: x┋ -A └┛ alt │ ││ -A ·└ normal │ ││ -A ···································└ normal ││ +S 19 ┋x[2020-12-10 06:56:41,099] DEBUG [m:85] Full reply text: x┋ +A └┛ alt ││ A └┛ alt A ················································································└ normal -S 19 ┋x x┋ +S 20 ┋x x┋ A └┛ alt │ ││ ││ ││ │ ││ -A ·└ normal ││ ││ ││ │ ││ A ·······└ fg(#008080)││ ││ │ ││ A ··············└ normal ││ │ ││ A ···············└ fg(#008000), bold │ ││ @@ -347,127 +311,120 @@ A ······························└ fg(#00800 A ··········································└ normal ││ A └┛ alt A ················································································└ normal -S 20 ┋x x┋ -A └┛ alt ││ -A ·└ normal ││ -A └┛ alt -A ················································································└ normal -S 21 ┋x x┋ +S 21 ┋x x┋ A └┛ alt ││ -A ·└ normal ││ A └┛ alt A ················································································└ normal -S 22 ┋ Files :: Text Filters :: Press TAB to edit ┋ -A └ fg(#c0c0c0), bg(#008080) │ │ +S 24 ┋ ┋ +A └ normal +S 22 ┋ Files :: Text Filters :: 0 of 1 enabled Press TAB to edit ┋ +A └ bg(#008080) ││ ││ │ │ +A ··························└ bold│ │ │ +A ···························└ normal, bg(#008080) │ │ +A ·······························└ bold │ │ +A ································└ normal, bg(#008080) │ │ A ····································································└ bold -A ·······································································└ normal, fg(#c0c0c0), bg(#008080) -S 23 ┋ 61 ┋ -A ···└ fg(#000000), bg(#c0c0c0) -A ··············└ carriage-return +A ·······································································└ normal, bg(#008080) +S 23 ┋ L2 58% ?:View Help ┋ +A └ fg(#000000), bg(#c0c0c0) S 24 ┋ ┋ A └ normal, normal K 70 -S 3 ┋ Received Time: 2020-12-10T06:56:41.092 -- in the future ┋ +S 4 ┋ Received Time: 2020-12-10T06:56:41.092 -- in the future ┋ A ················└ bold │ │ │ A ·······································└ normal │ A ···········································└ bold │ A ························································└ carriage-return -S 4 ┋ Pattern: xml_msg_log/regex/std = ^\[(?\d{4}-\d{2}-\d{2} \d{2}:\d{2} ┋ -A └ normal ││ │ │ │ │││││ │││││ │││││ │││││ ││││ -A ··································└ fg(#008080), bold││││ │││││ │││││ │││││ ││││ -A ···································└ normal │ │││││ │││││ │││││ │││││ ││││ -A ·····································└ fg(#008000), bold│ │││││ │││││ │││││ ││││ -A ········································└ normal │ │││││ │││││ │││││ │││││ ││││ -A ··················································└ fg(#000080), bold │││││ ││││ -A ····················································└ fg(#008000)││││ │││││ ││││ -A ·····················································└ normal││ │││││ │││││ ││││ -A ······················································└ fg(#008000), bold││ ││││ -A ·······················································└ normal │││││ │││││ ││││ -A ························································└ fg(#000080), bold ││││ -A ··························································└ fg(#008000)││││ ││││ -A ···························································└ normal││ │││││ ││││ -A ····························································└ fg(#008000), bold│ -A ·····························································└ normal │││││ ││││ -A ······························································└ fg(#000080), bold -A ································································└ fg(#008000)│││ -A ·································································└ normal││ ││││ -A ··································································└ fg(#008000), bold -A ···································································└ normal ││││ -A ····································································└ fg(#000080), bold -A ······································································└ fg(#008000) -A ·······································································└ normal│ -A ········································································└ fg(#008000), bold -A ·········································································└ normal -A ··········································································└ fg(#000080), bold -A ············································································└ fg(#008000) -A ·············································································└ normal -A ··············································································└ fg(#008000), bold +S 5 ┋ Pattern: /xml_msg_log/regex/std = ^\[(?\d{4}-\d{2}-\d{2} \d{2}:\d{2 ┋ +A └ normal ││ │ ││ ││ │││││ │││││ │││││ │││││ │││ +A ···································└ fg(#008080) ││ │││││ │││││ │││││ │││││ │││ +A ····································└ normal ││ │││││ │││││ │││││ │││││ │││ +A ······································└ fg(#008000), bold│ │││││ │││││ │││││ │││ +A ········································└ normal, fg(#008080)│││ │││││ │││││ │││ +A ·········································└ normal ││ │││││ │││││ │││││ │││││ │││ +A ··················································└ fg(#008080)│ │││││ │││││ │││ +A ···················································└ fg(#000080) │││││ │││││ │││ +A ·····················································└ fg(#008000), bold││││ │││ +A ······················································└ normal││ │││││ │││││ │││ +A ·······················································└ fg(#008000), bold││ │││ +A ························································└ normal │││││ │││││ │││ +A ·························································└ fg(#000080) │││││ │││ +A ···························································└ fg(#008000), bold││ +A ····························································└ normal││ │││││ │││ +A ·····························································└ fg(#008000), bold +A ······························································└ normal │││││ │││ +A ·······························································└ fg(#000080) │││ +A ·································································└ fg(#008000), bold +A ··································································└ normal││ │││ +A ···································································└ fg(#008000), bold +A ····································································└ normal │││ +A ·····································································└ fg(#000080) +A ·······································································└ fg(#008000), bold +A ········································································└ normal +A ·········································································└ fg(#008000), bold +A ··········································································└ normal +A ···········································································└ fg(#000080) +A ·············································································└ fg(#008000), bold +A ··············································································└ normal A ···············································································└ carriage-return -S 5 ┋ Known message fields for table xml_msg_log: ┋ -A └ normal │ ││ +S 6 ┋ Known message fields for table xml_msg_log: ┋ A ································└ bold ││ A ···········································└ normal A ············································└ carriage-return -S 6 ┋ t timestamp = 2020-12-10 06:56:41,092 ┋ -A └┛ alt │ │ │ -A ············└ normal │ +S 7 ┋ t log_time = 2020-12-10 06:56:41,092 ┋ +A └┛ alt │ │ A ···············└ bold │ A ···············································································└ carriage-return -S 7 ┋ t level = DEBUG ┋ -A └ normal│ │ │ -A └┛ alt │ │ │ -A ········└ normal │ +S 8 ┋ t level = DEBUG ┋ +A └ normal │ │ +A └┛ alt │ │ A ···············└ bold │ A ···············································································└ carriage-return -S 8 ┋ t module = connect.client ┋ -A └ normal │ │ │ -A └┛ alt │ │ │ -A ·········└ normal │ +S 9 ┋ t module = connect.client ┋ +A └ normal │ │ +A └┛ alt │ │ A ···············└ bold │ A ···············································································└ carriage-return -S 9 ┋ t line = 69 ┋ -A └ normal │ │ │ -A └┛ alt │ │ │ -A ·············└ normal │ +S 10 ┋ t line = 69 ┋ +A └ normal │ │ +A └┛ alt │ │ A ···············└ bold │ A ···············································································└ carriage-return -S 10 ┋ t body = Full request text: ┋ +S 11 ┋ t log_body = Full request text: ┋ A └ normal │ │ -A └┛ alt│ │ │ -A ·······└ normal│ │ +A └┛ alt │ │ A ···············└ bold │ A ···············································································└ carriage-return -S 11 ┋ t msg_data = ┋ -A └ normal │ │ │ -A └┛ alt │ │ │ -A ···········└ normal │ +S 12 ┋ t msg_data = ┋ +A └ normal │ │ +A └┛ alt │ │ A ···············└ bold │ A ···············································································└ carriage-return -S 12 ┋ XML fields: ┋ +S 13 ┋ XML fields: ┋ A └ normal │ A ············└ carriage-return -S 13 ┋ t xpath('/a-request/head/text()', msg_data) = x ┋ +S 14 ┋ t xpath('/a-request/head/text()', msg_data) = x ┋ A └┛ alt │ A ······└ bold │ A ···············································································└ carriage-return -S 14 ┋ t xpath('/a-request/request/@id', msg_data) = 1 ┋ +S 15 ┋ t xpath('/a-request/request/@id', msg_data) = 1 ┋ A └ normal │ A └┛ alt │ A ······└ bold │ A ···············································································└ carriage-return -S 15 ┋ t xpath('/a-request/request/name/text()', msg_data) = x ┋ +S 16 ┋ t xpath('/a-request/request/name/text()', msg_data) = x ┋ A └ normal │ A └┛ alt │ A ······└ bold │ A ···············································································└ carriage-return -S 16 ┋ t xpath('/a-request/source/text()', msg_data) = x ┋ +S 17 ┋ t xpath('/a-request/source/text()', msg_data) = x ┋ A └ normal │ A └┛ alt │ A ······└ bold │ A ···············································································└ carriage-return -S 17 ┋ No discovered message fields ┋ +S 18 ┋ No discovered message fields ┋ A └ normal -S 18 ┋ ┋ +S 19 ┋ ┋ A ·······└ fg(#008080)││ ││ │ A ··············└ normal ││ │ A ···············└ fg(#008000), bold │ @@ -476,13 +433,22 @@ A ·····················└ fg(#008080) │ A ·····························└ normal │ A ······························└ fg(#008000), bold A ··········································└ normal -S 19 ┋ a-request> ┋ -S 20 ┋ ┋ -S 21 ┋ x ┋ -A ·········└ carriage-return +S 20 ┋ a-request> ┋ +S 21 ┋ ┋ +A ··········└ carriage-return S 24 ┋ ┋ A └ normal K 71 +S 23 ┋ 0 ┋ +A ··└ fg(#000000), bg(#c0c0c0) +S 23 ┋ 0 ┋ +A ··············└ carriage-return +S 24 ┋ⓘ info: executing SQL statement, press CTRL+] to cancel ┋ +A └ normal │ │ │ +A ·······································└ fg(#800080), bold, underline +A ·············································└ normal │ +A ·······················································└ carriage-return +A └ normal CSI Erase all CSI Use normal screen buffer CTRL restore cursor