diff --git a/NEWS b/NEWS index e6f9659d..289e5cfc 100644 --- a/NEWS +++ b/NEWS @@ -21,7 +21,9 @@ lnav v0.8.2: users. * Pressing 'n'/'N' to move through the next/previous search hit will now skip adjacent lines, up to the vertical size of the view. This should - make scanning through clusters of hits much faster. + make scanning through clusters of hits much faster. Repeatedly + pressing these keys within a short time will also accelerate scanning + by moving the view at least a full page at a time. Breaking Changes: * The captured timestamp text in log files must fully match a known format diff --git a/src/help.txt b/src/help.txt index 6dec8252..897a82ed 100644 --- a/src/help.txt +++ b/src/help.txt @@ -196,7 +196,10 @@ Spatial Navigation e/E Move to the next/previous error. w/W Move to the next/previous warning. - n/N Move to the next/previous search hit. + n/N Move to the next/previous search hit. When pressed + repeatedly within a short time, the view will move at + least a full page at a time instead of moving to the + next hit. f/F Move to the next/previous file. In the log view, this moves to the next line from a different file. In the text view, this rotates the view to the next file. diff --git a/src/hotkeys.cc b/src/hotkeys.cc index d2e173fd..457bfeb1 100644 --- a/src/hotkeys.cc +++ b/src/hotkeys.cc @@ -332,21 +332,19 @@ void handle_paging_key(int ch) case 'n': moveto_cluster(&bookmark_vector::next, &textview_curses::BM_SEARCH, - tc->get_top()); + search_forward_from(tc)); lnav_data.ld_bottom_source.grep_error(""); lnav_data.ld_rl_view->set_alt_value( - "Press '" ANSI_BOLD(">") "' or '" ANSI_BOLD("<") - "' to scroll horizontally to a search result"); + "Press '" ANSI_BOLD(">") "' or '" ANSI_BOLD("<") + "' to scroll horizontally to a search result"); break; case 'N': - moveto_cluster(&bookmark_vector::prev, - &textview_curses::BM_SEARCH, - tc->get_top()); + previous_cluster(&textview_curses::BM_SEARCH, tc); lnav_data.ld_bottom_source.grep_error(""); lnav_data.ld_rl_view->set_alt_value( - "Press '" ANSI_BOLD(">") "' or '" ANSI_BOLD("<") - "' to scroll horizontally to a search result"); + "Press '" ANSI_BOLD(">") "' or '" ANSI_BOLD("<") + "' to scroll horizontally to a search result"); break; case 'y': diff --git a/src/lnav.cc b/src/lnav.cc index 429718d8..7384631d 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -892,8 +892,8 @@ vis_line_t next_cluster( } bool moveto_cluster(vis_line_t(bookmark_vector::*f) (vis_line_t), - bookmark_type_t *bt, - vis_line_t top) + bookmark_type_t *bt, + vis_line_t top) { textview_curses *tc = lnav_data.ld_view_stack.top(); vis_line_t new_top; @@ -909,6 +909,48 @@ bool moveto_cluster(vis_line_t(bookmark_vector::*f) (vis_line_t), return false; } +void previous_cluster(bookmark_type_t *bt, textview_curses *tc) +{ + key_repeat_history &krh = lnav_data.ld_key_repeat_history; + vis_line_t height, new_top, initial_top = tc->get_top(); + unsigned long width; + + new_top = next_cluster(&bookmark_vector::prev, + bt, + initial_top); + + tc->get_dimensions(height, width); + if (krh.krh_count > 1 && + initial_top < (krh.krh_start_line - (1.5 * height)) && + (initial_top - new_top) < height) { + bookmark_vector &bv = tc->get_bookmarks()[bt]; + new_top = bv.next(std::max(vis_line_t(0), initial_top - height)); + } + + if (new_top != -1) { + tc->set_top(new_top); + } + else { + alerter::singleton().chime(); + } +} + +vis_line_t search_forward_from(textview_curses *tc) +{ + vis_line_t height, retval = tc->get_top(); + key_repeat_history &krh = lnav_data.ld_key_repeat_history; + unsigned long width; + + tc->get_dimensions(height, width); + + if (krh.krh_count > 1 && + retval > (krh.krh_start_line + (1.5 * height))) { + retval += vis_line_t(0.90 * height); + } + + return retval; +} + static void handle_rl_key(int ch) { switch (ch) { @@ -1898,6 +1940,10 @@ static void looper(void) escape_index = 0; continue; } + + lnav_data.ld_key_repeat_history.update( + ch, lnav_data.ld_view_stack.top()->get_top()); + switch (ch) { case CEOF: case KEY_RESIZE: diff --git a/src/lnav.hh b/src/lnav.hh index 62c71253..69854ced 100644 --- a/src/lnav.hh +++ b/src/lnav.hh @@ -174,6 +174,40 @@ private: size_t ist_index; }; +struct key_repeat_history { + key_repeat_history() + : krh_key(0), + krh_count(0) { + this->krh_last_press_time.tv_sec = 0; + this->krh_last_press_time.tv_usec = 0; + } + + int krh_key; + int krh_count; + vis_line_t krh_start_line; + struct timeval krh_last_press_time; + + void update(int ch, vis_line_t top) { + struct timeval now, diff; + + gettimeofday(&now, NULL); + timersub(&now, &this->krh_last_press_time, &diff); + if (diff.tv_sec >= 1 || diff.tv_usec > (750 * 1000)) { + this->krh_key = 0; + this->krh_count = 0; + } + this->krh_last_press_time = now; + + if (this->krh_key == ch) { + this->krh_count += 1; + } else { + this->krh_key = ch; + this->krh_count = 1; + this->krh_start_line = top; + } + }; +}; + struct _lnav_data { std::string ld_session_id; time_t ld_session_time; @@ -264,6 +298,8 @@ struct _lnav_data { std::map > ld_scripts; int ld_fifo_counter; + + struct key_repeat_history ld_key_repeat_history; }; extern struct _lnav_data lnav_data; @@ -298,7 +334,9 @@ vis_line_t next_cluster( bookmark_type_t *bt, vis_line_t top); bool moveto_cluster(vis_line_t(bookmark_vector::*f) (vis_line_t), - bookmark_type_t *bt, - vis_line_t top); + bookmark_type_t *bt, + vis_line_t top); +void previous_cluster(bookmark_type_t *bt, textview_curses *tc); +vis_line_t search_forward_from(textview_curses *tc); #endif diff --git a/src/textview_curses.hh b/src/textview_curses.hh index 11aefe82..a83a3c6d 100644 --- a/src/textview_curses.hh +++ b/src/textview_curses.hh @@ -638,7 +638,9 @@ public: if (first_hit > 0) { --first_hit; } - this->set_top(first_hit); + if (first_hit > this->get_top()) { + this->set_top(first_hit); + } } } }