mirror of
https://github.com/tstack/lnav.git
synced 2024-10-05 17:17:37 +03:00
[textview] try to preserve textview location better when reloading
This commit is contained in:
parent
31cf49ec0d
commit
53b0a606d6
2
NEWS.md
2
NEWS.md
@ -12,6 +12,8 @@ Interface changes:
|
||||
example, after typing in `:filter-in` the current
|
||||
search term for the view will be suggested (if
|
||||
one is active).
|
||||
* The focused line should be preserved more reliably in
|
||||
the LOG/TEXT views.
|
||||
|
||||
## lnav v0.12.0
|
||||
|
||||
|
@ -300,14 +300,14 @@ db_label_source::row_for_time(struct timeval time_bucket)
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
nonstd::optional<struct timeval>
|
||||
nonstd::optional<text_time_translator::row_info>
|
||||
db_label_source::time_for_row(vis_line_t row)
|
||||
{
|
||||
if ((row < 0_vl) || (((size_t) row) >= this->dls_time_column.size())) {
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
return this->dls_time_column[row];
|
||||
return row_info{this->dls_time_column[row], row};
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -89,7 +89,7 @@ public:
|
||||
nonstd::optional<vis_line_t> row_for_time(
|
||||
struct timeval time_bucket) override;
|
||||
|
||||
nonstd::optional<struct timeval> time_for_row(vis_line_t row) override;
|
||||
nonstd::optional<row_info> time_for_row(vis_line_t row) override;
|
||||
|
||||
struct header_meta {
|
||||
explicit header_meta(std::string name) : hm_name(std::move(name)) {}
|
||||
|
@ -778,7 +778,7 @@ gantt_source::row_for_time(struct timeval time_bucket)
|
||||
return vis_line_t(std::distance(this->gs_time_order.begin(), closest_iter));
|
||||
}
|
||||
|
||||
nonstd::optional<struct timeval>
|
||||
nonstd::optional<text_time_translator::row_info>
|
||||
gantt_source::time_for_row(vis_line_t row)
|
||||
{
|
||||
if (row >= this->gs_time_order.size()) {
|
||||
@ -791,11 +791,17 @@ gantt_source::time_for_row(vis_line_t row)
|
||||
auto ov_sel = this->tss_view->get_overlay_selection();
|
||||
|
||||
if (ov_sel && ov_sel.value() < otr.otr_sub_ops.size()) {
|
||||
return otr.otr_sub_ops[ov_sel.value()].ostr_range.tr_begin;
|
||||
return row_info{
|
||||
otr.otr_sub_ops[ov_sel.value()].ostr_range.tr_begin,
|
||||
row,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return otr.otr_range.tr_begin;
|
||||
return row_info{
|
||||
otr.otr_range.tr_begin,
|
||||
row,
|
||||
};
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -73,7 +73,7 @@ public:
|
||||
|
||||
nonstd::optional<vis_line_t> row_for_time(
|
||||
struct timeval time_bucket) override;
|
||||
nonstd::optional<struct timeval> time_for_row(vis_line_t row) override;
|
||||
nonstd::optional<row_info> time_for_row(vis_line_t row) override;
|
||||
|
||||
void rebuild_indexes();
|
||||
|
||||
|
@ -166,7 +166,7 @@ hist_source2::end_of_row()
|
||||
}
|
||||
}
|
||||
|
||||
nonstd::optional<struct timeval>
|
||||
nonstd::optional<text_time_translator::row_info>
|
||||
hist_source2::time_for_row(vis_line_t row)
|
||||
{
|
||||
if (row < 0 || row > this->hs_line_count) {
|
||||
@ -175,7 +175,7 @@ hist_source2::time_for_row(vis_line_t row)
|
||||
|
||||
bucket_t& bucket = this->find_bucket(row);
|
||||
|
||||
return timeval{bucket.b_time, 0};
|
||||
return row_info{timeval{bucket.b_time, 0}, row};
|
||||
}
|
||||
|
||||
hist_source2::bucket_t&
|
||||
|
@ -376,7 +376,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
nonstd::optional<struct timeval> time_for_row(vis_line_t row) override;
|
||||
nonstd::optional<row_info> time_for_row(vis_line_t row) override;
|
||||
|
||||
nonstd::optional<vis_line_t> row_for_time(
|
||||
struct timeval tv_bucket) override;
|
||||
|
@ -253,8 +253,8 @@ handle_paging_key(int ch)
|
||||
lnav_data.ld_last_view = nullptr;
|
||||
if (src_view != nullptr && dst_view != nullptr) {
|
||||
src_view->time_for_row(top_tc->get_selection()) |
|
||||
[dst_view, tc](auto top_time) {
|
||||
dst_view->row_for_time(top_time) |
|
||||
[dst_view, tc](auto top_ri) {
|
||||
dst_view->row_for_time(top_ri.ri_time) |
|
||||
[tc](auto row) { tc->set_selection(row); };
|
||||
};
|
||||
}
|
||||
@ -578,9 +578,9 @@ handle_paging_key(int ch)
|
||||
if (lss) {
|
||||
const int step = 24 * 60 * 60;
|
||||
lss->time_for_row(tc->get_selection()) |
|
||||
[lss, tc](auto first_time) {
|
||||
[lss, tc](auto first_ri) {
|
||||
lss->find_from_time(
|
||||
roundup_size(first_time.tv_sec, step))
|
||||
roundup_size(first_ri.ri_time.tv_sec, step))
|
||||
| [tc](auto line) { tc->set_selection(line); };
|
||||
};
|
||||
}
|
||||
@ -589,8 +589,9 @@ handle_paging_key(int ch)
|
||||
case ')':
|
||||
if (lss) {
|
||||
lss->time_for_row(tc->get_selection()) |
|
||||
[lss, tc](auto first_time) {
|
||||
time_t day = rounddown(first_time.tv_sec, 24 * 60 * 60);
|
||||
[lss, tc](auto first_ri) {
|
||||
time_t day
|
||||
= rounddown(first_ri.ri_time.tv_sec, 24 * 60 * 60);
|
||||
lss->find_from_time(day) | [tc](auto line) {
|
||||
if (line != 0_vl) {
|
||||
--line;
|
||||
@ -607,9 +608,9 @@ handle_paging_key(int ch)
|
||||
"the top of the log has been reached");
|
||||
} else if (lss) {
|
||||
lss->time_for_row(tc->get_selection()) |
|
||||
[lss, ch, tc](auto first_time) {
|
||||
[lss, ch, tc](auto first_ri) {
|
||||
int step = ch == 'D' ? (24 * 60 * 60) : (60 * 60);
|
||||
time_t top_time = first_time.tv_sec;
|
||||
time_t top_time = first_ri.ri_time.tv_sec;
|
||||
lss->find_from_time(top_time - step) | [tc](auto line) {
|
||||
if (line != 0_vl) {
|
||||
--line;
|
||||
@ -625,9 +626,9 @@ handle_paging_key(int ch)
|
||||
case 'd':
|
||||
if (lss) {
|
||||
lss->time_for_row(tc->get_selection()) |
|
||||
[ch, lss, tc](auto first_time) {
|
||||
[ch, lss, tc](auto first_ri) {
|
||||
int step = ch == 'd' ? (24 * 60 * 60) : (60 * 60);
|
||||
lss->find_from_time(first_time.tv_sec + step) |
|
||||
lss->find_from_time(first_ri.ri_time.tv_sec + step) |
|
||||
[tc](auto line) { tc->set_selection(line); };
|
||||
};
|
||||
|
||||
@ -729,12 +730,13 @@ handle_paging_key(int ch)
|
||||
|
||||
if (src_view != nullptr) {
|
||||
src_view->time_for_row(tc->get_selection()) |
|
||||
[](auto log_top) {
|
||||
lnav_data.ld_hist_source2.row_for_time(log_top) |
|
||||
[](auto row) {
|
||||
lnav_data.ld_views[LNV_HISTOGRAM]
|
||||
.set_selection(row);
|
||||
};
|
||||
[](auto log_top_ri) {
|
||||
lnav_data.ld_hist_source2.row_for_time(
|
||||
log_top_ri.ri_time)
|
||||
| [](auto row) {
|
||||
lnav_data.ld_views[LNV_HISTOGRAM]
|
||||
.set_selection(row);
|
||||
};
|
||||
};
|
||||
}
|
||||
} else {
|
||||
@ -749,10 +751,10 @@ handle_paging_key(int ch)
|
||||
auto curr_top_time_opt
|
||||
= dst_view->time_for_row(top_tc->get_selection());
|
||||
if (hist_top_time_opt && curr_top_time_opt
|
||||
&& hs.row_for_time(hist_top_time_opt.value())
|
||||
!= hs.row_for_time(curr_top_time_opt.value()))
|
||||
&& hs.row_for_time(hist_top_time_opt->ri_time)
|
||||
!= hs.row_for_time(curr_top_time_opt->ri_time))
|
||||
{
|
||||
dst_view->row_for_time(hist_top_time_opt.value()) |
|
||||
dst_view->row_for_time(hist_top_time_opt->ri_time) |
|
||||
[top_tc](auto new_top) {
|
||||
top_tc->set_selection(new_top);
|
||||
top_tc->set_needs_update();
|
||||
|
@ -724,7 +724,7 @@ com_goto(exec_context& ec, std::string cmdline, std::vector<std::string>& args)
|
||||
auto top_time_opt = ttt->time_for_row(tc->get_selection());
|
||||
|
||||
if (top_time_opt) {
|
||||
auto top_time_tv = top_time_opt.value();
|
||||
auto top_time_tv = top_time_opt.value().ri_time;
|
||||
struct tm top_tm;
|
||||
|
||||
localtime_r(&top_time_tv.tv_sec, &top_tm);
|
||||
@ -745,7 +745,7 @@ com_goto(exec_context& ec, std::string cmdline, std::vector<std::string>& args)
|
||||
if (!tv_opt) {
|
||||
return ec.make_error("cannot get time for the top row");
|
||||
}
|
||||
tv = tv_opt.value();
|
||||
tv = tv_opt.value().ri_time;
|
||||
|
||||
vis_line_t vl = tc->get_selection(), new_vl;
|
||||
bool done = false;
|
||||
@ -4286,7 +4286,7 @@ com_zoom_to(exec_context& ec,
|
||||
auto old_time_opt = lnav_data.ld_hist_source2.time_for_row(
|
||||
lnav_data.ld_views[LNV_HISTOGRAM].get_top());
|
||||
if (old_time_opt) {
|
||||
old_time = old_time_opt.value();
|
||||
old_time = old_time_opt.value().ri_time;
|
||||
rebuild_hist();
|
||||
lnav_data.ld_hist_source2.row_for_time(old_time) |
|
||||
[](auto new_top) {
|
||||
@ -4307,7 +4307,7 @@ com_zoom_to(exec_context& ec,
|
||||
spectro_view.reload_data();
|
||||
if (old_time_opt) {
|
||||
lnav_data.ld_spectro_source->row_for_time(
|
||||
old_time_opt.value())
|
||||
old_time_opt.value().ri_time)
|
||||
| [](auto new_top) {
|
||||
lnav_data.ld_views[LNV_SPECTRO].set_selection(
|
||||
new_top);
|
||||
@ -4616,9 +4616,9 @@ com_hide_line(exec_context& ec,
|
||||
struct exttm tm;
|
||||
|
||||
auto vl = tc->get_selection();
|
||||
auto log_tv = ttt->time_for_row(vl);
|
||||
if (log_tv) {
|
||||
tm = exttm::from_tv(log_tv.value());
|
||||
auto log_vl_ri = ttt->time_for_row(vl);
|
||||
if (log_vl_ri) {
|
||||
tm = exttm::from_tv(log_vl_ri.value().ri_time);
|
||||
tv_opt = parse_res.unwrap().adjust(tm).to_timeval();
|
||||
}
|
||||
}
|
||||
|
@ -2778,3 +2778,31 @@ logfile_sub_source::get_filtered_count_for(size_t filter_index) const
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
nonstd::optional<vis_line_t>
|
||||
logfile_sub_source::row_for(const row_info& ri)
|
||||
{
|
||||
auto lb = std::lower_bound(this->lss_filtered_index.begin(),
|
||||
this->lss_filtered_index.end(),
|
||||
ri.ri_time,
|
||||
filtered_logline_cmp(*this));
|
||||
if (lb != this->lss_filtered_index.end()) {
|
||||
auto first_lb = lb;
|
||||
while (true) {
|
||||
auto cl = this->lss_index[*lb];
|
||||
if (content_line_t(ri.ri_id) == cl) {
|
||||
first_lb = lb;
|
||||
break;
|
||||
}
|
||||
auto ll = this->find_line(cl);
|
||||
if (ll->get_timeval() != ri.ri_time) {
|
||||
break;
|
||||
}
|
||||
++lb;
|
||||
}
|
||||
|
||||
return vis_line_t(first_lb - this->lss_filtered_index.begin());
|
||||
}
|
||||
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
@ -477,14 +477,20 @@ public:
|
||||
|
||||
nonstd::optional<vis_line_t> find_from_content(content_line_t cl);
|
||||
|
||||
nonstd::optional<struct timeval> time_for_row(vis_line_t row)
|
||||
nonstd::optional<row_info> time_for_row(vis_line_t row)
|
||||
{
|
||||
if (row >= 0_vl && row < (ssize_t) this->text_line_count()) {
|
||||
return this->find_line(this->at(row))->get_timeval();
|
||||
auto cl = this->at(row);
|
||||
return row_info{
|
||||
this->find_line(cl)->get_timeval(),
|
||||
(int64_t) cl,
|
||||
};
|
||||
}
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
nonstd::optional<vis_line_t> row_for(const row_info& ri);
|
||||
|
||||
nonstd::optional<vis_line_t> row_for_time(struct timeval time_bucket)
|
||||
{
|
||||
return this->find_from_time(time_bucket);
|
||||
|
@ -82,7 +82,7 @@ public:
|
||||
return this->fss_time_delegate->row_for_time(time_bucket);
|
||||
}
|
||||
|
||||
nonstd::optional<struct timeval> time_for_row(vis_line_t row) override
|
||||
nonstd::optional<row_info> time_for_row(vis_line_t row) override
|
||||
{
|
||||
return this->fss_lines | lnav::itertools::nth(row)
|
||||
| lnav::itertools::flat_map([this](const auto row) {
|
||||
|
@ -82,7 +82,7 @@ spectrogram_source::list_input_handle_key(listview_curses& lv, int ch)
|
||||
return true;
|
||||
}
|
||||
auto begin_time = begin_time_opt.value();
|
||||
struct timeval end_time = begin_time;
|
||||
struct timeval end_time = begin_time.ri_time;
|
||||
|
||||
end_time.tv_sec += this->ss_granularity;
|
||||
double range_min, range_max, column_size;
|
||||
@ -93,7 +93,7 @@ spectrogram_source::list_input_handle_key(listview_curses& lv, int ch)
|
||||
+ this->ss_cursor_column.value_or(0) * column_size;
|
||||
range_max = range_min + column_size;
|
||||
this->ss_value_source->spectro_mark((textview_curses&) lv,
|
||||
begin_time.tv_sec,
|
||||
begin_time.ri_time.tv_sec,
|
||||
end_time.tv_sec,
|
||||
range_min,
|
||||
range_max);
|
||||
@ -291,7 +291,7 @@ spectrogram_source::text_line_width(textview_curses& tc)
|
||||
return width;
|
||||
}
|
||||
|
||||
nonstd::optional<struct timeval>
|
||||
nonstd::optional<text_time_translator::row_info>
|
||||
spectrogram_source::time_for_row(vis_line_t row)
|
||||
{
|
||||
if (this->ss_details_source != nullptr) {
|
||||
@ -306,7 +306,7 @@ spectrogram_source::time_for_row(vis_line_t row)
|
||||
return this->time_for_row_int(row);
|
||||
}
|
||||
|
||||
nonstd::optional<struct timeval>
|
||||
nonstd::optional<text_time_translator::row_info>
|
||||
spectrogram_source::time_for_row_int(vis_line_t row)
|
||||
{
|
||||
struct timeval retval {
|
||||
@ -318,7 +318,7 @@ spectrogram_source::time_for_row_int(vis_line_t row)
|
||||
= rounddown(this->ss_cached_bounds.sb_begin_time, this->ss_granularity)
|
||||
+ row * this->ss_granularity;
|
||||
|
||||
return retval;
|
||||
return row_info{retval, row};
|
||||
}
|
||||
|
||||
nonstd::optional<vis_line_t>
|
||||
@ -359,9 +359,9 @@ spectrogram_source::text_value_for_line(textview_curses& tc,
|
||||
value_out.clear();
|
||||
return;
|
||||
}
|
||||
auto row_time = row_time_opt.value();
|
||||
auto ri = row_time_opt.value();
|
||||
|
||||
gmtime_r(&row_time.tv_sec, &tm);
|
||||
gmtime_r(&ri.ri_time.tv_sec, &tm);
|
||||
strftime(tm_buffer, sizeof(tm_buffer), " %a %b %d %H:%M:%S", &tm);
|
||||
|
||||
value_out = tm_buffer;
|
||||
|
@ -154,7 +154,7 @@ public:
|
||||
|
||||
void text_selection_changed(textview_curses& tc) override;
|
||||
|
||||
nonstd::optional<struct timeval> time_for_row(vis_line_t row) override;
|
||||
nonstd::optional<row_info> time_for_row(vis_line_t row) override;
|
||||
|
||||
nonstd::optional<vis_line_t> row_for_time(
|
||||
struct timeval time_bucket) override;
|
||||
@ -170,7 +170,7 @@ public:
|
||||
|
||||
void cache_bounds();
|
||||
|
||||
nonstd::optional<struct timeval> time_for_row_int(vis_line_t row);
|
||||
nonstd::optional<row_info> time_for_row_int(vis_line_t row);
|
||||
|
||||
const spectrogram_row& load_row(const listview_curses& lv, int row);
|
||||
|
||||
|
@ -84,15 +84,15 @@ sql_log_top_datetime()
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
auto top_time = lnav_data.ld_log_source.time_for_row(
|
||||
auto top_ri = lnav_data.ld_log_source.time_for_row(
|
||||
lnav_data.ld_views[LNV_LOG].get_selection());
|
||||
if (!top_time) {
|
||||
if (!top_ri) {
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
char buffer[64];
|
||||
|
||||
sql_strftime(buffer, sizeof(buffer), top_time.value());
|
||||
sql_strftime(buffer, sizeof(buffer), top_ri->ri_time);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -429,18 +429,13 @@ textfile_sub_source::push_back(const std::shared_ptr<logfile>& lf)
|
||||
void
|
||||
textfile_sub_source::text_filters_changed()
|
||||
{
|
||||
for (auto iter = this->tss_files.begin(); iter != this->tss_files.end();) {
|
||||
++iter;
|
||||
}
|
||||
for (auto iter = this->tss_hidden_files.begin();
|
||||
iter != this->tss_hidden_files.end();)
|
||||
{
|
||||
++iter;
|
||||
auto lf = this->current_file();
|
||||
if (lf == nullptr || lf->get_text_format() == text_format_t::TF_BINARY) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<logfile> lf = this->current_file();
|
||||
|
||||
if (lf == nullptr) {
|
||||
auto rend_iter = this->tss_rendered_files.find(lf->get_filename());
|
||||
if (rend_iter != this->tss_rendered_files.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -462,6 +457,37 @@ textfile_sub_source::text_filters_changed()
|
||||
}
|
||||
|
||||
this->tss_view->redo_search();
|
||||
|
||||
auto iter = std::lower_bound(lfo->lfo_filter_state.tfs_index.begin(),
|
||||
lfo->lfo_filter_state.tfs_index.end(),
|
||||
this->tss_content_line);
|
||||
auto vl = vis_line_t(
|
||||
std::distance(lfo->lfo_filter_state.tfs_index.begin(), iter));
|
||||
this->tss_view->set_selection(vl);
|
||||
}
|
||||
|
||||
void
|
||||
textfile_sub_source::scroll_invoked(textview_curses* tc)
|
||||
{
|
||||
auto lf = this->current_file();
|
||||
if (lf == nullptr || lf->get_text_format() == text_format_t::TF_BINARY) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto rend_iter = this->tss_rendered_files.find(lf->get_filename());
|
||||
if (rend_iter != this->tss_rendered_files.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto line = tc->get_selection();
|
||||
auto* lfo = dynamic_cast<line_filter_observer*>(lf->get_logline_observer());
|
||||
if (lfo == nullptr || line < 0_vl
|
||||
|| line >= lfo->lfo_filter_state.tfs_index.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->tss_content_line = lfo->lfo_filter_state.tfs_index[line];
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -166,6 +166,8 @@ public:
|
||||
|
||||
logline* text_accel_get_line(vis_line_t vl) override;
|
||||
|
||||
void scroll_invoked(textview_curses* tc) override;
|
||||
|
||||
private:
|
||||
void detach_observer(std::shared_ptr<logfile> lf)
|
||||
{
|
||||
@ -193,6 +195,7 @@ private:
|
||||
size_t tss_line_indent_size{0};
|
||||
bool tss_completed_last_scan{true};
|
||||
attr_line_t tss_hex_line;
|
||||
int64_t tss_content_line{0};
|
||||
};
|
||||
|
||||
class textfile_header_overlay : public list_overlay_source {
|
||||
|
@ -822,11 +822,21 @@ textview_curses::grep_value_for_line(vis_line_t line, std::string& value_out)
|
||||
}
|
||||
|
||||
void
|
||||
text_time_translator::scroll_invoked(textview_curses* tc)
|
||||
text_sub_source::scroll_invoked(textview_curses* tc)
|
||||
{
|
||||
if (tc->get_inner_height() > 0) {
|
||||
auto* ttt = dynamic_cast<text_time_translator*>(this);
|
||||
|
||||
if (ttt != nullptr) {
|
||||
ttt->ttt_scroll_invoked(tc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
text_time_translator::ttt_scroll_invoked(textview_curses* tc)
|
||||
{
|
||||
if (tc->get_inner_height() > 0 && tc->get_selection() >= 0_vl) {
|
||||
this->time_for_row(tc->get_selection()) |
|
||||
[this](auto new_top_time) { this->ttt_top_time = new_top_time; };
|
||||
[this](auto new_top_ri) { this->ttt_top_row_info = new_top_ri; };
|
||||
}
|
||||
}
|
||||
|
||||
@ -834,29 +844,13 @@ void
|
||||
text_time_translator::data_reloaded(textview_curses* tc)
|
||||
{
|
||||
if (tc->get_inner_height() == 0) {
|
||||
this->ttt_top_row_info = nonstd::nullopt;
|
||||
return;
|
||||
}
|
||||
if (tc->get_selection() < 0_vl
|
||||
|| tc->get_selection() > tc->get_inner_height())
|
||||
{
|
||||
if (this->ttt_top_time.tv_sec != 0) {
|
||||
this->row_for_time(this->ttt_top_time) |
|
||||
[tc](auto new_top) { tc->set_selection(new_top); };
|
||||
}
|
||||
return;
|
||||
if (this->ttt_top_row_info) {
|
||||
this->row_for(this->ttt_top_row_info.value()) |
|
||||
[tc](auto new_top) { tc->set_selection(new_top); };
|
||||
}
|
||||
this->time_for_row(tc->get_selection()) | [this, tc](auto top_time) {
|
||||
if (top_time != this->ttt_top_time) {
|
||||
if (this->ttt_top_time.tv_sec != 0) {
|
||||
this->row_for_time(this->ttt_top_time) |
|
||||
[tc](auto new_top) { tc->set_selection(new_top); };
|
||||
}
|
||||
this->time_for_row(tc->get_selection()) |
|
||||
[this](auto new_top_time) {
|
||||
this->ttt_top_time = new_top_time;
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template class bookmark_vector<vis_line_t>;
|
||||
|
@ -250,22 +250,32 @@ private:
|
||||
|
||||
class text_time_translator {
|
||||
public:
|
||||
struct row_info {
|
||||
struct timeval ri_time {
|
||||
0, 0
|
||||
};
|
||||
int64_t ri_id{-1};
|
||||
};
|
||||
|
||||
virtual ~text_time_translator() = default;
|
||||
|
||||
virtual nonstd::optional<vis_line_t> row_for_time(
|
||||
struct timeval time_bucket)
|
||||
= 0;
|
||||
|
||||
virtual nonstd::optional<struct timeval> time_for_row(vis_line_t row) = 0;
|
||||
virtual nonstd::optional<vis_line_t> row_for(const row_info& ri)
|
||||
{
|
||||
return this->row_for_time(ri.ri_time);
|
||||
}
|
||||
|
||||
void scroll_invoked(textview_curses* tc);
|
||||
virtual nonstd::optional<row_info> time_for_row(vis_line_t row) = 0;
|
||||
|
||||
void data_reloaded(textview_curses* tc);
|
||||
|
||||
void ttt_scroll_invoked(textview_curses* tc);
|
||||
|
||||
protected:
|
||||
struct timeval ttt_top_time {
|
||||
0, 0
|
||||
};
|
||||
nonstd::optional<row_info> ttt_top_row_info;
|
||||
};
|
||||
|
||||
class text_accel_source {
|
||||
@ -496,6 +506,8 @@ public:
|
||||
|
||||
virtual void quiesce() {}
|
||||
|
||||
virtual void scroll_invoked(textview_curses* tc);
|
||||
|
||||
bool tss_supports_filtering{false};
|
||||
bool tss_apply_filters{true};
|
||||
|
||||
@ -777,11 +789,7 @@ public:
|
||||
void invoke_scroll()
|
||||
{
|
||||
if (this->tc_sub_source != nullptr) {
|
||||
auto ttt = dynamic_cast<text_time_translator*>(this->tc_sub_source);
|
||||
|
||||
if (ttt != nullptr) {
|
||||
ttt->scroll_invoked(this);
|
||||
}
|
||||
this->tc_sub_source->scroll_invoked(this);
|
||||
}
|
||||
|
||||
listview_curses::invoke_scroll();
|
||||
|
@ -300,15 +300,15 @@ CREATE TABLE lnav_views (
|
||||
= dynamic_cast<text_time_translator*>(tc.get_sub_source());
|
||||
|
||||
if (time_source != nullptr && tc.get_inner_height() > 0) {
|
||||
auto top_time_opt
|
||||
auto top_ri_opt
|
||||
= time_source->time_for_row(tc.get_selection());
|
||||
|
||||
if (top_time_opt) {
|
||||
if (top_ri_opt) {
|
||||
char timestamp[64];
|
||||
|
||||
sql_strftime(timestamp,
|
||||
sizeof(timestamp),
|
||||
top_time_opt.value(),
|
||||
top_ri_opt->ri_time,
|
||||
' ');
|
||||
sqlite3_result_text(
|
||||
ctx, timestamp, -1, SQLITE_TRANSIENT);
|
||||
@ -373,15 +373,15 @@ CREATE TABLE lnav_views (
|
||||
|
||||
top_line_meta tlm;
|
||||
if (time_source != nullptr) {
|
||||
auto top_time_opt
|
||||
auto top_ri_opt
|
||||
= time_source->time_for_row(tc.get_selection());
|
||||
|
||||
if (top_time_opt) {
|
||||
if (top_ri_opt) {
|
||||
char timestamp[64];
|
||||
|
||||
sql_strftime(timestamp,
|
||||
sizeof(timestamp),
|
||||
top_time_opt.value(),
|
||||
top_ri_opt->ri_time,
|
||||
' ');
|
||||
tlm.tlm_time = timestamp;
|
||||
}
|
||||
@ -530,11 +530,11 @@ CREATE TABLE lnav_views (
|
||||
tc.get_title().c_str(),
|
||||
top_time);
|
||||
if (dts.convert_to_timeval(top_time, -1, nullptr, tv)) {
|
||||
auto last_time_opt
|
||||
auto last_ri_opt
|
||||
= time_source->time_for_row(tc.get_selection());
|
||||
|
||||
if (last_time_opt) {
|
||||
auto last_time = last_time_opt.value();
|
||||
if (last_ri_opt) {
|
||||
auto last_time = last_ri_opt->ri_time;
|
||||
if (tv != last_time) {
|
||||
time_source->row_for_time(tv) |
|
||||
[&tc, &selection](auto row) {
|
||||
|
@ -1228,6 +1228,8 @@ EXPECTED_FILES = \
|
||||
$(srcdir)/%reldir%/test_text_file.sh_6a24078983cf1b7a80b6fb65d5186cd125498136.out \
|
||||
$(srcdir)/%reldir%/test_text_file.sh_73f69c883f60761bff9f8874f61d21a189e92912.err \
|
||||
$(srcdir)/%reldir%/test_text_file.sh_73f69c883f60761bff9f8874f61d21a189e92912.out \
|
||||
$(srcdir)/%reldir%/test_text_file.sh_786c7262f977201af36b0e69ba1a2aba130bbb06.err \
|
||||
$(srcdir)/%reldir%/test_text_file.sh_786c7262f977201af36b0e69ba1a2aba130bbb06.out \
|
||||
$(srcdir)/%reldir%/test_text_file.sh_78f252288519c8f767bb2759ea32959dab2ebc46.err \
|
||||
$(srcdir)/%reldir%/test_text_file.sh_78f252288519c8f767bb2759ea32959dab2ebc46.out \
|
||||
$(srcdir)/%reldir%/test_text_file.sh_7b00f32a3fff7fc2d78a87045ae842e58be88480.err \
|
||||
|
@ -0,0 +1,4 @@
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit
|
||||
esse cillum dolore eu fugiat nulla pariatur. Excepteur
|
||||
sint occaecat cupidatat non proident, sunt in culpa qui
|
||||
officia deserunt mollit anim id est laborum.
|
@ -4,6 +4,11 @@ export TZ=UTC
|
||||
export YES_COLOR=1
|
||||
unset XDG_CONFIG_HOME
|
||||
|
||||
run_cap_test ${lnav_test} -n \
|
||||
-c ':goto 5' \
|
||||
-c ':filter-out Lorem|sed' \
|
||||
${test_dir}/textfile_plain.0
|
||||
|
||||
run_cap_test ${lnav_test} -n \
|
||||
${top_srcdir}/README.md
|
||||
|
||||
|
9
test/textfile_plain.0
Normal file
9
test/textfile_plain.0
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
|
||||
sed do eiusmod tempor incididunt ut labore et dolore magna
|
||||
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
|
||||
ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit
|
||||
esse cillum dolore eu fugiat nulla pariatur. Excepteur
|
||||
sint occaecat cupidatat non proident, sunt in culpa qui
|
||||
officia deserunt mollit anim id est laborum.
|
Loading…
Reference in New Issue
Block a user