From 635452f2b47cdddb5118f07fe831224c93eb9803 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 25 Jun 2025 10:59:10 +1000 Subject: Rework highlighting management of cursor position Move the whole responsibility of making the cursor visible to the window, removing cursor_pos from the display setup and resolving the cursor location by finding it in the display buffer afterwards. This simplifies hightlighters' do_compute_display_setup as they do not need to compute the cursor location. Highlighting may run on more lines than necessary after this change but this should be a minor performance hit. --- src/highlighter.hh | 3 -- src/highlighters.cc | 102 +--------------------------------------------------- src/window.cc | 58 ++++++++++++------------------ 3 files changed, 24 insertions(+), 139 deletions(-) (limited to 'src') diff --git a/src/highlighter.hh b/src/highlighter.hh index 73520c53..8a60c0c1 100644 --- a/src/highlighter.hh +++ b/src/highlighter.hh @@ -43,11 +43,8 @@ struct DisplaySetup LineCount line_count; ColumnCount first_column; ColumnCount widget_columns; - // Position of the cursor in the window - DisplayCoord cursor_pos; // Offset of line and columns that must remain visible around cursor DisplayCoord scroll_offset; - bool ensure_cursor_visible; }; using HighlighterIdList = ConstArrayView; diff --git a/src/highlighters.cc b/src/highlighters.cc index 25f93245..2044ccd5 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -613,9 +613,7 @@ struct WrapHighlighter : Highlighter return; const Buffer& buffer = context.context.buffer(); - const auto& cursor = context.context.selections().main().cursor(); const int tabstop = context.context.options()["tabstop"].get(); - const LineCount win_height = context.context.window().dimensions().line; const ColumnCount marker_len = zero_if_greater(m_marker.column_length(), wrap_column); const Face face_marker = context.context.faces()["WrapMarker"]; for (auto it = display_buffer.lines().begin(); @@ -658,19 +656,6 @@ struct WrapHighlighter : Highlighter it->replace(String{' ', indent - marker_len}); } - if (it+1 - display_buffer.lines().begin() == win_height) - { - if (cursor >= new_line.range().begin) // strip first lines if cursor is not visible - { - display_buffer.lines().erase(display_buffer.lines().begin(), display_buffer.lines().begin()+1); - --it; - } - else - { - display_buffer.lines().erase(it+1, display_buffer.lines().end()); - return; - } - } it = display_buffer.lines().insert(it+1, new_line); pos = next_split_pos(buffer, wrap_column - prefix_len, prefix_len, tabstop, buf_line, pos); @@ -688,80 +673,9 @@ struct WrapHighlighter : Highlighter if (wrap_column <= 0) return; - const Buffer& buffer = context.context.buffer(); - const auto& cursor = context.context.selections().main().cursor(); - const int tabstop = context.context.options()["tabstop"].get(); - - auto line_wrap_count = [&](LineCount line, ColumnCount prefix_len) { - LineCount count = 0; - const ByteCount line_length = buffer[line].length(); - SplitPos pos{0, 0}; - while (true) - { - pos = next_split_pos(buffer, wrap_column - (pos.byte == 0 ? 0_col : prefix_len), - prefix_len, tabstop, line, pos); - if (pos.byte == line_length) - break; - ++count; - } - return count; - }; - - const auto win_height = context.context.window().dimensions().line; - // Disable horizontal scrolling when using a WrapHighlighter setup.first_column = 0; - setup.line_count = 0; setup.scroll_offset.column = 0; - - const ColumnCount marker_len = zero_if_greater(m_marker.column_length(), wrap_column); - - for (auto buf_line = setup.first_line, win_line = 0_line; - win_line < win_height or (setup.ensure_cursor_visible and buf_line <= cursor.line); - ++buf_line, ++setup.line_count) - { - if (buf_line >= buffer.line_count()) - break; - - const ColumnCount indent = m_preserve_indent ? - zero_if_greater(line_indent(buffer, tabstop, buf_line), wrap_column) : 0_col; - const ColumnCount prefix_len = std::max(marker_len, indent); - - if (buf_line == cursor.line) - { - SplitPos pos{0, 0}; - for (LineCount count = 0; true; ++count) - { - auto next_pos = next_split_pos(buffer, wrap_column - (pos.byte != 0 ? prefix_len : 0_col), - prefix_len, tabstop, buf_line, pos); - if (next_pos.byte > cursor.column) - { - setup.cursor_pos = DisplayCoord{ - win_line + count, - get_column(buffer, tabstop, cursor) - - pos.column + (pos.byte != 0 ? indent : 0_col) - }; - break; - } - pos = next_pos; - } - } - const auto wrap_count = line_wrap_count(buf_line, prefix_len); - win_line += wrap_count + 1; - - // scroll window to keep cursor visible, and update range as lines gets removed - while (setup.ensure_cursor_visible and - buf_line >= cursor.line and setup.first_line < cursor.line and - setup.cursor_pos.line + setup.scroll_offset.line >= win_height) - { - auto remove_count = 1 + line_wrap_count(setup.first_line, indent); - ++setup.first_line; - --setup.line_count; - setup.cursor_pos.line -= std::min(win_height, remove_count); - win_line -= remove_count; - kak_assert(setup.cursor_pos.line >= 0); - } - } } void fill_unique_ids(Vector& unique_ids) const override @@ -947,7 +861,6 @@ struct TabulationHighlighter : Highlighter const ColumnCount offset = std::max(column + width - win_end, 0_col); setup.first_column += offset; - setup.cursor_pos.column -= offset; } }; @@ -1694,7 +1607,6 @@ private: auto& buffer = context.context.buffer(); auto& sels = context.context.selections(); auto& range_and_faces = get_option(context); - const int tabstop = context.context.options()["tabstop"].get(); update_ranges(buffer, range_and_faces.prefix, range_and_faces.list); range_and_faces.prefix = buffer.timestamp(); @@ -1707,19 +1619,7 @@ private: if (range.first.line < setup.first_line and last.line >= setup.first_line) setup.first_line = range.first.line; - const auto& cursor = context.context.selections().main().cursor(); - if (cursor.line == last.line and cursor.column >= last.column) - { - auto first_column = get_column(buffer, tabstop, range.first); - auto last_column = get_column(buffer, tabstop, last); - auto replacement = parse_display_line(spec, context.context.faces()); - auto cursor_move = replacement.length() - ((range.first.line == last.line) ? last_column - first_column : last_column); - setup.cursor_pos.line -= last.line - range.first.line; - setup.cursor_pos.column += cursor_move; - } - - if (setup.ensure_cursor_visible and - last.line >= setup.first_line and + if (last.line >= setup.first_line and range.first.line <= setup.first_line + setup.line_count and range.first.line != last.line) { diff --git a/src/window.cc b/src/window.cc index 520d77e1..2b8d4be9 100644 --- a/src/window.cc +++ b/src/window.cc @@ -132,7 +132,7 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context) return m_display_buffer; kak_assert(&buffer() == &context.buffer()); - const DisplaySetup setup = compute_display_setup(context); + DisplaySetup setup = compute_display_setup(context); for (LineCount line = 0; line < setup.line_count; ++line) { @@ -147,6 +147,24 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context) m_builtin_highlighters.highlight({context, setup, HighlightPass::Wrap, {}}, m_display_buffer, range); m_builtin_highlighters.highlight({context, setup, HighlightPass::Move, {}}, m_display_buffer, range); + if (context.ensure_cursor_visible) + { + auto cursor_pos = display_coord(context.selections().main().cursor()); + kak_assert(cursor_pos); + + if (auto line_overflow = cursor_pos->line - m_dimensions.line + setup.scroll_offset.line + 1; line_overflow > 0) + { + lines.erase(lines.begin(), lines.begin() + (size_t)line_overflow); + setup.first_line = lines.begin()->range().begin.line; + } + + auto max_first_column = cursor_pos->column - (setup.widget_columns + setup.scroll_offset.column); + setup.first_column = std::min(setup.first_column, max_first_column); + + auto min_first_column = cursor_pos->column - (m_dimensions.column - setup.scroll_offset.column) + 1; + setup.first_column = std::max(setup.first_column, min_first_column); + } + for (auto& line : m_display_buffer.lines()) line.trim_from(setup.widget_columns, setup.first_column, m_dimensions.column); if (m_display_buffer.lines().size() > m_dimensions.line) @@ -203,11 +221,9 @@ DisplaySetup Window::compute_display_setup(const Context& context) const offset.line = std::min(offset.line, (m_dimensions.line + 1) / 2); offset.column = std::min(offset.column, (m_dimensions.column + 1) / 2); - const int tabstop = context.options()["tabstop"].get(); const auto& cursor = context.selections().main().cursor(); - bool ensure_cursor_visible = context.ensure_cursor_visible; - if (ensure_cursor_visible) + if (context.ensure_cursor_visible) { if (cursor.line - offset.line < win_pos.line) win_pos.line = std::max(0_line, cursor.line - offset.line); @@ -216,39 +232,11 @@ DisplaySetup Window::compute_display_setup(const Context& context) const } win_pos.line = std::min(win_pos.line, buffer().line_count()-1); - DisplaySetup setup{ - win_pos.line, - m_dimensions.line, - win_pos.column, - 0_col, - {cursor.line - win_pos.line, - get_column(buffer(), tabstop, cursor) - win_pos.column}, - offset, - ensure_cursor_visible - }; - for (auto pass : { HighlightPass::Move, HighlightPass::Wrap }) - m_builtin_highlighters.compute_display_setup({context, setup, pass, {}}, setup); + DisplaySetup setup{win_pos.line, m_dimensions.line, win_pos.column, 0_col, offset}; + m_builtin_highlighters.compute_display_setup({context, setup, HighlightPass::Move, {}}, setup); + m_builtin_highlighters.compute_display_setup({context, setup, HighlightPass::Wrap, {}}, setup); check_display_setup(setup, *this); - // now ensure the cursor column is visible - if (ensure_cursor_visible) - { - auto underflow = std::max(-setup.first_column, - setup.cursor_pos.column - setup.scroll_offset.column); - if (underflow < 0) - { - setup.first_column += underflow; - setup.cursor_pos.column -= underflow; - } - auto overflow = setup.cursor_pos.column + setup.scroll_offset.column - (m_dimensions.column - setup.widget_columns) + 1; - if (overflow > 0) - { - setup.first_column += overflow; - setup.cursor_pos.column -= overflow; - } - check_display_setup(setup, *this); - } - return setup; } -- cgit v1.2.3