From b5cb38d454309649d1d017ceb1063bfe181f5655 Mon Sep 17 00:00:00 2001 From: Tim Stack Date: Mon, 29 Aug 2022 16:00:33 -0700 Subject: [PATCH] [user_notifications] treat message as markdown --- .../event-session-loaded-v1.schema.json | 16 + docs/source/events.rst | 3 + .../formats/tutorial-lib/tutorial.sql | 21 +- docs/tutorials/tutorial1/index.md | 27 +- src/dump_internals.cc | 1 + src/help.md | 4 +- src/lnav.cc | 3 +- src/lnav.events.cc | 14 + src/lnav.events.hh | 11 + src/md4cpp.cc | 453 +++++++++--------- src/session_data.cc | 4 + src/statusview_curses.cc | 2 +- src/statusview_curses.hh | 4 + src/top_status_source.cc | 23 +- ...a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out | 10 +- 15 files changed, 349 insertions(+), 247 deletions(-) create mode 100644 docs/schemas/event-session-loaded-v1.schema.json diff --git a/docs/schemas/event-session-loaded-v1.schema.json b/docs/schemas/event-session-loaded-v1.schema.json new file mode 100644 index 00000000..f64f0511 --- /dev/null +++ b/docs/schemas/event-session-loaded-v1.schema.json @@ -0,0 +1,16 @@ +{ + "$id": "https://lnav.org/event-session-loaded-v1.schema.json", + "title": "https://lnav.org/event-session-loaded-v1.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Event fired when a session is loaded.", + "properties": { + "$schema": { + "title": "/$schema", + "type": "string", + "examples": [ + "https://lnav.org/event-session-loaded-v1.schema.json" + ] + } + }, + "additionalProperties": false +} diff --git a/docs/source/events.rst b/docs/source/events.rst index 54cecdfd..8318abf6 100644 --- a/docs/source/events.rst +++ b/docs/source/events.rst @@ -51,3 +51,6 @@ The following tables describe the schema of the event JSON objects. .. jsonschema:: ../schemas/event-log-msg-detected-v1.schema.json# :lift_description: + +.. jsonschema:: ../schemas/event-session-loaded-v1.schema.json# + :lift_description: diff --git a/docs/tutorials/tutorial-lib/formats/tutorial-lib/tutorial.sql b/docs/tutorials/tutorial-lib/formats/tutorial-lib/tutorial.sql index 80af3629..28133577 100644 --- a/docs/tutorials/tutorial-lib/formats/tutorial-lib/tutorial.sql +++ b/docs/tutorials/tutorial-lib/formats/tutorial-lib/tutorial.sql @@ -1,3 +1,5 @@ + +-- Tracks the current step in the tutorial CREATE TABLE lnav_tutorial_step ( name TEXT NOT NULL PRIMARY KEY, @@ -7,6 +9,7 @@ CREATE TABLE lnav_tutorial_step INSERT INTO lnav_tutorial_step VALUES ('tutorial1', 1); +-- A description of each step in the tutorial with its achievements CREATE TABLE lnav_tutorial_steps ( name TEXT NOT NULL, @@ -15,6 +18,7 @@ CREATE TABLE lnav_tutorial_steps PRIMARY KEY (name, step) ); +-- Tracks the progress through the achievements in a step of the tutorial CREATE TABLE IF NOT EXISTS lnav_tutorial_progress ( name TEXT NOT NULL, @@ -34,6 +38,8 @@ CREATE TABLE IF NOT EXISTS lnav_tutorial_lines log_comment TEXT ); +-- Copy the tutorial data from the markdown frontmatter to +-- the appropriate tables. CREATE TRIGGER IF NOT EXISTS add_tutorial_data AFTER INSERT ON lnav_events @@ -63,7 +69,14 @@ BEGIN REPLACE INTO lnav_user_notifications (id, views, message) SELECT * FROM lnav_tutorial_log_notification; +END; +CREATE TRIGGER IF NOT EXISTS tutorial_move_log_after_load + AFTER INSERT + ON lnav_events + WHEN jget(new.content, '/$schema') = 'https://lnav.org/event-session-loaded-v1.schema.json' +BEGIN + UPDATE lnav_views SET top = 0 WHERE name = 'log'; END; CREATE TRIGGER IF NOT EXISTS lnav_tutorial_view_listener UPDATE OF top @@ -122,9 +135,9 @@ SELECT * FROM (SELECT 'org.lnav.tutorial.log' AS id, '["log"]' AS views, jget(value, '/notification') AS message FROM lnav_tutorial_remaining_achievements UNION ALL - SELECT 'org.lnav.tutorial.log' AS id, - '["log"]' AS views, - 'Press y to go to the next step in the tutorial' AS message) + SELECT 'org.lnav.tutorial.log' AS id, + '["log"]' AS views, + 'Press `y` to go to the next step in the tutorial' AS message) LIMIT 1; CREATE TRIGGER IF NOT EXISTS lnav_tutorial_progress_listener @@ -138,4 +151,4 @@ BEGIN END; REPLACE INTO lnav_user_notifications (id, views, message) - VALUES ('org.lnav.tutorial.text', '["text"]', 'Press "q" to go to the log view') + VALUES ('org.lnav.tutorial.text', '["text"]', 'Press `q` to go to the log view') diff --git a/docs/tutorials/tutorial1/index.md b/docs/tutorials/tutorial1/index.md index 908479bd..1c4da716 100644 --- a/docs/tutorials/tutorial1/index.md +++ b/docs/tutorials/tutorial1/index.md @@ -5,7 +5,9 @@ steps: description: "Move to an error" view_ptr: /top view_value: 6 - notification: "Press e/Shift+E to move through the errors" + notification: | + Press `e`/`Shift+E` to move through the + errors comment: | You found the error! [Log formats](https://docs.lnav.org/en/latest/formats.html#format-file-reference) @@ -14,7 +16,9 @@ steps: how the levels are displayed. move-to-warning: description: "Move to a warning" - notification: "Press w/Shift+W to move through the warnings" + notification: | + Press `w`/`Shift+W` to move through the + warnings view_ptr: /top view_value: 3 comment: | @@ -25,12 +29,12 @@ steps: view. - search-for-term: description: "Search for something" - notification: "Press / to search for '1AF9...'" + notification: "Press `/` to search for '1AF9...'" view_ptr: /search view_value: 1AF9293A-F42D-4318-BCDF-60234B240955 move-to-next-hit: description: "Move to the next hit" - notification: "Press n/Shift+N to move through the search hits" + notification: "Press `n`/`Shift+N` to move through the search hits" view_ptr: /top view_value: 53 comment: | @@ -43,7 +47,7 @@ steps: the way back to the start of the line. move-right: description: "Move to the right" - notification: "Press > to move horizontally to view the search hit" + notification: "Press `>` to move horizontally to view the search hit" view_ptr: /left view_value: 150 --- @@ -71,8 +75,8 @@ can then use the following hotkeys to jump to them in the log view: To complete this step in the tutorial, you'll need to navigate to the errors and warnings in the sample log file. You can check the upper-right -status bar for tips on what you need to do next. Now, press `q` to switch -to the log view and begin navigating the sample log file. +↗↗↗ status bar for tips on what you need to do next. Now, press `q` to +switch to the log view and begin navigating the sample log file. ## Step 2 @@ -87,12 +91,13 @@ Press `q` to switch to the log view and try searching for the UUID. ## Conclusion -That's all for now, visit https://lnav.org/downloads to find how to -download/install a copy of lnav for your system. The full documentation -is available at https://docs.lnav.org. +That's all for now, thanks for your time! Visit the +[downloads](https://lnav.org/downloads) page to find out how to +download or install **lnav** for your system. The full +documentation is available at https://docs.lnav.org ## Colophon The source for this tutorial is available here: -https://github.com/tstack/lnav/tree/master/docs/tutorials/tutorial1 +https://github.com/tstack/lnav/tree/master/docs/tutorials/ diff --git a/src/dump_internals.cc b/src/dump_internals.cc index 79752d83..83177696 100644 --- a/src/dump_internals.cc +++ b/src/dump_internals.cc @@ -49,6 +49,7 @@ dump_internals(const char* internals_dir) &lnav::events::file::open::handlers, &lnav::events::file::format_detected::handlers, &lnav::events::log::msg_detected::handlers, + &lnav::events::session::loaded::handlers, }) { dump_schema_to(*handlers, internals_dir); diff --git a/src/help.md b/src/help.md index d49cefd6..2a7aa21c 100644 --- a/src/help.md +++ b/src/help.md @@ -529,5 +529,5 @@ http://lnav.org For support questions, email: -lnav@googlegroups.com -support@lnav.org +* lnav@googlegroups.com +* support@lnav.org diff --git a/src/lnav.cc b/src/lnav.cc index b62a4b97..b58d9640 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -1336,7 +1336,8 @@ looper() = &lnav_data.ld_exec_context; lnav_data.ld_status[LNS_TOP].set_top(0); - lnav_data.ld_status[LNS_TOP].set_enabled(false); + lnav_data.ld_status[LNS_TOP].set_default_role( + role_t::VCR_INACTIVE_STATUS); lnav_data.ld_status[LNS_TOP].set_data_source(&lnav_data.ld_top_source); lnav_data.ld_status[LNS_BOTTOM].set_top(-(rlc->get_height() + 1)); for (auto& stat_bar : lnav_data.ld_status) { diff --git a/src/lnav.events.cc b/src/lnav.events.cc index bf04ebd0..d341493b 100644 --- a/src/lnav.events.cc +++ b/src/lnav.events.cc @@ -105,6 +105,20 @@ const typed_json_path_container msg_detected::handlers = typed_jso } // namespace log +namespace session { + +const std::string loaded::SCHEMA_ID + = "https://lnav.org/event-session-loaded-v1.schema.json"; + +const typed_json_path_container loaded::handlers = typed_json_path_container{ + yajlpp::property_handler("$schema").for_field(&loaded::l_schema) + .with_example(loaded::SCHEMA_ID), +} + .with_schema_id2(loaded::SCHEMA_ID) + .with_description2("Event fired when a session is loaded."); + +} // namespace session + int register_events_tab(sqlite3* db) { diff --git a/src/lnav.events.hh b/src/lnav.events.hh index 1ad71a3d..d4a95266 100644 --- a/src/lnav.events.hh +++ b/src/lnav.events.hh @@ -75,6 +75,17 @@ struct msg_detected { } // namespace log +namespace session { + +struct loaded { + std::string l_schema{SCHEMA_ID}; + + static const std::string SCHEMA_ID; + static const typed_json_path_container handlers; +}; + +} // namespace session + int register_events_tab(sqlite3* db); namespace details { diff --git a/src/md4cpp.cc b/src/md4cpp.cc index 33a18c9f..40fc2a8b 100644 --- a/src/md4cpp.cc +++ b/src/md4cpp.cc @@ -37,254 +37,267 @@ namespace md4cpp { - static const typed_json_path_container xml_entity_handlers = { - yajlpp::property_handler("characters").for_field(&xml_entity::xe_chars), - }; - - static const typed_json_path_container xml_entity_map_handlers - = { - yajlpp::pattern_property_handler("(?\\&\\w+;?)") - .with_synopsis("") - .with_path_provider( - [](struct xml_entity_map *xem, - std::vector &paths_out) { - for (const auto &iter: xem->xem_entities) { - paths_out.emplace_back(iter.first); - } - }) - .with_obj_provider( - [](const yajlpp_provider_context &ypc, xml_entity_map *xem) { - auto entity_name = ypc.get_substr(0); - return &xem->xem_entities[entity_name]; - }) - .with_children(xml_entity_handlers), - }; - - static const typed_json_path_container emoji_handlers = { - yajlpp::property_handler("emoji").for_field(&emoji::e_value), - yajlpp::property_handler("shortname").for_field(&emoji::e_shortname), - }; - - static const typed_json_path_container emoji_map_handlers = { - yajlpp::property_handler("emojis#") - .for_field(&emoji_map::em_emojis) - .with_children(emoji_handlers), - }; - - static xml_entity_map - load_xml_entity_map() { - static const intern_string_t name - = intern_string::lookup(xml_entities_json.get_name()); - auto parse_res - = xml_entity_map_handlers.parser_for(name).with_ignore_unused(true).of( - xml_entities_json.to_string_fragment()); - - assert(parse_res.isOk()); - - return parse_res.unwrap(); +static const typed_json_path_container xml_entity_handlers = { + yajlpp::property_handler("characters").for_field(&xml_entity::xe_chars), +}; + +static const typed_json_path_container xml_entity_map_handlers + = { + yajlpp::pattern_property_handler("(?\\&\\w+;?)") + .with_synopsis("") + .with_path_provider( + [](struct xml_entity_map* xem, + std::vector& paths_out) { + for (const auto& iter : xem->xem_entities) { + paths_out.emplace_back(iter.first); + } + }) + .with_obj_provider( + [](const yajlpp_provider_context& ypc, xml_entity_map* xem) { + auto entity_name = ypc.get_substr(0); + return &xem->xem_entities[entity_name]; + }) + .with_children(xml_entity_handlers), +}; + +static const typed_json_path_container emoji_handlers = { + yajlpp::property_handler("emoji").for_field(&emoji::e_value), + yajlpp::property_handler("shortname").for_field(&emoji::e_shortname), +}; + +static const typed_json_path_container emoji_map_handlers = { + yajlpp::property_handler("emojis#") + .for_field(&emoji_map::em_emojis) + .with_children(emoji_handlers), +}; + +static xml_entity_map +load_xml_entity_map() +{ + static const intern_string_t name + = intern_string::lookup(xml_entities_json.get_name()); + auto parse_res + = xml_entity_map_handlers.parser_for(name).with_ignore_unused(true).of( + xml_entities_json.to_string_fragment()); + + assert(parse_res.isOk()); + + return parse_res.unwrap(); +} + +const xml_entity_map& +get_xml_entity_map() +{ + static const auto retval = load_xml_entity_map(); + + return retval; +} + +static emoji_map +load_emoji_map() +{ + static const intern_string_t name + = intern_string::lookup(emojis_json.get_name()); + auto parse_res + = emoji_map_handlers.parser_for(name).with_ignore_unused(true).of( + emojis_json.to_string_fragment()); + + assert(parse_res.isOk()); + + auto retval = parse_res.unwrap(); + for (auto& em : retval.em_emojis) { + retval.em_shortname2emoji.emplace(em.e_shortname, em); } - const xml_entity_map & - get_xml_entity_map() { - static const auto retval = load_xml_entity_map(); - - return retval; + return retval; +} + +const emoji_map& +get_emoji_map() +{ + static const auto retval = load_emoji_map(); + + return retval; +} + +struct parse_userdata { + event_handler& pu_handler; + std::string pu_error_msg; +}; + +static event_handler::block +build_block(MD_BLOCKTYPE type, void* detail) +{ + switch (type) { + case MD_BLOCK_DOC: + return event_handler::block_doc{}; + case MD_BLOCK_QUOTE: + return event_handler::block_quote{}; + case MD_BLOCK_UL: + return static_cast(detail); + case MD_BLOCK_OL: + return static_cast(detail); + case MD_BLOCK_LI: + return static_cast(detail); + case MD_BLOCK_HR: + return event_handler::block_hr{}; + case MD_BLOCK_H: + return static_cast(detail); + case MD_BLOCK_CODE: + return static_cast(detail); + case MD_BLOCK_HTML: + return event_handler::block_html{}; + case MD_BLOCK_P: + return event_handler::block_p{}; + case MD_BLOCK_TABLE: + return static_cast(detail); + case MD_BLOCK_THEAD: + return event_handler::block_thead{}; + case MD_BLOCK_TBODY: + return event_handler::block_tbody{}; + case MD_BLOCK_TR: + return event_handler::block_tr{}; + case MD_BLOCK_TH: + return event_handler::block_th{}; + case MD_BLOCK_TD: + return static_cast(detail); } - static emoji_map - load_emoji_map() { - static const intern_string_t name - = intern_string::lookup(emojis_json.get_name()); - auto parse_res - = emoji_map_handlers.parser_for(name).with_ignore_unused(true).of( - emojis_json.to_string_fragment()); + return {}; +} + +static event_handler::span +build_span(MD_SPANTYPE type, void* detail) +{ + switch (type) { + case MD_SPAN_EM: + return event_handler::span_em{}; + case MD_SPAN_STRONG: + return event_handler::span_strong{}; + case MD_SPAN_A: + return static_cast(detail); + case MD_SPAN_IMG: + return static_cast(detail); + case MD_SPAN_CODE: + return event_handler::span_code{}; + case MD_SPAN_DEL: + return event_handler::span_del{}; + case MD_SPAN_U: + return event_handler::span_u{}; + default: + break; + } - assert(parse_res.isOk()); + return {}; +} - auto retval = parse_res.unwrap(); - for (auto &em: retval.em_emojis) { - retval.em_shortname2emoji.emplace(em.e_shortname, em); - } +static int +md4cpp_enter_block(MD_BLOCKTYPE type, void* detail, void* userdata) +{ + auto* pu = static_cast(userdata); - return retval; + auto enter_res = pu->pu_handler.enter_block(build_block(type, detail)); + if (enter_res.isErr()) { + pu->pu_error_msg = enter_res.unwrapErr(); + return 1; } - const emoji_map & - get_emoji_map() { - static const auto retval = load_emoji_map(); + return 0; +} - return retval; - } - - struct parse_userdata { - event_handler &pu_handler; - std::string pu_error_msg; - }; - - static event_handler::block - build_block(MD_BLOCKTYPE type, void *detail) { - switch (type) { - case MD_BLOCK_DOC: - return event_handler::block_doc{}; - case MD_BLOCK_QUOTE: - return event_handler::block_quote{}; - case MD_BLOCK_UL: - return static_cast(detail); - case MD_BLOCK_OL: - return static_cast(detail); - case MD_BLOCK_LI: - return static_cast(detail); - case MD_BLOCK_HR: - return event_handler::block_hr{}; - case MD_BLOCK_H: - return static_cast(detail); - case MD_BLOCK_CODE: - return static_cast(detail); - case MD_BLOCK_HTML: - return event_handler::block_html{}; - case MD_BLOCK_P: - return event_handler::block_p{}; - case MD_BLOCK_TABLE: - return static_cast(detail); - case MD_BLOCK_THEAD: - return event_handler::block_thead{}; - case MD_BLOCK_TBODY: - return event_handler::block_tbody{}; - case MD_BLOCK_TR: - return event_handler::block_tr{}; - case MD_BLOCK_TH: - return event_handler::block_th{}; - case MD_BLOCK_TD: - return static_cast(detail); - } - - return {}; - } +static int +md4cpp_leave_block(MD_BLOCKTYPE type, void* detail, void* userdata) +{ + auto* pu = static_cast(userdata); - static event_handler::span - build_span(MD_SPANTYPE type, void *detail) { - switch (type) { - case MD_SPAN_EM: - return event_handler::span_em{}; - case MD_SPAN_STRONG: - return event_handler::span_strong{}; - case MD_SPAN_A: - return static_cast(detail); - case MD_SPAN_IMG: - return static_cast(detail); - case MD_SPAN_CODE: - return event_handler::span_code{}; - case MD_SPAN_DEL: - return event_handler::span_del{}; - case MD_SPAN_U: - return event_handler::span_u{}; - default: - break; - } - - return {}; + auto leave_res = pu->pu_handler.leave_block(build_block(type, detail)); + if (leave_res.isErr()) { + pu->pu_error_msg = leave_res.unwrapErr(); + return 1; } - static int - md4cpp_enter_block(MD_BLOCKTYPE type, void *detail, void *userdata) { - auto *pu = static_cast(userdata); + return 0; +} - auto enter_res = pu->pu_handler.enter_block(build_block(type, detail)); - if (enter_res.isErr()) { - pu->pu_error_msg = enter_res.unwrapErr(); - return 1; - } +static int +md4cpp_enter_span(MD_SPANTYPE type, void* detail, void* userdata) +{ + auto* pu = static_cast(userdata); - return 0; + auto enter_res = pu->pu_handler.enter_span(build_span(type, detail)); + if (enter_res.isErr()) { + pu->pu_error_msg = enter_res.unwrapErr(); + return 1; } - static int - md4cpp_leave_block(MD_BLOCKTYPE type, void *detail, void *userdata) { - auto *pu = static_cast(userdata); + return 0; +} - auto leave_res = pu->pu_handler.leave_block(build_block(type, detail)); - if (leave_res.isErr()) { - pu->pu_error_msg = leave_res.unwrapErr(); - return 1; - } +static int +md4cpp_leave_span(MD_SPANTYPE type, void* detail, void* userdata) +{ + auto* pu = static_cast(userdata); - return 0; + auto leave_res = pu->pu_handler.leave_span(build_span(type, detail)); + if (leave_res.isErr()) { + pu->pu_error_msg = leave_res.unwrapErr(); + return 1; } - static int - md4cpp_enter_span(MD_SPANTYPE type, void *detail, void *userdata) { - auto *pu = static_cast(userdata); - - auto enter_res = pu->pu_handler.enter_span(build_span(type, detail)); - if (enter_res.isErr()) { - pu->pu_error_msg = enter_res.unwrapErr(); - return 1; - } - - return 0; + return 0; +} + +static int +md4cpp_text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userdata) +{ + auto* pu = static_cast(userdata); + auto text_res = pu->pu_handler.text(type, string_fragment(text, 0, size)); + if (text_res.isErr()) { + pu->pu_error_msg = text_res.unwrapErr(); + return 1; } - static int - md4cpp_leave_span(MD_SPANTYPE type, void *detail, void *userdata) { - auto *pu = static_cast(userdata); + return 0; +} + +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)); + } - auto leave_res = pu->pu_handler.leave_span(build_span(type, detail)); - if (leave_res.isErr()) { - pu->pu_error_msg = leave_res.unwrapErr(); - return 1; - } + MD_PARSER parser = {0}; + auto pu = parse_userdata{eh}; - return 0; - } + parser.abi_version = 0; + parser.flags = (MD_DIALECT_GITHUB | MD_FLAG_UNDERLINE) + & ~(MD_FLAG_PERMISSIVEAUTOLINKS); + parser.enter_block = md4cpp_enter_block; + parser.leave_block = md4cpp_leave_block; + parser.enter_span = md4cpp_enter_span; + parser.leave_span = md4cpp_leave_span; + parser.text = md4cpp_text; - static int - md4cpp_text(MD_TEXTTYPE type, const MD_CHAR *text, MD_SIZE size, void *userdata) { - auto *pu = static_cast(userdata); - auto text_res = pu->pu_handler.text(type, string_fragment(text, 0, size)); - if (text_res.isErr()) { - pu->pu_error_msg = text_res.unwrapErr(); - return 1; - } + auto rc = md_parse(sf.data(), sf.length(), &parser, &pu); - return 0; + if (rc == 0) { + return Ok(); } - 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}; - - parser.abi_version = 0; - parser.flags = MD_DIALECT_GITHUB | MD_FLAG_UNDERLINE; - parser.enter_block = md4cpp_enter_block; - parser.leave_block = md4cpp_leave_block; - parser.enter_span = md4cpp_enter_span; - parser.leave_span = md4cpp_leave_span; - parser.text = md4cpp_text; - - auto rc = md_parse(sf.data(), sf.length(), &parser, &pu); - - if (rc == 0) { - return Ok(); - } - - return Err(pu.pu_error_msg); - } - } // namespace details + return Err(pu.pu_error_msg); +} +} // namespace details } // namespace md4cpp diff --git a/src/session_data.cc b/src/session_data.cc index a0dbd9cf..e67844cd 100644 --- a/src/session_data.cc +++ b/src/session_data.cc @@ -46,6 +46,7 @@ #include "base/paths.hh" #include "command_executor.hh" #include "config.h" +#include "lnav.events.hh" #include "lnav.hh" #include "lnav_util.hh" #include "log_format_ext.hh" @@ -964,6 +965,9 @@ load_session() lnav_data.ld_text_source.text_filters_changed(); } }; + + lnav::events::publish(lnav_data.ld_db.in(), + lnav::events::session::loaded{}); } static void diff --git a/src/statusview_curses.cc b/src/statusview_curses.cc index c73857f4..f27bff00 100644 --- a/src/statusview_curses.cc +++ b/src/statusview_curses.cc @@ -101,7 +101,7 @@ statusview_curses::do_update() top = this->sc_top < 0 ? height + this->sc_top : this->sc_top; right = width; auto attrs = vc.attrs_for_role( - this->sc_enabled ? role_t::VCR_STATUS : role_t::VCR_INACTIVE_STATUS); + this->sc_enabled ? this->sc_default_role : role_t::VCR_INACTIVE_STATUS); auto pair = vc.ensure_color_pair(attrs.ta_fg_color, attrs.ta_bg_color); wattr_set(this->sc_window, attrs.ta_attrs, pair, nullptr); diff --git a/src/statusview_curses.hh b/src/statusview_curses.hh index 73f8f309..c9c59161 100644 --- a/src/statusview_curses.hh +++ b/src/statusview_curses.hh @@ -171,6 +171,9 @@ public: void set_enabled(bool value) { this->sc_enabled = value; } bool get_enabled() const { return this->sc_enabled; } + void set_default_role(role_t role) { this->sc_default_role = role; } + role_t get_default_role() const { return this->sc_default_role; } + void window_change(); void do_update() override; @@ -180,6 +183,7 @@ private: WINDOW* sc_window{nullptr}; int sc_top{0}; bool sc_enabled{true}; + role_t sc_default_role{role_t::VCR_STATUS}; }; #endif diff --git a/src/top_status_source.cc b/src/top_status_source.cc index 34670cf9..4a0dcaac 100644 --- a/src/top_status_source.cc +++ b/src/top_status_source.cc @@ -34,8 +34,13 @@ #include "base/injector.hh" #include "bound_tags.hh" #include "config.h" +#include "lnav.hh" #include "lnav_config.hh" #include "logfile_sub_source.hh" +#include "md2attr_line.hh" +#include "md4cpp.hh" +#include "shlex.hh" +#include "shlex.resolver.hh" #include "sql_util.hh" #include "sqlitepp.client.hh" @@ -107,7 +112,23 @@ top_status_source::update_user_msg() auto fetch_res = um_stmt.ums_stmt.fetch_row(); fetch_res.match( [&al](const std::string& value) { - al.with_ansi_string(value); + shlex lexer(value); + std::string user_note; + + lexer.with_ignore_quotes(true).eval( + user_note, lnav_data.ld_exec_context.ec_global_vars); + + md2attr_line mdal; + auto parse_res = md4cpp::parse(user_note, mdal); + if (parse_res.isOk()) { + al = parse_res.unwrap(); + } else { + log_error("failed to parse user note as markdown: %s", + parse_res.unwrapErr().c_str()); + al = user_note; + } + + scrub_ansi_string(al.get_string(), &al.get_attrs()); al.append(" "); }, [](const prepared_stmt::end_of_rows&) {}, diff --git a/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out b/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out index 2b5d658f..b6b30316 100644 --- a/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out +++ b/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out @@ -664,16 +664,12 @@ commands, which is especially useful when scripting lnav. For more information, visit the lnav website at: -http://lnav.org[1] - - ▌[1] - http://lnav.org +http://lnav.org For support questions, email: -lnav@googlegroups.com[1] support@lnav.org[2] - - ▌[1] - mailto:lnav@googlegroups.com - ▌[2] - mailto:support@lnav.org + • lnav@googlegroups.com + • support@lnav.org Command Reference