diff --git a/docs/source/ui.rst b/docs/source/ui.rst index 64f14e01..0e42452a 100644 --- a/docs/source/ui.rst +++ b/docs/source/ui.rst @@ -41,7 +41,16 @@ Above and below the main body are status lines that display: * the current view; * the line number for the top line in the display; * the current search hit and the total number of hits; -* the number of lines that are **not** displayed because of filtering. + +If the view supports filtering, there will be a status line showing the +following: + + * the number of enabled filters and the total number of filters; + * the number of lines that are **not** displayed because of filtering. + +To edit the filters, you can press TAB to change the focus from the main +view to the filter editor. The editor allows you to create, enable/disable, +and delete filters easily. Finally, the last line on the display is where you can enter search patterns and execute internal commands, such as converting a diff --git a/src/filter_status_source.cc b/src/filter_status_source.cc index 777faeab..32847f87 100644 --- a/src/filter_status_source.cc +++ b/src/filter_status_source.cc @@ -32,7 +32,7 @@ #include "lnav.hh" #include "filter_status_source.hh" -static auto TOGGLE_MSG = "Press(" ANSI_BOLD("TAB") ") to edit "; +static auto TOGGLE_MSG = "Press " ANSI_BOLD("TAB") " to edit "; static auto HOTKEY_HELP = ANSI_BOLD("SPC") ": Enable/Disable | " ANSI_BOLD("ENTER") ": Edit | " @@ -49,7 +49,10 @@ filter_status_source::filter_status_source() this->tss_fields[TSF_STITCH_TITLE].set_stitch_value( view_colors::ansi_color_pair_index(COLOR_BLUE, COLOR_WHITE)); - this->tss_fields[TSF_FILTERED].set_width(20); + this->tss_fields[TSF_COUNT].set_width(22); + this->tss_fields[TSF_COUNT].set_role(view_colors::VCR_STATUS); + + this->tss_fields[TSF_FILTERED].set_width(30); this->tss_fields[TSF_FILTERED].set_role(view_colors::VCR_BOLD_STATUS); this->tss_fields[TSF_HELP].right_justify(true); @@ -76,6 +79,31 @@ size_t filter_status_source::statusview_fields() } if (this->tss_prompt.empty() && this->tss_error.empty()) { + lnav_data.ld_view_stack.top() | [this] (auto tc) { + text_sub_source *tss = tc->get_sub_source(); + if (tss == nullptr) { + return; + } + + filter_stack &fs = tss->get_filters(); + auto enabled_count = 0, filter_count = 0; + + for (const auto &tf : fs) { + if (tf->is_enabled()) { + enabled_count += 1; + } + filter_count += 1; + } + if (filter_count == 0) { + this->tss_fields[TSF_COUNT].set_value(""); + } else { + this->tss_fields[TSF_COUNT].set_value( + " " ANSI_BOLD("%d") + " of " ANSI_BOLD("%d") + " enabled ", enabled_count, filter_count); + } + }; + return TSF__MAX; } @@ -122,6 +150,6 @@ void filter_status_source::update_filtered(text_sub_source *tss) this->bss_last_filtered_count = tss->get_filtered_count(); timer.start_fade(this->bss_filter_counter, 3); } - sf.set_value("%'9d Not Shown", tss->get_filtered_count()); + sf.set_value("%'9d Lines not shown", tss->get_filtered_count()); } } diff --git a/src/help.txt b/src/help.txt index ce54c5bc..572d7b7c 100644 --- a/src/help.txt +++ b/src/help.txt @@ -143,8 +143,17 @@ Above and below the main body are status lines that display: * the current view; * the line number for the top line in the display; * the current search hit and the total number of hits; + +If the view supports filtering, there will be a status line showing the +following: + + * the number of enabled filters and the total number of filters; * the number of lines not displayed because of filtering. +To edit the filters, you can press TAB to change the focus from the main +view to the filter editor. The editor allows you to create, enable/disable, +and delete filters easily. + Finally, the last line on the display is where you can enter search patterns and execute internal commands, such as converting a unix-timestamp into a human-readable date. The command-line is diff --git a/src/hotkeys.cc b/src/hotkeys.cc index 1994595b..2174e34f 100644 --- a/src/hotkeys.cc +++ b/src/hotkeys.cc @@ -110,6 +110,7 @@ void handle_paging_key(int ch) textview_curses *tc = *lnav_data.ld_view_stack.top(); exec_context &ec = lnav_data.ld_exec_context; logfile_sub_source *lss = NULL; + text_sub_source *tc_tss = tc->get_sub_source(); bookmarks::type & bm = tc->get_bookmarks(); if (tc->handle_key(ch)) { @@ -927,9 +928,11 @@ void handle_paging_key(int ch) ); tc->reload_data(); - } else { + } else if (tc_tss != nullptr && tc_tss->tss_supports_filtering) { lnav_data.ld_mode = LNM_FILTER; lnav_data.ld_filter_view.reload_data(); + } else { + alerter::singleton().chime(); } break; diff --git a/src/logfile_sub_source.cc b/src/logfile_sub_source.cc index 7740afa2..19d14d9b 100644 --- a/src/logfile_sub_source.cc +++ b/src/logfile_sub_source.cc @@ -106,6 +106,7 @@ logfile_sub_source::logfile_sub_source() lss_longest_line(0), lss_meta_grepper(*this) { + this->tss_supports_filtering = true; this->clear_line_size_cache(); this->clear_min_max_log_times(); } diff --git a/src/textfile_sub_source.hh b/src/textfile_sub_source.hh index aa668518..abbc93a9 100644 --- a/src/textfile_sub_source.hh +++ b/src/textfile_sub_source.hh @@ -40,7 +40,9 @@ class textfile_sub_source : public text_sub_source { public: typedef std::list>::iterator file_iterator; - textfile_sub_source() { }; + textfile_sub_source() { + this->tss_supports_filtering = true; + }; bool empty() const { return this->tss_files.empty(); diff --git a/src/textview_curses.hh b/src/textview_curses.hh index 29771d84..2d5791e1 100644 --- a/src/textview_curses.hh +++ b/src/textview_curses.hh @@ -455,6 +455,7 @@ public: return nonstd::nullopt; } + bool tss_supports_filtering{false}; protected: textview_curses *tss_view; filter_stack tss_filters; diff --git a/src/view_helpers.cc b/src/view_helpers.cc index eec23a61..6b408667 100644 --- a/src/view_helpers.cc +++ b/src/view_helpers.cc @@ -215,6 +215,19 @@ void layout_views() bool doc_side_by_side = width > (90 + 60); bool preview_status_open = !lnav_data.ld_preview_status_source .get_description().empty(); + bool filter_status_open = false; + + lnav_data.ld_view_stack.top() | [&] (auto tc) { + text_sub_source *tss = tc->get_sub_source(); + + if (tss == nullptr) { + return; + } + + if (tss->tss_supports_filtering) { + filter_status_open = true; + } + }; if (doc_side_by_side) { doc_height = std::max( @@ -255,9 +268,12 @@ void layout_views() + lnav_data.ld_rl_view->get_height(); for (auto &tc : lnav_data.ld_views) { - tc.set_height(vis_line_t(-(bottom_height + filter_height))); + tc.set_height(vis_line_t(-(bottom_height + + (filter_status_open ? 1 : 0) + + filter_height))); } lnav_data.ld_status[LNS_TOP].set_enabled(!filters_open); + lnav_data.ld_status[LNS_FILTER].set_visible(filter_status_open); lnav_data.ld_status[LNS_FILTER].set_enabled(filters_open); lnav_data.ld_status[LNS_FILTER].set_top(-(bottom_height + filter_height + 1)); lnav_data.ld_status[LNS_BOTTOM].set_top(-(match_height + 2)); diff --git a/test/expected_help.txt b/test/expected_help.txt index 431e8468..20bf9e6f 100644 --- a/test/expected_help.txt +++ b/test/expected_help.txt @@ -143,8 +143,17 @@ Above and below the main body are status lines that display: * the current view; * the line number for the top line in the display; * the current search hit and the total number of hits; + +If the view supports filtering, there will be a status line showing the +following: + + * the number of enabled filters and the total number of filters; * the number of lines not displayed because of filtering. +To edit the filters, you can press TAB to change the focus from the main +view to the filter editor. The editor allows you to create, enable/disable, +and delete filters easily. + Finally, the last line on the display is where you can enter search patterns and execute internal commands, such as converting a unix-timestamp into a human-readable date. The command-line is