Skip to content

Commit 897fa37

Browse files
committed
[timeline] add commands for hiding/showing row types
1 parent 9566375 commit 897fa37

33 files changed

Lines changed: 792 additions & 413 deletions

File tree

NEWS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@ Features:
153153
instance extending to the end of the log. Partition
154154
rows span from their start time to the next partition
155155
(or end of log).
156+
* Added `:hide-in-timeline` and `:show-in-timeline`
157+
commands to control which row types (logfile, thread,
158+
opid, tag, partition) are visible in the timeline view.
159+
The `:hide-in-timeline` command supports live preview,
160+
highlighting rows that would be hidden in red.
156161
* The `timestamp-point-of-reference` log format property
157162
has been added to specify the related of the timestamp
158163
to the operation that the message refers to, either:

src/cmds.display.cc

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "base/intern_string.hh"
3131
#include "lnav.hh"
3232
#include "readline_context.hh"
33+
#include "timeline_source.hh"
3334

3435
static Result<std::string, lnav::console::user_message>
3536
com_set_text_view_mode(exec_context& ec,
@@ -157,6 +158,67 @@ com_toggle_field(exec_context& ec,
157158
return Ok(retval);
158159
}
159160

161+
static Result<std::string, lnav::console::user_message>
162+
com_timeline_row_type_visibility(exec_context& ec,
163+
std::string cmdline,
164+
std::vector<std::string>& args)
165+
{
166+
std::string retval;
167+
168+
if (args.size() < 2) {
169+
auto* tss = static_cast<timeline_source*>(
170+
lnav_data.ld_views[LNV_TIMELINE].get_sub_source());
171+
tss->gs_preview_hidden_row_types.clear();
172+
lnav_data.ld_views[LNV_TIMELINE].set_needs_update();
173+
return ec.make_error("Expecting a row type");
174+
}
175+
176+
const auto hide = args[0] == "hide-in-timeline";
177+
std::vector<std::string> found_types, unknown_types;
178+
179+
for (size_t lpc = 1; lpc < args.size(); lpc++) {
180+
auto rt_opt = timeline_source::row_type_from_string(args[lpc]);
181+
if (rt_opt) {
182+
found_types.emplace_back(args[lpc]);
183+
} else {
184+
unknown_types.emplace_back(args[lpc]);
185+
}
186+
}
187+
188+
if (!unknown_types.empty()) {
189+
return ec.make_error("unknown row type(s) -- {}",
190+
fmt::join(unknown_types, ", "));
191+
}
192+
193+
auto* tss = static_cast<timeline_source*>(
194+
lnav_data.ld_views[LNV_TIMELINE].get_sub_source());
195+
if (ec.ec_dry_run) {
196+
tss->gs_preview_hidden_row_types.clear();
197+
if (hide) {
198+
for (const auto& type_name : found_types) {
199+
auto rt_opt = timeline_source::row_type_from_string(type_name);
200+
tss->gs_preview_hidden_row_types.insert(rt_opt.value());
201+
}
202+
}
203+
lnav_data.ld_views[LNV_TIMELINE].set_needs_update();
204+
retval = "";
205+
} else {
206+
tss->gs_preview_hidden_row_types.clear();
207+
for (const auto& type_name : found_types) {
208+
auto rt_opt = timeline_source::row_type_from_string(type_name);
209+
tss->set_row_type_visibility(rt_opt.value(), !hide);
210+
}
211+
tss->text_filters_changed();
212+
213+
auto visibility = hide ? "hiding" : "showing";
214+
retval = fmt::format(FMT_STRING("info: {} row type(s) -- {}"),
215+
visibility,
216+
fmt::join(found_types, ", "));
217+
}
218+
219+
return Ok(retval);
220+
}
221+
160222
static readline_context::command_t DISPLAY_COMMANDS[] = {
161223
{
162224
"set-text-view-mode",
@@ -208,6 +270,46 @@ static readline_context::command_t DISPLAY_COMMANDS[] = {
208270
.with_opposites({"hide-fields"})
209271
.with_tags({"display"}),
210272
},
273+
{
274+
"hide-in-timeline",
275+
com_timeline_row_type_visibility,
276+
277+
help_text(":hide-in-timeline")
278+
.with_summary("Hide rows of the given type(s) in the timeline "
279+
"view")
280+
.with_parameter(help_text("row-type", "The type of row to hide")
281+
.one_or_more()
282+
.with_enum_values({
283+
"logfile"_frag,
284+
"thread"_frag,
285+
"opid"_frag,
286+
"tag"_frag,
287+
"partition"_frag,
288+
}))
289+
.with_example({"To hide logfile and thread rows", "logfile thread"})
290+
.with_opposites({"show-in-timeline"})
291+
.with_tags({"display"}),
292+
},
293+
{
294+
"show-in-timeline",
295+
com_timeline_row_type_visibility,
296+
297+
help_text(":show-in-timeline")
298+
.with_summary("Show rows of the given type(s) that were "
299+
"previously hidden in the timeline view")
300+
.with_parameter(help_text("row-type", "The type of row to show")
301+
.one_or_more()
302+
.with_enum_values({
303+
"logfile"_frag,
304+
"thread"_frag,
305+
"opid"_frag,
306+
"tag"_frag,
307+
"partition"_frag,
308+
}))
309+
.with_example({"To show logfile and thread rows", "logfile thread"})
310+
.with_opposites({"hide-in-timeline"})
311+
.with_tags({"display"}),
312+
},
211313
};
212314

213315
void

src/internals/cmd-ref.rst

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,29 @@
853853
----
854854

855855

856+
.. _hide_in_timeline:
857+
858+
:hide-in-timeline *row-type*
859+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
860+
861+
Hide rows of the given type(s) in the timeline view
862+
863+
**Parameters**
864+
* **row-type** --- The type of row to hide
865+
866+
**Examples**
867+
To hide logfile and thread rows:
868+
869+
.. code-block:: lnav
870+
871+
:hide-in-timeline logfile thread
872+
873+
**See Also**
874+
:ref:`enable_word_wrap`, :ref:`hide_fields`, :ref:`set_text_view_mode`, :ref:`show_in_timeline`
875+
876+
----
877+
878+
856879
.. _hide_lines_after:
857880

858881
:hide-lines-after *date*
@@ -1513,6 +1536,29 @@
15131536
----
15141537

15151538

1539+
.. _show_in_timeline:
1540+
1541+
:show-in-timeline *row-type*
1542+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1543+
1544+
Show rows of the given type(s) that were previously hidden in the timeline view
1545+
1546+
**Parameters**
1547+
* **row-type** --- The type of row to show
1548+
1549+
**Examples**
1550+
To show logfile and thread rows:
1551+
1552+
.. code-block:: lnav
1553+
1554+
:show-in-timeline logfile thread
1555+
1556+
**See Also**
1557+
:ref:`enable_word_wrap`, :ref:`hide_fields`, :ref:`hide_in_timeline`, :ref:`set_text_view_mode`
1558+
1559+
----
1560+
1561+
15161562
.. _show_lines_before_and_after:
15171563

15181564
:show-lines-before-and-after

src/session_data.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "sql_util.hh"
5858
#include "sqlitepp.client.hh"
5959
#include "tailer/tailer.looper.hh"
60+
#include "timeline_source.hh"
6061
#include "vtab_module.hh"
6162
#include "yajlpp/yajlpp.hh"
6263
#include "yajlpp/yajlpp_def.hh"
@@ -1793,6 +1794,12 @@ reset_session()
17931794

17941795
lnav_data.ld_db_row_source.reset_user_state();
17951796

1797+
auto* tss = static_cast<timeline_source*>(
1798+
lnav_data.ld_views[LNV_TIMELINE].get_sub_source());
1799+
if (tss != nullptr) {
1800+
tss->gs_hidden_row_types.clear();
1801+
}
1802+
17961803
for (auto& tc : lnav_data.ld_views) {
17971804
text_sub_source* tss = tc.get_sub_source();
17981805

src/timeline_source.cc

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,62 @@ timeline_source::timeline_source(textview_curses& log_view,
464464
this->gs_preview_view.set_overlay_source(&this->gs_preview_overlay);
465465
}
466466

467+
std::optional<timeline_source::row_type>
468+
timeline_source::row_type_from_string(const std::string& str)
469+
{
470+
if (str == "logfile") {
471+
return row_type::logfile;
472+
}
473+
if (str == "thread") {
474+
return row_type::thread;
475+
}
476+
if (str == "opid") {
477+
return row_type::opid;
478+
}
479+
if (str == "tag") {
480+
return row_type::tag;
481+
}
482+
if (str == "partition") {
483+
return row_type::partition;
484+
}
485+
return std::nullopt;
486+
}
487+
488+
const char*
489+
timeline_source::row_type_to_string(row_type rt)
490+
{
491+
switch (rt) {
492+
case row_type::logfile:
493+
return "logfile";
494+
case row_type::thread:
495+
return "thread";
496+
case row_type::opid:
497+
return "opid";
498+
case row_type::tag:
499+
return "tag";
500+
case row_type::partition:
501+
return "partition";
502+
}
503+
return "unknown";
504+
}
505+
506+
void
507+
timeline_source::set_row_type_visibility(row_type rt, bool visible)
508+
{
509+
if (visible) {
510+
this->gs_hidden_row_types.erase(rt);
511+
} else {
512+
this->gs_hidden_row_types.insert(rt);
513+
}
514+
}
515+
516+
bool
517+
timeline_source::is_row_type_visible(row_type rt) const
518+
{
519+
return this->gs_hidden_row_types.find(rt)
520+
== this->gs_hidden_row_types.end();
521+
}
522+
467523
bool
468524
timeline_source::list_input_handle_key(listview_curses& lv, const ncinput& ch)
469525
{
@@ -571,7 +627,7 @@ timeline_source::text_value_for_line(textview_curses& tc,
571627
auto duration
572628
= row.or_value.otr_range.tr_end - row.or_value.otr_range.tr_begin;
573629
auto duration_str = fmt::format(
574-
FMT_STRING(" {: >13}"),
630+
FMT_STRING("{: >13}"),
575631
humanize::time::duration::from_tv(to_timeval(duration))
576632
.to_string());
577633

@@ -601,6 +657,18 @@ timeline_source::text_value_for_line(textview_curses& tc,
601657
icon = ui_icon_t::partition;
602658
break;
603659
}
660+
if (this->gs_preview_hidden_row_types.count(row.or_type) > 0) {
661+
this->gs_rendered_line.append(
662+
"-",
663+
VC_STYLE.value(text_attrs{
664+
lnav::enums::to_underlying(text_attrs::style::blink),
665+
styling::color_unit::from_palette(
666+
lnav::enums::to_underlying(ansi_color::red)),
667+
}));
668+
} else {
669+
this->gs_rendered_line.append(" ");
670+
}
671+
604672
this->gs_rendered_line
605673
.append(duration_str, VC_ROLE.value(role_t::VCR_OFFSET_TIME))
606674
.append(" ")
@@ -1007,6 +1075,11 @@ timeline_source::rebuild_indexes()
10071075
full_desc += pair.second.or_description;
10081076
}
10091077

1078+
if (!this->is_row_type_visible(row.or_type)) {
1079+
this->gs_filtered_count += 1;
1080+
continue;
1081+
}
1082+
10101083
shared_buffer sb_opid;
10111084
shared_buffer_ref sbr_opid;
10121085
sbr_opid.share(
@@ -1379,6 +1452,25 @@ timeline_source::text_filters_changed()
13791452
this->tss_view->redo_search();
13801453
}
13811454

1455+
void
1456+
timeline_source::clear_preview()
1457+
{
1458+
text_sub_source::clear_preview();
1459+
this->gs_preview_hidden_row_types.clear();
1460+
}
1461+
1462+
void
1463+
timeline_source::add_commands_for_session(
1464+
const std::function<void(const std::string&)>& receiver)
1465+
{
1466+
text_sub_source::add_commands_for_session(receiver);
1467+
1468+
for (const auto& rt : this->gs_hidden_row_types) {
1469+
receiver(fmt::format(FMT_STRING("hide-in-timeline {}"),
1470+
row_type_to_string(rt)));
1471+
}
1472+
}
1473+
13821474
int
13831475
timeline_source::get_filtered_count() const
13841476
{

src/timeline_source.hh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <functional>
3535
#include <memory>
3636
#include <optional>
37+
#include <set>
3738
#include <string>
3839
#include <vector>
3940

@@ -99,6 +100,9 @@ public:
99100
void text_selection_changed(textview_curses& tc) override;
100101

101102
void text_filters_changed() override;
103+
void clear_preview() override;
104+
void add_commands_for_session(
105+
const std::function<void(const std::string&)>& receiver) override;
102106
int get_filtered_count() const override;
103107
int get_filtered_count_for(size_t filter_index) const override;
104108

@@ -199,6 +203,15 @@ public:
199203
frag_hasher,
200204
std::equal_to<string_fragment>>;
201205

206+
static std::optional<row_type> row_type_from_string(const std::string& str);
207+
static const char* row_type_to_string(row_type rt);
208+
209+
void set_row_type_visibility(row_type rt, bool visible);
210+
bool is_row_type_visible(row_type rt) const;
211+
212+
std::set<row_type> gs_hidden_row_types;
213+
std::set<row_type> gs_preview_hidden_row_types;
214+
202215
timeline_preview_overlay gs_preview_overlay;
203216
attr_line_t gs_rendered_line;
204217
size_t gs_opid_width{0};

0 commit comments

Comments
 (0)