diff --git a/src/buffer.hh b/src/buffer.hh index e4410566..d30a125e 100644 --- a/src/buffer.hh +++ b/src/buffer.hh @@ -26,9 +26,7 @@ struct BufferCoord : LineAndColumn template explicit BufferCoord(const LineAndColumn& other) - : LineAndColumn(other.line, other.column) - { - } + : LineAndColumn(other.line, other.column) {} }; class BufferIterator diff --git a/src/display_buffer.cc b/src/display_buffer.cc index f36527be..394fc0fb 100644 --- a/src/display_buffer.cc +++ b/src/display_buffer.cc @@ -5,6 +5,76 @@ namespace Kakoune { +BufferString DisplayAtom::content() const +{ + if (m_replacement_text.empty()) + return m_begin.buffer().string(m_begin, m_end); + else + return m_replacement_text; +} + +template +static DisplayCoord advance_coord(const DisplayCoord& pos, + Iterator begin, Iterator end) +{ + DisplayCoord res = pos; + while (begin != end) + { + if (*begin == '\n') + { + ++res.line; + res.column = 0; + } + else + ++res.column; + ++begin; + } + return res; +} + +DisplayCoord DisplayAtom::end_coord() const +{ + if (m_replacement_text.empty()) + return advance_coord(m_coord, m_begin, m_end); + else + return advance_coord(m_coord, m_replacement_text.begin(), + m_replacement_text.end()); +} + +BufferIterator DisplayAtom::iterator_at(const DisplayCoord& coord) const +{ + if (not m_replacement_text.empty() or coord <= m_coord) + return m_begin; + + DisplayCoord pos = m_coord; + for (BufferIterator it = m_begin; it != m_end; ++it) + { + if (*it == '\n') + { + ++pos.line; + pos.column = 0; + } + else + ++pos.column; + + if (coord == pos) + return it+1; + else if (coord < pos) + return it; + } + return m_end; +} + +DisplayCoord DisplayAtom::line_and_column_at(const BufferIterator& iterator) const +{ + assert(iterator >= m_begin and iterator < m_end); + + if (not m_replacement_text.empty()) + return m_coord; + + return advance_coord(m_coord, m_begin, iterator); +} + DisplayBuffer::DisplayBuffer() { } @@ -12,22 +82,47 @@ DisplayBuffer::DisplayBuffer() DisplayBuffer::iterator DisplayBuffer::split(iterator atom, const BufferIterator& pos) { assert(atom < end()); - assert(pos > atom->begin); - assert(pos < atom->end); - DisplayAtom new_atom(atom->begin, pos, - atom->fg_color, atom->bg_color, atom->attribute); + assert(pos > atom->begin()); + assert(pos < atom->end()); + DisplayAtom new_atom(atom->coord(), atom->begin(), pos, + atom->fg_color(), atom->bg_color(), atom->attribute()); - atom->begin = pos; - return insert(atom, std::move(new_atom)); + atom->m_begin = pos; + atom->m_coord = new_atom.end_coord(); + iterator res = insert(atom, std::move(new_atom)); + check_invariant(); + return res; } void DisplayBuffer::check_invariant() const { for (size_t i = 0; i < m_atoms.size(); ++i) { - assert(m_atoms[i].end > m_atoms[i].begin); + assert(m_atoms[i].end() > m_atoms[i].begin()); if (i > 0) - assert(m_atoms[i-1].end == m_atoms[i].begin); + { + assert(m_atoms[i-1].end() == m_atoms[i].begin()); + assert(m_atoms[i-1].end_coord() == m_atoms[i].coord()); + } + } +} + +void DisplayBuffer::replace_atom_content(iterator atom, + const BufferString& replacement) +{ + assert(atom < end()); + atom->m_replacement_text = replacement; + + // update coordinates of subsequents atoms + DisplayCoord new_coord = atom->end_coord(); + while (true) + { + new_coord = atom->end_coord(); + ++atom; + + if (atom == end() or new_coord == atom->m_coord) + break; + atom->m_coord = new_coord; } } diff --git a/src/display_buffer.hh b/src/display_buffer.hh index a3451c35..874276a8 100644 --- a/src/display_buffer.hh +++ b/src/display_buffer.hh @@ -15,6 +15,10 @@ struct DisplayCoord : LineAndColumn { DisplayCoord(int line = 0, int column = 0) : LineAndColumn(line, column) {} + + template + explicit DisplayCoord(const LineAndColumn& other) + : LineAndColumn(other.line, other.column) {} }; typedef int Attribute; @@ -43,23 +47,45 @@ enum class Color struct DisplayAtom { - BufferIterator begin; - BufferIterator end; - Color fg_color; - Color bg_color; - Attribute attribute; - BufferString replacement_text; - - DisplayAtom(BufferIterator begin, BufferIterator end, + DisplayAtom(const DisplayCoord& coord, + const BufferIterator& begin, const BufferIterator& end, Color fg_color = Color::Default, Color bg_color = Color::Default, Attribute attribute = Attributes::Normal) - : begin(begin), - end(end), - fg_color(fg_color), - bg_color(bg_color), - attribute(attribute) + : m_coord(coord), + m_begin(begin), m_end(end), + m_fg_color(fg_color), + m_bg_color(bg_color), + m_attribute(attribute) {} + + const DisplayCoord& coord() const { return m_coord; } + const BufferIterator& begin() const { return m_begin; } + const BufferIterator& end() const { return m_end; } + const Color& fg_color() const { return m_fg_color; } + const Color& bg_color() const { return m_bg_color; } + const Attribute& attribute() const { return m_attribute; } + + + Color& fg_color() { return m_fg_color; } + Color& bg_color() { return m_bg_color; } + Attribute& attribute() { return m_attribute; } + + BufferString content() const; + DisplayCoord end_coord() const; + BufferIterator iterator_at(const DisplayCoord& coord) const; + DisplayCoord line_and_column_at(const BufferIterator& iterator) const; + +private: + friend class DisplayBuffer; + + DisplayCoord m_coord; + BufferIterator m_begin; + BufferIterator m_end; + Color m_fg_color; + Color m_bg_color; + Attribute m_attribute; + BufferString m_replacement_text; }; class DisplayBuffer @@ -76,12 +102,17 @@ public: iterator insert(iterator where, const DisplayAtom& atom) { return m_atoms.insert(where, atom); } iterator split(iterator atom, const BufferIterator& pos); + void replace_atom_content(iterator atom, const BufferString& replacement); + iterator begin() { return m_atoms.begin(); } iterator end() { return m_atoms.end(); } const_iterator begin() const { return m_atoms.begin(); } const_iterator end() const { return m_atoms.end(); } + const DisplayAtom& front() const { return m_atoms.front(); } + const DisplayAtom& back() const { return m_atoms.back(); } + void check_invariant() const; private: AtomList m_atoms; diff --git a/src/filters.cc b/src/filters.cc index 5b306f2f..7e534618 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -10,17 +10,18 @@ void colorize_regex(DisplayBuffer& display_buffer, atom_it != display_buffer.end(); ++atom_it) { boost::match_results matches; - if (boost::regex_search(atom_it->begin, atom_it->end, matches, ex, boost::match_nosubs)) + if (boost::regex_search(atom_it->begin(), atom_it->end(), + matches, ex, boost::match_nosubs)) { const BufferIterator& begin = matches.begin()->first; - if (begin != atom_it->begin) + if (begin != atom_it->begin()) atom_it = display_buffer.split(atom_it, begin) + 1; const BufferIterator& end = matches.begin()->second; - if (end != atom_it->end) + if (end != atom_it->end()) atom_it = display_buffer.split(atom_it, end); - atom_it->fg_color = color; + atom_it->fg_color() = color; } } } @@ -58,19 +59,32 @@ void expand_tabulations(DisplayBuffer& display_buffer) for (auto atom_it = display_buffer.begin(); atom_it != display_buffer.end(); ++atom_it) { - for (BufferIterator it = atom_it->begin; it != atom_it->end; ++it) + for (BufferIterator it = atom_it->begin(); it != atom_it->end(); ++it) { if (*it == '\t') { - if (it != atom_it->begin) + if (it != atom_it->begin()) atom_it = display_buffer.split(atom_it, it) + 1; - if (it+1 != atom_it->end) + if (it+1 != atom_it->end()) atom_it = display_buffer.split(atom_it, it+1); BufferCoord pos = it.buffer().line_and_column_at(it); - int count = tabstop - (pos.column % tabstop); - atom_it->replacement_text = std::string(count, ' '); + + int column = 0; + for (auto line_it = it.buffer().iterator_at({pos.line, 0}); + line_it != it; ++line_it) + { + assert(*line_it != '\n'); + if (*line_it == '\t') + column += tabstop - (column % tabstop); + else + ++column; + } + + int count = tabstop - (column % tabstop); + display_buffer.replace_atom_content(atom_it, + std::string(count, ' ')); } } } diff --git a/src/main.cc b/src/main.cc index 7f6902df..104721fc 100644 --- a/src/main.cc +++ b/src/main.cc @@ -85,15 +85,15 @@ void draw_window(Window& window) DisplayCoord position; for (const DisplayAtom& atom : window.display_buffer()) { - const std::string content = atom.replacement_text.empty() ? - window.buffer().string(atom.begin, atom.end) : atom.replacement_text; + assert(position == atom.coord()); + const std::string content = atom.content(); - set_attribute(A_UNDERLINE, atom.attribute & Underline); - set_attribute(A_REVERSE, atom.attribute & Reverse); - set_attribute(A_BLINK, atom.attribute & Blink); - set_attribute(A_BOLD, atom.attribute & Bold); + set_attribute(A_UNDERLINE, atom.attribute() & Underline); + set_attribute(A_REVERSE, atom.attribute() & Reverse); + set_attribute(A_BLINK, atom.attribute() & Blink); + set_attribute(A_BOLD, atom.attribute() & Bold); - set_color(atom.fg_color, atom.bg_color); + set_color(atom.fg_color(), atom.bg_color()); size_t pos = 0; size_t end; diff --git a/src/window.cc b/src/window.cc index f03bf5d5..50a5e908 100644 --- a/src/window.cc +++ b/src/window.cc @@ -60,40 +60,40 @@ public: DisplayAtom& atom = *atom_it; // [###------] - if (atom.begin >= sel.begin() and atom.begin < sel.end() and atom.end > sel.end()) + if (atom.begin() >= sel.begin() and atom.begin() < sel.end() and atom.end() > sel.end()) { atom_it = display_buffer.split(atom_it, sel.end()); - atom_it->attribute |= Attributes::Underline; + atom_it->attribute() |= Attributes::Underline; ++atom_it; ++sel_it; } // [---###---] - else if (atom.begin < sel.begin() and atom.end > sel.end()) + else if (atom.begin() < sel.begin() and atom.end() > sel.end()) { atom_it = display_buffer.split(atom_it, sel.begin()); atom_it = display_buffer.split(atom_it + 1, sel.end()); - atom_it->attribute |= Attributes::Underline; + atom_it->attribute() |= Attributes::Underline; ++atom_it; ++sel_it; } // [------###] - else if (atom.begin < sel.begin() and atom.end > sel.begin()) + else if (atom.begin() < sel.begin() and atom.end() > sel.begin()) { atom_it = display_buffer.split(atom_it, sel.begin()) + 1; - atom_it->attribute |= Attributes::Underline; + atom_it->attribute() |= Attributes::Underline; ++atom_it; } // [#########] - else if (atom.begin >= sel.begin() and atom.end <= sel.end()) + else if (atom.begin() >= sel.begin() and atom.end() <= sel.end()) { - atom_it->attribute |= Attributes::Underline; + atom_it->attribute() |= Attributes::Underline; ++atom_it; } // [---------] - else if (atom.begin >= sel.end()) + else if (atom.begin() >= sel.end()) ++sel_it; // [---------] - else if (atom.end <= sel.begin()) + else if (atom.end() <= sel.begin()) ++atom_it; else assert(false); @@ -124,7 +124,13 @@ void Window::check_invariant() const DisplayCoord Window::cursor_position() const { check_invariant(); - return line_and_column_at(m_selections.back().last()); + return line_and_column_at(cursor_iterator()); +} + +BufferIterator Window::cursor_iterator() const +{ + check_invariant(); + return m_selections.back().last(); } void Window::erase() @@ -206,26 +212,47 @@ bool Window::redo() return m_buffer.redo(); } -BufferCoord Window::window_to_buffer(const DisplayCoord& window_pos) const -{ - return BufferCoord(m_position.line + window_pos.line, - m_position.column + window_pos.column); -} - -DisplayCoord Window::buffer_to_window(const BufferCoord& buffer_pos) const -{ - return DisplayCoord(buffer_pos.line - m_position.line, - buffer_pos.column - m_position.column); -} - BufferIterator Window::iterator_at(const DisplayCoord& window_pos) const { - return m_buffer.iterator_at(window_to_buffer(window_pos)); + if (m_display_buffer.begin() == m_display_buffer.end()) + return m_buffer.begin(); + + if (DisplayCoord(0,0) <= window_pos) + { + for (auto atom_it = m_display_buffer.begin(); + atom_it != m_display_buffer.end(); ++atom_it) + { + if (window_pos < atom_it->coord()) + { + const DisplayAtom& atom = *(atom_it - 1); + return atom.iterator_at(window_pos); + } + } + } + + return m_buffer.iterator_at(m_position + BufferCoord(window_pos)); } DisplayCoord Window::line_and_column_at(const BufferIterator& iterator) const { - return buffer_to_window(m_buffer.line_and_column_at(iterator)); + if (m_display_buffer.begin() == m_display_buffer.end()) + return DisplayCoord(0, 0); + + if (iterator >= m_display_buffer.front().begin() and + iterator < m_display_buffer.back().end()) + { + for (auto& atom : m_display_buffer) + { + if (atom.end() > iterator) + { + assert(atom.begin() <= iterator); + return atom.line_and_column_at(iterator); + } + } + } + BufferCoord coord = m_buffer.line_and_column_at(iterator); + return DisplayCoord(coord.line - m_position.line, + coord.column - m_position.column); } void Window::clear_selections() @@ -268,13 +295,16 @@ BufferString Window::selection_content() const void Window::move_cursor(const DisplayCoord& offset, bool append) { if (not append) - move_cursor_to(iterator_at(cursor_position() + offset)); + { + BufferCoord pos = m_buffer.line_and_column_at(cursor_iterator()); + move_cursor_to(m_buffer.iterator_at(pos + BufferCoord(offset))); + } else { for (auto& sel : m_selections) { - DisplayCoord pos = line_and_column_at(sel.last()); - sel = Selection(sel.first(), iterator_at(pos + offset)); + BufferCoord pos = m_buffer.line_and_column_at(sel.last()); + sel = Selection(sel.first(), m_buffer.iterator_at(pos + BufferCoord(offset))); } scroll_to_keep_cursor_visible_ifn(); } @@ -298,7 +328,7 @@ void Window::update_display_buffer() if (begin == end) return; - m_display_buffer.append(DisplayAtom(begin, end)); + m_display_buffer.append(DisplayAtom(DisplayCoord(0,0), begin, end)); for (auto& filter : m_filters) { @@ -338,7 +368,7 @@ void Window::scroll_to_keep_cursor_visible_ifn() std::string Window::status_line() const { - BufferCoord cursor = window_to_buffer(cursor_position()); + BufferCoord cursor = m_buffer.line_and_column_at(m_selections.back().end()); std::ostringstream oss; oss << m_buffer.name(); if (m_buffer.is_modified()) diff --git a/src/window.hh b/src/window.hh index 05141fe2..9ae7862c 100644 --- a/src/window.hh +++ b/src/window.hh @@ -42,7 +42,8 @@ public: void append(const String& string); const BufferCoord& position() const { return m_position; } - DisplayCoord cursor_position() const; + DisplayCoord cursor_position() const; + BufferIterator cursor_iterator() const; Buffer& buffer() const { return m_buffer; } @@ -80,9 +81,6 @@ private: void insert_noundo(const String& string); void append_noundo(const String& string); - BufferCoord window_to_buffer(const DisplayCoord& window_pos) const; - DisplayCoord buffer_to_window(const BufferCoord& buffer_pos) const; - friend class IncrementalInserter; IncrementalInserter* m_current_inserter;