[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#
: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
(
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')

@ -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
<span class="-lnav_log-level-styles_error">errors</span>
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
<span class="-lnav_log-level-styles_warning">warnings</span>
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/

@ -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);

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

@ -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) {

@ -105,6 +105,20 @@ const typed_json_path_container<msg_detected> 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> 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
register_events_tab(sqlite3* db)
{

@ -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<loaded> handlers;
};
} // namespace session
int register_events_tab(sqlite3* db);
namespace details {

@ -37,254 +37,267 @@
namespace md4cpp {
static const typed_json_path_container<xml_entity> xml_entity_handlers = {
yajlpp::property_handler("characters").for_field(&xml_entity::xe_chars),
};
static const typed_json_path_container<xml_entity_map> xml_entity_map_handlers
= {
yajlpp::pattern_property_handler("(?<var_name>\\&\\w+;?)")
.with_synopsis("<name>")
.with_path_provider<xml_entity_map>(
[](struct xml_entity_map *xem,
std::vector<std::string> &paths_out) {
for (const auto &iter: xem->xem_entities) {
paths_out.emplace_back(iter.first);
}
})
.with_obj_provider<xml_entity, xml_entity_map>(
[](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> 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> 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> xml_entity_handlers = {
yajlpp::property_handler("characters").for_field(&xml_entity::xe_chars),
};
static const typed_json_path_container<xml_entity_map> xml_entity_map_handlers
= {
yajlpp::pattern_property_handler("(?<var_name>\\&\\w+;?)")
.with_synopsis("<name>")
.with_path_provider<xml_entity_map>(
[](struct xml_entity_map* xem,
std::vector<std::string>& paths_out) {
for (const auto& iter : xem->xem_entities) {
paths_out.emplace_back(iter.first);
}
})
.with_obj_provider<xml_entity, xml_entity_map>(
[](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> 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> 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<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
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<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();
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<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 &
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<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 int
md4cpp_leave_block(MD_BLOCKTYPE type, void* detail, void* userdata)
{
auto* pu = static_cast<parse_userdata*>(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<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 {};
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<parse_userdata *>(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<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
md4cpp_leave_block(MD_BLOCKTYPE type, void *detail, void *userdata) {
auto *pu = static_cast<parse_userdata *>(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<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
md4cpp_enter_span(MD_SPANTYPE type, void *detail, void *userdata) {
auto *pu = static_cast<parse_userdata *>(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<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;
}
static int
md4cpp_leave_span(MD_SPANTYPE type, void *detail, void *userdata) {
auto *pu = static_cast<parse_userdata *>(userdata);
return 0;
}
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));
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<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;
}
auto rc = md_parse(sf.data(), sf.length(), &parser, &pu);
return 0;
if (rc == 0) {
return Ok();
}
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));
}
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

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

@ -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);

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

@ -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<std::string>();
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&) {},

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

Loading…
Cancel
Save