Window: store a stack of selections
This commit is contained in:
parent
c11b548662
commit
f77fc3980b
|
@ -52,7 +52,8 @@ Window::Window(Buffer& buffer)
|
||||||
m_dimensions(0, 0),
|
m_dimensions(0, 0),
|
||||||
m_current_inserter(nullptr)
|
m_current_inserter(nullptr)
|
||||||
{
|
{
|
||||||
m_selections.push_back(Selection(buffer.begin(), buffer.begin()));
|
m_selections.push_back(SelectionList());
|
||||||
|
selections().push_back(Selection(buffer.begin(), buffer.begin()));
|
||||||
|
|
||||||
HighlighterRegistry& registry = HighlighterRegistry::instance();
|
HighlighterRegistry& registry = HighlighterRegistry::instance();
|
||||||
|
|
||||||
|
@ -65,7 +66,7 @@ Window::Window(Buffer& buffer)
|
||||||
|
|
||||||
void Window::check_invariant() const
|
void Window::check_invariant() const
|
||||||
{
|
{
|
||||||
assert(not m_selections.empty());
|
assert(not selections().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayCoord Window::cursor_position() const
|
DisplayCoord Window::cursor_position() const
|
||||||
|
@ -77,7 +78,7 @@ DisplayCoord Window::cursor_position() const
|
||||||
BufferIterator Window::cursor_iterator() const
|
BufferIterator Window::cursor_iterator() const
|
||||||
{
|
{
|
||||||
check_invariant();
|
check_invariant();
|
||||||
return m_selections.back().last();
|
return selections().back().last();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::erase()
|
void Window::erase()
|
||||||
|
@ -94,7 +95,7 @@ void Window::erase()
|
||||||
void Window::erase_noundo()
|
void Window::erase_noundo()
|
||||||
{
|
{
|
||||||
check_invariant();
|
check_invariant();
|
||||||
for (auto& sel : m_selections)
|
for (auto& sel : selections())
|
||||||
m_buffer.modify(Modification::make_erase(sel.begin(), sel.end()));
|
m_buffer.modify(Modification::make_erase(sel.begin(), sel.end()));
|
||||||
scroll_to_keep_cursor_visible_ifn();
|
scroll_to_keep_cursor_visible_ifn();
|
||||||
}
|
}
|
||||||
|
@ -135,7 +136,7 @@ void Window::insert(const String& string)
|
||||||
|
|
||||||
void Window::insert_noundo(const String& string)
|
void Window::insert_noundo(const String& string)
|
||||||
{
|
{
|
||||||
for (auto& sel : m_selections)
|
for (auto& sel : selections())
|
||||||
m_buffer.modify(Modification::make_insert(sel.begin(), string));
|
m_buffer.modify(Modification::make_insert(sel.begin(), string));
|
||||||
scroll_to_keep_cursor_visible_ifn();
|
scroll_to_keep_cursor_visible_ifn();
|
||||||
}
|
}
|
||||||
|
@ -153,7 +154,7 @@ void Window::append(const String& string)
|
||||||
|
|
||||||
void Window::append_noundo(const String& string)
|
void Window::append_noundo(const String& string)
|
||||||
{
|
{
|
||||||
for (auto& sel : m_selections)
|
for (auto& sel : selections())
|
||||||
m_buffer.modify(Modification::make_insert(sel.end(), string));
|
m_buffer.modify(Modification::make_insert(sel.end(), string));
|
||||||
scroll_to_keep_cursor_visible_ifn();
|
scroll_to_keep_cursor_visible_ifn();
|
||||||
}
|
}
|
||||||
|
@ -228,14 +229,14 @@ DisplayCoord Window::line_and_column_at(const BufferIterator& iterator) const
|
||||||
void Window::clear_selections()
|
void Window::clear_selections()
|
||||||
{
|
{
|
||||||
check_invariant();
|
check_invariant();
|
||||||
BufferIterator pos = m_selections.back().last();
|
BufferIterator pos = selections().back().last();
|
||||||
|
|
||||||
if (*pos == '\n' and not pos.is_begin() and *(pos-1) != '\n')
|
if (*pos == '\n' and not pos.is_begin() and *(pos-1) != '\n')
|
||||||
--pos;
|
--pos;
|
||||||
|
|
||||||
Selection sel = Selection(pos, pos);
|
Selection sel = Selection(pos, pos);
|
||||||
m_selections.clear();
|
selections().clear();
|
||||||
m_selections.push_back(std::move(sel));
|
selections().push_back(std::move(sel));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::select(const Selector& selector, bool append)
|
void Window::select(const Selector& selector, bool append)
|
||||||
|
@ -244,13 +245,13 @@ void Window::select(const Selector& selector, bool append)
|
||||||
|
|
||||||
if (not append)
|
if (not append)
|
||||||
{
|
{
|
||||||
Selection sel = selector(m_selections.back().last());
|
Selection sel = selector(selections().back().last());
|
||||||
m_selections.clear();
|
selections().clear();
|
||||||
m_selections.push_back(std::move(sel));
|
selections().push_back(std::move(sel));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (auto& sel : m_selections)
|
for (auto& sel : selections())
|
||||||
{
|
{
|
||||||
sel.merge_with(selector(sel.last()));
|
sel.merge_with(selector(sel.last()));
|
||||||
}
|
}
|
||||||
|
@ -268,7 +269,7 @@ void Window::multi_select(const MultiSelector& selector)
|
||||||
check_invariant();
|
check_invariant();
|
||||||
|
|
||||||
SelectionList new_selections;
|
SelectionList new_selections;
|
||||||
for (auto& sel : m_selections)
|
for (auto& sel : selections())
|
||||||
{
|
{
|
||||||
SelectionList selections = selector(sel);
|
SelectionList selections = selector(sel);
|
||||||
std::copy(selections.begin(), selections.end(),
|
std::copy(selections.begin(), selections.end(),
|
||||||
|
@ -277,7 +278,7 @@ void Window::multi_select(const MultiSelector& selector)
|
||||||
if (new_selections.empty())
|
if (new_selections.empty())
|
||||||
throw nothing_selected();
|
throw nothing_selected();
|
||||||
|
|
||||||
m_selections = std::move(new_selections);
|
selections() = std::move(new_selections);
|
||||||
scroll_to_keep_cursor_visible_ifn();
|
scroll_to_keep_cursor_visible_ifn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,8 +286,8 @@ BufferString Window::selection_content() const
|
||||||
{
|
{
|
||||||
check_invariant();
|
check_invariant();
|
||||||
|
|
||||||
return m_buffer.string(m_selections.back().begin(),
|
return m_buffer.string(selections().back().begin(),
|
||||||
m_selections.back().end());
|
selections().back().end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::move_cursor(const DisplayCoord& offset, bool append)
|
void Window::move_cursor(const DisplayCoord& offset, bool append)
|
||||||
|
@ -298,7 +299,7 @@ void Window::move_cursor(const DisplayCoord& offset, bool append)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (auto& sel : m_selections)
|
for (auto& sel : selections())
|
||||||
{
|
{
|
||||||
BufferCoord pos = m_buffer.line_and_column_at(sel.last());
|
BufferCoord pos = m_buffer.line_and_column_at(sel.last());
|
||||||
sel = Selection(sel.first(), m_buffer.iterator_at(pos + BufferCoord(offset)));
|
sel = Selection(sel.first(), m_buffer.iterator_at(pos + BufferCoord(offset)));
|
||||||
|
@ -309,8 +310,8 @@ void Window::move_cursor(const DisplayCoord& offset, bool append)
|
||||||
|
|
||||||
void Window::move_cursor_to(const BufferIterator& iterator)
|
void Window::move_cursor_to(const BufferIterator& iterator)
|
||||||
{
|
{
|
||||||
m_selections.clear();
|
selections().clear();
|
||||||
m_selections.push_back(Selection(iterator, iterator));
|
selections().push_back(Selection(iterator, iterator));
|
||||||
|
|
||||||
scroll_to_keep_cursor_visible_ifn();
|
scroll_to_keep_cursor_visible_ifn();
|
||||||
}
|
}
|
||||||
|
@ -343,7 +344,7 @@ void Window::scroll_to_keep_cursor_visible_ifn()
|
||||||
{
|
{
|
||||||
check_invariant();
|
check_invariant();
|
||||||
|
|
||||||
DisplayCoord cursor = line_and_column_at(m_selections.back().last());
|
DisplayCoord cursor = line_and_column_at(selections().back().last());
|
||||||
if (cursor.line < 0)
|
if (cursor.line < 0)
|
||||||
{
|
{
|
||||||
m_position.line = std::max(m_position.line + cursor.line, 0);
|
m_position.line = std::max(m_position.line + cursor.line, 0);
|
||||||
|
@ -365,13 +366,13 @@ void Window::scroll_to_keep_cursor_visible_ifn()
|
||||||
|
|
||||||
std::string Window::status_line() const
|
std::string Window::status_line() const
|
||||||
{
|
{
|
||||||
BufferCoord cursor = m_buffer.line_and_column_at(m_selections.back().last());
|
BufferCoord cursor = m_buffer.line_and_column_at(selections().back().last());
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << m_buffer.name();
|
oss << m_buffer.name();
|
||||||
if (m_buffer.is_modified())
|
if (m_buffer.is_modified())
|
||||||
oss << " [+]";
|
oss << " [+]";
|
||||||
oss << " -- " << cursor.line+1 << "," << cursor.column+1
|
oss << " -- " << cursor.line+1 << "," << cursor.column+1
|
||||||
<< " -- " << m_selections.size() << " sel -- ";
|
<< " -- " << selections().size() << " sel -- ";
|
||||||
if (m_current_inserter)
|
if (m_current_inserter)
|
||||||
oss << "[Insert]";
|
oss << "[Insert]";
|
||||||
return oss.str();
|
return oss.str();
|
||||||
|
@ -413,6 +414,19 @@ CandidateList Window::complete_filterid(const std::string& prefix,
|
||||||
return m_filters.complete_id<str_to_str>(prefix, cursor_pos);
|
return m_filters.complete_id<str_to_str>(prefix, cursor_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::push_selections()
|
||||||
|
{
|
||||||
|
SelectionList current_selections = selections();
|
||||||
|
m_selections.push_back(std::move(current_selections));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::pop_selections()
|
||||||
|
{
|
||||||
|
if (m_selections.size() > 1)
|
||||||
|
m_selections.pop_back();
|
||||||
|
else
|
||||||
|
throw runtime_error("no more selections on stack");
|
||||||
|
}
|
||||||
|
|
||||||
IncrementalInserter::IncrementalInserter(Window& window, Mode mode)
|
IncrementalInserter::IncrementalInserter(Window& window, Mode mode)
|
||||||
: m_window(window)
|
: m_window(window)
|
||||||
|
@ -426,7 +440,7 @@ IncrementalInserter::IncrementalInserter(Window& window, Mode mode)
|
||||||
if (mode == Mode::Change)
|
if (mode == Mode::Change)
|
||||||
window.erase_noundo();
|
window.erase_noundo();
|
||||||
|
|
||||||
for (auto& sel : m_window.m_selections)
|
for (auto& sel : m_window.selections())
|
||||||
{
|
{
|
||||||
DynamicBufferIterator pos;
|
DynamicBufferIterator pos;
|
||||||
switch (mode)
|
switch (mode)
|
||||||
|
@ -478,13 +492,13 @@ void IncrementalInserter::apply(Modification&& modification) const
|
||||||
|
|
||||||
void IncrementalInserter::insert(const Window::String& string)
|
void IncrementalInserter::insert(const Window::String& string)
|
||||||
{
|
{
|
||||||
for (auto& sel : m_window.m_selections)
|
for (auto& sel : m_window.selections())
|
||||||
apply(Modification::make_insert(sel.begin(), string));
|
apply(Modification::make_insert(sel.begin(), string));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IncrementalInserter::insert_capture(size_t index)
|
void IncrementalInserter::insert_capture(size_t index)
|
||||||
{
|
{
|
||||||
for (auto& sel : m_window.m_selections)
|
for (auto& sel : m_window.selections())
|
||||||
m_window.m_buffer.modify(Modification::make_insert(sel.begin(),
|
m_window.m_buffer.modify(Modification::make_insert(sel.begin(),
|
||||||
sel.capture(index)));
|
sel.capture(index)));
|
||||||
m_window.scroll_to_keep_cursor_visible_ifn();
|
m_window.scroll_to_keep_cursor_visible_ifn();
|
||||||
|
@ -492,7 +506,7 @@ void IncrementalInserter::insert_capture(size_t index)
|
||||||
|
|
||||||
void IncrementalInserter::erase()
|
void IncrementalInserter::erase()
|
||||||
{
|
{
|
||||||
for (auto& sel : m_window.m_selections)
|
for (auto& sel : m_window.selections())
|
||||||
{
|
{
|
||||||
sel = Selection(sel.first() - 1, sel.last() - 1);
|
sel = Selection(sel.first() - 1, sel.last() - 1);
|
||||||
apply(Modification::make_erase(sel.begin(), sel.end()));
|
apply(Modification::make_erase(sel.begin(), sel.end()));
|
||||||
|
@ -503,7 +517,7 @@ void IncrementalInserter::erase()
|
||||||
|
|
||||||
void IncrementalInserter::move_cursor(const DisplayCoord& offset)
|
void IncrementalInserter::move_cursor(const DisplayCoord& offset)
|
||||||
{
|
{
|
||||||
for (auto& sel : m_window.m_selections)
|
for (auto& sel : m_window.selections())
|
||||||
{
|
{
|
||||||
DisplayCoord pos = m_window.line_and_column_at(sel.last());
|
DisplayCoord pos = m_window.line_and_column_at(sel.last());
|
||||||
BufferIterator it = m_window.iterator_at(pos + offset);
|
BufferIterator it = m_window.iterator_at(pos + offset);
|
||||||
|
|
|
@ -76,7 +76,7 @@ public:
|
||||||
void select(const Selector& selector, bool append = false);
|
void select(const Selector& selector, bool append = false);
|
||||||
void multi_select(const MultiSelector& selector);
|
void multi_select(const MultiSelector& selector);
|
||||||
BufferString selection_content() const;
|
BufferString selection_content() const;
|
||||||
const SelectionList selections() const { return m_selections; }
|
const SelectionList& selections() const { return m_selections.back(); }
|
||||||
|
|
||||||
void set_dimensions(const DisplayCoord& dimensions);
|
void set_dimensions(const DisplayCoord& dimensions);
|
||||||
|
|
||||||
|
@ -107,6 +107,8 @@ public:
|
||||||
CandidateList complete_filterid(const std::string& prefix,
|
CandidateList complete_filterid(const std::string& prefix,
|
||||||
size_t cursor_pos = std::string::npos);
|
size_t cursor_pos = std::string::npos);
|
||||||
|
|
||||||
|
void push_selections();
|
||||||
|
void pop_selections();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Buffer;
|
friend class Buffer;
|
||||||
|
@ -121,13 +123,15 @@ private:
|
||||||
void insert_noundo(const String& string);
|
void insert_noundo(const String& string);
|
||||||
void append_noundo(const String& string);
|
void append_noundo(const String& string);
|
||||||
|
|
||||||
|
SelectionList& selections() { return m_selections.back(); }
|
||||||
|
|
||||||
friend class IncrementalInserter;
|
friend class IncrementalInserter;
|
||||||
IncrementalInserter* m_current_inserter;
|
IncrementalInserter* m_current_inserter;
|
||||||
|
|
||||||
Buffer& m_buffer;
|
Buffer& m_buffer;
|
||||||
BufferCoord m_position;
|
BufferCoord m_position;
|
||||||
DisplayCoord m_dimensions;
|
DisplayCoord m_dimensions;
|
||||||
SelectionList m_selections;
|
std::vector<SelectionList> m_selections;
|
||||||
DisplayBuffer m_display_buffer;
|
DisplayBuffer m_display_buffer;
|
||||||
|
|
||||||
idvaluemap<std::string, HighlighterFunc> m_highlighters;
|
idvaluemap<std::string, HighlighterFunc> m_highlighters;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user