From f310db639c4ad063f74d4f556ab86afa7d4469b9 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 9 Jun 2017 13:22:32 +0100 Subject: [PATCH] Rework partial line display logic Instead of highlighting full lines and then trim them to make them fit in the window, highlight only the visible portion, and rely on the compute_display_setup system introduced for wrapping to setup our buffer range correctly --- src/display_buffer.cc | 18 ----- src/display_buffer.hh | 8 +- src/highlighters.cc | 75 ++++++++++++------- src/window.cc | 8 +- .../horizontal-scroll-onto-tab/display | 4 +- test/highlight/regions/display | 2 +- 6 files changed, 58 insertions(+), 57 deletions(-) diff --git a/src/display_buffer.cc b/src/display_buffer.cc index 3796cf2a..c4e2d366 100644 --- a/src/display_buffer.cc +++ b/src/display_buffer.cc @@ -53,7 +53,6 @@ void DisplayAtom::trim_begin(ColumnCount count) count).coord(); else m_text = m_text.substr(count).str(); - check_invariant(); } void DisplayAtom::trim_end(ColumnCount count) @@ -64,18 +63,6 @@ void DisplayAtom::trim_end(ColumnCount count) -count).coord(); else m_text = m_text.substr(0, m_text.column_length() - count).str(); - check_invariant(); -} - -void DisplayAtom::check_invariant() const -{ -#ifdef KAK_DEBUG - if (has_buffer_range()) - { - kak_assert(m_buffer->is_valid(m_range.begin)); - kak_assert(m_buffer->is_valid(m_range.end)); - } -#endif } DisplayLine::DisplayLine(AtomList atoms) @@ -93,8 +80,6 @@ DisplayLine::iterator DisplayLine::split(iterator it, BufferCoord pos) DisplayAtom atom = *it; atom.m_range.end = pos; it->m_range.begin = pos; - atom.check_invariant(); - it->check_invariant(); return m_atoms.insert(it, std::move(atom)); } @@ -106,8 +91,6 @@ DisplayLine::iterator DisplayLine::split(iterator it, ColumnCount pos) DisplayAtom atom(it->m_text.substr(0, pos).str()); it->m_text = it->m_text.substr(pos).str(); - atom.check_invariant(); - it->check_invariant(); return m_atoms.insert(it, std::move(atom)); } @@ -174,7 +157,6 @@ void DisplayLine::optimize() next_atom_it = m_atoms.erase(next_atom_it); else atom_it = next_atom_it++; - atom_it->check_invariant(); } } diff --git a/src/display_buffer.hh b/src/display_buffer.hh index 981f4960..ac6d4e82 100644 --- a/src/display_buffer.hh +++ b/src/display_buffer.hh @@ -31,12 +31,10 @@ public: enum Type { Range, ReplacedRange, Text }; DisplayAtom(const Buffer& buffer, BufferCoord begin, BufferCoord end) - : m_type(Range), m_buffer(&buffer), m_range{begin, end} - { check_invariant(); } + : m_type(Range), m_buffer(&buffer), m_range{begin, end} {} DisplayAtom(String str, Face face = Face{}) - : m_type(Text), m_text(std::move(str)), face(face) - { check_invariant(); } + : m_type(Text), m_text(std::move(str)), face(face) {} StringView content() const; ColumnCount length() const; @@ -72,8 +70,6 @@ public: void trim_begin(ColumnCount count); void trim_end(ColumnCount count); - void check_invariant() const; - bool operator==(const DisplayAtom& other) const { return face == other.face and type() == other.type() and diff --git a/src/highlighters.cc b/src/highlighters.cc index 66ff7d9d..caecdbf5 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -880,40 +880,63 @@ struct WrapHighlighter : Highlighter const ColumnCount m_max_width; }; -void expand_tabulations(const Context& context, HighlightPass, DisplayBuffer& display_buffer, BufferRange) +struct TabulationHighlighter : Highlighter { - const ColumnCount tabstop = context.options()["tabstop"].get(); - auto& buffer = context.buffer(); - for (auto& line : display_buffer.lines()) + TabulationHighlighter() : Highlighter{HighlightPass::Move} {} + + void do_highlight(const Context& context, HighlightPass, + DisplayBuffer& display_buffer, BufferRange) override { - for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it) + const ColumnCount tabstop = context.options()["tabstop"].get(); + auto& buffer = context.buffer(); + auto win_column = context.window().position().column; + for (auto& line : display_buffer.lines()) { - if (atom_it->type() != DisplayAtom::Range) - continue; - - auto begin = buffer.iterator_at(atom_it->begin()); - auto end = buffer.iterator_at(atom_it->end()); - for (BufferIterator it = begin; it != end; ++it) + for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it) { - if (*it == '\t') - { - if (it != begin) - atom_it = ++line.split(atom_it, it.coord()); - if (it+1 != end) - atom_it = line.split(atom_it, (it+1).coord()); + if (atom_it->type() != DisplayAtom::Range) + continue; - ColumnCount column = get_column(buffer, tabstop, it.coord()); - ColumnCount count = tabstop - (column % tabstop); - String padding; - for (int i = 0; i < count; ++i) - padding += ' '; - atom_it->replace(padding); - break; + auto begin = buffer.iterator_at(atom_it->begin()); + auto end = buffer.iterator_at(atom_it->end()); + for (BufferIterator it = begin; it != end; ++it) + { + if (*it == '\t') + { + if (it != begin) + atom_it = ++line.split(atom_it, it.coord()); + if (it+1 != end) + atom_it = line.split(atom_it, (it+1).coord()); + + const ColumnCount column = get_column(buffer, tabstop, it.coord()); + const ColumnCount count = tabstop - (column % tabstop) - + std::max(win_column - column, 0_col); + atom_it->replace(String{' ', count}); + break; + } } } } } -} + + void do_compute_display_setup(const Context& context, HighlightPass, DisplaySetup& setup) override + { + auto& buffer = context.buffer(); + // Ensure that a cursor on a tab character makes the full tab character visible + auto cursor = context.selections().main().cursor(); + if (buffer.byte_at(cursor) != '\t') + return; + + const ColumnCount tabstop = context.options()["tabstop"].get(); + const ColumnCount column = get_column(buffer, tabstop, cursor); + const ColumnCount width = tabstop - (column % tabstop); + const ColumnCount win_end = setup.window_pos.column + setup.window_range.column; + const ColumnCount offset = std::max(column + width - win_end, 0_col); + + setup.window_pos.column += offset; + setup.cursor_pos.column -= offset; + } +}; void show_whitespaces(const Context& context, HighlightPass, DisplayBuffer& display_buffer, BufferRange, StringView tab, StringView tabpad, @@ -1935,7 +1958,7 @@ private: void setup_builtin_highlighters(HighlighterGroup& group) { - group.add_child({"tabulations"_str, make_highlighter(expand_tabulations)}); + group.add_child({"tabulations"_str, make_unique()}); group.add_child({"unprintable"_str, make_highlighter(expand_unprintable)}); group.add_child({"selections"_str, make_highlighter(highlight_selections)}); } diff --git a/src/window.cc b/src/window.cc index 1dee2c2a..26cf3021 100644 --- a/src/window.cc +++ b/src/window.cc @@ -122,12 +122,15 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context) kak_assert(&buffer() == &context.buffer()); compute_display_setup(context); + const int tabstop = context.options()["tabstop"].get(); for (LineCount line = 0; line < m_range.line; ++line) { LineCount buffer_line = m_position.line + line; if (buffer_line >= buffer().line_count()) break; - lines.emplace_back(AtomList{ {buffer(), buffer_line, buffer_line+1} }); + auto beg_byte = get_byte_to_column(buffer(), tabstop, {buffer_line, m_position.column}); + auto end_byte = get_byte_to_column(buffer(), tabstop, {buffer_line, m_position.column + m_range.column}); + lines.emplace_back(AtomList{ {buffer(), {buffer_line, beg_byte}, {buffer_line, end_byte}} }); } m_display_buffer.compute_range(); @@ -137,9 +140,6 @@ const DisplayBuffer& Window::update_display_buffer(const Context& context) for (auto pass : { HighlightPass::Wrap, HighlightPass::Move, HighlightPass::Colorize }) m_builtin_highlighters.highlight(context, pass, m_display_buffer, range); - // cut the start of the line before m_position.column - for (auto& line : lines) - line.trim(m_position.column, m_dimensions.column, true); m_display_buffer.optimize(); m_last_setup = build_setup(context); diff --git a/test/display/horizontal-scroll-onto-tab/display b/test/display/horizontal-scroll-onto-tab/display index 3505ae3b..1b655f09 100644 --- a/test/display/horizontal-scroll-onto-tab/display +++ b/test/display/horizontal-scroll-onto-tab/display @@ -1,6 +1,6 @@ -{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "23456789012345678901234567890123456789012345678901234567890123456789012345678901" }], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "234567890123456789012345678901234567890123456789012345678901234567890123456" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "black", "bg": "white", "attributes": [] }, "contents": " " }], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "90" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "7890\u000a" }]], { "fg": "default", "bg": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "attributes": [] }] } +{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "90123456789012345678901234567890123456789012345678901234567890123456789012345678" }], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "90123456789012345678901234567890123456789012345678901234567890123456" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "black", "bg": "white", "attributes": [] }, "contents": " " }], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "90" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "7890\u000a" }]], { "fg": "default", "bg": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "attributes": [] }] } { "jsonrpc": "2.0", "method": "menu_hide", "params": [] } { "jsonrpc": "2.0", "method": "info_hide", "params": [] } { "jsonrpc": "2.0", "method": "draw_status", "params": [[], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "out 2:78 " }, { "face": { "fg": "black", "bg": "yellow", "attributes": [] }, "contents": "" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "blue", "bg": "default", "attributes": [] }, "contents": "1 sel" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " - unnamed0@[kak-tests]" }], { "fg": "cyan", "bg": "default", "attributes": [] }] } -{ "jsonrpc": "2.0", "method": "set_cursor", "params": ["buffer", { "line": 1, "column": 79 }] } +{ "jsonrpc": "2.0", "method": "set_cursor", "params": ["buffer", { "line": 1, "column": 72 }] } { "jsonrpc": "2.0", "method": "refresh", "params": [true] } diff --git a/test/highlight/regions/display b/test/highlight/regions/display index ee4ba80b..8581701e 100644 --- a/test/highlight/regions/display +++ b/test/highlight/regions/display @@ -1,4 +1,4 @@ -{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "black", "bg": "white", "attributes": [] }, "contents": "\"" }, { "face": { "fg": "green", "bg": "default", "attributes": [] }, "contents": "abcdefgh\"" }, { "face": { "fg": "yellow", "bg": "default", "attributes": [] }, "contents": " hehe " }, { "face": { "fg": "red", "bg": "default", "attributes": [] }, "contents": "${ youhou{hihi} }" }, { "face": { "fg": "yellow", "bg": "default", "attributes": [] }, "contents": "\u000a" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "" }]], { "fg": "default", "bg": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "attributes": [] }] } +{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "black", "bg": "white", "attributes": [] }, "contents": "\"" }, { "face": { "fg": "green", "bg": "default", "attributes": [] }, "contents": "abcdefgh\"" }, { "face": { "fg": "yellow", "bg": "default", "attributes": [] }, "contents": " hehe " }, { "face": { "fg": "red", "bg": "default", "attributes": [] }, "contents": "${ youhou{hihi} }" }, { "face": { "fg": "yellow", "bg": "default", "attributes": [] }, "contents": "\u000a" }]], { "fg": "default", "bg": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "attributes": [] }] } { "jsonrpc": "2.0", "method": "menu_hide", "params": [] } { "jsonrpc": "2.0", "method": "info_hide", "params": [] } { "jsonrpc": "2.0", "method": "draw_status", "params": [[], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "out 1:1 " }, { "face": { "fg": "black", "bg": "yellow", "attributes": [] }, "contents": "" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "blue", "bg": "default", "attributes": [] }, "contents": "1 sel" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " - unnamed0@[kak-tests]" }], { "fg": "cyan", "bg": "default", "attributes": [] }] }