mirror of https://github.com/tstack/lnav.git
parent
312a97bca7
commit
db7173caec
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
104
src/hotkeys.cc
104
src/hotkeys.cc
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue