summaryrefslogtreecommitdiffstats
path: root/src/lnav_config.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lnav_config.cc402
1 files changed, 363 insertions, 39 deletions
diff --git a/src/lnav_config.cc b/src/lnav_config.cc
index e706f75..e8f91d3 100644
--- a/src/lnav_config.cc
+++ b/src/lnav_config.cc
@@ -56,8 +56,10 @@
#include "base/paths.hh"
#include "base/string_util.hh"
#include "bin2c.hh"
+#include "command_executor.hh"
#include "config.h"
#include "default-config.h"
+#include "scn/scn.h"
#include "styling.hh"
#include "view_curses.hh"
#include "yajlpp/yajlpp.hh"
@@ -81,21 +83,33 @@ lnav_config_listener* lnav_config_listener::LISTENER_LIST;
static auto a = injector::bind<archive_manager::config>::to_instance(
+[]() { return &lnav_config.lc_archive_manager; });
+static auto dtc = injector::bind<date_time_scanner_ns::config>::to_instance(
+ +[]() { return &lnav_config.lc_log_date_time; });
+
static auto fvc = injector::bind<file_vtab::config>::to_instance(
+[]() { return &lnav_config.lc_file_vtab; });
static auto lc = injector::bind<lnav::logfile::config>::to_instance(
+[]() { return &lnav_config.lc_logfile; });
+static auto p = injector::bind<lnav::piper::config>::to_instance(
+ +[]() { return &lnav_config.lc_piper; });
+
static auto tc = injector::bind<tailer::config>::to_instance(
+[]() { return &lnav_config.lc_tailer; });
static auto scc = injector::bind<sysclip::config>::to_instance(
+[]() { return &lnav_config.lc_sysclip; });
+static auto uh = injector::bind<lnav::url_handler::config>::to_instance(
+ +[]() { return &lnav_config.lc_url_handlers; });
+
static auto lsc = injector::bind<logfile_sub_source_ns::config>::to_instance(
+[]() { return &lnav_config.lc_log_source; });
+static auto annoc = injector::bind<lnav::log::annotate::config>::to_instance(
+ +[]() { return &lnav_config.lc_log_annotations; });
+
static auto tssc = injector::bind<top_status_source_cfg>::to_instance(
+[]() { return &lnav_config.lc_top_status_cfg; });
@@ -134,7 +148,11 @@ ensure_dotlnav()
for (const auto* sub_path : subdirs) {
auto full_path = path / sub_path;
- log_perror(mkdir(full_path.c_str(), 0755));
+ if (mkdir(full_path.c_str(), 0755) == -1 && errno != EEXIST) {
+ log_error("unable to make directory: %s -- %s",
+ full_path.c_str(),
+ strerror(errno));
+ }
}
auto crash_dir_path = path / "crash";
@@ -240,19 +258,23 @@ install_from_git(const std::string& repo)
}
auto finished_child = std::move(git_cmd).wait_for_child();
-
if (!finished_child.was_normal_exit() || finished_child.exit_status() != 0)
{
return false;
}
+ if (ghc::filesystem::is_directory(local_formats_path)
+ || ghc::filesystem::is_directory(local_configs_path))
+ {
+ return false;
+ }
if (!ghc::filesystem::is_directory(local_staging_path)) {
auto um
= lnav::console::user_message::error(
attr_line_t("failed to install git repo: ")
.append(lnav::roles::file(repo)))
.with_reason(
- attr_line_t("git failed to create the local directory")
+ attr_line_t("git failed to create the local directory ")
.append(
lnav::roles::file(local_staging_path.string())));
lnav::console::print(stderr, um);
@@ -362,13 +384,11 @@ update_installs_from_git()
git_dir.string());
int ret = system(pull_cmd.c_str());
if (ret == -1) {
- std::cerr << "Failed to spawn command "
- << "\"" << pull_cmd << "\": " << strerror(errno)
- << std::endl;
+ std::cerr << "Failed to spawn command " << "\"" << pull_cmd
+ << "\": " << strerror(errno) << std::endl;
retval = false;
} else if (ret > 0) {
- std::cerr << "Command "
- << "\"" << pull_cmd
+ std::cerr << "Command " << "\"" << pull_cmd
<< "\" failed: " << strerror(errno) << std::endl;
retval = false;
}
@@ -379,7 +399,7 @@ update_installs_from_git()
if (!found) {
printf(
"No formats from git repositories found, "
- "use 'lnav -i extra' to install third-party foramts\n");
+ "use 'lnav -i extra' to install third-party formats\n");
}
return retval;
@@ -468,12 +488,17 @@ config_error_reporter(const yajlpp_parse_context& ypc,
}
static const struct json_path_container key_command_handlers = {
+ yajlpp::property_handler("id")
+ .with_synopsis("<id>")
+ .with_description(
+ "The identifier that can be used to refer to this key")
+ .for_field(&key_command::kc_id),
yajlpp::property_handler("command")
.with_synopsis("<command>")
.with_description(
"The command to execute for the given key sequence. Use a script "
"to execute more complicated operations.")
- .with_pattern("^[:|;].*")
+ .with_pattern("^$|^[:|;].*")
.with_example(":goto next hour")
.for_field(&key_command::kc_cmd),
yajlpp::property_handler("alt-msg")
@@ -495,6 +520,14 @@ static const struct json_path_container keymap_def_handlers = {
[](const yajlpp_provider_context& ypc, key_map* km) {
auto& retval = km->km_seq_to_cmd[ypc.get_substr("key_seq")];
+ if (ypc.ypc_parse_context != nullptr) {
+ retval.kc_cmd.pp_path
+ = ypc.ypc_parse_context->get_full_path();
+ retval.kc_cmd.pp_location.sl_source
+ = ypc.ypc_parse_context->ypc_source;
+ retval.kc_cmd.pp_location.sl_line_number
+ = ypc.ypc_parse_context->get_line_number();
+ }
return &retval;
})
.with_path_provider<key_map>(
@@ -541,6 +574,23 @@ static const struct json_path_container movement_handlers = {
.for_field<>(&_lnav_config::lc_ui_movement, &movement_config::mode),
};
+static const json_path_handler_base::enum_value_t _mouse_mode_values[] = {
+ {"disabled", lnav_mouse_mode::disabled},
+ {"enabled", lnav_mouse_mode::enabled},
+
+ json_path_handler_base::ENUM_TERMINATOR,
+};
+
+static const struct json_path_container mouse_handlers = {
+ yajlpp::property_handler("mode")
+ .with_synopsis("enabled|disabled")
+ .with_enum_values(_mouse_mode_values)
+ .with_example("enabled")
+ .with_example("disabled")
+ .with_description("Overall control for mouse support")
+ .for_field<>(&_lnav_config::lc_mouse_mode),
+};
+
static const struct json_path_container global_var_handlers = {
yajlpp::pattern_property_handler("(?<var_name>\\w+)")
.with_synopsis("<name>")
@@ -595,6 +645,10 @@ static const struct json_path_container theme_styles_handlers = {
.with_description("Styling for plain text")
.for_child(&lnav_theme::lt_style_text)
.with_children(style_config_handlers),
+ yajlpp::property_handler("selected-text")
+ .with_description("Styling for text selected in a view")
+ .for_child(&lnav_theme::lt_style_selected_text)
+ .with_children(style_config_handlers),
yajlpp::property_handler("alt-text")
.with_description("Styling for plain text when alternating")
.for_child(&lnav_theme::lt_style_alt_text)
@@ -623,6 +677,10 @@ static const struct json_path_container theme_styles_handlers = {
.with_description("Styling for the cursor line in the main view")
.for_child(&lnav_theme::lt_style_cursor_line)
.with_children(style_config_handlers),
+ yajlpp::property_handler("disabled-cursor-line")
+ .with_description("Styling for the cursor line when it is disabled")
+ .for_child(&lnav_theme::lt_style_disabled_cursor_line)
+ .with_children(style_config_handlers),
yajlpp::property_handler("adjusted-time")
.with_description("Styling for timestamps that have been adjusted")
.for_child(&lnav_theme::lt_style_adjusted_time)
@@ -632,8 +690,12 @@ static const struct json_path_container theme_styles_handlers = {
"Styling for timestamps that are different from the received time")
.for_child(&lnav_theme::lt_style_skewed_time)
.with_children(style_config_handlers),
+ yajlpp::property_handler("file-offset")
+ .with_description("Styling for a file offset")
+ .for_child(&lnav_theme::lt_style_file_offset)
+ .with_children(style_config_handlers),
yajlpp::property_handler("offset-time")
- .with_description("Styling for hidden fields")
+ .with_description("Styling for the elapsed time column")
.for_child(&lnav_theme::lt_style_offset_time)
.with_children(style_config_handlers),
yajlpp::property_handler("invalid-msg")
@@ -660,6 +722,12 @@ static const struct json_path_container theme_styles_handlers = {
.with_description("Styling for top-level headers")
.with_obj_provider<style_config, lnav_theme>(
[](const yajlpp_provider_context& ypc, lnav_theme* root) {
+ if (ypc.ypc_parse_context != nullptr
+ && root->lt_style_header[0].pp_path.empty())
+ {
+ root->lt_style_header[0].pp_path
+ = ypc.ypc_parse_context->get_full_path();
+ }
return &root->lt_style_header[0].pp_value;
})
.with_children(style_config_handlers),
@@ -667,6 +735,12 @@ static const struct json_path_container theme_styles_handlers = {
.with_description("Styling for 2nd-level headers")
.with_obj_provider<style_config, lnav_theme>(
[](const yajlpp_provider_context& ypc, lnav_theme* root) {
+ if (ypc.ypc_parse_context != nullptr
+ && root->lt_style_header[1].pp_path.empty())
+ {
+ root->lt_style_header[1].pp_path
+ = ypc.ypc_parse_context->get_full_path();
+ }
return &root->lt_style_header[1].pp_value;
})
.with_children(style_config_handlers),
@@ -674,6 +748,12 @@ static const struct json_path_container theme_styles_handlers = {
.with_description("Styling for 3rd-level headers")
.with_obj_provider<style_config, lnav_theme>(
[](const yajlpp_provider_context& ypc, lnav_theme* root) {
+ if (ypc.ypc_parse_context != nullptr
+ && root->lt_style_header[2].pp_path.empty())
+ {
+ root->lt_style_header[2].pp_path
+ = ypc.ypc_parse_context->get_full_path();
+ }
return &root->lt_style_header[2].pp_value;
})
.with_children(style_config_handlers),
@@ -681,6 +761,12 @@ static const struct json_path_container theme_styles_handlers = {
.with_description("Styling for 4th-level headers")
.with_obj_provider<style_config, lnav_theme>(
[](const yajlpp_provider_context& ypc, lnav_theme* root) {
+ if (ypc.ypc_parse_context != nullptr
+ && root->lt_style_header[3].pp_path.empty())
+ {
+ root->lt_style_header[3].pp_path
+ = ypc.ypc_parse_context->get_full_path();
+ }
return &root->lt_style_header[3].pp_value;
})
.with_children(style_config_handlers),
@@ -688,6 +774,12 @@ static const struct json_path_container theme_styles_handlers = {
.with_description("Styling for 5th-level headers")
.with_obj_provider<style_config, lnav_theme>(
[](const yajlpp_provider_context& ypc, lnav_theme* root) {
+ if (ypc.ypc_parse_context != nullptr
+ && root->lt_style_header[4].pp_path.empty())
+ {
+ root->lt_style_header[4].pp_path
+ = ypc.ypc_parse_context->get_full_path();
+ }
return &root->lt_style_header[4].pp_value;
})
.with_children(style_config_handlers),
@@ -695,6 +787,12 @@ static const struct json_path_container theme_styles_handlers = {
.with_description("Styling for 6th-level headers")
.with_obj_provider<style_config, lnav_theme>(
[](const yajlpp_provider_context& ypc, lnav_theme* root) {
+ if (ypc.ypc_parse_context != nullptr
+ && root->lt_style_header[5].pp_path.empty())
+ {
+ root->lt_style_header[5].pp_path
+ = ypc.ypc_parse_context->get_full_path();
+ }
return &root->lt_style_header[5].pp_value;
})
.with_children(style_config_handlers),
@@ -742,9 +840,17 @@ static const struct json_path_container theme_styles_handlers = {
.with_description("Styling for snippet borders")
.for_child(&lnav_theme::lt_style_snippet_border)
.with_children(style_config_handlers),
+ yajlpp::property_handler("indent-guide")
+ .with_description("Styling for indent guide lines")
+ .for_child(&lnav_theme::lt_style_indent_guide)
+ .with_children(style_config_handlers),
};
static const struct json_path_container theme_syntax_styles_handlers = {
+ yajlpp::property_handler("inline-code")
+ .with_description("Styling for inline code blocks")
+ .for_child(&lnav_theme::lt_style_inline_code)
+ .with_children(style_config_handlers),
yajlpp::property_handler("quoted-code")
.with_description("Styling for quoted code blocks")
.for_child(&lnav_theme::lt_style_quoted_code)
@@ -778,10 +884,35 @@ static const struct json_path_container theme_syntax_styles_handlers = {
.with_description("Styling for symbols in source files")
.for_child(&lnav_theme::lt_style_symbol)
.with_children(style_config_handlers),
+ yajlpp::property_handler("null")
+ .with_description("Styling for nulls in source files")
+ .for_child(&lnav_theme::lt_style_null)
+ .with_children(style_config_handlers),
+ yajlpp::property_handler("ascii-control")
+ .with_description(
+ "Styling for ASCII control characters in source files")
+ .for_child(&lnav_theme::lt_style_ascii_ctrl)
+ .with_children(style_config_handlers),
+ yajlpp::property_handler("non-ascii")
+ .with_description("Styling for non-ASCII characters in source files")
+ .for_child(&lnav_theme::lt_style_non_ascii)
+ .with_children(style_config_handlers),
yajlpp::property_handler("number")
.with_description("Styling for numbers in source files")
.for_child(&lnav_theme::lt_style_number)
.with_children(style_config_handlers),
+ yajlpp::property_handler("type")
+ .with_description("Styling for types in source files")
+ .for_child(&lnav_theme::lt_style_type)
+ .with_children(style_config_handlers),
+ yajlpp::property_handler("function")
+ .with_description("Styling for functions in source files")
+ .for_child(&lnav_theme::lt_style_function)
+ .with_children(style_config_handlers),
+ yajlpp::property_handler("separators-references-accessors")
+ .with_description("Styling for sigils in source files")
+ .for_child(&lnav_theme::lt_style_sep_ref_acc)
+ .with_children(style_config_handlers),
yajlpp::property_handler("re-special")
.with_description(
"Styling for special characters in regular expressions")
@@ -876,6 +1007,10 @@ static const struct json_path_container theme_status_styles_handlers = {
.with_description("Styling for hotkey highlights of status bars")
.for_child(&lnav_theme::lt_style_status_hotkey)
.with_children(style_config_handlers),
+ yajlpp::property_handler("suggestion")
+ .with_description("Styling for suggested values")
+ .for_child(&lnav_theme::lt_style_suggestion)
+ .with_children(style_config_handlers),
};
static const struct json_path_container theme_log_level_styles_handlers = {
@@ -1029,6 +1164,9 @@ static const struct json_path_container ui_handlers = {
yajlpp::property_handler("theme-defs")
.with_description("Theme definitions.")
.with_children(theme_defs_handlers),
+ yajlpp::property_handler("mouse")
+ .with_description("Mouse-related settings")
+ .with_children(mouse_handlers),
yajlpp::property_handler("movement")
.with_description("Log file cursor movement mode settings")
.with_children(movement_handlers),
@@ -1057,6 +1195,27 @@ static const struct json_path_container archive_handlers = {
&archive_manager::config::amc_cache_ttl),
};
+static const struct json_path_container piper_handlers = {
+ yajlpp::property_handler("max-size")
+ .with_synopsis("<bytes>")
+ .with_description("The maximum size of a capture file")
+ .with_min_value(128)
+ .for_field(&_lnav_config::lc_piper, &lnav::piper::config::c_max_size),
+ yajlpp::property_handler("rotations")
+ .with_synopsis("<count>")
+ .with_min_value(2)
+ .with_description("The number of rotated files to keep")
+ .for_field(&_lnav_config::lc_piper, &lnav::piper::config::c_rotations),
+ yajlpp::property_handler("ttl")
+ .with_synopsis("<duration>")
+ .with_description(
+ "The time-to-live for captured data, expressed as a duration "
+ "(e.g. '3d' for three days)")
+ .with_example("3d")
+ .with_example("12h")
+ .for_field(&_lnav_config::lc_piper, &lnav::piper::config::c_ttl),
+};
+
static const struct json_path_container file_vtab_handlers = {
yajlpp::property_handler("max-content-size")
.with_synopsis("<bytes>")
@@ -1211,7 +1370,7 @@ static const struct json_path_container log_source_watch_expr_handlers = {
};
static const struct json_path_container log_source_watch_handlers = {
- yajlpp::pattern_property_handler("(?<watch_name>[\\w\\-]+)")
+ yajlpp::pattern_property_handler("(?<watch_name>[\\w\\.\\-]+)")
.with_synopsis("<name>")
.with_description("A log message watch expression")
.with_obj_provider<logfile_sub_source_ns::watch_expression,
@@ -1235,16 +1394,98 @@ static const struct json_path_container log_source_watch_handlers = {
.with_children(log_source_watch_expr_handlers),
};
+static const struct json_path_container annotation_handlers = {
+ yajlpp::property_handler("description")
+ .with_synopsis("<text>")
+ .with_description("A description of this annotation")
+ .for_field(&lnav::log::annotate::annotation_def::a_description),
+ yajlpp::property_handler("condition")
+ .with_synopsis("<SQL-expression>")
+ .with_description(
+ "The SQLite expression to execute for a log message that "
+ "determines whether or not this annotation is applicable. The "
+ "expression is evaluated the same way as a filter expression")
+ .with_min_length(1)
+ .for_field(&lnav::log::annotate::annotation_def::a_condition),
+ yajlpp::property_handler("handler")
+ .with_synopsis("<script>")
+ .with_description("The script to execute to generate the annotation "
+ "content. A JSON object with the log message content "
+ "will be sent to the script on the standard input")
+ .with_min_length(1)
+ .for_field(&lnav::log::annotate::annotation_def::a_handler),
+};
+
+static const struct json_path_container annotations_handlers = {
+ yajlpp::pattern_property_handler(R"((?<annotation_name>[\w\.\-]+))")
+ .with_obj_provider<lnav::log::annotate::annotation_def, _lnav_config>(
+ [](const yajlpp_provider_context& ypc, _lnav_config* root) {
+ auto* retval = &(root->lc_log_annotations
+ .a_definitions[ypc.get_substr_i(0)]);
+
+ return retval;
+ })
+ .with_path_provider<_lnav_config>(
+ [](struct _lnav_config* cfg, std::vector<std::string>& paths_out) {
+ for (const auto& iter : cfg->lc_log_annotations.a_definitions) {
+ paths_out.emplace_back(iter.first.to_string());
+ }
+ })
+ .with_children(annotation_handlers),
+};
+
+static const struct json_path_container log_date_time_handlers = {
+ yajlpp::property_handler("convert-zoned-to-local")
+ .with_description("Convert timestamps with ")
+ .with_pattern(R"(^[\w\-]+(?!\.lnav)$)")
+ .for_field(&_lnav_config::lc_log_date_time,
+ &date_time_scanner_ns::config::c_zoned_to_local),
+};
+
static const struct json_path_container log_source_handlers = {
+ yajlpp::property_handler("date-time")
+ .with_description("Settings related to log message dates and times")
+ .with_children(log_date_time_handlers),
yajlpp::property_handler("watch-expressions")
.with_description("Log message watch expressions")
.with_children(log_source_watch_handlers),
+ yajlpp::property_handler("annotations").with_children(annotations_handlers),
+};
+
+static const struct json_path_container url_scheme_handlers = {
+ yajlpp::property_handler("handler")
+ .with_description(
+ "The name of the lnav script that can handle URLs "
+ "with of this scheme. This should not include the '.lnav' suffix.")
+ .with_pattern(R"(^[\w\-]+(?!\.lnav)$)")
+ .for_field(&lnav::url_handler::scheme::p_handler),
+};
+
+static const struct json_path_container url_handlers = {
+ yajlpp::pattern_property_handler(R"((?<url_scheme>[a-z][\w\-\+\.]+))")
+ .with_description("Definition of a custom URL scheme")
+ .with_obj_provider<lnav::url_handler::scheme, _lnav_config>(
+ [](const yajlpp_provider_context& ypc, _lnav_config* root) {
+ auto& retval = root->lc_url_handlers
+ .c_schemes[ypc.get_substr("url_scheme")];
+ return &retval;
+ })
+ .with_path_provider<_lnav_config>(
+ [](struct _lnav_config* cfg, std::vector<std::string>& paths_out) {
+ for (const auto& iter : cfg->lc_url_handlers.c_schemes) {
+ paths_out.emplace_back(iter.first);
+ }
+ })
+ .with_children(url_scheme_handlers),
};
static const struct json_path_container tuning_handlers = {
yajlpp::property_handler("archive-manager")
.with_description("Settings related to opening archive files")
.with_children(archive_handlers),
+ yajlpp::property_handler("piper")
+ .with_description("Settings related to capturing piped data")
+ .with_children(piper_handlers),
yajlpp::property_handler("file-vtab")
.with_description("Settings related to the lnav_file virtual-table")
.with_children(file_vtab_handlers),
@@ -1257,6 +1498,9 @@ static const struct json_path_container tuning_handlers = {
yajlpp::property_handler("clipboard")
.with_description("Settings related to the clipboard")
.with_children(sysclip_handlers),
+ yajlpp::property_handler("url-scheme")
+ .with_description("Settings related to custom URL handling")
+ .with_children(url_handlers),
};
const char* DEFAULT_CONFIG_SCHEMA
@@ -1288,10 +1532,10 @@ read_id(yajlpp_parse_context* ypc, const unsigned char* str, size_t len)
}
ypc->report_error(
lnav::console::user_message::error(
- attr_line_t("'")
- .append(lnav::roles::symbol(file_id))
+ attr_line_t()
+ .append_quoted(lnav::roles::symbol(file_id))
.append(
- "' is not a supported configuration $schema version"))
+ " is not a supported configuration $schema version"))
.with_snippet(ypc->get_snippet())
.with_note(notes)
.with_help(handler->get_help_text(ypc)));
@@ -1326,14 +1570,74 @@ const json_path_container lnav_config_handlers = json_path_container {
class active_key_map_listener : public lnav_config_listener {
public:
+ active_key_map_listener() : lnav_config_listener(__FILE__) {}
+
void reload_config(error_reporter& reporter) override
{
lnav_config.lc_active_keymap = lnav_config.lc_ui_keymaps["default"];
for (const auto& pair :
lnav_config.lc_ui_keymaps[lnav_config.lc_ui_keymap].km_seq_to_cmd)
{
- lnav_config.lc_active_keymap.km_seq_to_cmd[pair.first]
- = pair.second;
+ if (pair.second.kc_cmd.pp_value.empty()) {
+ lnav_config.lc_active_keymap.km_seq_to_cmd.erase(pair.first);
+ } else {
+ lnav_config.lc_active_keymap.km_seq_to_cmd[pair.first]
+ = pair.second;
+ }
+ }
+
+ auto& ec = injector::get<exec_context&>();
+ for (const auto& pair : lnav_config.lc_active_keymap.km_seq_to_cmd) {
+ if (pair.second.kc_id.empty()) {
+ continue;
+ }
+
+ auto keyseq_sf = string_fragment::from_str(pair.first);
+ std::string keystr;
+ if (keyseq_sf.startswith("f")) {
+ auto sv = keyseq_sf.to_string_view();
+ int32_t value;
+ auto scan_res = scn::scan(sv, "f{}", value);
+ if (!scan_res) {
+ log_error("invalid function key sequence: %s", keyseq_sf);
+ continue;
+ }
+ if (value < 0 || value > 64) {
+ log_error("invalid function key number: %s", keyseq_sf);
+ continue;
+ }
+
+ keystr = toupper(pair.first);
+ } else {
+ auto sv
+ = string_fragment::from_str(pair.first).to_string_view();
+ while (!sv.empty()) {
+ int32_t value;
+ auto scan_res = scn::scan(sv, "x{:2x}", value);
+ if (!scan_res) {
+ log_error("invalid key sequence: %s",
+ pair.first.c_str());
+ break;
+ }
+ auto ch = (char) (value & 0xff);
+ switch (ch) {
+ case '\t':
+ keystr.append("TAB");
+ break;
+ case '\r':
+ keystr.append("ENTER");
+ break;
+ default:
+ keystr.push_back(ch);
+ break;
+ }
+ sv = scan_res.range_as_string_view();
+ }
+ }
+
+ if (!keystr.empty()) {
+ ec.ec_global_vars[pair.second.kc_id] = keystr;
+ }
}
}
};
@@ -1398,11 +1702,10 @@ load_config_from(_lnav_config& lconfig,
.with_errno_reason());
}
} else {
- auto_mem<yajl_handle_t> handle(yajl_free);
char buffer[2048];
ssize_t rc = -1;
- handle = yajl_alloc(&ypc.ypc_callbacks, nullptr, &ypc);
+ auto handle = yajlpp::alloc_handle(&ypc.ypc_callbacks, &ypc);
yajl_config(handle, yajl_allow_comments, 1);
yajl_config(handle, yajl_allow_multiple_values, 1);
ypc.ypc_handle = handle;
@@ -1438,10 +1741,10 @@ load_default_config(struct _lnav_config& config_obj,
{
yajlpp_parse_context ypc_builtin(intern_string::lookup(bsf.get_name()),
&lnav_config_handlers);
- auto_mem<yajl_handle_t> handle(yajl_free);
struct config_userdata ud(errors);
- handle = yajl_alloc(&ypc_builtin.ypc_callbacks, nullptr, &ypc_builtin);
+ auto handle
+ = yajlpp::alloc_handle(&ypc_builtin.ypc_callbacks, &ypc_builtin);
ypc_builtin.ypc_locations = &lnav_config_locations;
ypc_builtin.with_handle(handle);
ypc_builtin.with_obj(config_obj);
@@ -1455,9 +1758,7 @@ load_default_config(struct _lnav_config& config_obj,
yajl_config(handle, yajl_allow_comments, 1);
yajl_config(handle, yajl_allow_multiple_values, 1);
- if (ypc_builtin.parse(bsf.to_string_fragment()) == yajl_status_ok) {
- ypc_builtin.complete_parse();
- }
+ ypc_builtin.parse_doc(bsf.to_string_fragment());
return path == "*" || ypc_builtin.ypc_active_paths.empty();
}
@@ -1541,6 +1842,19 @@ load_config(const std::vector<ghc::filesystem::path>& extra_paths,
rollback_lnav_config = lnav_config;
}
+std::string
+dump_config()
+{
+ yajlpp_gen gen;
+ yajlpp_gen_context ygc(gen, lnav_config_handlers);
+
+ yajl_gen_config(gen, yajl_gen_beautify, true);
+ ygc.with_obj(lnav_config);
+ ygc.gen();
+
+ return gen.to_string_fragment().to_string();
+}
+
void
reset_config(const std::string& path)
{
@@ -1627,36 +1941,46 @@ save_config()
void
reload_config(std::vector<lnav::console::user_message>& errors)
{
- lnav_config_listener* curr = lnav_config_listener::LISTENER_LIST;
+ auto* curr = lnav_config_listener::LISTENER_LIST;
while (curr != nullptr) {
auto reporter = [&errors](const void* cfg_value,
const lnav::console::user_message& errmsg) {
+ log_error("configuration error: %s",
+ errmsg.to_attr_line().get_string().c_str());
auto cb = [&cfg_value, &errors, &errmsg](
const json_path_handler_base& jph,
const std::string& path,
- void* mem) {
+ const void* mem) {
if (mem != cfg_value) {
return;
}
auto loc_iter
= lnav_config_locations.find(intern_string::lookup(path));
- if (loc_iter == lnav_config_locations.end()) {
- return;
+ auto has_loc = loc_iter != lnav_config_locations.end();
+ auto um = has_loc
+ ? lnav::console::user_message::error(
+ attr_line_t()
+ .append("invalid value for property ")
+ .append_quoted(lnav::roles::symbol(path)))
+ .with_reason(errmsg)
+ : errmsg;
+ um.with_help(jph.get_help_text(path));
+
+ if (has_loc) {
+ um.with_snippet(
+ lnav::console::snippet::from(loc_iter->second.sl_source,
+ "")
+ .with_line(loc_iter->second.sl_line_number));
+ } else {
+ um.um_message
+ = attr_line_t()
+ .append("missing value for property ")
+ .append_quoted(lnav::roles::symbol(path));
}
- errors.emplace_back(
- lnav::console::user_message::error(
- attr_line_t()
- .append("invalid value for property ")
- .append_quoted(lnav::roles::symbol(path)))
- .with_reason(errmsg)
- .with_snippet(
- lnav::console::snippet::from(
- loc_iter->second.sl_source, "")
- .with_line(loc_iter->second.sl_line_number))
- .with_help(jph.get_help_text(path)));
+ errors.emplace_back(um);
};
for (const auto& jph : lnav_config_handlers.jpc_children) {