[user_notifications] treat message as markdown

pull/1031/head
Tim Stack 2 years ago
parent ff91cfc3a0
commit b5cb38d454

@ -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
}

@ -51,3 +51,6 @@ The following tables describe the schema of the event JSON objects.
.. jsonschema:: ../schemas/event-log-msg-detected-v1.schema.json# .. jsonschema:: ../schemas/event-log-msg-detected-v1.schema.json#
:lift_description: :lift_description:
.. jsonschema:: ../schemas/event-session-loaded-v1.schema.json#
:lift_description:

@ -1,3 +1,5 @@
-- Tracks the current step in the tutorial
CREATE TABLE lnav_tutorial_step CREATE TABLE lnav_tutorial_step
( (
name TEXT NOT NULL PRIMARY KEY, name TEXT NOT NULL PRIMARY KEY,
@ -7,6 +9,7 @@ CREATE TABLE lnav_tutorial_step
INSERT INTO lnav_tutorial_step INSERT INTO lnav_tutorial_step
VALUES ('tutorial1', 1); VALUES ('tutorial1', 1);
-- A description of each step in the tutorial with its achievements
CREATE TABLE lnav_tutorial_steps CREATE TABLE lnav_tutorial_steps
( (
name TEXT NOT NULL, name TEXT NOT NULL,
@ -15,6 +18,7 @@ CREATE TABLE lnav_tutorial_steps
PRIMARY KEY (name, step) PRIMARY KEY (name, step)
); );
-- Tracks the progress through the achievements in a step of the tutorial
CREATE TABLE IF NOT EXISTS lnav_tutorial_progress CREATE TABLE IF NOT EXISTS lnav_tutorial_progress
( (
name TEXT NOT NULL, name TEXT NOT NULL,
@ -34,6 +38,8 @@ CREATE TABLE IF NOT EXISTS lnav_tutorial_lines
log_comment TEXT log_comment TEXT
); );
-- Copy the tutorial data from the markdown frontmatter to
-- the appropriate tables.
CREATE TRIGGER IF NOT EXISTS add_tutorial_data CREATE TRIGGER IF NOT EXISTS add_tutorial_data
AFTER INSERT AFTER INSERT
ON lnav_events ON lnav_events
@ -63,7 +69,14 @@ BEGIN
REPLACE INTO lnav_user_notifications (id, views, message) REPLACE INTO lnav_user_notifications (id, views, message)
SELECT * SELECT *
FROM lnav_tutorial_log_notification; 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; END;
CREATE TRIGGER IF NOT EXISTS lnav_tutorial_view_listener UPDATE OF top 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 (SELECT 'org.lnav.tutorial.log' AS id, '["log"]' AS views, jget(value, '/notification') AS message
FROM lnav_tutorial_remaining_achievements FROM lnav_tutorial_remaining_achievements
UNION ALL UNION ALL
SELECT 'org.lnav.tutorial.log' AS id, SELECT 'org.lnav.tutorial.log' AS id,
'["log"]' AS views, '["log"]' AS views,
'Press y to go to the next step in the tutorial' AS message) 'Press `y` to go to the next step in the tutorial' AS message)
LIMIT 1; LIMIT 1;
CREATE TRIGGER IF NOT EXISTS lnav_tutorial_progress_listener CREATE TRIGGER IF NOT EXISTS lnav_tutorial_progress_listener
@ -138,4 +151,4 @@ BEGIN
END; END;
REPLACE INTO lnav_user_notifications (id, views, message) 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')

@ -5,7 +5,9 @@ steps:
description: "Move to an error" description: "Move to an error"
view_ptr: /top view_ptr: /top
view_value: 6 view_value: 6
notification: "Press e/Shift+E to move through the errors" notification: |
Press `e`/`Shift+E` to move through the
<span class="-lnav_log-level-styles_error">errors</span>
comment: | comment: |
You found the error! You found the error!
[Log formats](https://docs.lnav.org/en/latest/formats.html#format-file-reference) [Log formats](https://docs.lnav.org/en/latest/formats.html#format-file-reference)
@ -14,7 +16,9 @@ steps:
how the levels are displayed. how the levels are displayed.
move-to-warning: move-to-warning:
description: "Move to a 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
<span class="-lnav_log-level-styles_warning">warnings</span>
view_ptr: /top view_ptr: /top
view_value: 3 view_value: 3
comment: | comment: |
@ -25,12 +29,12 @@ steps:
view. view.
- search-for-term: - search-for-term:
description: "Search for something" description: "Search for something"
notification: "Press / to search for '1AF9...'" notification: "Press `/` to search for '1AF9...'"
view_ptr: /search view_ptr: /search
view_value: 1AF9293A-F42D-4318-BCDF-60234B240955 view_value: 1AF9293A-F42D-4318-BCDF-60234B240955
move-to-next-hit: move-to-next-hit:
description: "Move to the 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_ptr: /top
view_value: 53 view_value: 53
comment: | comment: |
@ -43,7 +47,7 @@ steps:
the way back to the start of the line. the way back to the start of the line.
move-right: move-right:
description: "Move to the 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_ptr: /left
view_value: 150 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 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 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 ↗↗↗ status bar for tips on what you need to do next. Now, press `q` to
to the log view and begin navigating the sample log file. switch to the log view and begin navigating the sample log file.
## Step 2 ## Step 2
@ -87,12 +91,13 @@ Press `q` to switch to the log view and try searching for the UUID.
## Conclusion ## Conclusion
That's all for now, visit https://lnav.org/downloads to find how to That's all for now, thanks for your time! Visit the
download/install a copy of lnav for your system. The full documentation [downloads](https://lnav.org/downloads) page to find out how to
is available at https://docs.lnav.org. download or install **lnav** for your system. The full
documentation is available at https://docs.lnav.org
## Colophon ## Colophon
The source for this tutorial is available here: 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/

@ -49,6 +49,7 @@ dump_internals(const char* internals_dir)
&lnav::events::file::open::handlers, &lnav::events::file::open::handlers,
&lnav::events::file::format_detected::handlers, &lnav::events::file::format_detected::handlers,
&lnav::events::log::msg_detected::handlers, &lnav::events::log::msg_detected::handlers,
&lnav::events::session::loaded::handlers,
}) })
{ {
dump_schema_to(*handlers, internals_dir); dump_schema_to(*handlers, internals_dir);

@ -529,5 +529,5 @@ http://lnav.org
For support questions, email: For support questions, email:
lnav@googlegroups.com * lnav@googlegroups.com
support@lnav.org * support@lnav.org

@ -1336,7 +1336,8 @@ looper()
= &lnav_data.ld_exec_context; = &lnav_data.ld_exec_context;
lnav_data.ld_status[LNS_TOP].set_top(0); 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_TOP].set_data_source(&lnav_data.ld_top_source);
lnav_data.ld_status[LNS_BOTTOM].set_top(-(rlc->get_height() + 1)); lnav_data.ld_status[LNS_BOTTOM].set_top(-(rlc->get_height() + 1));
for (auto& stat_bar : lnav_data.ld_status) { for (auto& stat_bar : lnav_data.ld_status) {

@ -105,6 +105,20 @@ const typed_json_path_container<msg_detected> msg_detected::handlers = typed_jso
} // namespace log } // 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> loaded::handlers = typed_json_path_container<loaded>{
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 int
register_events_tab(sqlite3* db) register_events_tab(sqlite3* db)
{ {

@ -75,6 +75,17 @@ struct msg_detected {
} // namespace log } // namespace log
namespace session {
struct loaded {
std::string l_schema{SCHEMA_ID};
static const std::string SCHEMA_ID;
static const typed_json_path_container<loaded> handlers;
};
} // namespace session
int register_events_tab(sqlite3* db); int register_events_tab(sqlite3* db);
namespace details { namespace details {

@ -37,254 +37,267 @@
namespace md4cpp { namespace md4cpp {
static const typed_json_path_container<xml_entity> xml_entity_handlers = { static const typed_json_path_container<xml_entity> xml_entity_handlers = {
yajlpp::property_handler("characters").for_field(&xml_entity::xe_chars), yajlpp::property_handler("characters").for_field(&xml_entity::xe_chars),
}; };
static const typed_json_path_container<xml_entity_map> xml_entity_map_handlers static const typed_json_path_container<xml_entity_map> xml_entity_map_handlers
= { = {
yajlpp::pattern_property_handler("(?<var_name>\\&\\w+;?)") yajlpp::pattern_property_handler("(?<var_name>\\&\\w+;?)")
.with_synopsis("<name>") .with_synopsis("<name>")
.with_path_provider<xml_entity_map>( .with_path_provider<xml_entity_map>(
[](struct xml_entity_map *xem, [](struct xml_entity_map* xem,
std::vector<std::string> &paths_out) { std::vector<std::string>& paths_out) {
for (const auto &iter: xem->xem_entities) { for (const auto& iter : xem->xem_entities) {
paths_out.emplace_back(iter.first); paths_out.emplace_back(iter.first);
} }
}) })
.with_obj_provider<xml_entity, xml_entity_map>( .with_obj_provider<xml_entity, xml_entity_map>(
[](const yajlpp_provider_context &ypc, xml_entity_map *xem) { [](const yajlpp_provider_context& ypc, xml_entity_map* xem) {
auto entity_name = ypc.get_substr(0); auto entity_name = ypc.get_substr(0);
return &xem->xem_entities[entity_name]; return &xem->xem_entities[entity_name];
}) })
.with_children(xml_entity_handlers), .with_children(xml_entity_handlers),
}; };
static const typed_json_path_container<emoji> emoji_handlers = { static const typed_json_path_container<emoji> emoji_handlers = {
yajlpp::property_handler("emoji").for_field(&emoji::e_value), yajlpp::property_handler("emoji").for_field(&emoji::e_value),
yajlpp::property_handler("shortname").for_field(&emoji::e_shortname), yajlpp::property_handler("shortname").for_field(&emoji::e_shortname),
}; };
static const typed_json_path_container<emoji_map> emoji_map_handlers = { static const typed_json_path_container<emoji_map> emoji_map_handlers = {
yajlpp::property_handler("emojis#") yajlpp::property_handler("emojis#")
.for_field(&emoji_map::em_emojis) .for_field(&emoji_map::em_emojis)
.with_children(emoji_handlers), .with_children(emoji_handlers),
}; };
static xml_entity_map static xml_entity_map
load_xml_entity_map() { load_xml_entity_map()
static const intern_string_t name {
= intern_string::lookup(xml_entities_json.get_name()); static const intern_string_t name
auto parse_res = intern_string::lookup(xml_entities_json.get_name());
= xml_entity_map_handlers.parser_for(name).with_ignore_unused(true).of( auto parse_res
xml_entities_json.to_string_fragment()); = xml_entity_map_handlers.parser_for(name).with_ignore_unused(true).of(
xml_entities_json.to_string_fragment());
assert(parse_res.isOk());
assert(parse_res.isOk());
return parse_res.unwrap();
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 & return retval;
get_xml_entity_map() { }
static const auto retval = load_xml_entity_map();
const emoji_map&
return retval; 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<MD_BLOCK_UL_DETAIL*>(detail);
case MD_BLOCK_OL:
return static_cast<MD_BLOCK_OL_DETAIL*>(detail);
case MD_BLOCK_LI:
return static_cast<MD_BLOCK_LI_DETAIL*>(detail);
case MD_BLOCK_HR:
return event_handler::block_hr{};
case MD_BLOCK_H:
return static_cast<MD_BLOCK_H_DETAIL*>(detail);
case MD_BLOCK_CODE:
return static_cast<MD_BLOCK_CODE_DETAIL*>(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<MD_BLOCK_TABLE_DETAIL*>(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<MD_BLOCK_TD_DETAIL*>(detail);
} }
static emoji_map return {};
load_emoji_map() { }
static const intern_string_t name
= intern_string::lookup(emojis_json.get_name()); static event_handler::span
auto parse_res build_span(MD_SPANTYPE type, void* detail)
= emoji_map_handlers.parser_for(name).with_ignore_unused(true).of( {
emojis_json.to_string_fragment()); 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<MD_SPAN_A_DETAIL*>(detail);
case MD_SPAN_IMG:
return static_cast<MD_SPAN_IMG_DETAIL*>(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(); static int
for (auto &em: retval.em_emojis) { md4cpp_enter_block(MD_BLOCKTYPE type, void* detail, void* userdata)
retval.em_shortname2emoji.emplace(em.e_shortname, em); {
} auto* pu = static_cast<parse_userdata*>(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 & return 0;
get_emoji_map() { }
static const auto retval = load_emoji_map();
return retval; static int
} md4cpp_leave_block(MD_BLOCKTYPE type, void* detail, void* userdata)
{
struct parse_userdata { auto* pu = static_cast<parse_userdata*>(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<MD_BLOCK_UL_DETAIL *>(detail);
case MD_BLOCK_OL:
return static_cast<MD_BLOCK_OL_DETAIL *>(detail);
case MD_BLOCK_LI:
return static_cast<MD_BLOCK_LI_DETAIL *>(detail);
case MD_BLOCK_HR:
return event_handler::block_hr{};
case MD_BLOCK_H:
return static_cast<MD_BLOCK_H_DETAIL *>(detail);
case MD_BLOCK_CODE:
return static_cast<MD_BLOCK_CODE_DETAIL *>(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<MD_BLOCK_TABLE_DETAIL *>(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<MD_BLOCK_TD_DETAIL *>(detail);
}
return {};
}
static event_handler::span auto leave_res = pu->pu_handler.leave_block(build_block(type, detail));
build_span(MD_SPANTYPE type, void *detail) { if (leave_res.isErr()) {
switch (type) { pu->pu_error_msg = leave_res.unwrapErr();
case MD_SPAN_EM: return 1;
return event_handler::span_em{};
case MD_SPAN_STRONG:
return event_handler::span_strong{};
case MD_SPAN_A:
return static_cast<MD_SPAN_A_DETAIL *>(detail);
case MD_SPAN_IMG:
return static_cast<MD_SPAN_IMG_DETAIL *>(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 {};
} }
static int return 0;
md4cpp_enter_block(MD_BLOCKTYPE type, void *detail, void *userdata) { }
auto *pu = static_cast<parse_userdata *>(userdata);
auto enter_res = pu->pu_handler.enter_block(build_block(type, detail)); static int
if (enter_res.isErr()) { md4cpp_enter_span(MD_SPANTYPE type, void* detail, void* userdata)
pu->pu_error_msg = enter_res.unwrapErr(); {
return 1; auto* pu = static_cast<parse_userdata*>(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 return 0;
md4cpp_leave_block(MD_BLOCKTYPE type, void *detail, void *userdata) { }
auto *pu = static_cast<parse_userdata *>(userdata);
auto leave_res = pu->pu_handler.leave_block(build_block(type, detail)); static int
if (leave_res.isErr()) { md4cpp_leave_span(MD_SPANTYPE type, void* detail, void* userdata)
pu->pu_error_msg = leave_res.unwrapErr(); {
return 1; auto* pu = static_cast<parse_userdata*>(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 return 0;
md4cpp_enter_span(MD_SPANTYPE type, void *detail, void *userdata) { }
auto *pu = static_cast<parse_userdata *>(userdata);
static int
auto enter_res = pu->pu_handler.enter_span(build_span(type, detail)); md4cpp_text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userdata)
if (enter_res.isErr()) { {
pu->pu_error_msg = enter_res.unwrapErr(); auto* pu = static_cast<parse_userdata*>(userdata);
return 1; 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 0; return 1;
} }
static int return 0;
md4cpp_leave_span(MD_SPANTYPE type, void *detail, void *userdata) { }
auto *pu = static_cast<parse_userdata *>(userdata);
namespace details {
Result<void, std::string>
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)); MD_PARSER parser = {0};
if (leave_res.isErr()) { auto pu = parse_userdata{eh};
pu->pu_error_msg = leave_res.unwrapErr();
return 1;
}
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 auto rc = md_parse(sf.data(), sf.length(), &parser, &pu);
md4cpp_text(MD_TEXTTYPE type, const MD_CHAR *text, MD_SIZE size, void *userdata) {
auto *pu = static_cast<parse_userdata *>(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;
}
return 0; if (rc == 0) {
return Ok();
} }
namespace details { return Err(pu.pu_error_msg);
Result<void, std::string> }
parse(const string_fragment &sf, event_handler &eh) { } // namespace details
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
} // namespace md4cpp } // namespace md4cpp

@ -46,6 +46,7 @@
#include "base/paths.hh" #include "base/paths.hh"
#include "command_executor.hh" #include "command_executor.hh"
#include "config.h" #include "config.h"
#include "lnav.events.hh"
#include "lnav.hh" #include "lnav.hh"
#include "lnav_util.hh" #include "lnav_util.hh"
#include "log_format_ext.hh" #include "log_format_ext.hh"
@ -964,6 +965,9 @@ load_session()
lnav_data.ld_text_source.text_filters_changed(); lnav_data.ld_text_source.text_filters_changed();
} }
}; };
lnav::events::publish(lnav_data.ld_db.in(),
lnav::events::session::loaded{});
} }
static void static void

@ -101,7 +101,7 @@ statusview_curses::do_update()
top = this->sc_top < 0 ? height + this->sc_top : this->sc_top; top = this->sc_top < 0 ? height + this->sc_top : this->sc_top;
right = width; right = width;
auto attrs = vc.attrs_for_role( 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); auto pair = vc.ensure_color_pair(attrs.ta_fg_color, attrs.ta_bg_color);
wattr_set(this->sc_window, attrs.ta_attrs, pair, nullptr); wattr_set(this->sc_window, attrs.ta_attrs, pair, nullptr);

@ -171,6 +171,9 @@ public:
void set_enabled(bool value) { this->sc_enabled = value; } void set_enabled(bool value) { this->sc_enabled = value; }
bool get_enabled() const { return this->sc_enabled; } 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 window_change();
void do_update() override; void do_update() override;
@ -180,6 +183,7 @@ private:
WINDOW* sc_window{nullptr}; WINDOW* sc_window{nullptr};
int sc_top{0}; int sc_top{0};
bool sc_enabled{true}; bool sc_enabled{true};
role_t sc_default_role{role_t::VCR_STATUS};
}; };
#endif #endif

@ -34,8 +34,13 @@
#include "base/injector.hh" #include "base/injector.hh"
#include "bound_tags.hh" #include "bound_tags.hh"
#include "config.h" #include "config.h"
#include "lnav.hh"
#include "lnav_config.hh" #include "lnav_config.hh"
#include "logfile_sub_source.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 "sql_util.hh"
#include "sqlitepp.client.hh" #include "sqlitepp.client.hh"
@ -107,7 +112,23 @@ top_status_source::update_user_msg()
auto fetch_res = um_stmt.ums_stmt.fetch_row<std::string>(); auto fetch_res = um_stmt.ums_stmt.fetch_row<std::string>();
fetch_res.match( fetch_res.match(
[&al](const std::string& value) { [&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(" "); al.append(" ");
}, },
[](const prepared_stmt::end_of_rows&) {}, [](const prepared_stmt::end_of_rows&) {},

@ -664,16 +664,12 @@ commands, which is especially useful when scripting lnav.
For more information, visit the lnav website at: For more information, visit the lnav website at:
http://lnav.org[1] http://lnav.org
▌[1] - http://lnav.org
For support questions, email: For support questions, email:
lnav@googlegroups.com[1] support@lnav.org[2] • lnav@googlegroups.com
• support@lnav.org
▌[1] - mailto:lnav@googlegroups.com
▌[2] - mailto:support@lnav.org
Command Reference Command Reference

Loading…
Cancel
Save