diff --git a/src/editor.cc b/src/editor.cc index 5d2e4a81..13253ae2 100644 --- a/src/editor.cc +++ b/src/editor.cc @@ -168,16 +168,20 @@ void sort_and_merge_overlapping(SelectionList& selections, size_t& main_selectio merge_overlapping(selections, main_selection, overlaps); } +BufferCoord Editor::offset_coord(const BufferCoord& coord, CharCount offset) +{ + auto& line = buffer()[coord.line]; + auto character = std::max(0_char, std::min(line.char_count_to(coord.column) + offset, + line.char_length() - 2)); + return {coord.line, line.byte_count_to(character)}; +} + void Editor::move_selections(CharCount offset, SelectMode mode) { kak_assert(mode == SelectMode::Replace or mode == SelectMode::Extend); for (auto& sel : m_selections) { - auto last = sel.last(); - auto& line = buffer()[last.line]; - auto character = std::max(0_char, std::min(line.char_count_to(last.column) + offset, - line.char_length() - 2)); - last.column = line.byte_count_to(character); + auto last = offset_coord(sel.last(), offset); sel.first() = mode == SelectMode::Extend ? sel.first() : last; sel.last() = last; avoid_eol(*m_buffer, sel); @@ -185,17 +189,22 @@ void Editor::move_selections(CharCount offset, SelectMode mode) sort_and_merge_overlapping(m_selections, m_main_sel); } +BufferCoord Editor::offset_coord(const BufferCoord& coord, LineCount offset) +{ + auto character = (*m_buffer)[coord.line].char_count_to(coord.column); + auto line = clamp(coord.line + offset, 0_line, m_buffer->line_count()-1); + auto& content = (*m_buffer)[line]; + + character = std::max(0_char, std::min(character, content.char_length() - 2)); + return {line, content.byte_count_to(character)}; +} + void Editor::move_selections(LineCount offset, SelectMode mode) { kak_assert(mode == SelectMode::Replace or mode == SelectMode::Extend); for (auto& sel : m_selections) { - auto character = (*m_buffer)[sel.last().line].char_count_to(sel.last().column); - auto line = clamp(sel.last().line + offset, 0_line, m_buffer->line_count()-1); - auto& content = (*m_buffer)[line]; - - character = std::max(0_char, std::min(character, content.char_length() - 2)); - BufferCoord pos{line, content.byte_count_to(character)}; + auto pos = offset_coord(sel.last(), offset); sel.first() = mode == SelectMode::Extend ? sel.first() : pos; sel.last() = pos; avoid_eol(*m_buffer, sel); diff --git a/src/editor.hh b/src/editor.hh index d8785a87..95ddd2b1 100644 --- a/src/editor.hh +++ b/src/editor.hh @@ -91,6 +91,9 @@ private: void begin_edition(); void end_edition(); + virtual BufferCoord offset_coord(const BufferCoord& coord, LineCount move); + virtual BufferCoord offset_coord(const BufferCoord& coord, CharCount move); + int m_edition_level; void check_invariant() const; diff --git a/src/window.cc b/src/window.cc index 8e8f2ee8..6c73e11f 100644 --- a/src/window.cc +++ b/src/window.cc @@ -167,31 +167,81 @@ void Window::scroll_to_keep_cursor_visible_ifn() } } +namespace +{ +CharCount find_display_column(const DisplayLine& line, const Buffer& buffer, + const BufferCoord& coord) +{ + kak_assert(coord.line == line.buffer_line()); + CharCount column = 0; + for (auto& atom : line) + { + auto& content = atom.content; + if (content.has_buffer_range() and + coord >= content.begin() and coord < content.end()) + { + if (content.type() == AtomContent::BufferRange) + column += utf8::distance(buffer.iterator_at(content.begin()), + buffer.iterator_at(coord)); + return column; + } + column += content.length(); + } + return column; +} + +BufferCoord find_buffer_coord(const DisplayLine& line, const Buffer& buffer, + CharCount column) +{ + LineCount l = line.buffer_line(); + for (auto& atom : line) + { + auto& content = atom.content; + CharCount len = content.length(); + if (content.has_buffer_range() and column < len) + { + if (content.type() == AtomContent::BufferRange) + return utf8::advance(buffer.iterator_at(content.begin()), buffer.iterator_at(l+1), + std::max(0_char, column)).coord(); + return content.begin(); + } + column -= len; + } + return buffer.clamp({l, buffer[l].length()}); +} +} + DisplayCoord Window::display_position(const BufferCoord& coord) { - DisplayCoord res{0,0}; + LineCount l = 0; for (auto& line : m_display_buffer.lines()) { if (line.buffer_line() == coord.line) - { - for (auto& atom : line) - { - auto& content = atom.content; - if (content.has_buffer_range() and - coord >= content.begin() and coord < content.end()) - { - res.column += utf8::distance(buffer().iterator_at(content.begin()), - buffer().iterator_at(coord)); - return res; - } - res.column += content.length(); - } - } - ++res.line; + return {l, find_display_column(line, buffer(), coord)}; + ++l; } return { 0, 0 }; } +BufferCoord Window::offset_coord(const BufferCoord& coord, LineCount offset) +{ + auto line = clamp(coord.line + offset, 0_line, buffer().line_count()-1); + DisplayBuffer display_buffer; + DisplayBuffer::LineList& lines = display_buffer.lines(); + { + lines.emplace_back(coord.line); + lines.back().push_back({AtomContent(buffer(), coord.line, coord.line+1)}); + lines.emplace_back(line); + lines.back().push_back({AtomContent(buffer(), line, line+1)}); + } + display_buffer.compute_range(); + m_highlighters(*this, display_buffer); + m_builtin_highlighters(*this, display_buffer); + + CharCount column = find_display_column(lines[0], buffer(), coord); + return find_buffer_coord(lines[1], buffer(), column); +} + void Window::on_option_changed(const Option& option) { String desc = option.name() + "=" + option.get_as_string(); diff --git a/src/window.hh b/src/window.hh index 25890e81..08ee23f0 100644 --- a/src/window.hh +++ b/src/window.hh @@ -56,6 +56,8 @@ private: void scroll_to_keep_cursor_visible_ifn(); + BufferCoord offset_coord(const BufferCoord& coord, LineCount move) override; + DisplayCoord m_position; DisplayCoord m_dimensions; DisplayBuffer m_display_buffer;