DisplayBuffer: refactoring, correct support of replacements
DisplayAtoms now know where they are on the screen and have line_and_column_at and iterator_at methods.
This commit is contained in:
parent
187a99aba2
commit
dc74934e59
|
@ -26,9 +26,7 @@ struct BufferCoord : LineAndColumn<BufferCoord>
|
|||
|
||||
template<typename T>
|
||||
explicit BufferCoord(const LineAndColumn<T>& other)
|
||||
: LineAndColumn(other.line, other.column)
|
||||
{
|
||||
}
|
||||
: LineAndColumn(other.line, other.column) {}
|
||||
};
|
||||
|
||||
class BufferIterator
|
||||
|
|
|
@ -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<typename Iterator>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@ struct DisplayCoord : LineAndColumn<DisplayCoord>
|
|||
{
|
||||
DisplayCoord(int line = 0, int column = 0)
|
||||
: LineAndColumn(line, column) {}
|
||||
|
||||
template<typename T>
|
||||
explicit DisplayCoord(const LineAndColumn<T>& 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;
|
||||
|
|
|
@ -10,17 +10,18 @@ void colorize_regex(DisplayBuffer& display_buffer,
|
|||
atom_it != display_buffer.end(); ++atom_it)
|
||||
{
|
||||
boost::match_results<BufferIterator> 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, ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
14
src/main.cc
14
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;
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
|
||||
const BufferCoord& position() const { return m_position; }
|
||||
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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user