[views] fix some issues with empty views

Related to #908
This commit is contained in:
Timothy Stack 2021-09-07 21:08:01 -07:00
parent 312a97bca7
commit db7173caec
19 changed files with 238 additions and 187 deletions

View File

@ -261,7 +261,7 @@ long db_label_source::column_name_to_index(const std::string &name) const
return std::distance(this->dls_headers.begin(), iter);
}
int db_label_source::row_for_time(struct timeval time_bucket)
nonstd::optional<vis_line_t> db_label_source::row_for_time(struct timeval time_bucket)
{
std::vector<struct timeval>::iterator iter;
@ -269,9 +269,9 @@ int db_label_source::row_for_time(struct timeval time_bucket)
this->dls_time_column.end(),
time_bucket);
if (iter != this->dls_time_column.end()) {
return std::distance(this->dls_time_column.begin(), iter);
return vis_line_t(std::distance(this->dls_time_column.begin(), iter));
}
return -1;
return nonstd::nullopt;
}
size_t db_overlay_source::list_overlay_count(const listview_curses &lv)

View File

@ -81,11 +81,11 @@ public:
long column_name_to_index(const std::string &name) const;
int row_for_time(struct timeval time_bucket);
nonstd::optional<vis_line_t> row_for_time(struct timeval time_bucket);
struct timeval time_for_row(int row) {
if ((row < 0) || (((size_t) row) >= this->dls_time_column.size())) {
return { -1, 0 };
nonstd::optional<struct timeval> 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];

View File

@ -85,18 +85,18 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
time_t five_minutes_ago = local_now - (5 * 60 * 60);
time_t ten_secs_ago = local_now - 10;
vis_line_t from_five_min_ago = lss.find_from_time(five_minutes_ago);
vis_line_t from_ten_secs_ago = lss.find_from_time(ten_secs_ago);
auto from_five_min_ago_opt = lss.find_from_time(five_minutes_ago);
auto from_ten_secs_ago_opt = lss.find_from_time(ten_secs_ago);
auto &bm = tc.get_bookmarks();
auto error_bm_iter = bm.find(&logfile_sub_source::BM_ERRORS);
if (now > last_line->get_time() && from_five_min_ago != -1 &&
if (now > last_line->get_time() && from_five_min_ago_opt &&
error_bm_iter != bm.end()) {
auto& error_bookmarks = error_bm_iter->second;
auto five_min_lower =
lower_bound(error_bookmarks.begin(),
error_bookmarks.end(),
from_five_min_ago);
from_five_min_ago_opt.value());
if (five_min_lower != error_bookmarks.end()) {
double error_count = distance(
five_min_lower, error_bookmarks.end());
@ -108,11 +108,11 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
}
error_rate = error_count / time_diff;
if (from_ten_secs_ago != -1) {
if (from_ten_secs_ago_opt) {
auto ten_sec_lower =
lower_bound(error_bookmarks.begin(),
error_bookmarks.end(),
from_ten_secs_ago);
from_ten_secs_ago_opt.value());
if (ten_sec_lower != error_bookmarks.end()) {
double recent_error_count = distance(
ten_sec_lower, error_bookmarks.end());

View File

@ -99,9 +99,9 @@ bool files_sub_source::list_input_handle_key(listview_curses &lv, int ch)
if (lf->get_format() != nullptr) {
auto& log_view = lnav_data.ld_views[LNV_LOG];
auto row = lss.row_for_time(lf->front().get_timeval());
log_view.set_top(vis_line_t(row));
lss.row_for_time(lf->front().get_timeval()) | [](auto row) {
log_view.set_top(row);
};
ensure_view(&log_view);
} else {
auto& tv = lnav_data.ld_views[LNV_TEXT];

View File

@ -36,7 +36,7 @@ using namespace std;
const char *hist_source2::LINE_FORMAT = " %8d normal %8d errors %8d warnings %8d marks";
int hist_source2::row_for_time(struct timeval tv_bucket)
nonstd::optional<vis_line_t> hist_source2::row_for_time(struct timeval tv_bucket)
{
std::map<int64_t, struct bucket_block>::iterator iter;
int retval = 0;
@ -57,11 +57,11 @@ int hist_source2::row_for_time(struct timeval tv_bucket)
for (unsigned int lpc = 0; lpc <= bb.bb_used; lpc++, retval++) {
if (time_bucket <= bb.bb_buckets[lpc].b_time) {
return retval;
return vis_line_t(retval);
}
}
}
return retval;
return vis_line_t(retval);
}
void hist_source2::text_value_for_line(textview_curses &tc, int row,

View File

@ -396,16 +396,17 @@ public:
return 0;
};
struct timeval time_for_row(int row) {
require(row >= 0);
require(row < this->hs_line_count);
nonstd::optional<struct timeval> time_for_row(vis_line_t row) {
if (row < 0 || row > this->hs_line_count) {
return nonstd::nullopt;
}
bucket_t &bucket = this->find_bucket(row);
return { bucket.b_time, 0 };
return timeval{ bucket.b_time, 0 };
};
int row_for_time(struct timeval tv_bucket);
nonstd::optional<vis_line_t> row_for_time(struct timeval tv_bucket);
private:
static const char *LINE_FORMAT;

View File

@ -228,9 +228,11 @@ bool handle_paging_key(int ch)
lnav_data.ld_last_view = nullptr;
if (src_view != nullptr && dst_view != nullptr) {
struct timeval top_time = src_view->time_for_row(top_tc->get_top());
tc->set_top(vis_line_t(dst_view->row_for_time(top_time)));
src_view->time_for_row(top_tc->get_top()) | [dst_view, tc](auto top_time) {
dst_view->row_for_time(top_time) | [tc](auto row) {
tc->set_top(row);
};
};
}
ensure_view(tc);
}
@ -516,23 +518,26 @@ bool handle_paging_key(int ch)
case '0':
if (lss) {
struct timeval first_time = lss->time_for_row(tc->get_top());
int step = 24 * 60 * 60;
vis_line_t line =
lss->find_from_time(roundup_size(first_time.tv_sec, step));
tc->set_top(line);
const int step = 24 * 60 * 60;
lss->time_for_row(tc->get_top()) | [lss, tc](auto first_time) {
lss->find_from_time(roundup_size(first_time.tv_sec, step)) | [tc](auto line) {
tc->set_top(line);
};
};
}
break;
case ')':
if (lss) {
struct timeval first_time = lss->time_for_row(tc->get_top());
time_t day = rounddown(first_time.tv_sec, 24 * 60 * 60);
vis_line_t line = lss->find_from_time(day);
--line;
tc->set_top(line);
lss->time_for_row(tc->get_top()) | [lss, tc](auto first_time) {
time_t day = rounddown(first_time.tv_sec, 24 * 60 * 60);
lss->find_from_time(day) | [tc](auto line) {
if (line != 0_vl) {
--line;
}
tc->set_top(line);
};
};
}
break;
@ -541,15 +546,16 @@ bool handle_paging_key(int ch)
alerter::singleton().chime();
}
else if (lss) {
struct timeval first_time = lss->time_for_row(tc->get_top());
int step = ch == 'D' ? (24 * 60 * 60) : (60 * 60);
time_t top_time = first_time.tv_sec;
vis_line_t line = lss->find_from_time(top_time - step);
if (line != 0) {
--line;
}
tc->set_top(line);
lss->time_for_row(tc->get_top()) | [lss, ch, tc](auto first_time) {
int step = ch == 'D' ? (24 * 60 * 60) : (60 * 60);
time_t top_time = first_time.tv_sec;
lss->find_from_time(top_time - step) | [tc](auto line) {
if (line != 0_vl) {
--line;
}
tc->set_top(line);
};
};
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_1(/, "to search"));
}
@ -557,12 +563,12 @@ bool handle_paging_key(int ch)
case 'd':
if (lss) {
struct timeval first_time = lss->time_for_row(tc->get_top());
int step = ch == 'd' ? (24 * 60 * 60) : (60 * 60);
vis_line_t line =
lss->find_from_time(first_time.tv_sec + step);
tc->set_top(line);
lss->time_for_row(tc->get_top()) | [ch, lss, tc](auto first_time) {
int step = ch == 'd' ? (24 * 60 * 60) : (60 * 60);
lss->find_from_time(first_time.tv_sec + step) | [tc](auto line) {
tc->set_top(line);
};
};
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_1(/, "to search"));
}
@ -682,9 +688,11 @@ bool handle_paging_key(int ch)
auto *src_view = dynamic_cast<text_time_translator *>(tc->get_sub_source());
if (src_view != nullptr) {
struct timeval log_top = src_view->time_for_row(tc->get_top());
hist_tc.set_top(vis_line_t(hs.row_for_time(log_top)));
src_view->time_for_row(tc->get_top()) | [&hs, &hist_tc](auto log_top) {
hs.row_for_time(log_top) | [&hist_tc](auto row) {
hist_tc.set_top(row);
};
};
}
}
else {
@ -692,12 +700,15 @@ bool handle_paging_key(int ch)
auto *dst_view = dynamic_cast<text_time_translator *>(top_tc->get_sub_source());
if (dst_view != nullptr) {
struct timeval hist_top_time = hs.time_for_row(hist_tc.get_top());
struct timeval curr_top_time = dst_view->time_for_row(top_tc->get_top());
if (hs.row_for_time(hist_top_time) != hs.row_for_time(curr_top_time)) {
vis_line_t new_top = vis_line_t(dst_view->row_for_time(hist_top_time));
top_tc->set_top(new_top);
top_tc->set_needs_update();
auto hist_top_time_opt = hs.time_for_row(hist_tc.get_top());
auto curr_top_time_opt = dst_view->time_for_row(top_tc->get_top());
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())) {
dst_view->row_for_time(hist_top_time_opt.value()) | [top_tc](auto new_top) {
top_tc->set_top(new_top);
top_tc->set_needs_update();
};
}
}
};
@ -764,11 +775,10 @@ bool handle_paging_key(int ch)
size_t col_len = strlen(col_value);
if (dts.scan(col_value, col_len, nullptr, &tm, tv) != nullptr) {
vis_line_t vl;
vl = lnav_data.ld_log_source.find_from_time(tv);
tc->set_top(vl);
tc->set_needs_update();
lnav_data.ld_log_source.find_from_time(tv) | [tc](auto vl) {
tc->set_top(vl);
tc->set_needs_update();
};
break;
}
}
@ -879,7 +889,11 @@ bool handle_paging_key(int ch)
ll->to_exttm(tm);
do {
tm = rt.adjust(tm);
new_vl = lnav_data.ld_log_source.find_from_time(tm);
auto new_vl_opt = lnav_data.ld_log_source.find_from_time(tm);
if (!new_vl_opt) {
break;
}
new_vl = new_vl_opt.value();
if (new_vl == 0_vl || new_vl != vl || !rt.is_relative()) {
vl = new_vl;

View File

@ -326,6 +326,14 @@ public:
/** @return The line number that is displayed at the top. */
vis_line_t get_top() const { return this->lv_top; };
nonstd::optional<vis_line_t> get_top_opt() const {
if (this->get_inner_height() == 0_vl) {
return nonstd::nullopt;
}
return this->lv_top;
}
/** @return The line number that is displayed at the bottom. */
vis_line_t get_bottom() const
{

View File

@ -348,47 +348,58 @@ static Result<string, string> com_goto(exec_context &ec, string cmdline, vector<
auto parse_res = relative_time::from_str(all_args);
if (parse_res.isOk()) {
if (ttt != nullptr) {
struct timeval tv = ttt->time_for_row(tc->get_top());
vis_line_t vl = tc->get_top(), new_vl;
bool done = false;
auto rt = parse_res.unwrap();
if (rt.is_relative()) {
injector::get<relative_time&, last_relative_time_tag>() = rt;
}
do {
auto tm = rt.adjust(tv);
tv = tm.to_timeval();
new_vl = vis_line_t(ttt->row_for_time(tv));
if (new_vl == 0_vl || new_vl != vl || !rt.is_relative()) {
vl = new_vl;
done = true;
}
} while (!done);
dst_vl = vl;
if (!ec.ec_dry_run && !rt.is_absolute() && lnav_data.ld_rl_view != nullptr) {
lnav_data.ld_rl_view->set_alt_value(
HELP_MSG_2(r, R,
"to move forward/backward the same amount of time"));
}
} else {
if (ttt == nullptr) {
return ec.make_error("relative time values only work in a time-indexed view");
}
if (tc->get_inner_height() == 0_vl) {
return ec.make_error("view is empty");
}
auto tv_opt = ttt->time_for_row(tc->get_top());
if (!tv_opt) {
return ec.make_error("cannot get time for the top row");
}
tv = tv_opt.value();
vis_line_t vl = tc->get_top(), new_vl;
bool done = false;
auto rt = parse_res.unwrap();
if (rt.is_relative()) {
injector::get<relative_time&, last_relative_time_tag>() = rt;
}
do {
auto tm = rt.adjust(tv);
tv = tm.to_timeval();
auto new_vl_opt = ttt->row_for_time(tv);
if (!new_vl_opt) {
break;
}
new_vl = new_vl_opt.value();
if (new_vl == 0_vl || new_vl != vl || !rt.is_relative()) {
vl = new_vl;
done = true;
}
} while (!done);
dst_vl = vl;
if (!ec.ec_dry_run && !rt.is_absolute() && lnav_data.ld_rl_view != nullptr) {
lnav_data.ld_rl_view->set_alt_value(
HELP_MSG_2(r, R,
"to move forward/backward the same amount of time"));
}
}
else if (dts.scan(args[1].c_str(), args[1].size(), nullptr, &tm, tv) !=
nullptr) {
if (ttt != nullptr) {
dst_vl = vis_line_t(ttt->row_for_time(tv));
}
else {
return ec.make_error("time values only work in a time-indexed view");
if (ttt == nullptr) {
return ec.make_error(
"time values only work in a time-indexed view");
}
dst_vl = ttt->row_for_time(tv);
}
else if (sscanf(args[1].c_str(), "%f%n", &value, &consumed) == 1) {
if (args[1][consumed] == '%') {
@ -3342,24 +3353,30 @@ static Result<string, string> com_zoom_to(exec_context &ec, string cmdline, vect
textview_curses &hist_view = lnav_data.ld_views[LNV_HISTOGRAM];
if (hist_view.get_inner_height() > 0) {
old_time = lnav_data.ld_hist_source2.time_for_row(
auto old_time_opt = lnav_data.ld_hist_source2.time_for_row(
lnav_data.ld_views[LNV_HISTOGRAM].get_top());
rebuild_hist();
lnav_data.ld_views[LNV_HISTOGRAM].set_top(
vis_line_t(
lnav_data.ld_hist_source2.row_for_time(old_time)));
if (old_time_opt) {
old_time = old_time_opt.value();
rebuild_hist();
lnav_data.ld_hist_source2.row_for_time(old_time) | [](auto new_top) {
lnav_data.ld_views[LNV_HISTOGRAM].set_top(new_top);
};
}
}
textview_curses &spectro_view = lnav_data.ld_views[LNV_SPECTRO];
if (spectro_view.get_inner_height() > 0) {
old_time = lnav_data.ld_spectro_source.time_for_row(
auto old_time_opt = lnav_data.ld_spectro_source.time_for_row(
lnav_data.ld_views[LNV_SPECTRO].get_top());
ss.ss_granularity = ZOOM_LEVELS[lnav_data.ld_zoom_level];
ss.invalidate();
lnav_data.ld_views[LNV_SPECTRO].set_top(
vis_line_t(lnav_data.ld_spectro_source.row_for_time(
old_time)));
if (old_time_opt) {
lnav_data.ld_spectro_source.row_for_time(old_time_opt.value()) |
[](auto new_top) {
lnav_data.ld_views[LNV_SPECTRO].set_top(new_top);
};
}
}
lnav_data.ld_view_stack.set_needs_update();
@ -4135,17 +4152,11 @@ public:
void spectro_row(spectrogram_request &sr, spectrogram_row &row_out) {
logfile_sub_source &lss = lnav_data.ld_log_source;
vis_line_t begin_line = lss.find_from_time(sr.sr_begin_time);
vis_line_t end_line = lss.find_from_time(sr.sr_end_time);
vis_line_t begin_line = lss.find_from_time(sr.sr_begin_time).value_or(0_vl);
vis_line_t end_line = lss.find_from_time(sr.sr_end_time).value_or(lss.text_line_count());
vector<logline_value> values;
string_attrs_t sa;
if (begin_line == -1) {
begin_line = 0_vl;
}
if (end_line == -1) {
end_line = vis_line_t(lss.text_line_count());
}
for (vis_line_t curr_line = begin_line; curr_line < end_line; ++curr_line) {
content_line_t cl = lss.at(curr_line);
std::shared_ptr<logfile> lf = lss.find(cl);
@ -4188,17 +4199,11 @@ public:
// XXX need to refactor this and the above method
textview_curses &log_tc = lnav_data.ld_views[LNV_LOG];
logfile_sub_source &lss = lnav_data.ld_log_source;
vis_line_t begin_line = lss.find_from_time(begin_time);
vis_line_t end_line = lss.find_from_time(end_time);
vis_line_t begin_line = lss.find_from_time(begin_time).value_or(0_vl);
vis_line_t end_line = lss.find_from_time(end_time).value_or(lss.text_line_count());
vector<logline_value> values;
string_attrs_t sa;
if (begin_line == -1) {
begin_line = 0_vl;
}
if (end_line == -1) {
end_line = vis_line_t(lss.text_line_count());
}
for (vis_line_t curr_line = begin_line; curr_line < end_line; ++curr_line) {
content_line_t cl = lss.at(curr_line);
std::shared_ptr<logfile> lf = lss.find(cl);
@ -4317,17 +4322,10 @@ public:
void spectro_row(spectrogram_request &sr, spectrogram_row &row_out) {
db_label_source &dls = lnav_data.ld_db_row_source;
int begin_row = dls.row_for_time({ sr.sr_begin_time, 0 });
int end_row = dls.row_for_time({ sr.sr_end_time, 0 });
auto begin_row = dls.row_for_time({ sr.sr_begin_time, 0 }).value_or(0_vl);
auto end_row = dls.row_for_time({ sr.sr_end_time, 0 }).value_or(dls.dls_rows.size());
if (begin_row == -1) {
begin_row = 0;
}
if (end_row == -1) {
end_row = dls.dls_rows.size();
}
for (int lpc = begin_row; lpc < end_row; lpc++) {
for (auto lpc = begin_row; lpc < end_row; ++lpc) {
double value = 0.0;
sscanf(dls.dls_rows[lpc][this->dsvs_column_index], "%lf", &value);

View File

@ -792,14 +792,14 @@ static int vt_filter(sqlite3_vtab_cursor *p_vtc,
date_time_scanner dts;
struct timeval tv;
struct exttm mytm;
vis_line_t vl;
dts.scan((const char *)datestr, strlen((const char *)datestr), NULL, &mytm, tv);
if ((vl = vt->lss->find_from_time(tv)) == -1) {
auto vl_opt = vt->lss->find_from_time(tv);
if (!vl_opt) {
p_cur->log_cursor.lc_curr_line = p_cur->log_cursor.lc_end_line;
}
else {
p_cur->log_cursor.update(index[lpc].op, vl, false);
p_cur->log_cursor.update(index[lpc].op, vl_opt.value(), false);
}
}
break;

View File

@ -137,19 +137,17 @@ shared_ptr<logfile> logfile_sub_source::find(const char *fn,
return retval;
}
vis_line_t logfile_sub_source::find_from_time(const struct timeval &start) const
nonstd::optional<vis_line_t> logfile_sub_source::find_from_time(const struct timeval &start) const
{
vis_line_t retval(-1);
auto lb = lower_bound(this->lss_filtered_index.begin(),
this->lss_filtered_index.end(),
start,
filtered_logline_cmp(*this));
if (lb != this->lss_filtered_index.end()) {
retval = vis_line_t(lb - this->lss_filtered_index.begin());
return vis_line_t(lb - this->lss_filtered_index.begin());
}
return retval;
return nonstd::nullopt;
}
void logfile_sub_source::text_value_for_line(textview_curses &tc,

View File

@ -528,15 +528,15 @@ public:
return retval;
};
vis_line_t find_from_time(const struct timeval &start) const;
nonstd::optional<vis_line_t> find_from_time(const struct timeval &start) const;
vis_line_t find_from_time(time_t start) {
nonstd::optional<vis_line_t> find_from_time(time_t start) const {
struct timeval tv = { start, 0 };
return this->find_from_time(tv);
};
vis_line_t find_from_time(const exttm &etm) const {
nonstd::optional<vis_line_t> find_from_time(const exttm &etm) const {
return this->find_from_time(etm.to_timeval());
};
@ -547,7 +547,13 @@ public:
if (lf != nullptr) {
auto ll_iter = lf->begin() + line;
auto &ll = *ll_iter;
vis_line_t vis_start = this->find_from_time(ll.get_timeval());
auto vis_start_opt = this->find_from_time(ll.get_timeval());
if (!vis_start_opt) {
return nonstd::nullopt;
}
auto vis_start = *vis_start_opt;
while (vis_start < vis_line_t(this->text_line_count())) {
content_line_t guess_cl = this->at(vis_start);
@ -569,11 +575,14 @@ public:
return nonstd::nullopt;
}
struct timeval time_for_row(int row) {
return this->find_line(this->at(vis_line_t(row)))->get_timeval();
nonstd::optional<struct timeval> time_for_row(vis_line_t row) {
if (row < this->text_line_count()) {
return this->find_line(this->at(row))->get_timeval();
}
return nonstd::nullopt;
};
int row_for_time(struct timeval time_bucket) {
nonstd::optional<vis_line_t> row_for_time(struct timeval time_bucket) {
return this->find_from_time(time_bucket);
};

View File

@ -52,7 +52,11 @@ bool spectrogram_source::list_input_handle_key(listview_curses &lv, int ch)
lv.get_dimensions(height, width);
spectrogram_bounds &sb = this->ss_cached_bounds;
struct timeval begin_time = this->time_for_row(this->ss_cursor_top);
auto begin_time_opt = this->time_for_row(this->ss_cursor_top);
if (!begin_time_opt) {
return true;
}
auto begin_time = begin_time_opt.value();
struct timeval end_time = begin_time;
end_time.tv_sec += this->ss_granularity;
@ -207,7 +211,7 @@ size_t spectrogram_source::text_line_width(textview_curses &tc)
return width;
}
struct timeval spectrogram_source::time_for_row(int row)
nonstd::optional<struct timeval> spectrogram_source::time_for_row(vis_line_t row)
{
struct timeval retval { 0, 0 };
@ -219,10 +223,10 @@ struct timeval spectrogram_source::time_for_row(int row)
return retval;
}
int spectrogram_source::row_for_time(struct timeval time_bucket)
nonstd::optional<vis_line_t> spectrogram_source::row_for_time(struct timeval time_bucket)
{
if (this->ss_value_source == nullptr) {
return 0;
return nonstd::nullopt;
}
time_t diff;
@ -230,13 +234,13 @@ int spectrogram_source::row_for_time(struct timeval time_bucket)
this->cache_bounds();
if (time_bucket.tv_sec < this->ss_cached_bounds.sb_begin_time) {
return 0;
return 0_vl;
}
diff = time_bucket.tv_sec - this->ss_cached_bounds.sb_begin_time;
retval = diff / this->ss_granularity;
return retval;
return vis_line_t(retval);
}
void spectrogram_source::text_value_for_line(textview_curses &tc, int row,
@ -245,11 +249,15 @@ void spectrogram_source::text_value_for_line(textview_curses &tc, int row,
{
spectrogram_row &s_row = this->load_row(tc, row);
struct timeval row_time;
char tm_buffer[128];
struct tm tm;
row_time = this->time_for_row(row);
auto row_time_opt = this->time_for_row(vis_line_t(row));
if (!row_time_opt) {
value_out.clear();
return;
}
auto row_time = row_time_opt.value();
gmtime_r(&row_time.tv_sec, &tm);
strftime(tm_buffer, sizeof(tm_buffer), " %a %b %d %H:%M:%S", &tm);

View File

@ -133,9 +133,9 @@ public:
return 0;
};
struct timeval time_for_row(int row) override;
nonstd::optional<struct timeval> time_for_row(vis_line_t row) override;
int row_for_time(struct timeval time_bucket) override;
nonstd::optional<vis_line_t> row_for_time(struct timeval time_bucket) override;
void text_value_for_line(textview_curses &tc,
int row,

View File

@ -59,9 +59,14 @@ static nonstd::optional<std::string> sql_log_top_datetime()
return nonstd::nullopt;
}
auto top_time = lnav_data.ld_log_source.time_for_row(lnav_data.ld_views[LNV_LOG].get_top());
if (!top_time) {
return nonstd::nullopt;
}
char buffer[64];
sql_strftime(buffer, sizeof(buffer), lnav_data.ld_log_source.time_for_row(lnav_data.ld_views[LNV_LOG].get_top()));
sql_strftime(buffer, sizeof(buffer), top_time.value());
return buffer;
}

View File

@ -730,25 +730,27 @@ textview_curses::toggle_user_mark(bookmark_type_t *bm, vis_line_t start_line,
void text_time_translator::scroll_invoked(textview_curses *tc)
{
if (tc->get_inner_height() > 0) {
this->ttt_top_time = this->time_for_row((int) tc->get_top());
this->time_for_row(tc->get_top()) | [this](auto new_top_time) {
this->ttt_top_time = new_top_time;
};
}
}
void text_time_translator::data_reloaded(textview_curses *tc)
{
if (tc->get_inner_height() > 0) {
struct timeval top_time = this->time_for_row((int) tc->get_top());
if (top_time != this->ttt_top_time) {
if (this->ttt_top_time.tv_sec != 0) {
vis_line_t new_top(this->row_for_time(this->ttt_top_time));
if (new_top >= 0) {
tc->set_top(new_top);
this->time_for_row(tc->get_top()) | [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_top(new_top);
};
}
this->time_for_row(tc->get_top()) | [this](auto new_top_time) {
this->ttt_top_time = new_top_time;
};
}
this->ttt_top_time = this->time_for_row((int) tc->get_top());
}
};
}
}

View File

@ -360,9 +360,9 @@ class text_time_translator {
public:
virtual ~text_time_translator() = default;
virtual int row_for_time(struct timeval time_bucket) = 0;
virtual nonstd::optional<vis_line_t> row_for_time(struct timeval time_bucket) = 0;
virtual struct timeval time_for_row(int row) = 0;
virtual nonstd::optional<struct timeval> time_for_row(vis_line_t row) = 0;
void scroll_invoked(textview_curses *tc);

View File

@ -156,11 +156,16 @@ CREATE TABLE lnav_views (
auto *time_source = dynamic_cast<text_time_translator *>(tc.get_sub_source());
if (time_source != nullptr && tc.get_inner_height() > 0) {
char timestamp[64];
auto top_time_opt = time_source->time_for_row(tc.get_top());
sql_strftime(timestamp, sizeof(timestamp), time_source->time_for_row(tc.get_top()), 'T');
if (top_time_opt) {
char timestamp[64];
sqlite3_result_text(ctx, timestamp, -1, SQLITE_TRANSIENT);
sql_strftime(timestamp, sizeof(timestamp), top_time_opt.value(), 'T');
sqlite3_result_text(ctx, timestamp, -1, SQLITE_TRANSIENT);
} else {
sqlite3_result_null(ctx);
}
} else {
sqlite3_result_null(ctx);
}
@ -231,12 +236,15 @@ CREATE TABLE lnav_views (
struct timeval tv;
if (dts.convert_to_timeval(top_time, -1, nullptr, tv)) {
struct timeval last_time = time_source->time_for_row(tc.get_top());
auto last_time_opt = time_source->time_for_row(tc.get_top());
if (tv != last_time) {
int row = time_source->row_for_time(tv);
tc.set_top(vis_line_t(row));
if (last_time_opt) {
auto last_time = last_time_opt.value();
if (tv != last_time) {
time_source->row_for_time(tv) | [&tc](auto row) {
tc.set_top(row);
};
}
}
} else {
tab->zErrMsg = sqlite3_mprintf("Invalid time: %s", top_time);

View File

@ -367,7 +367,6 @@ TESTS = \
test_log_accel \
test_logfile.sh \
test_reltime \
test_remote.sh \
test_scripts.sh \
test_sessions.sh \
test_shlexer.sh \
@ -386,6 +385,7 @@ TESTS = \
test_vt52_curses.sh
DISABLED_TESTS = \
test_remote.sh \
test_top_status \
test_line_buffer2 \
test_line_buffer.sh