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:
Maxime Coste 2011-10-15 04:45:49 +00:00
parent 187a99aba2
commit dc74934e59
7 changed files with 240 additions and 74 deletions

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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, ' '));
}
}
}

View File

@ -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;

View File

@ -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())

View File

@ -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;