[readline] add support for default completions

pull/1242/head
Tim Stack 3 months ago
parent db5db6a07e
commit 6bb616e034

@ -7,6 +7,11 @@ Interface changes:
configuration panel instead of `q`. This should make
it easier to avoid accidentally exiting lnav.
* Added some default help text for the command prompt.
* Suggestions are now shown for some commands and can
be accepted by pressing the right arrow key. For
example, after typing in `:filter-in` the current
search term for the view will be suggested (if
one is active).
## lnav v0.12.0

@ -680,6 +680,11 @@
"description": "Styling for hotkey highlights of status bars",
"title": "/ui/theme-defs/<theme_name>/status-styles/hotkey",
"$ref": "#/definitions/style"
},
"suggestion": {
"description": "Styling for suggested values",
"title": "/ui/theme-defs/<theme_name>/status-styles/suggestion",
"$ref": "#/definitions/style"
}
},
"additionalProperties": false

@ -135,6 +135,7 @@ enum class role_t : int32_t {
VCR_FUNCTION,
VCR_TYPE,
VCR_SEP_REF_ACC,
VCR_SUGGESTION,
VCR__MAX
};
@ -535,6 +536,14 @@ h6(S str)
VC_ROLE.template value(role_t::VCR_H6));
}
template<typename S>
inline std::pair<S, string_attr_pair>
suggestion(S str)
{
return std::make_pair(std::move(str),
VC_ROLE.template value(role_t::VCR_SUGGESTION));
}
namespace literals {
inline std::pair<std::string, string_attr_pair> operator"" _ok(const char* str,

@ -300,6 +300,8 @@ breadcrumb_curses::handle_key(int ch)
case '\r':
this->perform_selection(perform_behavior_t::always);
break;
case KEY_ESCAPE:
break;
default:
if (isprint(ch)) {
this->bc_current_search.push_back(ch);

@ -151,9 +151,9 @@ filter_sub_source::list_input_handle_key(listview_curses& lv, int ch)
return true;
}
case 'i': {
textview_curses* top_view = *lnav_data.ld_view_stack.top();
text_sub_source* tss = top_view->get_sub_source();
filter_stack& fs = tss->get_filters();
auto* top_view = *lnav_data.ld_view_stack.top();
auto* tss = top_view->get_sub_source();
auto& fs = tss->get_filters();
auto filter_index = fs.next_index();
if (!filter_index) {
@ -434,25 +434,32 @@ filter_sub_source::rl_change(readline_curses* rc)
case filter_lang_t::NONE:
break;
case filter_lang_t::REGEX: {
auto regex_res
= lnav::pcre2pp::code::from(new_value, PCRE2_CASELESS);
if (regex_res.isErr()) {
auto pe = regex_res.unwrapErr();
lnav_data.ld_filter_help_status_source.fss_error.set_value(
"error: %s", pe.get_message().c_str());
if (new_value.empty()) {
if (fs.get_filter(top_view->get_current_search()) == nullptr) {
this->fss_editor->set_suggestion(
top_view->get_current_search());
}
} else {
auto& hm = top_view->get_highlights();
highlighter hl(regex_res.unwrap().to_shared());
auto role = tf->get_type() == text_filter::EXCLUDE
? role_t::VCR_DIFF_DELETE
: role_t::VCR_DIFF_ADD;
hl.with_role(role);
hl.with_attrs(text_attrs{A_BLINK | A_REVERSE});
hm[{highlight_source_t::PREVIEW, "preview"}] = hl;
top_view->set_needs_update();
lnav_data.ld_filter_help_status_source.fss_error.clear();
auto regex_res
= lnav::pcre2pp::code::from(new_value, PCRE2_CASELESS);
if (regex_res.isErr()) {
auto pe = regex_res.unwrapErr();
lnav_data.ld_filter_help_status_source.fss_error.set_value(
"error: %s", pe.get_message().c_str());
} else {
auto& hm = top_view->get_highlights();
highlighter hl(regex_res.unwrap().to_shared());
auto role = tf->get_type() == text_filter::EXCLUDE
? role_t::VCR_DIFF_DELETE
: role_t::VCR_DIFF_ADD;
hl.with_role(role);
hl.with_attrs(text_attrs{A_BLINK | A_REVERSE});
hm[{highlight_source_t::PREVIEW, "preview"}] = hl;
top_view->set_needs_update();
lnav_data.ld_filter_help_status_source.fss_error.clear();
}
}
break;
}

@ -895,7 +895,7 @@ handle_key(int ch)
return handle_paging_key(ch);
case ln_mode_t::BREADCRUMBS:
if (!breadcrumb_view.handle_key(ch)) {
if (ch == '`' || !breadcrumb_view.handle_key(ch)) {
lnav_data.ld_mode = ln_mode_t::PAGING;
lnav_data.ld_view_stack.set_needs_update();
return true;

@ -436,47 +436,68 @@ com_set_file_timezone(exec_context& ec,
return Ok(retval);
}
static std::string
static readline_context::prompt_result_t
com_set_file_timezone_prompt(exec_context& ec, const std::string& cmdline)
{
std::string retval;
auto* tc = *lnav_data.ld_view_stack.top();
auto* lss = dynamic_cast<logfile_sub_source*>(tc->get_sub_source());
if (lss != nullptr && lss->text_line_count() > 0) {
auto line_pair = lss->find_line_with_file(lss->at(tc->get_selection()));
if (line_pair) {
try {
static auto& safe_options_hier
= injector::get<lnav::safe_file_options_hier&>();
if (lss == nullptr || lss->text_line_count() == 0) {
return {};
}
safe::ReadAccess<lnav::safe_file_options_hier> options_hier(
safe_options_hier);
auto file_zone = date::get_tzdb().current_zone()->name();
auto pattern_arg = line_pair->first->get_filename();
auto match_res
= options_hier->match(line_pair->first->get_filename());
if (match_res) {
file_zone
= match_res->second.fo_default_zone.pp_value->name();
pattern_arg = match_res->first;
}
shlex lexer(cmdline);
auto split_res = lexer.split(ec.create_resolver());
if (split_res.isErr()) {
return {};
}
retval = fmt::format(FMT_STRING("{} {} {}"),
trim(cmdline),
date::get_tzdb().current_zone()->name(),
pattern_arg);
} catch (const std::runtime_error& e) {
log_error("cannot get timezones: %s", e.what());
auto line_pair = lss->find_line_with_file(lss->at(tc->get_selection()));
if (!line_pair) {
return {};
}
auto elems = split_res.unwrap();
auto pattern_arg = line_pair->first->get_filename();
if (elems.size() == 1) {
try {
static auto& safe_options_hier
= injector::get<lnav::safe_file_options_hier&>();
safe::ReadAccess<lnav::safe_file_options_hier> options_hier(
safe_options_hier);
auto file_zone = date::get_tzdb().current_zone()->name();
auto match_res = options_hier->match(pattern_arg);
if (match_res) {
file_zone = match_res->second.fo_default_zone.pp_value->name();
pattern_arg = match_res->first;
auto new_prompt = fmt::format(FMT_STRING("{} {} {}"),
trim(cmdline),
file_zone,
pattern_arg);
return {new_prompt};
}
return {"", file_zone};
} catch (const std::runtime_error& e) {
log_error("cannot get timezones: %s", e.what());
}
}
auto arg_path = ghc::filesystem::path(pattern_arg);
auto arg_parent = arg_path.parent_path().string() + "/";
if (elems.size() == 2 && endswith(cmdline, " ")) {
return {"", arg_parent};
}
if (elems.size() == 3 && elems.back().se_value == arg_parent) {
return {"", arg_path.filename().string()};
}
return retval;
return {};
}
static std::string
static readline_context::prompt_result_t
com_clear_file_timezone_prompt(exec_context& ec, const std::string& cmdline)
{
std::string retval;
@ -511,7 +532,7 @@ com_clear_file_timezone_prompt(exec_context& ec, const std::string& cmdline)
}
}
return retval;
return {retval};
}
static Result<std::string, lnav::console::user_message>
@ -1031,18 +1052,20 @@ com_mark_expr(exec_context& ec,
return Ok(retval);
}
static std::string
static readline_context::prompt_result_t
com_mark_expr_prompt(exec_context& ec, const std::string& cmdline)
{
textview_curses* tc = *lnav_data.ld_view_stack.top();
if (tc != &lnav_data.ld_views[LNV_LOG]) {
return "";
return {""};
}
return fmt::format(FMT_STRING("{} {}"),
trim(cmdline),
trim(lnav_data.ld_log_source.get_sql_marker_text()));
return {
fmt::format(FMT_STRING("{} {}"),
trim(cmdline),
trim(lnav_data.ld_log_source.get_sql_marker_text())),
};
}
static Result<std::string, lnav::console::user_message>
@ -2388,6 +2411,20 @@ com_filter(exec_context& ec,
return Ok(retval);
}
static readline_context::prompt_result_t
com_filter_prompt(exec_context& ec, const std::string& cmdline)
{
const auto* tc = lnav_data.ld_view_stack.top().value();
std::vector<std::string> args;
split_ws(cmdline, args);
if (args.size() > 1) {
return {};
}
return {"", tc->get_current_search()};
}
static Result<std::string, lnav::console::user_message>
com_delete_filter(exec_context& ec,
std::string cmdline,
@ -2564,18 +2601,20 @@ com_filter_expr(exec_context& ec,
return Ok(retval);
}
static std::string
static readline_context::prompt_result_t
com_filter_expr_prompt(exec_context& ec, const std::string& cmdline)
{
textview_curses* tc = *lnav_data.ld_view_stack.top();
auto* tc = *lnav_data.ld_view_stack.top();
if (tc != &lnav_data.ld_views[LNV_LOG]) {
return "";
return {""};
}
return fmt::format(FMT_STRING("{} {}"),
trim(cmdline),
trim(lnav_data.ld_log_source.get_sql_filter_text()));
return {
fmt::format(FMT_STRING("{} {}"),
trim(cmdline),
trim(lnav_data.ld_log_source.get_sql_filter_text())),
};
}
static Result<std::string, lnav::console::user_message>
@ -3616,13 +3655,13 @@ com_comment(exec_context& ec,
return Ok(retval);
}
static std::string
static readline_context::prompt_result_t
com_comment_prompt(exec_context& ec, const std::string& cmdline)
{
textview_curses* tc = *lnav_data.ld_view_stack.top();
auto* tc = *lnav_data.ld_view_stack.top();
if (tc != &lnav_data.ld_views[LNV_LOG]) {
return "";
return {""};
}
auto& lss = lnav_data.ld_log_source;
@ -3633,10 +3672,10 @@ com_comment_prompt(exec_context& ec, const std::string& cmdline)
auto buf = auto_buffer::alloc(trimmed_comment.size() + 16);
quote_content(buf, trimmed_comment, 0);
return trim(cmdline) + " " + buf.to_string();
return {trim(cmdline) + " " + buf.to_string()};
}
return "";
return {""};
}
static Result<std::string, lnav::console::user_message>
@ -6052,30 +6091,37 @@ readline_context::command_t STD_COMMANDS[] = {
.with_opposites({"highlight"})
.with_example(
{"To clear the highlight with the pattern 'foobar'", "foobar"})},
{"filter-in",
com_filter,
{
"filter-in",
com_filter,
help_text(":filter-in")
.with_summary("Only show lines that match the given regular "
"expression in the current view")
.with_parameter(
help_text("pattern", "The regular expression to match"))
.with_tags({"filtering"})
.with_example({"To filter out log messages that do not have the "
"string 'dhclient'",
"dhclient"})},
{"filter-out",
com_filter,
help_text(":filter-out")
.with_summary("Remove lines that match the given regular expression "
"in the current view")
.with_parameter(
help_text("pattern", "The regular expression to match"))
.with_tags({"filtering"})
.with_example({"To filter out log messages that contain the string "
"'last message repeated'",
"last message repeated"})},
help_text(":filter-in")
.with_summary("Only show lines that match the given regular "
"expression in the current view")
.with_parameter(
help_text("pattern", "The regular expression to match"))
.with_tags({"filtering"})
.with_example({"To filter out log messages that do not have the "
"string 'dhclient'",
"dhclient"}),
com_filter_prompt,
},
{
"filter-out",
com_filter,
help_text(":filter-out")
.with_summary(
"Remove lines that match the given regular expression "
"in the current view")
.with_parameter(
help_text("pattern", "The regular expression to match"))
.with_tags({"filtering"})
.with_example({"To filter out log messages that contain the string "
"'last message repeated'",
"last message repeated"}),
com_filter_prompt,
},
{"delete-filter",
com_delete_filter,

@ -969,6 +969,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 = {

@ -116,6 +116,7 @@ private:
};
class generic_log_format : public log_format {
public:
static const pcre_format* get_pcre_log_formats()
{
static const pcre_format log_fmt[] = {
@ -258,6 +259,9 @@ class generic_log_format : public log_format {
auto lr = to_line_range(ts_cap.trim());
sa.emplace_back(lr, logline::L_TIMESTAMP.value());
values.lvv_values.emplace_back(TS_META, line, lr);
values.lvv_values.back().lv_meta.lvm_format = (log_format*) this;
prefix_len = ts_cap.sf_end;
auto level_cap = md[2];
if (level_cap) {
@ -265,6 +269,11 @@ class generic_log_format : public log_format {
!= LEVEL_UNKNOWN)
{
prefix_len = level_cap->sf_end;
values.lvv_values.emplace_back(
LEVEL_META, line, to_line_range(level_cap->trim()));
values.lvv_values.back().lv_meta.lvm_format
= (log_format*) this;
}
}
@ -284,6 +293,41 @@ class generic_log_format : public log_format {
retval->lf_specialized = true;
return retval;
}
bool hide_field(const intern_string_t field_name, bool val) override
{
if (field_name == TS_META.lvm_name) {
TS_META.lvm_user_hidden = val;
return true;
} else if (field_name == LEVEL_META.lvm_name) {
LEVEL_META.lvm_user_hidden = val;
return true;
}
return false;
}
std::map<intern_string_t, logline_value_meta> get_field_states() override
{
return {
{TS_META.lvm_name, TS_META},
{LEVEL_META.lvm_name, LEVEL_META},
};
}
private:
static logline_value_meta TS_META;
static logline_value_meta LEVEL_META;
};
logline_value_meta generic_log_format::TS_META{
intern_string::lookup("log_time"),
value_kind_t::VALUE_TEXT,
logline_value_meta::table_column{2},
};
logline_value_meta generic_log_format::LEVEL_META{
intern_string::lookup("log_level"),
value_kind_t::VALUE_TEXT,
logline_value_meta::table_column{4},
};
std::string

@ -326,7 +326,9 @@ rl_change(readline_curses* rc)
if (!args.empty()) {
iter = lnav_commands.find(args[0]);
}
if (iter == lnav_commands.end()) {
if (iter == lnav_commands.end()
|| (args.size() == 1 && !endswith(line, " ")))
{
lnav_data.ld_doc_source.replace_with(CMD_HELP);
lnav_data.ld_example_source.replace_with(CMD_EXAMPLE);
lnav_data.ld_preview_source.clear();
@ -361,12 +363,12 @@ rl_change(readline_curses* rc)
} else if ((args[0] != "filter-expr" && args[0] != "mark-expr")
|| !rl_sql_help(rc))
{
readline_context::command_t& cmd = *iter->second;
const help_text& ht = cmd.c_help;
const auto& cmd = *iter->second;
const auto& ht = cmd.c_help;
if (ht.ht_name) {
textview_curses& dtc = lnav_data.ld_doc_view;
textview_curses& etc = lnav_data.ld_example_view;
auto& dtc = lnav_data.ld_doc_view;
auto& etc = lnav_data.ld_example_view;
unsigned long width;
vis_line_t height;
attr_line_t al;
@ -383,15 +385,17 @@ rl_change(readline_curses* rc)
etc.set_needs_update();
}
if (cmd.c_prompt != nullptr && generation == 0
&& trim(line) == args[0])
{
const auto new_prompt
if (cmd.c_prompt != nullptr) {
const auto prompt_res
= cmd.c_prompt(lnav_data.ld_exec_context, line);
if (!new_prompt.empty()) {
rc->rewrite_line(line.length(), new_prompt);
if (generation == 0 && trim(line) == args[0]
&& !prompt_res.pr_new_prompt.empty())
{
rc->rewrite_line(line.length(),
prompt_res.pr_new_prompt);
}
rc->set_suggestion(prompt_res.pr_suggestion);
}
lnav_data.ld_bottom_source.grep_error("");

@ -53,10 +53,16 @@ typedef void (*readline_highlighter_t)(attr_line_t& line, int x);
*/
class readline_context {
public:
typedef Result<std::string, lnav::console::user_message> (*command_func_t)(
using command_func_t = Result<std::string, lnav::console::user_message> (*)(
exec_context& ec, std::string cmdline, std::vector<std::string>& args);
typedef std::string (*prompt_func_t)(exec_context& ec,
const std::string& cmdline);
struct prompt_result_t {
std::string pr_new_prompt;
std::string pr_suggestion;
};
using prompt_func_t
= prompt_result_t (*)(exec_context& ec, const std::string& cmdline);
typedef struct _command_t {
const char* c_name;
command_func_t c_func;
@ -113,10 +119,7 @@ public:
return *this;
}
int get_append_character() const
{
return this->rc_append_character;
}
int get_append_character() const { return this->rc_append_character; }
readline_context& set_highlighter(readline_highlighter_t hl)
{

@ -92,6 +92,8 @@ static const char* RL_INIT[] = {
"set menu-complete-display-prefix on",
"TAB: menu-complete",
"\"\\e[Z\": menu-complete-backward",
"\"\\eC\": lnav-forward-complete",
"\"\\C-f\": lnav-forward-complete",
};
readline_context* readline_context::loaded_context;
@ -100,6 +102,7 @@ static std::string last_match_str;
static bool last_match_str_valid;
static bool arg_needs_shlex;
static nonstd::optional<std::string> rewrite_line_start;
static std::string rc_local_suggestion;
static void
sigalrm(int sig)
@ -542,6 +545,22 @@ readline_context::attempted_completion(const char* text, int start, int end)
return retval;
}
static int
lnav_forward_complete(int count, int key)
{
if (!rc_local_suggestion.empty() && rl_point == rl_end) {
rl_extend_line_buffer(strlen(rl_line_buffer)
+ rc_local_suggestion.size() + 1);
strcat(rl_line_buffer, rc_local_suggestion.c_str());
rl_point = strlen(rl_line_buffer);
rl_end = rl_point;
rc_local_suggestion.clear();
return 0;
}
return rl_forward_char(count, key);
}
static int
rubout_char_or_abort(int count, int key)
{
@ -828,6 +847,7 @@ readline_curses::start()
using_history();
stifle_history(HISTORY_SIZE);
rl_add_defun("lnav-forward-complete", lnav_forward_complete, -1);
rl_add_defun("rubout-char-or-abort", rubout_char_or_abort, '\b');
rl_add_defun("alt-done", alt_done_func, '\x0a');
// rl_add_defun("command-complete", readline_context::command_complete,
@ -835,7 +855,10 @@ readline_curses::start()
for (const auto* init_cmd : RL_INIT) {
snprintf(buffer, sizeof(buffer), "%s", init_cmd);
rl_parse_and_bind(buffer); /* NOTE: buffer is modified */
/* NOTE: buffer is modified */
if (rl_parse_and_bind(buffer)) {
log_error("rl_parse_and_bind(%s) failed", init_cmd);
}
}
child_this = this;
@ -964,6 +987,8 @@ readline_curses::start()
const char* cwd = &msg[3];
log_perror(chdir(cwd));
} else if (startswith(msg, "sugg:")) {
rc_local_suggestion = &msg[5];
} else if (sscanf(msg, "i:%d:%n", &rl_point, &prompt_start)
== 1)
{
@ -1213,6 +1238,7 @@ readline_curses::check_poll_set(const std::vector<struct pollfd>& pollfds)
if (rc > 0) {
int old_x = this->vc_x;
this->rc_suggestion.clear();
this->map_output(buffer, rc);
if (this->vc_x != old_x) {
this->rc_change(this);
@ -1300,6 +1326,7 @@ readline_curses::check_poll_set(const std::vector<struct pollfd>& pollfds)
case 'l':
this->rc_line_buffer = &msg[2];
if (this->rc_active_context != -1) {
this->rc_suggestion.clear();
this->rc_change(this);
}
this->rc_matches.clear();
@ -1310,6 +1337,7 @@ readline_curses::check_poll_set(const std::vector<struct pollfd>& pollfds)
case 'c':
this->rc_line_buffer = &msg[2];
this->rc_suggestion.clear();
this->rc_change(this);
this->rc_display_match(this);
break;
@ -1361,8 +1389,13 @@ readline_curses::focus(int context,
{
perror("focus: write failed");
}
wmove(this->vc_window, this->get_actual_y(), this->vc_left);
wclrtoeol(this->vc_window);
auto al = attr_line_t();
al.append(lnav::roles::suggestion(this->rc_suggestion));
view_curses::mvwattrline(this->vc_window,
this->get_actual_y(),
this->vc_left,
al,
line_range{0, (int) this->get_actual_width()});
if (!initial.empty()) {
this->rewrite_line(initial.size(), initial);
}
@ -1384,6 +1417,21 @@ readline_curses::rewrite_line(int pos, const std::string& value)
}
}
void
readline_curses::set_suggestion(const std::string& value)
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "sugg:%s", value.c_str());
if (sendstring(
this->rc_command_pipe[RCF_MASTER], buffer, strlen(buffer) + 1)
== -1)
{
perror("set_suggestion: write failed");
}
this->rc_suggestion = value;
}
void
readline_curses::abort()
{
@ -1543,13 +1591,14 @@ readline_curses::do_update()
}
if (this->rc_active_context != -1) {
readline_context* rc = this->rc_contexts[this->rc_active_context];
readline_highlighter_t hl = rc->get_highlighter();
attr_line_t al = this->vc_line;
auto* rc = this->rc_contexts[this->rc_active_context];
auto hl = rc->get_highlighter();
auto al = this->vc_line;
if (hl != nullptr) {
hl(al, this->vc_left + this->vc_x);
}
al.append(lnav::roles::suggestion(this->rc_suggestion));
view_curses::mvwattrline(this->vc_window,
this->get_actual_y(),
this->vc_left,

@ -171,6 +171,8 @@ public:
void rewrite_line(int pos, const std::string& value);
void set_suggestion(const std::string& value);
readline_context* get_active_context() const
{
require(this->rc_active_context != -1);
@ -328,6 +330,7 @@ private:
bool rc_is_alt_focus{false};
bool rc_ready_for_input{false};
std::string rc_remote_complete_path;
std::string rc_suggestion;
action rc_focus;
action rc_change;

@ -151,7 +151,9 @@ shlex::tokenize()
switch (this->s_state) {
case state_t::STATE_NORMAL:
retval.tr_frag.sf_begin = this->s_index;
while (isspace(this->s_str[this->s_index])) {
while (this->s_index < this->s_len
&& isspace(this->s_str[this->s_index]))
{
this->s_index += 1;
}
retval.tr_frag.sf_end = this->s_index;
@ -345,11 +347,13 @@ shlex::split(const scoped_resolver& vars)
auto tokenize_res = TRY(this->tokenize());
if (start_new) {
retval.emplace_back(split_element_t{
string_fragment::from_byte_range(
this->s_str, last_index, tokenize_res.tr_frag.sf_begin),
"",
});
if (last_index < this->s_len) {
retval.emplace_back(split_element_t{
string_fragment::from_byte_range(
this->s_str, last_index, tokenize_res.tr_frag.sf_begin),
"",
});
}
start_new = false;
} else if (tokenize_res.tr_token != shlex_token_t::whitespace) {
retval.back().se_origin.sf_end = tokenize_res.tr_frag.sf_end;

@ -147,6 +147,7 @@ struct lnav_theme {
positioned_property<style_config> lt_style_function;
positioned_property<style_config> lt_style_type;
positioned_property<style_config> lt_style_sep_ref_acc;
positioned_property<style_config> lt_style_suggestion;
positioned_property<style_config> lt_style_re_special;
positioned_property<style_config> lt_style_re_repeat;
positioned_property<style_config> lt_style_diff_delete;

@ -283,6 +283,9 @@
"inactive-alert": {
"color": "$red",
"background-color": "#2f2f2f"
},
"suggestion": {
"color": "#888"
}
},
"log-level-styles": {

@ -278,6 +278,9 @@
"inactive-alert": {
"color": "$red",
"background-color": "Grey"
},
"suggestion": {
"color": "#888"
}
},
"log-level-styles": {

@ -218,6 +218,9 @@
"inactive-alert": {
"color": "$red",
"background-color": "#2f2f2f"
},
"suggestion": {
"color": "#888"
}
},
"log-level-styles": {

@ -281,6 +281,9 @@
"inactive-alert": {
"color": "$red",
"background-color": "#2f2f2f"
},
"suggestion": {
"color": "#888"
}
},
"log-level-styles": {

@ -279,6 +279,9 @@
"background-color": "#2d5a80",
"bold": true,
"underline": true
},
"suggestion": {
"color": "#888"
}
},
"log-level-styles": {

@ -287,6 +287,9 @@
"inactive-alert": {
"color": "$red",
"background-color": "$base02"
},
"suggestion": {
"color": "$base02"
}
},
"log-level-styles": {

@ -193,6 +193,9 @@
"inactive-alert": {
"color": "$red",
"background-color": "$base03"
},
"suggestion": {
"color": "$base03"
}
},
"log-level-styles": {

@ -977,6 +977,8 @@ view_colors::init_roles(const lnav_theme& lt,
= this->to_attrs(lt, lt.lt_style_type, reporter);
this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SEP_REF_ACC)]
= this->to_attrs(lt, lt.lt_style_sep_ref_acc, reporter);
this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_SUGGESTION)]
= this->to_attrs(lt, lt.lt_style_suggestion, reporter);
this->vc_role_attrs[lnav::enums::to_underlying(role_t::VCR_RE_SPECIAL)]
= this->to_attrs(lt, lt.lt_style_re_special, reporter);

@ -90,6 +90,8 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_cmds.sh_38fa2a95b703d4ce12e82882eca1938264822690.out \
$(srcdir)/%reldir%/test_cmds.sh_3b20a298e2c059d7f6045cbc0c07ca3db3917695.err \
$(srcdir)/%reldir%/test_cmds.sh_3b20a298e2c059d7f6045cbc0c07ca3db3917695.out \
$(srcdir)/%reldir%/test_cmds.sh_3b4bea458c59d2bac492e568616b610625037ad0.err \
$(srcdir)/%reldir%/test_cmds.sh_3b4bea458c59d2bac492e568616b610625037ad0.out \
$(srcdir)/%reldir%/test_cmds.sh_453054e29aaca4c2662c45c2a1f2f63f3510d8dd.err \
$(srcdir)/%reldir%/test_cmds.sh_453054e29aaca4c2662c45c2a1f2f63f3510d8dd.out \
$(srcdir)/%reldir%/test_cmds.sh_4b2d91b19008d5b775090e3ef87c111f9e603b15.err \
@ -574,6 +576,8 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_shlexer.sh_e0599f0b53d1bd27af767113853f8e84291f137d.out \
$(srcdir)/%reldir%/test_shlexer.sh_e8fa2239ab17e7563d0c524f5400a79d6ff8bfda.err \
$(srcdir)/%reldir%/test_shlexer.sh_e8fa2239ab17e7563d0c524f5400a79d6ff8bfda.out \
$(srcdir)/%reldir%/test_shlexer.sh_e99fe1cde36b85ebbab86ca820f55ec861cdc20b.err \
$(srcdir)/%reldir%/test_shlexer.sh_e99fe1cde36b85ebbab86ca820f55ec861cdc20b.out \
$(srcdir)/%reldir%/test_sql.sh_02def66745b063518473df862987747909f56ccc.err \
$(srcdir)/%reldir%/test_sql.sh_02def66745b063518473df862987747909f56ccc.out \
$(srcdir)/%reldir%/test_sql.sh_0a5d13b62da4cb66a59a51b0240b5fe0b6036b7e.err \

@ -578,6 +578,12 @@
"background-color": "",
"underline": true,
"bold": true
},
"suggestion": {
"color": "",
"background-color": "",
"underline": false,
"bold": false
}
},
"log-level-styles": {
@ -1168,6 +1174,12 @@
"background-color": "",
"underline": true,
"bold": false
},
"suggestion": {
"color": "#888",
"background-color": "",
"underline": false,
"bold": false
}
},
"log-level-styles": {
@ -1720,6 +1732,12 @@
"background-color": "",
"underline": true,
"bold": false
},
"suggestion": {
"color": "#888",
"background-color": "",
"underline": false,
"bold": false
}
},
"log-level-styles": {
@ -2272,6 +2290,12 @@
"background-color": "",
"underline": true,
"bold": false
},
"suggestion": {
"color": "#888",
"background-color": "",
"underline": false,
"bold": false
}
},
"log-level-styles": {
@ -2825,6 +2849,12 @@
"background-color": "",
"underline": true,
"bold": false
},
"suggestion": {
"color": "#888",
"background-color": "",
"underline": false,
"bold": false
}
},
"log-level-styles": {
@ -3377,6 +3407,12 @@
"background-color": "",
"underline": true,
"bold": true
},
"suggestion": {
"color": "#888",
"background-color": "",
"underline": false,
"bold": false
}
},
"log-level-styles": {
@ -3938,6 +3974,12 @@
"background-color": "",
"underline": true,
"bold": false
},
"suggestion": {
"color": "$base02",
"background-color": "",
"underline": false,
"bold": false
}
},
"log-level-styles": {
@ -4499,6 +4541,12 @@
"background-color": "",
"underline": false,
"bold": false
},
"suggestion": {
"color": "$base03",
"background-color": "",
"underline": false,
"bold": false
}
},
"log-level-styles": {

@ -297,10 +297,10 @@
/ui/theme-defs/default/syntax-styles/type/color -> default-theme.json:218
/ui/theme-defs/default/syntax-styles/variable/color -> default-theme.json:167
/ui/theme-defs/default/vars/semantic_highlight_color -> default-theme.json:7
/ui/theme-defs/dracula/log-level-styles/critical/color -> dracula.json:296
/ui/theme-defs/dracula/log-level-styles/error/color -> dracula.json:293
/ui/theme-defs/dracula/log-level-styles/fatal/color -> dracula.json:299
/ui/theme-defs/dracula/log-level-styles/warning/color -> dracula.json:290
/ui/theme-defs/dracula/log-level-styles/critical/color -> dracula.json:299
/ui/theme-defs/dracula/log-level-styles/error/color -> dracula.json:296
/ui/theme-defs/dracula/log-level-styles/fatal/color -> dracula.json:302
/ui/theme-defs/dracula/log-level-styles/warning/color -> dracula.json:293
/ui/theme-defs/dracula/status-styles/active/background-color -> dracula.json:277
/ui/theme-defs/dracula/status-styles/active/color -> dracula.json:276
/ui/theme-defs/dracula/status-styles/alert/background-color -> dracula.json:273
@ -319,6 +319,7 @@
/ui/theme-defs/dracula/status-styles/subtitle/background-color -> dracula.json:247
/ui/theme-defs/dracula/status-styles/subtitle/bold -> dracula.json:248
/ui/theme-defs/dracula/status-styles/subtitle/color -> dracula.json:246
/ui/theme-defs/dracula/status-styles/suggestion/color -> dracula.json:288
/ui/theme-defs/dracula/status-styles/text/background-color -> dracula.json:265
/ui/theme-defs/dracula/status-styles/text/color -> dracula.json:264
/ui/theme-defs/dracula/status-styles/title-hotkey/background-color -> dracula.json:256
@ -427,10 +428,10 @@
/ui/theme-defs/dracula/vars/semantic_highlight_color -> dracula.json:18
/ui/theme-defs/dracula/vars/white -> dracula.json:14
/ui/theme-defs/dracula/vars/yellow -> dracula.json:10
/ui/theme-defs/eldar/log-level-styles/critical/color -> eldar.json:291
/ui/theme-defs/eldar/log-level-styles/error/color -> eldar.json:288
/ui/theme-defs/eldar/log-level-styles/fatal/color -> eldar.json:294
/ui/theme-defs/eldar/log-level-styles/warning/color -> eldar.json:285
/ui/theme-defs/eldar/log-level-styles/critical/color -> eldar.json:294
/ui/theme-defs/eldar/log-level-styles/error/color -> eldar.json:291
/ui/theme-defs/eldar/log-level-styles/fatal/color -> eldar.json:297
/ui/theme-defs/eldar/log-level-styles/warning/color -> eldar.json:288
/ui/theme-defs/eldar/status-styles/active/background-color -> eldar.json:259
/ui/theme-defs/eldar/status-styles/active/color -> eldar.json:258
/ui/theme-defs/eldar/status-styles/alert/background-color -> eldar.json:255
@ -449,6 +450,7 @@
/ui/theme-defs/eldar/status-styles/subtitle/background-color -> eldar.json:242
/ui/theme-defs/eldar/status-styles/subtitle/bold -> eldar.json:243
/ui/theme-defs/eldar/status-styles/subtitle/color -> eldar.json:241
/ui/theme-defs/eldar/status-styles/suggestion/color -> eldar.json:283
/ui/theme-defs/eldar/status-styles/text/background-color -> eldar.json:247
/ui/theme-defs/eldar/status-styles/text/color -> eldar.json:246
/ui/theme-defs/eldar/status-styles/title-hotkey/background-color -> eldar.json:267
@ -552,10 +554,10 @@
/ui/theme-defs/eldar/vars/semantic_highlight_color -> eldar.json:15
/ui/theme-defs/eldar/vars/white -> eldar.json:14
/ui/theme-defs/eldar/vars/yellow -> eldar.json:8
/ui/theme-defs/grayscale/log-level-styles/critical/color -> grayscale.json:231
/ui/theme-defs/grayscale/log-level-styles/error/color -> grayscale.json:228
/ui/theme-defs/grayscale/log-level-styles/fatal/color -> grayscale.json:234
/ui/theme-defs/grayscale/log-level-styles/warning/color -> grayscale.json:225
/ui/theme-defs/grayscale/log-level-styles/critical/color -> grayscale.json:234
/ui/theme-defs/grayscale/log-level-styles/error/color -> grayscale.json:231
/ui/theme-defs/grayscale/log-level-styles/fatal/color -> grayscale.json:237
/ui/theme-defs/grayscale/log-level-styles/warning/color -> grayscale.json:228
/ui/theme-defs/grayscale/status-styles/active/background-color -> grayscale.json:208
/ui/theme-defs/grayscale/status-styles/active/color -> grayscale.json:207
/ui/theme-defs/grayscale/status-styles/alert/background-color -> grayscale.json:204
@ -574,6 +576,7 @@
/ui/theme-defs/grayscale/status-styles/subtitle/background-color -> grayscale.json:182
/ui/theme-defs/grayscale/status-styles/subtitle/bold -> grayscale.json:183
/ui/theme-defs/grayscale/status-styles/subtitle/color -> grayscale.json:181
/ui/theme-defs/grayscale/status-styles/suggestion/color -> grayscale.json:223
/ui/theme-defs/grayscale/status-styles/text/background-color -> grayscale.json:196
/ui/theme-defs/grayscale/status-styles/text/color -> grayscale.json:195
/ui/theme-defs/grayscale/status-styles/title-hotkey/background-color -> grayscale.json:187
@ -655,10 +658,10 @@
/ui/theme-defs/grayscale/vars/red -> grayscale.json:8
/ui/theme-defs/grayscale/vars/white -> grayscale.json:14
/ui/theme-defs/grayscale/vars/yellow -> grayscale.json:10
/ui/theme-defs/monocai/log-level-styles/critical/color -> monocai.json:294
/ui/theme-defs/monocai/log-level-styles/error/color -> monocai.json:291
/ui/theme-defs/monocai/log-level-styles/fatal/color -> monocai.json:297
/ui/theme-defs/monocai/log-level-styles/warning/color -> monocai.json:288
/ui/theme-defs/monocai/log-level-styles/critical/color -> monocai.json:297
/ui/theme-defs/monocai/log-level-styles/error/color -> monocai.json:294
/ui/theme-defs/monocai/log-level-styles/fatal/color -> monocai.json:300
/ui/theme-defs/monocai/log-level-styles/warning/color -> monocai.json:291
/ui/theme-defs/monocai/status-styles/active/background-color -> monocai.json:275
/ui/theme-defs/monocai/status-styles/active/color -> monocai.json:274
/ui/theme-defs/monocai/status-styles/alert/background-color -> monocai.json:271
@ -677,6 +680,7 @@
/ui/theme-defs/monocai/status-styles/subtitle/background-color -> monocai.json:245
/ui/theme-defs/monocai/status-styles/subtitle/bold -> monocai.json:246
/ui/theme-defs/monocai/status-styles/subtitle/color -> monocai.json:244
/ui/theme-defs/monocai/status-styles/suggestion/color -> monocai.json:286
/ui/theme-defs/monocai/status-styles/text/background-color -> monocai.json:263
/ui/theme-defs/monocai/status-styles/text/color -> monocai.json:262
/ui/theme-defs/monocai/status-styles/title-hotkey/background-color -> monocai.json:254
@ -783,10 +787,10 @@
/ui/theme-defs/monocai/vars/semantic_highlight_color -> monocai.json:16
/ui/theme-defs/monocai/vars/white -> monocai.json:14
/ui/theme-defs/monocai/vars/yellow -> monocai.json:10
/ui/theme-defs/night-owl/log-level-styles/critical/color -> night-owl.json:292
/ui/theme-defs/night-owl/log-level-styles/error/color -> night-owl.json:289
/ui/theme-defs/night-owl/log-level-styles/fatal/color -> night-owl.json:295
/ui/theme-defs/night-owl/log-level-styles/warning/color -> night-owl.json:286
/ui/theme-defs/night-owl/log-level-styles/critical/color -> night-owl.json:295
/ui/theme-defs/night-owl/log-level-styles/error/color -> night-owl.json:292
/ui/theme-defs/night-owl/log-level-styles/fatal/color -> night-owl.json:298
/ui/theme-defs/night-owl/log-level-styles/warning/color -> night-owl.json:289
/ui/theme-defs/night-owl/status-styles/active/background-color -> night-owl.json:262
/ui/theme-defs/night-owl/status-styles/active/color -> night-owl.json:261
/ui/theme-defs/night-owl/status-styles/alert/background-color -> night-owl.json:258
@ -805,6 +809,7 @@
/ui/theme-defs/night-owl/status-styles/info/color -> night-owl.json:245
/ui/theme-defs/night-owl/status-styles/subtitle/background-color -> night-owl.json:242
/ui/theme-defs/night-owl/status-styles/subtitle/color -> night-owl.json:241
/ui/theme-defs/night-owl/status-styles/suggestion/color -> night-owl.json:284
/ui/theme-defs/night-owl/status-styles/text/background-color -> night-owl.json:250
/ui/theme-defs/night-owl/status-styles/text/color -> night-owl.json:249
/ui/theme-defs/night-owl/status-styles/title-hotkey/background-color -> night-owl.json:279
@ -909,10 +914,10 @@
/ui/theme-defs/night-owl/vars/semantic_highlight_color -> night-owl.json:15
/ui/theme-defs/night-owl/vars/white -> night-owl.json:14
/ui/theme-defs/night-owl/vars/yellow -> night-owl.json:10
/ui/theme-defs/solarized-dark/log-level-styles/critical/color -> solarized-dark.json:300
/ui/theme-defs/solarized-dark/log-level-styles/error/color -> solarized-dark.json:297
/ui/theme-defs/solarized-dark/log-level-styles/fatal/color -> solarized-dark.json:303
/ui/theme-defs/solarized-dark/log-level-styles/warning/color -> solarized-dark.json:294
/ui/theme-defs/solarized-dark/log-level-styles/critical/color -> solarized-dark.json:303
/ui/theme-defs/solarized-dark/log-level-styles/error/color -> solarized-dark.json:300
/ui/theme-defs/solarized-dark/log-level-styles/fatal/color -> solarized-dark.json:306
/ui/theme-defs/solarized-dark/log-level-styles/warning/color -> solarized-dark.json:297
/ui/theme-defs/solarized-dark/status-styles/active/background-color -> solarized-dark.json:268
/ui/theme-defs/solarized-dark/status-styles/active/color -> solarized-dark.json:267
/ui/theme-defs/solarized-dark/status-styles/alert/background-color -> solarized-dark.json:264
@ -931,6 +936,7 @@
/ui/theme-defs/solarized-dark/status-styles/subtitle/background-color -> solarized-dark.json:251
/ui/theme-defs/solarized-dark/status-styles/subtitle/bold -> solarized-dark.json:252
/ui/theme-defs/solarized-dark/status-styles/subtitle/color -> solarized-dark.json:250
/ui/theme-defs/solarized-dark/status-styles/suggestion/color -> solarized-dark.json:292
/ui/theme-defs/solarized-dark/status-styles/text/background-color -> solarized-dark.json:256
/ui/theme-defs/solarized-dark/status-styles/text/color -> solarized-dark.json:255
/ui/theme-defs/solarized-dark/status-styles/title-hotkey/background-color -> solarized-dark.json:276
@ -1043,10 +1049,10 @@
/ui/theme-defs/solarized-dark/vars/semantic_highlight_color -> solarized-dark.json:24
/ui/theme-defs/solarized-dark/vars/violet -> solarized-dark.json:20
/ui/theme-defs/solarized-dark/vars/yellow -> solarized-dark.json:16
/ui/theme-defs/solarized-light/log-level-styles/critical/color -> solarized-light.json:206
/ui/theme-defs/solarized-light/log-level-styles/error/color -> solarized-light.json:203
/ui/theme-defs/solarized-light/log-level-styles/fatal/color -> solarized-light.json:209
/ui/theme-defs/solarized-light/log-level-styles/warning/color -> solarized-light.json:200
/ui/theme-defs/solarized-light/log-level-styles/critical/color -> solarized-light.json:209
/ui/theme-defs/solarized-light/log-level-styles/error/color -> solarized-light.json:206
/ui/theme-defs/solarized-light/log-level-styles/fatal/color -> solarized-light.json:212
/ui/theme-defs/solarized-light/log-level-styles/warning/color -> solarized-light.json:203
/ui/theme-defs/solarized-light/status-styles/active/background-color -> solarized-light.json:183
/ui/theme-defs/solarized-light/status-styles/active/color -> solarized-light.json:182
/ui/theme-defs/solarized-light/status-styles/alert/background-color -> solarized-light.json:179
@ -1060,6 +1066,7 @@
/ui/theme-defs/solarized-light/status-styles/subtitle/background-color -> solarized-light.json:166
/ui/theme-defs/solarized-light/status-styles/subtitle/bold -> solarized-light.json:167
/ui/theme-defs/solarized-light/status-styles/subtitle/color -> solarized-light.json:165
/ui/theme-defs/solarized-light/status-styles/suggestion/color -> solarized-light.json:198
/ui/theme-defs/solarized-light/status-styles/text/background-color -> solarized-light.json:171
/ui/theme-defs/solarized-light/status-styles/text/color -> solarized-light.json:170
/ui/theme-defs/solarized-light/status-styles/title/background-color -> solarized-light.json:161

@ -0,0 +1,2 @@
⋮:⋮:foo bar baz
⋮:⋮:foo bar baz

@ -0,0 +1,6 @@
abc
wsp ^
eof ^
eval -- abc
split:
0 ^-^ -- abc

@ -179,6 +179,10 @@ run_cap_test ${lnav_test} -n \
-c ":hide-fields access_log.c_ip access_log.cs_uri_stem" \
${test_dir}/logfile_access_log.0
run_cap_test ${lnav_test} -n \
-c ':hide-fields log_time log_level' \
${test_dir}/logfile_generic.0
run_cap_test ${lnav_test} -f- -n < ${test_dir}/formats/scripts/multiline-echo.lnav
run_cap_test ${lnav_test} -n \

@ -30,3 +30,5 @@ run_cap_test ./drive_shlexer 'abc $DEF 123'
run_cap_test ./drive_shlexer '~ foo'
run_cap_test ./drive_shlexer '~nonexistent/bar baz'
run_cap_test ./drive_shlexer 'abc '

Loading…
Cancel
Save