mirror of https://github.com/tstack/lnav.git
[user_notifications] treat message as markdown
This commit is contained in:
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 {
|
||||
|
|
433
src/md4cpp.cc
433
src/md4cpp.cc
|
@ -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> 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<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> 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 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());
|
||||
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());
|
||||
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 &
|
||||
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 {};
|
||||
}
|
||||
|
||||
assert(parse_res.isOk());
|
||||
|
||||
auto retval = parse_res.unwrap();
|
||||
for (auto &em: retval.em_emojis) {
|
||||
retval.em_shortname2emoji.emplace(em.e_shortname, em);
|
||||
}
|
||||
|
||||
return retval;
|
||||
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;
|
||||
}
|
||||
|
||||
const emoji_map &
|
||||
get_emoji_map() {
|
||||
static const auto retval = load_emoji_map();
|
||||
return {};
|
||||
}
|
||||
|
||||
return retval;
|
||||
static int
|
||||
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));
|
||||
if (enter_res.isErr()) {
|
||||
pu->pu_error_msg = enter_res.unwrapErr();
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct parse_userdata {
|
||||
event_handler &pu_handler;
|
||||
std::string pu_error_msg;
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 int
|
||||
md4cpp_leave_block(MD_BLOCKTYPE type, void* detail, void* userdata)
|
||||
{
|
||||
auto* pu = static_cast<parse_userdata*>(userdata);
|
||||
|
||||
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 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 0;
|
||||
}
|
||||
|
||||
return {};
|
||||
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;
|
||||
}
|
||||
|
||||
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_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_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;
|
||||
}
|
||||
|
||||
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_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;
|
||||
}
|
||||
namespace details {
|
||||
Result<void, std::string>
|
||||
parse(const string_fragment& sf, event_handler& eh)
|
||||
{
|
||||
const char* utf8_errmsg = nullptr;
|
||||
int utf8_faulty_bytes = 0;
|
||||
|
||||
return 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));
|
||||
}
|
||||
|
||||
static int
|
||||
md4cpp_leave_span(MD_SPANTYPE type, void *detail, void *userdata) {
|
||||
auto *pu = static_cast<parse_userdata *>(userdata);
|
||||
MD_PARSER parser = {0};
|
||||
auto pu = parse_userdata{eh};
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
return 0;
|
||||
auto rc = md_parse(sf.data(), sf.length(), &parser, &pu);
|
||||
|
||||
if (rc == 0) {
|
||||
return Ok();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
[4mhttp://lnav.org[1][0m
|
||||
|
||||
▌[1] - http://lnav.org
|
||||
http://lnav.org
|
||||
|
||||
For support questions, email:
|
||||
|
||||
[4mlnav@googlegroups.com[1][0m [4msupport@lnav.org[2][0m
|
||||
|
||||
▌[1] - mailto:lnav@googlegroups.com
|
||||
▌[2] - mailto:support@lnav.org
|
||||
[33m•[0m lnav@googlegroups.com
|
||||
[33m•[0m support@lnav.org
|
||||
|
||||
[1mCommand Reference[0m
|
||||
|
||||
|
|
Loading…
Reference in New Issue