From 7fa4e253182bfc0d4fc4dc7fe6b7f19446a929bd Mon Sep 17 00:00:00 2001 From: Tim Stack Date: Tue, 9 Apr 2024 21:46:21 -0700 Subject: [PATCH] [ui] make cursor mode the default fix some wordwrap and scrolling issues as well --- NEWS.md | 5 +++ docs/source/ui.rst | 8 ++-- src/listview_curses.cc | 27 ++++++++++---- src/logfile_sub_source.cc | 4 +- src/root-config.json | 2 +- src/textfile_sub_source.cc | 12 ++++-- test/drive_listview.cc | 37 +++++++++++-------- ...3639753916f71254e8c9cce4ebb8bfd9978d3e.out | 2 +- test/listview_output_cursor.4 | 10 ++--- 9 files changed, 67 insertions(+), 40 deletions(-) diff --git a/NEWS.md b/NEWS.md index 37838b2c..7f54e190 100644 --- a/NEWS.md +++ b/NEWS.md @@ -15,6 +15,11 @@ Interface changes: individual columns instead of occupying the whole width of the view. The result is much cleaner, so the charts are now enabled by default again. +* Cursor mode in the main view is now the default instead of + using the top line as the focus. You can change back by + running: + + `:config /ui/movement/mode top` Bug Fixes: * With the recent xz backdoor shenanigans, it seems like a good diff --git a/docs/source/ui.rst b/docs/source/ui.rst index d94dc31e..de71e721 100644 --- a/docs/source/ui.rst +++ b/docs/source/ui.rst @@ -26,11 +26,11 @@ times in the views. **lnav** provides many operations to work with the log/text data in the main view. For example, you can add comments and tags to log messages. -By default, the top line is used as the reference point to edit the +The highlighted cursor line is used as the reference point to edit the comment or tags. Alternatively, you can press :kbd:`Ctrl` + :kbd:`x` -to switch to "cursor" mode where the "focused" line is highlighted and -most operations now work with that line. When in "cursor" mode, the -:kbd:`↑` and :kbd:`↓` keys now move the focused line instead of scrolling +to switch to "top" mode where the "focused" line is the top line in the +view and most operations now work with that line. When in "cursor" mode, +the :kbd:`↑` and :kbd:`↓` keys now move the focused line instead of scrolling the view. Jumping to bookmarks, like errors, will also move the focused line instead of moving the next error to the top of the view. diff --git a/src/listview_curses.cc b/src/listview_curses.cc index cc5fabf5..21cf1299 100644 --- a/src/listview_curses.cc +++ b/src/listview_curses.cc @@ -215,8 +215,9 @@ listview_curses::handle_key(int ch) { this->set_selection(0_vl); } else { - this->shift_top( - -(this->rows_available(this->lv_top, RD_UP) - 1_vl)); + auto shift_amount + = -(this->rows_available(this->lv_top, RD_UP) - 1_vl); + this->shift_top(shift_amount); } break; @@ -232,8 +233,12 @@ listview_curses::handle_key(int ch) } } - auto rows_avail - = this->rows_available(this->lv_top, RD_DOWN) - 1_vl; + auto rows_avail = this->rows_available(this->lv_top, RD_DOWN); + if (rows_avail == 0_vl) { + rows_avail = 2_vl; + } else if (rows_avail > 2_vl) { + rows_avail -= 1_vl; + } auto top_for_last = this->get_top_for_last_row(); if ((this->lv_top < top_for_last) @@ -436,8 +441,8 @@ listview_curses::do_update() al, lr, this->vc_default_role); - lr.lr_start += write_res.mr_chars_out; - lr.lr_end += write_res.mr_chars_out; + lr.lr_start = write_res.mr_chars_out; + lr.lr_end = write_res.mr_chars_out + width - 1; ++y; } while (this->lv_word_wrap && y < bottom && write_res.mr_bytes_remaining > 0); @@ -884,8 +889,14 @@ listview_curses::set_top(vis_line_t top, bool suppress_flash) this->get_dimensions(height, width); - if (bot != -1_vl && (bot - top) >= (height - 1)) { - if (this->lv_selection > (bot - this->lv_tail_space)) { + if (bot == -1_vl) { + this->set_selection(this->lv_top); + } else if (this->lv_selection < this->lv_top + || bot < this->lv_selection) + { + if (top + sel_diff > bot) { + this->set_selection(bot); + } else { this->set_selection(top + sel_diff); } } diff --git a/src/logfile_sub_source.cc b/src/logfile_sub_source.cc index 0c0e5ff4..aa4bd72d 100644 --- a/src/logfile_sub_source.cc +++ b/src/logfile_sub_source.cc @@ -2871,7 +2871,9 @@ logfile_sub_source::text_size_for_line(textview_curses& tc, std::string value; this->text_value_for_line(tc, row, value, flags); - this->lss_line_size_cache[index].second = value.size(); + scrub_ansi_string(value, nullptr); + this->lss_line_size_cache[index].second + = string_fragment::from_str(value).column_width(); this->lss_line_size_cache[index].first = row; } return this->lss_line_size_cache[index].second; diff --git a/src/root-config.json b/src/root-config.json index 43f69327..effdbed8 100644 --- a/src/root-config.json +++ b/src/root-config.json @@ -7,7 +7,7 @@ "keymap": "default", "theme": "default", "movement": { - "mode": "top" + "mode": "cursor" } }, "log": { diff --git a/src/textfile_sub_source.cc b/src/textfile_sub_source.cc index d0904dd5..92a5df8d 100644 --- a/src/textfile_sub_source.cc +++ b/src/textfile_sub_source.cc @@ -295,10 +295,14 @@ textfile_sub_source::text_size_for_line(textview_curses& tc, || line >= lfo->lfo_filter_state.tfs_index.size()) { } else { - retval - = lf->message_byte_length( - lf->begin() + lfo->lfo_filter_state.tfs_index[line]) - .mlr_length; + auto read_res = lf->read_line( + lf->begin() + lfo->lfo_filter_state.tfs_index[line]); + if (read_res.isOk()) { + auto sbr = read_res.unwrap(); + auto str = to_string(sbr); + scrub_ansi_string(str, nullptr); + retval = string_fragment::from_str(str).column_width(); + } } } else { retval = rend_iter->second.rf_text_source->text_size_for_line( diff --git a/test/drive_listview.cc b/test/drive_listview.cc index 76d3df8f..f9d6080b 100644 --- a/test/drive_listview.cc +++ b/test/drive_listview.cc @@ -41,12 +41,9 @@ static listview_curses lv; class my_source : public list_data_source { public: - my_source() : ms_rows(2){}; + my_source() : ms_rows(2) {} - size_t listview_rows(const listview_curses& lv) - { - return this->ms_rows; - }; + size_t listview_rows(const listview_curses& lv) { return this->ms_rows; } void listview_value_for_rows(const listview_curses& lv, vis_line_t row, @@ -67,12 +64,12 @@ public: } ++row; } - }; + } size_t listview_size_for_row(const listview_curses& lv, vis_line_t row) { return 100; - }; + } bool attrline_next_token(const view_curses& vc, int line, @@ -80,7 +77,7 @@ public: int& attrs_out) { return false; - }; + } int ms_rows; }; @@ -90,6 +87,7 @@ main(int argc, char* argv[]) { int c, retval = EXIT_SUCCESS; bool wait_for_input = false, set_height = false; + const char* keys = nullptr; my_source ms; WINDOW* win; @@ -111,15 +109,9 @@ main(int argc, char* argv[]) lv.set_height(vis_line_t(atoi(optarg))); set_height = true; break; - case 'k': { - // Treats the string argument as sequence of key presses (only - // individual characters supported as key input) - for (char* ptr = optarg; ptr != nullptr && *ptr != '\0'; ++ptr) - { - lv.handle_key(static_cast(*ptr)); - } + case 'k': + keys = optarg; break; - } case 't': lv.set_selection(vis_line_t(atoi(optarg))); break; @@ -141,6 +133,19 @@ main(int argc, char* argv[]) lv.set_height(vis_line_t(height - lv.get_y())); } + if (keys != nullptr) { + // Treats the string argument as sequence of key presses (only + // individual characters supported as key input) + for (const char* ptr = keys; ptr != nullptr && *ptr != '\0'; ++ptr) { + lv.do_update(); + if (wait_for_input) { + getch(); + refresh(); + } + lv.handle_key(static_cast(*ptr)); + } + } + lv.do_update(); refresh(); if (wait_for_input) { diff --git a/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out b/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out index 30b05009..9f16b891 100644 --- a/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out +++ b/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out @@ -4645,7 +4645,7 @@ } }, "movement": { - "mode": "top" + "mode": "cursor" }, "keymap-defs": { "de": { diff --git a/test/listview_output_cursor.4 b/test/listview_output_cursor.4 index 3980a0ba..3f9e3dfc 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 ┋Hello x┋ +S 1 ┋World! x┋ A └┛ alt -S 2 ┋World! x┋ +S 2 ┋2 x┋ A └┛ alt -S 3 ┋2 x┋ +S 3 ┋+3 x┋ A └┛ alt -S 4 ┋+3 x┋ +S 4 ┋4 x┋ A └┛ alt -S 5 ┋4 x┋ +S 5 ┋5 x┋ A └┛ alt CSI Erase all CSI Use normal screen buffer