diff --git a/NEWS.md b/NEWS.md index 4007a85e..d72e384d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,23 +7,27 @@ Features: * The `log_opid` column on log vtables can now by `UPDATE`d so that you can manually set an opid on log messages that don't have one. Setting an opid allows messages to show - up in the gantt chart view. + up in the Gantt chart view. * Add support for GitHub Markdown Alerts. Interface Changes: * In the Gantt chart view, pressing `ENTER` will focus on - the preview pane so you can scroll through messages + the preview pane, so you can scroll through messages with the selected Op ID. * With mouse mode enabled, `CTRL` can be used as an alternate to `SHIFT` when clicking/dragging in the main view to highlight lines. A few terminals capture shift+clicks as a way to select text and do not pass them to the application. +* Clicking on an internal link in a Markdown document will move + to that section. Bug Fixes: * Log messages in formats with custom timestamp formats were not being converted to the local timezone. * The timezone offset is now shown in the parser details overlay for log messages. +* If a theme does not define `cursor-line` or `selected-text` + styles, the styles from the default theme will be used. Maintenance: * You can now do an `UPDATE` on the `lnav_top_view` SQL view. diff --git a/src/base/string_util.cc b/src/base/string_util.cc index 1cfdc85d..deb7dc18 100644 --- a/src/base/string_util.cc +++ b/src/base/string_util.cc @@ -333,6 +333,36 @@ scrub_ws(const char* in, ssize_t len) return retval; } +static constexpr const char* const SUPERSCRIPT_NUMS[] = { + "⁰", + "¹", + "²", + "³", + "⁴", + "⁵", + "⁶", + "⁷", + "⁸", + "⁹", +}; + +std::string +to_superscript(const std::string& in) +{ + std::string retval; + for (const auto ch : in) { + if (isdigit(ch)) { + auto index = ch - '0'; + + retval.append(SUPERSCRIPT_NUMS[index]); + } else { + retval.push_back(ch); + } + } + + return retval; +} + namespace fmt { auto formatter::format(const lnav::tainted_string& ts, diff --git a/src/base/string_util.hh b/src/base/string_util.hh index 886fb6c2..b5ea8c22 100644 --- a/src/base/string_util.hh +++ b/src/base/string_util.hh @@ -246,6 +246,15 @@ on_blank(const std::string& str, const std::string& def) return str; } +std::string to_superscript(const std::string& in); + +template, bool> = true> +inline std::string +to_superscript(T in) +{ + return to_superscript(fmt::to_string(in)); +} + namespace lnav { class tainted_string { public: @@ -282,8 +291,8 @@ private: namespace fmt { template<> struct formatter : formatter { - auto format(const lnav::tainted_string& ts, - format_context& ctx) -> decltype(ctx.out()) const; + auto format(const lnav::tainted_string& ts, format_context& ctx) + -> decltype(ctx.out()) const; }; } // namespace fmt diff --git a/src/md2attr_line.cc b/src/md2attr_line.cc index ce08b340..68935859 100644 --- a/src/md2attr_line.cc +++ b/src/md2attr_line.cc @@ -573,7 +573,7 @@ md2attr_line::leave_span(const md4cpp::event_handler::span& sp) VC_STYLE.value(text_attrs{A_UNDERLINE}), }); } else if (sp.is()) { - auto* a_detail = sp.get(); + const auto* a_detail = sp.get(); auto href_str = std::string(a_detail->href.text, a_detail->href.size); line_range lr{ static_cast(this->ml_span_starts.back()), @@ -585,8 +585,9 @@ md2attr_line::leave_span(const md4cpp::event_handler::span& sp) }); this->append_url_footnote(href_str); } else if (sp.is()) { - auto* img_detail = sp.get(); - auto src_str = std::string(img_detail->src.text, img_detail->src.size); + const auto* img_detail = sp.get(); + const auto src_str + = std::string(img_detail->src.text, img_detail->src.size); this->append_url_footnote(src_str); } @@ -747,7 +748,7 @@ md2attr_line::to_attr_line(const pugi::xml_node& doc) .append(" ") .append( lnav::string::attrs::href(link_label, src_href.value())) - .appendf(FMT_STRING("[{}]"), this->ml_footnotes.size() + 1); + .append(to_superscript(this->ml_footnotes.size() + 1)); auto href = attr_line_t() @@ -1014,7 +1015,7 @@ md2attr_line::text(MD_TEXTTYPE tt, const string_fragment& sf) std::string span_text; auto loop_res = REPL_RE.capture_from(sf).for_each( - [&span_text](lnav::pcre2pp::match_data& md) { + [&span_text](const lnav::pcre2pp::match_data& md) { span_text += md.leading(); auto matched = *md[0]; @@ -1054,12 +1055,8 @@ md2attr_line::text(MD_TEXTTYPE tt, const string_fragment& sf) void md2attr_line::append_url_footnote(std::string href_str) { - if (startswith(href_str, "#")) { - return; - } - + auto is_internal = startswith(href_str, "#"); auto& last_block = this->ml_blocks.back(); - last_block.appendf(FMT_STRING("[{}]"), this->ml_footnotes.size() + 1); last_block.with_attr(string_attr{ line_range{ (int) this->ml_span_starts.back(), @@ -1067,6 +1064,15 @@ md2attr_line::append_url_footnote(std::string href_str) }, VC_STYLE.value(text_attrs{A_UNDERLINE}), }); + if (is_internal) { + return; + } + + if (this->ml_last_superscript_index == last_block.length()) { + last_block.append("\u02d2"); + } + last_block.append(to_superscript(this->ml_footnotes.size() + 1)); + this->ml_last_superscript_index = last_block.length(); 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/md2attr_line.hh b/src/md2attr_line.hh index eb29e271..3c07c48e 100644 --- a/src/md2attr_line.hh +++ b/src/md2attr_line.hh @@ -91,6 +91,7 @@ private: std::vector> ml_html_starts; std::vector ml_footnotes; int32_t ml_code_depth{0}; + ssize_t ml_last_superscript_index{-1}; }; #endif diff --git a/src/plain_text_source.cc b/src/plain_text_source.cc index f7e4a909..aa99910e 100644 --- a/src/plain_text_source.cc +++ b/src/plain_text_source.cc @@ -49,7 +49,8 @@ to_text_line(const std::vector& lines) }); } -plain_text_source::plain_text_source(const std::string& text) +plain_text_source:: +plain_text_source(const std::string& text) { size_t start = 0, end; @@ -64,12 +65,14 @@ plain_text_source::plain_text_source(const std::string& text) this->tds_longest_line = this->compute_longest_line(); } -plain_text_source::plain_text_source(const std::vector& text_lines) +plain_text_source:: +plain_text_source(const std::vector& text_lines) { this->replace_with(text_lines); } -plain_text_source::plain_text_source(const std::vector& text_lines) +plain_text_source:: +plain_text_source(const std::vector& text_lines) : tds_lines(to_text_line(text_lines)) { this->tds_longest_line = this->compute_longest_line(); @@ -432,8 +435,7 @@ plain_text_source::row_for_anchor(const std::string& id) meta.m_sections_root.get(), [this, &id, &retval](const lnav::document::hier_node* node) { for (const auto& child_pair : node->hn_named_children) { - const auto& child_anchor - = text_anchors::to_anchor_string(child_pair.first); + const auto& child_anchor = to_anchor_string(child_pair.first); if (child_anchor != id) { continue; @@ -456,8 +458,7 @@ plain_text_source::get_anchors() this->tds_doc_sections.m_sections_root.get(), [&retval](const lnav::document::hier_node* node) { for (const auto& child_pair : node->hn_named_children) { - retval.emplace( - text_anchors::to_anchor_string(child_pair.first)); + retval.emplace(to_anchor_string(child_pair.first)); } }); @@ -488,8 +489,7 @@ plain_text_source::anchor_for_row(vis_line_t vl) || this->tds_text_format == text_format_t::TF_MARKDOWN) && path_for_line.back().is()) { - return text_anchors::to_anchor_string( - path_for_line.back().get()); + return to_anchor_string(path_for_line.back().get()); } auto comps = path_for_line | lnav::itertools::map([](const auto& elem) { @@ -505,7 +505,7 @@ plain_text_source::anchor_for_row(vis_line_t vl) } std::optional -plain_text_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) +plain_text_source::adjacent_anchor(vis_line_t vl, direction dir) { if (vl > this->tds_lines.size() || this->tds_doc_sections.m_sections_root == nullptr) @@ -525,14 +525,14 @@ plain_text_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) } switch (dir) { - case text_anchors::direction::prev: { + case direction::prev: { if (neighbors_res->cnr_previous) { return this->line_for_offset( neighbors_res->cnr_previous.value()->hn_start); } break; } - case text_anchors::direction::next: { + case direction::next: { if (neighbors_res->cnr_next) { return this->line_for_offset( neighbors_res->cnr_next.value()->hn_start); @@ -585,14 +585,14 @@ plain_text_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) } switch (dir) { - case text_anchors::direction::prev: { + case direction::prev: { if (neighbors_res->cnr_previous) { return this->line_for_offset( neighbors_res->cnr_previous.value()->hn_start); } break; } - case text_anchors::direction::next: { + case direction::next: { if (neighbors_res->cnr_next) { return this->line_for_offset( neighbors_res->cnr_next.value()->hn_start); diff --git a/src/textview_curses.cc b/src/textview_curses.cc index 9eb9ed5a..baf187bd 100644 --- a/src/textview_curses.cc +++ b/src/textview_curses.cc @@ -38,6 +38,7 @@ #include "base/time_util.hh" #include "config.h" #include "data_scanner.hh" +#include "date/solar_hijri.h" #include "fmt/format.h" #include "lnav_config.hh" #include "log_format_fwd.hh" @@ -693,6 +694,29 @@ textview_curses::handle_mouse(mouse_event& me) } this->tc_selection_start = std::nullopt; } + if (me.me_button == mouse_button_t::BUTTON_LEFT + && mouse_line.is()) + { + const auto& [mc_line] = mouse_line.get(); + attr_line_t al; + + this->textview_value_for_row(mc_line, al); + auto get_res = get_string_attr(al.get_attrs(), + &VC_HYPERLINK, + this->lv_left + me.me_press_x); + if (get_res) { + auto href = get_res.value()->sa_value.get(); + + if (startswith(href, "#")) { + auto* ta + = dynamic_cast(this->tc_sub_source); + if (ta != nullptr) { + ta->row_for_anchor(href) | + [this](auto row) { this->set_selection(row); }; + } + } + } + } if (this->tc_delegate != nullptr) { this->tc_delegate->text_handle_mouse(*this, mouse_line, me); } diff --git a/src/view_curses.cc b/src/view_curses.cc index 75ff90b0..cf3046b2 100644 --- a/src/view_curses.cc +++ b/src/view_curses.cc @@ -848,11 +848,12 @@ void view_colors::init_roles(const lnav_theme& lt, lnav_config_listener::error_reporter& reporter) { + const auto& default_theme = lnav_config.lc_ui_theme_defs["default"]; rgb_color fg, bg; std::string err; /* Setup the mappings from roles to actual colors. */ - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_TEXT)] + this->get_role_attrs(role_t::VCR_TEXT) = this->to_attrs(lt, lt.lt_style_text, reporter); for (int ansi_fg = 0; ansi_fg < 8; ansi_fg++) { @@ -908,122 +909,119 @@ view_colors::init_roles(const lnav_theme& lt, } if (lnav_config.lc_ui_dim_text) { - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_TEXT)] - .ra_normal.ta_attrs - |= A_DIM; - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_TEXT)] - .ra_reverse.ta_attrs - |= A_DIM; + this->get_role_attrs(role_t::VCR_TEXT).ra_normal.ta_attrs |= A_DIM; + this->get_role_attrs(role_t::VCR_TEXT).ra_reverse.ta_attrs |= A_DIM; } - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SEARCH)] + this->get_role_attrs(role_t::VCR_SEARCH) = role_attrs{text_attrs{A_REVERSE}, text_attrs{A_REVERSE}}; - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SEARCH)] - .ra_class_name + this->get_role_attrs(role_t::VCR_SEARCH).ra_class_name = intern_string::lookup("-lnav_styles_search"); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_IDENTIFIER)] + this->get_role_attrs(role_t::VCR_IDENTIFIER) = this->to_attrs(lt, lt.lt_style_identifier, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_OK)] + this->get_role_attrs(role_t::VCR_OK) = this->to_attrs(lt, lt.lt_style_ok, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_INFO)] + this->get_role_attrs(role_t::VCR_INFO) = this->to_attrs(lt, lt.lt_style_info, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ERROR)] + this->get_role_attrs(role_t::VCR_ERROR) = this->to_attrs(lt, lt.lt_style_error, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_WARNING)] + this->get_role_attrs(role_t::VCR_WARNING) = this->to_attrs(lt, lt.lt_style_warning, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ALT_ROW)] + this->get_role_attrs(role_t::VCR_ALT_ROW) = this->to_attrs(lt, lt.lt_style_alt_text, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_HIDDEN)] + this->get_role_attrs(role_t::VCR_HIDDEN) = this->to_attrs(lt, lt.lt_style_hidden, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_CURSOR_LINE)] + this->get_role_attrs(role_t::VCR_CURSOR_LINE) = this->to_attrs(lt, lt.lt_style_cursor_line, reporter); - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_DISABLED_CURSOR_LINE)] + if (this->get_role_attrs(role_t::VCR_CURSOR_LINE).ra_normal.empty()) { + this->get_role_attrs(role_t::VCR_CURSOR_LINE) = this->to_attrs( + default_theme, default_theme.lt_style_cursor_line, reporter); + } + this->get_role_attrs(role_t::VCR_DISABLED_CURSOR_LINE) = this->to_attrs(lt, lt.lt_style_disabled_cursor_line, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ADJUSTED_TIME)] + if (this->get_role_attrs(role_t::VCR_DISABLED_CURSOR_LINE) + .ra_normal.empty()) + { + this->get_role_attrs(role_t::VCR_DISABLED_CURSOR_LINE) + = this->to_attrs(default_theme, + default_theme.lt_style_disabled_cursor_line, + reporter); + } + this->get_role_attrs(role_t::VCR_ADJUSTED_TIME) = this->to_attrs(lt, lt.lt_style_adjusted_time, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SKEWED_TIME)] + this->get_role_attrs(role_t::VCR_SKEWED_TIME) = this->to_attrs(lt, lt.lt_style_skewed_time, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_OFFSET_TIME)] + this->get_role_attrs(role_t::VCR_OFFSET_TIME) = this->to_attrs(lt, lt.lt_style_offset_time, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_FILE_OFFSET)] + this->get_role_attrs(role_t::VCR_FILE_OFFSET) = this->to_attrs(lt, lt.lt_style_file_offset, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_INVALID_MSG)] + this->get_role_attrs(role_t::VCR_INVALID_MSG) = this->to_attrs(lt, lt.lt_style_invalid_msg, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STATUS)] + this->get_role_attrs(role_t::VCR_STATUS) = this->to_attrs(lt, lt.lt_style_status, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_WARN_STATUS)] + this->get_role_attrs(role_t::VCR_WARN_STATUS) = this->to_attrs(lt, lt.lt_style_warn_status, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ALERT_STATUS)] + this->get_role_attrs(role_t::VCR_ALERT_STATUS) = this->to_attrs(lt, lt.lt_style_alert_status, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ACTIVE_STATUS)] + this->get_role_attrs(role_t::VCR_ACTIVE_STATUS) = this->to_attrs(lt, lt.lt_style_active_status, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ACTIVE_STATUS2)] - = role_attrs{ - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_ACTIVE_STATUS)] - .ra_normal, - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_ACTIVE_STATUS)] - .ra_reverse, - }; - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ACTIVE_STATUS2)] - .ra_normal.ta_attrs + this->get_role_attrs(role_t::VCR_ACTIVE_STATUS2) = role_attrs{ + this->get_role_attrs(role_t::VCR_ACTIVE_STATUS).ra_normal, + this->get_role_attrs(role_t::VCR_ACTIVE_STATUS).ra_reverse, + }; + this->get_role_attrs(role_t::VCR_ACTIVE_STATUS2).ra_normal.ta_attrs |= A_BOLD; - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ACTIVE_STATUS2)] - .ra_reverse.ta_attrs + this->get_role_attrs(role_t::VCR_ACTIVE_STATUS2).ra_reverse.ta_attrs |= A_BOLD; - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STATUS_TITLE)] + this->get_role_attrs(role_t::VCR_STATUS_TITLE) = this->to_attrs(lt, lt.lt_style_status_title, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STATUS_SUBTITLE)] + this->get_role_attrs(role_t::VCR_STATUS_SUBTITLE) = this->to_attrs(lt, lt.lt_style_status_subtitle, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STATUS_INFO)] + this->get_role_attrs(role_t::VCR_STATUS_INFO) = this->to_attrs(lt, lt.lt_style_status_info, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STATUS_HOTKEY)] + this->get_role_attrs(role_t::VCR_STATUS_HOTKEY) = this->to_attrs(lt, lt.lt_style_status_hotkey, reporter); - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_STATUS_TITLE_HOTKEY)] + this->get_role_attrs(role_t::VCR_STATUS_TITLE_HOTKEY) = this->to_attrs(lt, lt.lt_style_status_title_hotkey, reporter); - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_STATUS_DISABLED_TITLE)] + this->get_role_attrs(role_t::VCR_STATUS_DISABLED_TITLE) = this->to_attrs(lt, lt.lt_style_status_disabled_title, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H1)] + this->get_role_attrs(role_t::VCR_H1) = this->to_attrs(lt, lt.lt_style_header[0], reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H2)] + this->get_role_attrs(role_t::VCR_H2) = this->to_attrs(lt, lt.lt_style_header[1], reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H3)] + this->get_role_attrs(role_t::VCR_H3) = this->to_attrs(lt, lt.lt_style_header[2], reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H4)] + this->get_role_attrs(role_t::VCR_H4) = this->to_attrs(lt, lt.lt_style_header[3], reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H5)] + this->get_role_attrs(role_t::VCR_H5) = this->to_attrs(lt, lt.lt_style_header[4], reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_H6)] + this->get_role_attrs(role_t::VCR_H6) = this->to_attrs(lt, lt.lt_style_header[5], reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_HR)] + this->get_role_attrs(role_t::VCR_HR) = this->to_attrs(lt, lt.lt_style_hr, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_HYPERLINK)] + this->get_role_attrs(role_t::VCR_HYPERLINK) = this->to_attrs(lt, lt.lt_style_hyperlink, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_LIST_GLYPH)] + this->get_role_attrs(role_t::VCR_LIST_GLYPH) = this->to_attrs(lt, lt.lt_style_list_glyph, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_BREADCRUMB)] + this->get_role_attrs(role_t::VCR_BREADCRUMB) = this->to_attrs(lt, lt.lt_style_breadcrumb, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_TABLE_BORDER)] + this->get_role_attrs(role_t::VCR_TABLE_BORDER) = this->to_attrs(lt, lt.lt_style_table_border, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_TABLE_HEADER)] + this->get_role_attrs(role_t::VCR_TABLE_HEADER) = this->to_attrs(lt, lt.lt_style_table_header, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_QUOTE_BORDER)] + this->get_role_attrs(role_t::VCR_QUOTE_BORDER) = this->to_attrs(lt, lt.lt_style_quote_border, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_QUOTED_TEXT)] + this->get_role_attrs(role_t::VCR_QUOTED_TEXT) = this->to_attrs(lt, lt.lt_style_quoted_text, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_FOOTNOTE_BORDER)] + this->get_role_attrs(role_t::VCR_FOOTNOTE_BORDER) = this->to_attrs(lt, lt.lt_style_footnote_border, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_FOOTNOTE_TEXT)] + this->get_role_attrs(role_t::VCR_FOOTNOTE_TEXT) = this->to_attrs(lt, lt.lt_style_footnote_text, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SNIPPET_BORDER)] + this->get_role_attrs(role_t::VCR_SNIPPET_BORDER) = this->to_attrs(lt, lt.lt_style_snippet_border, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_INDENT_GUIDE)] + this->get_role_attrs(role_t::VCR_INDENT_GUIDE) = this->to_attrs(lt, lt.lt_style_indent_guide, reporter); { @@ -1033,8 +1031,7 @@ view_colors::init_roles(const lnav_theme& lt, = lt.lt_style_status_subtitle.pp_value.sc_background_color; stitch_sc.pp_value.sc_background_color = lt.lt_style_status_title.pp_value.sc_background_color; - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_STATUS_STITCH_TITLE_TO_SUB)] + this->get_role_attrs(role_t::VCR_STATUS_STITCH_TITLE_TO_SUB) = this->to_attrs(lt, stitch_sc, reporter); } { @@ -1044,8 +1041,7 @@ view_colors::init_roles(const lnav_theme& lt, = lt.lt_style_status_title.pp_value.sc_background_color; stitch_sc.pp_value.sc_background_color = lt.lt_style_status_subtitle.pp_value.sc_background_color; - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_STATUS_STITCH_SUB_TO_TITLE)] + this->get_role_attrs(role_t::VCR_STATUS_STITCH_SUB_TO_TITLE) = this->to_attrs(lt, stitch_sc, reporter); } @@ -1056,8 +1052,7 @@ view_colors::init_roles(const lnav_theme& lt, = lt.lt_style_status.pp_value.sc_background_color; stitch_sc.pp_value.sc_background_color = lt.lt_style_status_subtitle.pp_value.sc_background_color; - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_STATUS_STITCH_SUB_TO_NORMAL)] + this->get_role_attrs(role_t::VCR_STATUS_STITCH_SUB_TO_NORMAL) = this->to_attrs(lt, stitch_sc, reporter); } { @@ -1067,8 +1062,7 @@ view_colors::init_roles(const lnav_theme& lt, = lt.lt_style_status_subtitle.pp_value.sc_background_color; stitch_sc.pp_value.sc_background_color = lt.lt_style_status.pp_value.sc_background_color; - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_STATUS_STITCH_NORMAL_TO_SUB)] + this->get_role_attrs(role_t::VCR_STATUS_STITCH_NORMAL_TO_SUB) = this->to_attrs(lt, stitch_sc, reporter); } @@ -1079,8 +1073,7 @@ view_colors::init_roles(const lnav_theme& lt, = lt.lt_style_status.pp_value.sc_background_color; stitch_sc.pp_value.sc_background_color = lt.lt_style_status_title.pp_value.sc_background_color; - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_STATUS_STITCH_TITLE_TO_NORMAL)] + this->get_role_attrs(role_t::VCR_STATUS_STITCH_TITLE_TO_NORMAL) = this->to_attrs(lt, stitch_sc, reporter); } { @@ -1090,25 +1083,22 @@ view_colors::init_roles(const lnav_theme& lt, = lt.lt_style_status_title.pp_value.sc_background_color; stitch_sc.pp_value.sc_background_color = lt.lt_style_status.pp_value.sc_background_color; - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_STATUS_STITCH_NORMAL_TO_TITLE)] + this->get_role_attrs(role_t::VCR_STATUS_STITCH_NORMAL_TO_TITLE) = this->to_attrs(lt, stitch_sc, reporter); } - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_INACTIVE_STATUS)] + this->get_role_attrs(role_t::VCR_INACTIVE_STATUS) = this->to_attrs(lt, lt.lt_style_inactive_status, reporter); - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_INACTIVE_ALERT_STATUS)] + this->get_role_attrs(role_t::VCR_INACTIVE_ALERT_STATUS) = this->to_attrs(lt, lt.lt_style_inactive_alert_status, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_POPUP)] + this->get_role_attrs(role_t::VCR_POPUP) = this->to_attrs(lt, lt.lt_style_popup, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_FOCUSED)] + this->get_role_attrs(role_t::VCR_FOCUSED) = this->to_attrs(lt, lt.lt_style_focused, reporter); - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_DISABLED_FOCUSED)] + this->get_role_attrs(role_t::VCR_DISABLED_FOCUSED) = this->to_attrs(lt, lt.lt_style_disabled_focused, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SCROLLBAR)] + this->get_role_attrs(role_t::VCR_SCROLLBAR) = this->to_attrs(lt, lt.lt_style_scrollbar, reporter); { positioned_property bar_sc; @@ -1116,8 +1106,7 @@ view_colors::init_roles(const lnav_theme& lt, bar_sc.pp_value.sc_color = lt.lt_style_error.pp_value.sc_color; bar_sc.pp_value.sc_background_color = lt.lt_style_scrollbar.pp_value.sc_background_color; - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_SCROLLBAR_ERROR)] + this->get_role_attrs(role_t::VCR_SCROLLBAR_ERROR) = this->to_attrs(lt, bar_sc, reporter); } { @@ -1126,67 +1115,70 @@ view_colors::init_roles(const lnav_theme& lt, bar_sc.pp_value.sc_color = lt.lt_style_warning.pp_value.sc_color; bar_sc.pp_value.sc_background_color = lt.lt_style_scrollbar.pp_value.sc_background_color; - this->vc_role_attrs[lnav::enums::to_underlying( - role_t::VCR_SCROLLBAR_WARNING)] + this->get_role_attrs(role_t::VCR_SCROLLBAR_WARNING) = this->to_attrs(lt, bar_sc, reporter); } - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_INLINE_CODE)] + this->get_role_attrs(role_t::VCR_INLINE_CODE) = this->to_attrs(lt, lt.lt_style_inline_code, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_QUOTED_CODE)] + this->get_role_attrs(role_t::VCR_QUOTED_CODE) = this->to_attrs(lt, lt.lt_style_quoted_code, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_CODE_BORDER)] + this->get_role_attrs(role_t::VCR_CODE_BORDER) = this->to_attrs(lt, lt.lt_style_code_border, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_KEYWORD)] + this->get_role_attrs(role_t::VCR_KEYWORD) = this->to_attrs(lt, lt.lt_style_keyword, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_STRING)] + this->get_role_attrs(role_t::VCR_STRING) = this->to_attrs(lt, lt.lt_style_string, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_COMMENT)] + this->get_role_attrs(role_t::VCR_COMMENT) = this->to_attrs(lt, lt.lt_style_comment, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_DOC_DIRECTIVE)] + this->get_role_attrs(role_t::VCR_DOC_DIRECTIVE) = this->to_attrs(lt, lt.lt_style_doc_directive, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_VARIABLE)] + this->get_role_attrs(role_t::VCR_VARIABLE) = this->to_attrs(lt, lt.lt_style_variable, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SYMBOL)] + this->get_role_attrs(role_t::VCR_SYMBOL) = this->to_attrs(lt, lt.lt_style_symbol, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_NULL)] + this->get_role_attrs(role_t::VCR_NULL) = this->to_attrs(lt, lt.lt_style_null, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_ASCII_CTRL)] + this->get_role_attrs(role_t::VCR_ASCII_CTRL) = this->to_attrs(lt, lt.lt_style_ascii_ctrl, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_NON_ASCII)] + this->get_role_attrs(role_t::VCR_NON_ASCII) = this->to_attrs(lt, lt.lt_style_non_ascii, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_NUMBER)] + this->get_role_attrs(role_t::VCR_NUMBER) = this->to_attrs(lt, lt.lt_style_number, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_FUNCTION)] + this->get_role_attrs(role_t::VCR_FUNCTION) = this->to_attrs(lt, lt.lt_style_function, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_TYPE)] + this->get_role_attrs(role_t::VCR_TYPE) = this->to_attrs(lt, lt.lt_style_type, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SEP_REF_ACC)] + this->get_role_attrs(role_t::VCR_SEP_REF_ACC) = this->to_attrs(lt, lt.lt_style_sep_ref_acc, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SUGGESTION)] + this->get_role_attrs(role_t::VCR_SUGGESTION) = this->to_attrs(lt, lt.lt_style_suggestion, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SELECTED_TEXT)] + this->get_role_attrs(role_t::VCR_SELECTED_TEXT) = this->to_attrs(lt, lt.lt_style_selected_text, reporter); + if (this->get_role_attrs(role_t::VCR_SELECTED_TEXT).ra_normal.empty()) { + this->get_role_attrs(role_t::VCR_SELECTED_TEXT) = this->to_attrs( + default_theme, default_theme.lt_style_selected_text, reporter); + } - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_RE_SPECIAL)] + this->get_role_attrs(role_t::VCR_RE_SPECIAL) = this->to_attrs(lt, lt.lt_style_re_special, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_RE_REPEAT)] + this->get_role_attrs(role_t::VCR_RE_REPEAT) = this->to_attrs(lt, lt.lt_style_re_repeat, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_FILE)] + this->get_role_attrs(role_t::VCR_FILE) = this->to_attrs(lt, lt.lt_style_file, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_DIFF_DELETE)] + this->get_role_attrs(role_t::VCR_DIFF_DELETE) = this->to_attrs(lt, lt.lt_style_diff_delete, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_DIFF_ADD)] + this->get_role_attrs(role_t::VCR_DIFF_ADD) = this->to_attrs(lt, lt.lt_style_diff_add, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_DIFF_SECTION)] + this->get_role_attrs(role_t::VCR_DIFF_SECTION) = this->to_attrs(lt, lt.lt_style_diff_section, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_LOW_THRESHOLD)] + this->get_role_attrs(role_t::VCR_LOW_THRESHOLD) = this->to_attrs(lt, lt.lt_style_low_threshold, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_MED_THRESHOLD)] + this->get_role_attrs(role_t::VCR_MED_THRESHOLD) = this->to_attrs(lt, lt.lt_style_med_threshold, reporter); - this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_HIGH_THRESHOLD)] + this->get_role_attrs(role_t::VCR_HIGH_THRESHOLD) = this->to_attrs(lt, lt.lt_style_high_threshold, reporter); for (auto level = static_cast(LEVEL_UNKNOWN + 1); diff --git a/src/view_curses.hh b/src/view_curses.hh index c09e137c..03d8b5e8 100644 --- a/src/view_curses.hh +++ b/src/view_curses.hh @@ -292,6 +292,11 @@ private: const positioned_property& sc, lnav_config_listener::error_reporter& reporter); + role_attrs& get_role_attrs(const role_t role) + { + return this->vc_role_attrs[lnav::enums::to_underlying(role)]; + } + role_attrs vc_level_attrs[LEVEL__MAX]; /** Map of role IDs to attribute values. */ diff --git a/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out b/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out index 0ad0719a..71170643 100644 --- a/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out +++ b/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out @@ -426,7 +426,7 @@ can always use  q  to pop the top view off of the stack. CTRL+], ESCAPE Abort command-line entry started with  / ,  : ,  ; , or  | . - ▌Note: The regular expression format used by lnav is ]8;;http://perldoc.perl.org/perlre.html\PCRE]8;;\[1] + ▌Note: The regular expression format used by lnav is ]8;;http://perldoc.perl.org/perlre.html\PCRE]8;;\¹ ▌(Perl-Compatible Regular Expressions). ▌ ▌ ▌[1] - http://perldoc.perl.org/perlre.html @@ -577,7 +577,7 @@ example of a top ten query into the "/tmp/topten.db" file, you can do: PRQL Support -The Pipelined Relational Query Language ]8;;https://prql-lang.org\(PRQL)]8;;\[1] is an alternative +The Pipelined Relational Query Language ]8;;https://prql-lang.org\(PRQL)]8;;\¹ is an alternative database query language that compiles to SQL. The main advantage of PRQL, in the context of lnav, is that it is easier to work with interactively compared to SQL. For example, lnav can provide previews @@ -589,8 +589,8 @@ tab-completions for the columns in the result set. You can execute a PRQL query in the SQL prompt. A PRQL query starts with the  from  keyword that specifies the table to use as a data source. The next stage of a pipeline is started by entering a pipe -symbol ( | ) followed by a ]8;;https://prql-lang.org/book/reference/stdlib/transforms/index.html\PRQL transform]8;;\[1]. As you build the query -in the prompt, lnav will display any relevant help and preview for the +symbol ( | ) followed by a ]8;;https://prql-lang.org/book/reference/stdlib/transforms/index.html\PRQL transform]8;;\¹. As you build the query in +the prompt, lnav will display any relevant help and preview for the current and previous stages of the pipeline. ▌[1] - https://prql-lang.org/book/reference/stdlib/transforms/index.html diff --git a/test/expected/test_sql_views_vtab.sh_32acc1a8bb5028636fdbf08f077f9a835ab51bec.out b/test/expected/test_sql_views_vtab.sh_32acc1a8bb5028636fdbf08f077f9a835ab51bec.out index ff268662..eb3c0956 100644 --- a/test/expected/test_sql_views_vtab.sh_32acc1a8bb5028636fdbf08f077f9a835ab51bec.out +++ b/test/expected/test_sql_views_vtab.sh_32acc1a8bb5028636fdbf08f077f9a835ab51bec.out @@ -11,7 +11,7 @@ Run  ./autogen.sh  if compiling from a cloned repository. See Also -]8;;https://github.com/rcoh/angle-grinder\Angle-grinder]8;;\[1] is a tool to slice and dice log files on the +]8;;https://github.com/rcoh/angle-grinder\Angle-grinder]8;;\¹ is a tool to slice and dice log files on the command-line. If you're familiar with the SumoLogic query language, you might find this tool more comfortable to work with. diff --git a/test/expected/test_text_file.sh_5b51b55dff7332c5bee2c9b797c401c5614d574a.out b/test/expected/test_text_file.sh_5b51b55dff7332c5bee2c9b797c401c5614d574a.out index 33f5e7f4..3f4748f6 100644 --- a/test/expected/test_text_file.sh_5b51b55dff7332c5bee2c9b797c401c5614d574a.out +++ b/test/expected/test_text_file.sh_5b51b55dff7332c5bee2c9b797c401c5614d574a.out @@ -1,4 +1,4 @@ -]8;;https://github.com/tstack/lnav/actions?query=workflow%3Aci-build\🖼 Build[1]]8;;\[2] ]8;;https://docs.lnav.org\🖼 Docs[3]]8;;\[4] ]8;;https://coveralls.io/github/tstack/lnav?branch=master\🖼 Coverage Status[5]]8;;\[6] ]8;;https://snapcraft.io/lnav\🖼 lnav[7]]8;;\[8] +]8;;https://github.com/tstack/lnav/actions?query=workflow%3Aci-build\🖼 Build]8;;\]8;;https://github.com/tstack/lnav/actions?query=workflow%3Aci-build\¹]8;;\˒² ]8;;https://docs.lnav.org\🖼 Docs]8;;\]8;;https://docs.lnav.org\³]8;;\˒⁴ ]8;;https://coveralls.io/github/tstack/lnav?branch=master\🖼 Coverage Status]8;;\]8;;https://coveralls.io/github/tstack/lnav?branch=master\⁵]8;;\˒⁶ ]8;;https://snapcraft.io/lnav\🖼 lnav]8;;\]8;;https://snapcraft.io/lnav\⁷]8;;\˒⁸ ▌[1] - https://github.com/tstack/lnav/workflows/ci-build/badge.svg ▌[2] - https://github.com/tstack/lnav/actions?query=workflow%3Aci-build @@ -9,13 +9,13 @@ ▌[7] - https://snapcraft.io/lnav/badge.svg ▌[8] - https://snapcraft.io/lnav -]8;;https://discord.gg/erBPnKwz7R\🖼 ]8;;\]8;;https://discord.gg/erBPnKwz7R\Discord Logo]8;;\]8;;https://discord.gg/erBPnKwz7R\[1]]8;;\[2] +]8;;https://discord.gg/erBPnKwz7R\🖼 ]8;;\]8;;https://discord.gg/erBPnKwz7R\Discord Logo]8;;\]8;;https://discord.gg/erBPnKwz7R\¹]8;;\² ▌[1] - https://assets-global.website-files.com/6257adef93867e50d84d30e2/62594fddd654fc29fcc07359_cb48d2a8d4991281d7a6a95d2f58195e.svg ▌[2] - https://discord.gg/erBPnKwz7R -This is the source repository for lnav, visit ]8;;https://lnav.org\https://lnav.org]8;;\[1] for -a high level overview. +This is the source repository for lnav, visit ]8;;https://lnav.org\https://lnav.org]8;;\¹ for a +high level overview. ▌[1] - https://lnav.org @@ -30,21 +30,21 @@ set of files/directories, lnav will: • tail the files, follow renames, find new files in directories; • build an index of errors and warnings; - • ]8;;https://docs.lnav.org/en/latest/formats.html#json-lines\pretty-print JSON-lines]8;;\[1]. + • ]8;;https://docs.lnav.org/en/latest/formats.html#json-lines\pretty-print JSON-lines]8;;\¹. ▌[1] - https://docs.lnav.org/en/latest/formats.html#json-lines Then, in the lnav TUI, you can: - • jump quickly to the previous/next error (]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\press ]8;;\]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\ e ]8;;\]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\/]8;;\]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\ E ]8;;\[1]); - • search using regular expressions (]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\press ]8;;\]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\ / ]8;;\[2]); - • highlight text with a regular expression (]8;;https://docs.lnav.org/en/latest/commands.html#highlight-pattern\ :highlight ]8;;\[3] + • jump quickly to the previous/next error (]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\press ]8;;\]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\ e ]8;;\]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\/]8;;\]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\ E ]8;;\¹); + • search using regular expressions (]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\press ]8;;\]8;;https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation\ / ]8;;\²); + • highlight text with a regular expression (]8;;https://docs.lnav.org/en/latest/commands.html#highlight-pattern\ :highlight ]8;;\³ command); - • filter messages using ]8;;https://docs.lnav.org/en/latest/usage.html#regular-expression-match\regular expressions]8;;\[4] or ]8;;https://docs.lnav.org/en/latest/usage.html#sqlite-expression\SQLite]8;;\ - ]8;;https://docs.lnav.org/en/latest/usage.html#sqlite-expression\expressions]8;;\[5]; - • pretty-print structured text (]8;;https://docs.lnav.org/en/latest/ui.html#pretty\press ]8;;\]8;;https://docs.lnav.org/en/latest/ui.html#pretty\ P ]8;;\[6]); - • view a histogram of messages over time (]8;;https://docs.lnav.org/en/latest/ui.html#hist\press ]8;;\]8;;https://docs.lnav.org/en/latest/ui.html#hist\ i ]8;;\[7]); - • query messages using SQLite (]8;;https://docs.lnav.org/en/latest/sqlext.html\press ]8;;\]8;;https://docs.lnav.org/en/latest/sqlext.html\ ; ]8;;\[8]) + • filter messages using ]8;;https://docs.lnav.org/en/latest/usage.html#regular-expression-match\regular expressions]8;;\⁴ or ]8;;https://docs.lnav.org/en/latest/usage.html#sqlite-expression\SQLite]8;;\ + ]8;;https://docs.lnav.org/en/latest/usage.html#sqlite-expression\expressions]8;;\⁵; + • pretty-print structured text (]8;;https://docs.lnav.org/en/latest/ui.html#pretty\press ]8;;\]8;;https://docs.lnav.org/en/latest/ui.html#pretty\ P ]8;;\⁶); + • view a histogram of messages over time (]8;;https://docs.lnav.org/en/latest/ui.html#hist\press ]8;;\]8;;https://docs.lnav.org/en/latest/ui.html#hist\ i ]8;;\⁷); + • query messages using SQLite (]8;;https://docs.lnav.org/en/latest/sqlext.html\press ]8;;\]8;;https://docs.lnav.org/en/latest/sqlext.html\ ; ]8;;\⁸) ▌[1] - https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation ▌[2] - https://docs.lnav.org/en/latest/hotkeys.html#spatial-navigation @@ -61,7 +61,7 @@ The following screenshot shows a mix of syslog and web access log files. Failed requests are shown in red. Identifiers, like IP address and PIDs are semantically highlighted. -]8;;docs/assets/images/lnav-front-page.png\🖼 Screenshot[1]]8;;\[2] +]8;;docs/assets/images/lnav-front-page.png\🖼 Screenshot]8;;\]8;;docs/assets/images/lnav-front-page.png\¹]8;;\˒² ▌[1] - file://{top_srcdir}/docs/assets/images/lnav-front-page.png ▌[2] - file://{top_srcdir}/docs/assets/images/lnav-front-page.png @@ -83,21 +83,21 @@ You can SSH into a demo node to play with lnav before installing. The "playground" account starts lnav with a couple of log files as an example: -]8;;ssh://playground@demo.lnav.org\ $ ssh playground@demo.lnav.org ]8;;\[1] +]8;;ssh://playground@demo.lnav.org\ $ ssh playground@demo.lnav.org ]8;;\¹ ▌[1] - ssh://playground@demo.lnav.org The "tutorial 1" account is an interactive tutorial that can teach you the basics of operation: -]8;;ssh://tutorial1@demo.lnav.org\ $ ssh tutorial1@demo.lnav.org ]8;;\[1] +]8;;ssh://tutorial1@demo.lnav.org\ $ ssh tutorial1@demo.lnav.org ]8;;\¹ ▌[1] - ssh://tutorial1@demo.lnav.org Installation ]8;;https://github.com/tstack/lnav/releases/latest#release-artifacts\Download a statically-linked binary for Linux/MacOS from the release]8;;\ -]8;;https://github.com/tstack/lnav/releases/latest#release-artifacts\page]8;;\[1] +]8;;https://github.com/tstack/lnav/releases/latest#release-artifacts\page]8;;\¹ ▌[1] - https://github.com/tstack/lnav/releases/latest#release-artifacts @@ -118,7 +118,7 @@ indexing has finished, the LOG view will display the log messages that were recognized[^1]. You can then use the usual hotkeys to move around the view (arrow keys or  j / k / h / l  to move down/up/left/right). -See the ]8;;https://docs.lnav.org/en/latest/usage.html\Usage section]8;;\[1] of the online documentation for more +See the ]8;;https://docs.lnav.org/en/latest/usage.html\Usage section]8;;\¹ of the online documentation for more information. ▌[1] - https://docs.lnav.org/en/latest/usage.html @@ -173,9 +173,9 @@ log lines fed into  lnav  via  journalctl 's [ Please file issues on this repository or use the discussions section. The following alternatives are also available: - • ]8;;mailto:support@lnav.org\support@lnav.org]8;;\[1] - • ]8;;https://discord.gg/erBPnKwz7R\Discord]8;;\[2] - • ]8;;https://groups.google.com/g/lnav\Google Groups]8;;\[3] + • ]8;;mailto:support@lnav.org\support@lnav.org]8;;\¹ + • ]8;;https://discord.gg/erBPnKwz7R\Discord]8;;\² + • ]8;;https://groups.google.com/g/lnav\Google Groups]8;;\³ ▌[1] - mailto:support@lnav.org ▌[2] - https://discord.gg/erBPnKwz7R @@ -183,9 +183,9 @@ The following alternatives are also available: Links - • ]8;;https://lnav.org\Main Site]8;;\[1] - • ]8;;https://docs.lnav.org\Documentation]8;;\[2] on Read the Docs - • ]8;;ARCHITECTURE.md\Internal Architecture]8;;\[3] + • ]8;;https://lnav.org\Main Site]8;;\¹ + • ]8;;https://docs.lnav.org\Documentation]8;;\² on Read the Docs + • ]8;;ARCHITECTURE.md\Internal Architecture]8;;\³ ▌[1] - https://lnav.org ▌[2] - https://docs.lnav.org @@ -193,7 +193,7 @@ The following alternatives are also available: Contributing - • ]8;;https://github.com/sponsors/tstack\Become a Sponsor on GitHub]8;;\[1] + • ]8;;https://github.com/sponsors/tstack\Become a Sponsor on GitHub]8;;\¹ ▌[1] - https://github.com/sponsors/tstack @@ -234,7 +234,7 @@ Run  ./autogen.sh  if compiling from a cloned repository. See Also -]8;;https://github.com/rcoh/angle-grinder\Angle-grinder]8;;\[1] is a tool to slice and dice log files on the +]8;;https://github.com/rcoh/angle-grinder\Angle-grinder]8;;\¹ is a tool to slice and dice log files on the command-line. If you're familiar with the SumoLogic query language, you might find this tool more comfortable to work with. diff --git a/test/expected/test_text_file.sh_6a24078983cf1b7a80b6fb65d5186cd125498136.out b/test/expected/test_text_file.sh_6a24078983cf1b7a80b6fb65d5186cd125498136.out index 068cc372..a9d7df50 100644 --- a/test/expected/test_text_file.sh_6a24078983cf1b7a80b6fb65d5186cd125498136.out +++ b/test/expected/test_text_file.sh_6a24078983cf1b7a80b6fb65d5186cd125498136.out @@ -4,7 +4,7 @@ The following screenshot shows a mix of syslog and web access log files. Failed requests are shown in red. Identifiers, like IP address and PIDs are semantically highlighted. -]8;;docs/assets/images/lnav-front-page.png\🖼 Screenshot[1]]8;;\[2] +]8;;docs/assets/images/lnav-front-page.png\🖼 Screenshot]8;;\]8;;docs/assets/images/lnav-front-page.png\¹]8;;\˒² ▌[1] - file://{top_srcdir}/docs/assets/images/lnav-front-page.png ▌[2] - file://{top_srcdir}/docs/assets/images/lnav-front-page.png @@ -26,21 +26,21 @@ You can SSH into a demo node to play with lnav before installing. The "playground" account starts lnav with a couple of log files as an example: -]8;;ssh://playground@demo.lnav.org\ $ ssh playground@demo.lnav.org ]8;;\[1] +]8;;ssh://playground@demo.lnav.org\ $ ssh playground@demo.lnav.org ]8;;\¹ ▌[1] - ssh://playground@demo.lnav.org The "tutorial 1" account is an interactive tutorial that can teach you the basics of operation: -]8;;ssh://tutorial1@demo.lnav.org\ $ ssh tutorial1@demo.lnav.org ]8;;\[1] +]8;;ssh://tutorial1@demo.lnav.org\ $ ssh tutorial1@demo.lnav.org ]8;;\¹ ▌[1] - ssh://tutorial1@demo.lnav.org Installation ]8;;https://github.com/tstack/lnav/releases/latest#release-artifacts\Download a statically-linked binary for Linux/MacOS from the release]8;;\ -]8;;https://github.com/tstack/lnav/releases/latest#release-artifacts\page]8;;\[1] +]8;;https://github.com/tstack/lnav/releases/latest#release-artifacts\page]8;;\¹ ▌[1] - https://github.com/tstack/lnav/releases/latest#release-artifacts @@ -61,7 +61,7 @@ indexing has finished, the LOG view will display the log messages that were recognized[^1]. You can then use the usual hotkeys to move around the view (arrow keys or  j / k / h / l  to move down/up/left/right). -See the ]8;;https://docs.lnav.org/en/latest/usage.html\Usage section]8;;\[1] of the online documentation for more +See the ]8;;https://docs.lnav.org/en/latest/usage.html\Usage section]8;;\¹ of the online documentation for more information. ▌[1] - https://docs.lnav.org/en/latest/usage.html @@ -116,9 +116,9 @@ log lines fed into  lnav  via  journalctl 's [ Please file issues on this repository or use the discussions section. The following alternatives are also available: - • ]8;;mailto:support@lnav.org\support@lnav.org]8;;\[1] - • ]8;;https://discord.gg/erBPnKwz7R\Discord]8;;\[2] - • ]8;;https://groups.google.com/g/lnav\Google Groups]8;;\[3] + • ]8;;mailto:support@lnav.org\support@lnav.org]8;;\¹ + • ]8;;https://discord.gg/erBPnKwz7R\Discord]8;;\² + • ]8;;https://groups.google.com/g/lnav\Google Groups]8;;\³ ▌[1] - mailto:support@lnav.org ▌[2] - https://discord.gg/erBPnKwz7R @@ -126,9 +126,9 @@ The following alternatives are also available: Links - • ]8;;https://lnav.org\Main Site]8;;\[1] - • ]8;;https://docs.lnav.org\Documentation]8;;\[2] on Read the Docs - • ]8;;ARCHITECTURE.md\Internal Architecture]8;;\[3] + • ]8;;https://lnav.org\Main Site]8;;\¹ + • ]8;;https://docs.lnav.org\Documentation]8;;\² on Read the Docs + • ]8;;ARCHITECTURE.md\Internal Architecture]8;;\³ ▌[1] - https://lnav.org ▌[2] - https://docs.lnav.org @@ -136,7 +136,7 @@ The following alternatives are also available: Contributing - • ]8;;https://github.com/sponsors/tstack\Become a Sponsor on GitHub]8;;\[1] + • ]8;;https://github.com/sponsors/tstack\Become a Sponsor on GitHub]8;;\¹ ▌[1] - https://github.com/sponsors/tstack @@ -177,7 +177,7 @@ Run  ./autogen.sh  if compiling from a cloned repository. See Also -]8;;https://github.com/rcoh/angle-grinder\Angle-grinder]8;;\[1] is a tool to slice and dice log files on the +]8;;https://github.com/rcoh/angle-grinder\Angle-grinder]8;;\¹ is a tool to slice and dice log files on the command-line. If you're familiar with the SumoLogic query language, you might find this tool more comfortable to work with. diff --git a/test/expected/test_text_file.sh_d59b67113864ef5e77267d7fd8ad4072f5aef0fc.out b/test/expected/test_text_file.sh_d59b67113864ef5e77267d7fd8ad4072f5aef0fc.out index d17c6311..8d492c0c 100644 --- a/test/expected/test_text_file.sh_d59b67113864ef5e77267d7fd8ad4072f5aef0fc.out +++ b/test/expected/test_text_file.sh_d59b67113864ef5e77267d7fd8ad4072f5aef0fc.out @@ -1,13 +1,18 @@ +Table of Contents + + • ]8;;#test\Test]8;;\ + • ]8;;#github-alerts\Github Alerts]8;;\ + Test • One • Two • Three -🖼 ]8;;file://{top_srcdir}/docs/lnav-tui.png\lnav-tui.png]8;;\[1] +🖼 ]8;;file://{top_srcdir}/docs/lnav-tui.png\lnav-tui.png]8;;\¹ -🖼 ]8;;file://{top_srcdir}/docs/lnav-architecture.png\The internal architecture of lnav]8;;\[2] +🖼 ]8;;file://{top_srcdir}/docs/lnav-architecture.png\The internal architecture of lnav]8;;\² ▌[1] - file://{top_srcdir}/docs/lnav-tui.png ▌[2] - file://{top_srcdir}/docs/lnav-architecture.png @@ -50,7 +55,9 @@ Goodbye, ▌World╏! ▌  ▌  - ▌ⓘ Note +Github Alerts + + ▌ⓘ Note ▌Useful information that users should know, even when ▌skimming content. @@ -60,7 +67,7 @@ Goodbye, ▌World╏! ▌🌟 Important ▌Key information users need to know to achieve their goal. - ▌⚠️ Warning + ▌⚠️ Warning ▌Urgent info that needs immediate user attention to avoid ▌problems. diff --git a/test/expected/test_text_file.sh_e088ea61a5382458cc48a2607e2639e52b0be1da.out b/test/expected/test_text_file.sh_e088ea61a5382458cc48a2607e2639e52b0be1da.out index 068cc372..a9d7df50 100644 --- a/test/expected/test_text_file.sh_e088ea61a5382458cc48a2607e2639e52b0be1da.out +++ b/test/expected/test_text_file.sh_e088ea61a5382458cc48a2607e2639e52b0be1da.out @@ -4,7 +4,7 @@ The following screenshot shows a mix of syslog and web access log files. Failed requests are shown in red. Identifiers, like IP address and PIDs are semantically highlighted. -]8;;docs/assets/images/lnav-front-page.png\🖼 Screenshot[1]]8;;\[2] +]8;;docs/assets/images/lnav-front-page.png\🖼 Screenshot]8;;\]8;;docs/assets/images/lnav-front-page.png\¹]8;;\˒² ▌[1] - file://{top_srcdir}/docs/assets/images/lnav-front-page.png ▌[2] - file://{top_srcdir}/docs/assets/images/lnav-front-page.png @@ -26,21 +26,21 @@ You can SSH into a demo node to play with lnav before installing. The "playground" account starts lnav with a couple of log files as an example: -]8;;ssh://playground@demo.lnav.org\ $ ssh playground@demo.lnav.org ]8;;\[1] +]8;;ssh://playground@demo.lnav.org\ $ ssh playground@demo.lnav.org ]8;;\¹ ▌[1] - ssh://playground@demo.lnav.org The "tutorial 1" account is an interactive tutorial that can teach you the basics of operation: -]8;;ssh://tutorial1@demo.lnav.org\ $ ssh tutorial1@demo.lnav.org ]8;;\[1] +]8;;ssh://tutorial1@demo.lnav.org\ $ ssh tutorial1@demo.lnav.org ]8;;\¹ ▌[1] - ssh://tutorial1@demo.lnav.org Installation ]8;;https://github.com/tstack/lnav/releases/latest#release-artifacts\Download a statically-linked binary for Linux/MacOS from the release]8;;\ -]8;;https://github.com/tstack/lnav/releases/latest#release-artifacts\page]8;;\[1] +]8;;https://github.com/tstack/lnav/releases/latest#release-artifacts\page]8;;\¹ ▌[1] - https://github.com/tstack/lnav/releases/latest#release-artifacts @@ -61,7 +61,7 @@ indexing has finished, the LOG view will display the log messages that were recognized[^1]. You can then use the usual hotkeys to move around the view (arrow keys or  j / k / h / l  to move down/up/left/right). -See the ]8;;https://docs.lnav.org/en/latest/usage.html\Usage section]8;;\[1] of the online documentation for more +See the ]8;;https://docs.lnav.org/en/latest/usage.html\Usage section]8;;\¹ of the online documentation for more information. ▌[1] - https://docs.lnav.org/en/latest/usage.html @@ -116,9 +116,9 @@ log lines fed into  lnav  via  journalctl 's [ Please file issues on this repository or use the discussions section. The following alternatives are also available: - • ]8;;mailto:support@lnav.org\support@lnav.org]8;;\[1] - • ]8;;https://discord.gg/erBPnKwz7R\Discord]8;;\[2] - • ]8;;https://groups.google.com/g/lnav\Google Groups]8;;\[3] + • ]8;;mailto:support@lnav.org\support@lnav.org]8;;\¹ + • ]8;;https://discord.gg/erBPnKwz7R\Discord]8;;\² + • ]8;;https://groups.google.com/g/lnav\Google Groups]8;;\³ ▌[1] - mailto:support@lnav.org ▌[2] - https://discord.gg/erBPnKwz7R @@ -126,9 +126,9 @@ The following alternatives are also available: Links - • ]8;;https://lnav.org\Main Site]8;;\[1] - • ]8;;https://docs.lnav.org\Documentation]8;;\[2] on Read the Docs - • ]8;;ARCHITECTURE.md\Internal Architecture]8;;\[3] + • ]8;;https://lnav.org\Main Site]8;;\¹ + • ]8;;https://docs.lnav.org\Documentation]8;;\² on Read the Docs + • ]8;;ARCHITECTURE.md\Internal Architecture]8;;\³ ▌[1] - https://lnav.org ▌[2] - https://docs.lnav.org @@ -136,7 +136,7 @@ The following alternatives are also available: Contributing - • ]8;;https://github.com/sponsors/tstack\Become a Sponsor on GitHub]8;;\[1] + • ]8;;https://github.com/sponsors/tstack\Become a Sponsor on GitHub]8;;\¹ ▌[1] - https://github.com/sponsors/tstack @@ -177,7 +177,7 @@ Run  ./autogen.sh  if compiling from a cloned repository. See Also -]8;;https://github.com/rcoh/angle-grinder\Angle-grinder]8;;\[1] is a tool to slice and dice log files on the +]8;;https://github.com/rcoh/angle-grinder\Angle-grinder]8;;\¹ is a tool to slice and dice log files on the command-line. If you're familiar with the SumoLogic query language, you might find this tool more comfortable to work with. diff --git a/test/textfile_0.md b/test/textfile_0.md index 7db0a60d..fe7b7c04 100644 --- a/test/textfile_0.md +++ b/test/textfile_0.md @@ -2,6 +2,11 @@ "comment": "This is JSON front-matter" } +# Table of Contents + +- [Test](#test) +- [Github Alerts](#github-alerts) + ## Test * One @@ -59,6 +64,8 @@ def hw(name): ``` +## Github Alerts + > [!NOTE] > Useful information that users should know, even when skimming content.