diff --git a/src/files_sub_source.cc b/src/files_sub_source.cc index 48a3f56e..03d03030 100644 --- a/src/files_sub_source.cc +++ b/src/files_sub_source.cc @@ -84,37 +84,38 @@ files_sub_source::list_input_handle_key(listview_curses& lv, int ch) case '\r': { auto sel = files_model::from_selection(lv.get_selection()); - sel.match([](files_model::no_selection) {}, - [](files_model::error_selection) {}, - [](files_model::other_selection) {}, - [&](files_model::file_selection& fs) { - auto& lss = lnav_data.ld_log_source; - auto lf = *fs.sb_iter; - - lss.find_data(lf) | [](auto ld) { - ld->set_visibility(true); - lnav_data.ld_log_source.text_filters_changed(); - }; - - if (lf->get_format() != nullptr) { - auto& log_view = lnav_data.ld_views[LNV_LOG]; - lss.row_for_time(lf->front().get_timeval()) | - [](auto row) { - lnav_data.ld_views[LNV_LOG].set_top(row); - }; - ensure_view(&log_view); - } else { - auto& tv = lnav_data.ld_views[LNV_TEXT]; - auto& tss = lnav_data.ld_text_source; - - tss.to_front(lf); - tv.reload_data(); - ensure_view(&tv); - } + sel.match( + [](files_model::no_selection) {}, + [](files_model::error_selection) {}, + [](files_model::other_selection) {}, + [&](files_model::file_selection& fs) { + auto& lss = lnav_data.ld_log_source; + auto lf = *fs.sb_iter; + + lss.find_data(lf) | [](auto ld) { + ld->set_visibility(true); + lnav_data.ld_log_source.text_filters_changed(); + }; + + if (lf->get_format() != nullptr) { + auto& log_view = lnav_data.ld_views[LNV_LOG]; + lss.row_for_time(lf->front().get_timeval()) | + [](auto row) { + lnav_data.ld_views[LNV_LOG].set_selection(row); + }; + ensure_view(&log_view); + } else { + auto& tv = lnav_data.ld_views[LNV_TEXT]; + auto& tss = lnav_data.ld_text_source; + + tss.to_front(lf); + tv.reload_data(); + ensure_view(&tv); + } - lv.reload_data(); - lnav_data.ld_mode = ln_mode_t::PAGING; - }); + lv.reload_data(); + lnav_data.ld_mode = ln_mode_t::PAGING; + }); return true; } @@ -308,29 +309,25 @@ files_sub_source::text_attrs_for_line(textview_curses& tc, std::max((size_t) 40, (size_t) dim.second - 30)); if (selected) { - value_out.emplace_back(line_range{0, 1}, - VC_GRAPHIC.value(ACS_RARROW)); + value_out.emplace_back(line_range{0, 1}, VC_GRAPHIC.value(ACS_RARROW)); } if (line < fc.fc_name_to_errors.size()) { if (selected) { - value_out.emplace_back( - line_range{0, -1}, - VC_ROLE.value(role_t::VCR_DISABLED_FOCUSED)); + value_out.emplace_back(line_range{0, -1}, + VC_ROLE.value(role_t::VCR_DISABLED_FOCUSED)); } - value_out.emplace_back( - line_range{4 + (int) filename_width, -1}, - VC_ROLE_FG.value(role_t::VCR_ERROR)); + value_out.emplace_back(line_range{4 + (int) filename_width, -1}, + VC_ROLE_FG.value(role_t::VCR_ERROR)); return; } line -= fc.fc_name_to_errors.size(); if (line < fc.fc_other_files.size()) { if (selected) { - value_out.emplace_back( - line_range{0, -1}, - VC_ROLE.value(role_t::VCR_DISABLED_FOCUSED)); + value_out.emplace_back(line_range{0, -1}, + VC_ROLE.value(role_t::VCR_DISABLED_FOCUSED)); } if (line == fc.fc_other_files.size() - 1) { value_out.emplace_back(line_range{0, -1}, @@ -342,9 +339,8 @@ files_sub_source::text_attrs_for_line(textview_curses& tc, line -= fc.fc_other_files.size(); if (selected) { - value_out.emplace_back( - line_range{0, -1}, - VC_ROLE.value(role_t::VCR_FOCUSED)); + value_out.emplace_back(line_range{0, -1}, + VC_ROLE.value(role_t::VCR_FOCUSED)); } auto& lss = lnav_data.ld_log_source; @@ -355,8 +351,7 @@ files_sub_source::text_attrs_for_line(textview_curses& tc, if (ld_opt && !ld_opt.value()->ld_visible) { visible = ' '; } - value_out.emplace_back(line_range{2, 3}, - VC_GRAPHIC.value(visible)); + value_out.emplace_back(line_range{2, 3}, VC_GRAPHIC.value(visible)); if (visible == ACS_DIAMOND) { value_out.emplace_back(line_range{2, 3}, VC_FOREGROUND.value(COLOR_GREEN)); diff --git a/src/hotkeys.cc b/src/hotkeys.cc index 12757ee6..dd3af900 100644 --- a/src/hotkeys.cc +++ b/src/hotkeys.cc @@ -803,7 +803,7 @@ handle_paging_key(int ch) { vis_line_t db_line(row); - db_tc->set_top(db_line); + db_tc->set_selection(db_line); db_tc->set_needs_update(); break; } @@ -826,7 +826,7 @@ handle_paging_key(int ch) &line_number) && line_number < tc->listview_rows(*tc)) { - tc->set_top(vis_line_t(line_number)); + tc->set_selection(vis_line_t(line_number)); tc->set_needs_update(); } } else { @@ -842,7 +842,7 @@ handle_paging_key(int ch) { lnav_data.ld_log_source.find_from_time(tv) | [tc](auto vl) { - tc->set_top(vl); + tc->set_selection(vl); tc->set_needs_update(); }; break; diff --git a/src/listview_curses.cc b/src/listview_curses.cc index 843e68e0..27bc8f74 100644 --- a/src/listview_curses.cc +++ b/src/listview_curses.cc @@ -43,6 +43,52 @@ list_gutter_source listview_curses::DEFAULT_GUTTER_SOURCE; listview_curses::listview_curses() : lv_scroll(noop_func{}) {} +void +listview_curses::update_top_from_selection() +{ + if (!this->lv_selectable) { + return; + } + + vis_line_t height; + unsigned long width; + + this->get_dimensions(height, width); + + if (this->lv_selection < 0_vl) { + this->set_top(0_vl); + } else if (this->lv_sync_selection_and_top) { + this->set_top(this->lv_selection); + } else if (this->lv_selection == this->get_inner_height() - 1_vl) { + this->set_top(this->get_top_for_last_row()); + } else if (this->lv_selection + >= (this->lv_top + height - this->lv_tail_space - 1_vl)) + { + auto diff = this->lv_selection + - (this->lv_top + height - this->lv_tail_space - 1_vl); + + if (height < 10 || diff < (height / 8_vl)) { + // for small differences between the bottom and the + // selection, just move a little bit. + this->set_top( + this->lv_selection - height + 1_vl + this->lv_tail_space, true); + } else { + // for large differences, put the focus in the middle + this->set_top(this->lv_selection - height / 2_vl, true); + } + } else if (this->lv_selection <= this->lv_top) { + auto diff = this->lv_top - this->lv_selection; + + if (this->lv_selection > 0 && (height < 10 || diff < (height / 8_vl))) { + this->set_top(this->lv_selection - 1_vl); + } else if (this->lv_selection < height) { + this->set_top(0_vl); + } else { + this->set_top(this->lv_selection - height / 2_vl, true); + } + } +} + void listview_curses::reload_data() { @@ -65,6 +111,8 @@ listview_curses::reload_data() this->lv_selection = -1_vl; this->set_selection(curr_sel); } + + this->update_top_from_selection(); } } this->vc_needs_update = true; @@ -199,42 +247,8 @@ listview_curses::do_update() vis_line_t height; unsigned long width; + this->update_top_from_selection(); this->get_dimensions(height, width); - - if (this->lv_selectable) { - if (this->lv_selection < 0_vl) { - this->set_top(0_vl); - } else if (this->lv_sync_selection_and_top) { - this->set_top(this->lv_selection); - } else if (this->lv_selection - >= (this->lv_top + height - this->lv_tail_space - 1_vl)) - { - auto diff = this->lv_selection - - (this->lv_top + height - this->lv_tail_space - 1_vl); - - if (diff < (height / 8_vl)) { - // for small differences between the bottom and the selection, - // just move a little bit. - this->set_top( - this->lv_selection - height + 1_vl + this->lv_tail_space, - true); - } else { - // for large differences, put the focus in the middle - this->set_top(this->lv_selection - height / 2_vl, true); - } - } else if (this->lv_selection <= this->lv_top) { - auto diff = this->lv_top - this->lv_selection; - - if (this->lv_selection > 0 && diff < (height / 8_vl)) { - this->set_top(this->lv_selection - 1_vl); - } else if (this->lv_selection < height) { - this->set_top(0_vl); - } else { - this->set_top(this->lv_selection - height / 2_vl, true); - } - } - } - while (this->vc_needs_update) { auto& vc = view_colors::singleton(); vis_line_t row; @@ -670,3 +684,26 @@ listview_curses::set_selection(vis_line_t sel) this->set_top(sel); } } + +vis_line_t +listview_curses::get_top_for_last_row() +{ + auto inner_height = this->get_inner_height(); + auto retval = 0_vl; + + if (inner_height > 0) { + auto last_line = inner_height - 1_vl; + unsigned long width; + vis_line_t height; + + this->get_dimensions(height, width); + retval = last_line - this->rows_available(last_line, RD_UP) + 1_vl; + if (inner_height >= (height - this->lv_tail_space) + && (retval + this->lv_tail_space) < inner_height) + { + retval += this->lv_tail_space; + } + } + + return retval; +} diff --git a/src/listview_curses.hh b/src/listview_curses.hh index 503d45bb..4625be77 100644 --- a/src/listview_curses.hh +++ b/src/listview_curses.hh @@ -315,22 +315,7 @@ public: /** @return The line number that is displayed at the bottom. */ vis_line_t get_bottom() const; - vis_line_t get_top_for_last_row() - { - auto retval = 0_vl; - - if (this->get_inner_height() > 0) { - vis_line_t last_line(this->get_inner_height() - 1); - - retval = last_line - - vis_line_t(this->rows_available(last_line, RD_UP) - 1); - if ((retval + this->lv_tail_space) < this->get_inner_height()) { - retval += this->lv_tail_space; - } - } - - return retval; - } + vis_line_t get_top_for_last_row(); /** @return True if the given line is visible. */ bool is_line_visible(vis_line_t line) const @@ -536,6 +521,8 @@ protected: } } + void update_top_from_selection(); + enum class lv_mode_t { NONE, DOWN, diff --git a/src/lnav.cc b/src/lnav.cc index d72ca804..1afba099 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -321,7 +321,7 @@ setup_logline_table(exec_context& ec) if (log_view.get_inner_height()) { static intern_string_t logline = intern_string::lookup("logline"); - vis_line_t vl = log_view.get_top(); + vis_line_t vl = log_view.get_selection(); content_line_t cl = lnav_data.ld_log_source.at_base(vl); lnav_data.ld_vtab_manager->unregister_vtab(logline); diff --git a/src/lnav.indexing.cc b/src/lnav.indexing.cc index fe709de6..d2a68d73 100644 --- a/src/lnav.indexing.cc +++ b/src/lnav.indexing.cc @@ -333,16 +333,16 @@ rebuild_indexes(nonstd::optional deadline) for (int lpc = 0; lpc < LNV__MAX; lpc++) { auto& scroll_view = lnav_data.ld_views[lpc]; - if (scroll_downs[lpc] - && scroll_view.get_top_for_last_row() > scroll_view.get_top()) - { + if (scroll_downs[lpc]) { if (scroll_view.is_selectable()) { auto inner_height = scroll_view.get_inner_height(); if (inner_height > 0_vl) { scroll_view.set_selection(inner_height - 1_vl); } - } else { + } else if (scroll_view.get_top_for_last_row() + > scroll_view.get_top()) + { scroll_view.set_top(scroll_view.get_top_for_last_row()); } } diff --git a/src/log_data_table.cc b/src/log_data_table.cc index 7a7c5379..384d7ce0 100644 --- a/src/log_data_table.cc +++ b/src/log_data_table.cc @@ -119,7 +119,10 @@ log_data_table::next(log_cursor& lc, logfile_sub_source& lss) content_line_t cl; cl = lss.at(lc.lc_curr_line); - std::shared_ptr lf = lss.find(cl); + auto* lf = lss.find_file_ptr(cl); + if (lf->get_format()->get_name() != this->ldt_format_impl->get_name()) { + return false; + } auto lf_iter = lf->begin() + cl; if (!lf_iter->is_message()) { diff --git a/src/views_vtab.cc b/src/views_vtab.cc index bfbc94c2..6dee241f 100644 --- a/src/views_vtab.cc +++ b/src/views_vtab.cc @@ -457,9 +457,9 @@ CREATE TABLE lnav_views ( } } } - if (movement == "top") { + if (movement == "top" && tc.is_selectable()) { tc.set_selectable(false); - } else if (movement == "cursor") { + } else if (movement == "cursor" && !tc.is_selectable()) { // First, toggle modes, otherwise get_selection() returns top tc.set_selectable(true); diff --git a/test/listview_output_cursor.3 b/test/listview_output_cursor.3 index 0bfca212..62ae2345 100644 --- a/test/listview_output_cursor.3 +++ b/test/listview_output_cursor.3 @@ -6,15 +6,15 @@ S -1 ┋ A └ normal CSI Reset Replace mode CSI Erase all -S 1 ┋2 x┋ +S 1 ┋World! x┋ A └┛ alt -S 2 ┋3 x┋ +S 2 ┋2 x┋ A └┛ alt -S 3 ┋+4 x┋ +S 3 ┋3 x┋ A └┛ alt -S 4 ┋5 x┋ +S 4 ┋+4 x┋ A └┛ alt -S 5 ┋6 x┋ +S 5 ┋5 x┋ A └┛ alt CSI Erase all CSI Use normal screen buffer diff --git a/test/listview_output_cursor.4 b/test/listview_output_cursor.4 index 3f9e3dfc..3980a0ba 100644 --- a/test/listview_output_cursor.4 +++ b/test/listview_output_cursor.4 @@ -6,15 +6,15 @@ S -1 ┋ A └ normal CSI Reset Replace mode CSI Erase all -S 1 ┋World! x┋ +S 1 ┋Hello x┋ A └┛ alt -S 2 ┋2 x┋ +S 2 ┋World! x┋ A └┛ alt -S 3 ┋+3 x┋ +S 3 ┋2 x┋ A └┛ alt -S 4 ┋4 x┋ +S 4 ┋+3 x┋ A └┛ alt -S 5 ┋5 x┋ +S 5 ┋4 x┋ A └┛ alt CSI Erase all CSI Use normal screen buffer