diff --git a/NEWS.md b/NEWS.md index e5abda4e..e5bd3d31 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 diff --git a/docs/schemas/config-v1.schema.json b/docs/schemas/config-v1.schema.json index 13e9ed72..1c021567 100644 --- a/docs/schemas/config-v1.schema.json +++ b/docs/schemas/config-v1.schema.json @@ -680,6 +680,11 @@ "description": "Styling for hotkey highlights of status bars", "title": "/ui/theme-defs//status-styles/hotkey", "$ref": "#/definitions/style" + }, + "suggestion": { + "description": "Styling for suggested values", + "title": "/ui/theme-defs//status-styles/suggestion", + "$ref": "#/definitions/style" } }, "additionalProperties": false diff --git a/src/base/string_attr_type.hh b/src/base/string_attr_type.hh index 1657d77f..42d34f36 100644 --- a/src/base/string_attr_type.hh +++ b/src/base/string_attr_type.hh @@ -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 +inline std::pair +suggestion(S str) +{ + return std::make_pair(std::move(str), + VC_ROLE.template value(role_t::VCR_SUGGESTION)); +} + namespace literals { inline std::pair operator"" _ok(const char* str, diff --git a/src/breadcrumb_curses.cc b/src/breadcrumb_curses.cc index 99a49dc8..cec25f69 100644 --- a/src/breadcrumb_curses.cc +++ b/src/breadcrumb_curses.cc @@ -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); diff --git a/src/filter_sub_source.cc b/src/filter_sub_source.cc index 61641ab7..c9ee9106 100644 --- a/src/filter_sub_source.cc +++ b/src/filter_sub_source.cc @@ -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; } diff --git a/src/lnav.cc b/src/lnav.cc index 2ee06531..154c7f92 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -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; diff --git a/src/lnav_commands.cc b/src/lnav_commands.cc index ec5371b0..e208cf7e 100644 --- a/src/lnav_commands.cc +++ b/src/lnav_commands.cc @@ -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(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(); + if (lss == nullptr || lss->text_line_count() == 0) { + return {}; + } - safe::ReadAccess 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(); + + safe::ReadAccess 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 @@ -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 @@ -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 args; + + split_ws(cmdline, args); + if (args.size() > 1) { + return {}; + } + + return {"", tc->get_current_search()}; +} + static Result 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 @@ -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 @@ -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, diff --git a/src/lnav_config.cc b/src/lnav_config.cc index efd74d16..812ecd64 100644 --- a/src/lnav_config.cc +++ b/src/lnav_config.cc @@ -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 = { diff --git a/src/log_format_impls.cc b/src/log_format_impls.cc index 58fc03ce..474794b9 100644 --- a/src/log_format_impls.cc +++ b/src/log_format_impls.cc @@ -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 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 diff --git a/src/readline_callbacks.cc b/src/readline_callbacks.cc index c4ce3870..2d449622 100644 --- a/src/readline_callbacks.cc +++ b/src/readline_callbacks.cc @@ -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(""); diff --git a/src/readline_context.hh b/src/readline_context.hh index 047cf565..33322784 100644 --- a/src/readline_context.hh +++ b/src/readline_context.hh @@ -53,10 +53,16 @@ typedef void (*readline_highlighter_t)(attr_line_t& line, int x); */ class readline_context { public: - typedef Result (*command_func_t)( + using command_func_t = Result (*)( exec_context& ec, std::string cmdline, std::vector& 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) { diff --git a/src/readline_curses.cc b/src/readline_curses.cc index f59ef057..c6d151cf 100644 --- a/src/readline_curses.cc +++ b/src/readline_curses.cc @@ -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 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& 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& 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& 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, diff --git a/src/readline_curses.hh b/src/readline_curses.hh index 55b2ff3a..3c68c8ca 100644 --- a/src/readline_curses.hh +++ b/src/readline_curses.hh @@ -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; diff --git a/src/shlex.cc b/src/shlex.cc index 1f2f28f1..6264152f 100644 --- a/src/shlex.cc +++ b/src/shlex.cc @@ -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; diff --git a/src/styling.hh b/src/styling.hh index d17a8fd8..fa10eafa 100644 --- a/src/styling.hh +++ b/src/styling.hh @@ -147,6 +147,7 @@ struct lnav_theme { positioned_property lt_style_function; positioned_property lt_style_type; positioned_property lt_style_sep_ref_acc; + positioned_property lt_style_suggestion; positioned_property lt_style_re_special; positioned_property lt_style_re_repeat; positioned_property lt_style_diff_delete; diff --git a/src/themes/dracula.json b/src/themes/dracula.json index fe8d474f..65316646 100644 --- a/src/themes/dracula.json +++ b/src/themes/dracula.json @@ -283,6 +283,9 @@ "inactive-alert": { "color": "$red", "background-color": "#2f2f2f" + }, + "suggestion": { + "color": "#888" } }, "log-level-styles": { diff --git a/src/themes/eldar.json b/src/themes/eldar.json index 8e653789..8e29981c 100644 --- a/src/themes/eldar.json +++ b/src/themes/eldar.json @@ -278,6 +278,9 @@ "inactive-alert": { "color": "$red", "background-color": "Grey" + }, + "suggestion": { + "color": "#888" } }, "log-level-styles": { diff --git a/src/themes/grayscale.json b/src/themes/grayscale.json index 35d133c5..a4b338ac 100644 --- a/src/themes/grayscale.json +++ b/src/themes/grayscale.json @@ -218,6 +218,9 @@ "inactive-alert": { "color": "$red", "background-color": "#2f2f2f" + }, + "suggestion": { + "color": "#888" } }, "log-level-styles": { diff --git a/src/themes/monocai.json b/src/themes/monocai.json index a87bbd42..20626125 100644 --- a/src/themes/monocai.json +++ b/src/themes/monocai.json @@ -281,6 +281,9 @@ "inactive-alert": { "color": "$red", "background-color": "#2f2f2f" + }, + "suggestion": { + "color": "#888" } }, "log-level-styles": { diff --git a/src/themes/night-owl.json b/src/themes/night-owl.json index b6ec7307..337a4027 100644 --- a/src/themes/night-owl.json +++ b/src/themes/night-owl.json @@ -279,6 +279,9 @@ "background-color": "#2d5a80", "bold": true, "underline": true + }, + "suggestion": { + "color": "#888" } }, "log-level-styles": { diff --git a/src/themes/solarized-dark.json b/src/themes/solarized-dark.json index 9dee6458..c44aa2f2 100644 --- a/src/themes/solarized-dark.json +++ b/src/themes/solarized-dark.json @@ -287,6 +287,9 @@ "inactive-alert": { "color": "$red", "background-color": "$base02" + }, + "suggestion": { + "color": "$base02" } }, "log-level-styles": { diff --git a/src/themes/solarized-light.json b/src/themes/solarized-light.json index 79d33489..2af7f24d 100644 --- a/src/themes/solarized-light.json +++ b/src/themes/solarized-light.json @@ -193,6 +193,9 @@ "inactive-alert": { "color": "$red", "background-color": "$base03" + }, + "suggestion": { + "color": "$base03" } }, "log-level-styles": { diff --git a/src/view_curses.cc b/src/view_curses.cc index b4a60f97..0a5674b5 100644 --- a/src/view_curses.cc +++ b/src/view_curses.cc @@ -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); diff --git a/test/expected/expected.am b/test/expected/expected.am index f1f5d599..5f5da76c 100644 --- a/test/expected/expected.am +++ b/test/expected/expected.am @@ -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 \ diff --git a/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out b/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out index 6af10341..e36514c6 100644 --- a/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out +++ b/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out @@ -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": { diff --git a/test/expected/test_cli.sh_cc06341dd560f927512e92c7c0985ed8b25827ae.out b/test/expected/test_cli.sh_cc06341dd560f927512e92c7c0985ed8b25827ae.out index ef835bb0..ecbdf779 100644 --- a/test/expected/test_cli.sh_cc06341dd560f927512e92c7c0985ed8b25827ae.out +++ b/test/expected/test_cli.sh_cc06341dd560f927512e92c7c0985ed8b25827ae.out @@ -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 diff --git a/test/expected/test_cmds.sh_3b4bea458c59d2bac492e568616b610625037ad0.err b/test/expected/test_cmds.sh_3b4bea458c59d2bac492e568616b610625037ad0.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_cmds.sh_3b4bea458c59d2bac492e568616b610625037ad0.out b/test/expected/test_cmds.sh_3b4bea458c59d2bac492e568616b610625037ad0.out new file mode 100644 index 00000000..891f4a77 --- /dev/null +++ b/test/expected/test_cmds.sh_3b4bea458c59d2bac492e568616b610625037ad0.out @@ -0,0 +1,2 @@ +⋮:⋮:foo bar baz +⋮:⋮:foo bar baz diff --git a/test/expected/test_shlexer.sh_e99fe1cde36b85ebbab86ca820f55ec861cdc20b.err b/test/expected/test_shlexer.sh_e99fe1cde36b85ebbab86ca820f55ec861cdc20b.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_shlexer.sh_e99fe1cde36b85ebbab86ca820f55ec861cdc20b.out b/test/expected/test_shlexer.sh_e99fe1cde36b85ebbab86ca820f55ec861cdc20b.out new file mode 100644 index 00000000..9a7083dd --- /dev/null +++ b/test/expected/test_shlexer.sh_e99fe1cde36b85ebbab86ca820f55ec861cdc20b.out @@ -0,0 +1,6 @@ + abc +wsp ^ +eof ^ +eval -- abc +split: + 0 ^-^ -- abc diff --git a/test/test_cmds.sh b/test/test_cmds.sh index 930b5a84..5103f79d 100644 --- a/test/test_cmds.sh +++ b/test/test_cmds.sh @@ -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 \ diff --git a/test/test_shlexer.sh b/test/test_shlexer.sh index 747de95e..e05cc500 100644 --- a/test/test_shlexer.sh +++ b/test/test_shlexer.sh @@ -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 '