2012-01-31 20:12:06 +01:00
|
|
|
#include "editor.hh"
|
|
|
|
|
|
|
|
#include "exception.hh"
|
2012-02-10 00:47:55 +01:00
|
|
|
#include "register.hh"
|
|
|
|
#include "register_manager.hh"
|
2012-10-08 14:27:43 +02:00
|
|
|
#include "utf8_iterator.hh"
|
2013-04-09 20:05:40 +02:00
|
|
|
#include "utils.hh"
|
2012-10-08 14:27:43 +02:00
|
|
|
|
2012-02-10 14:58:29 +01:00
|
|
|
#include <array>
|
|
|
|
|
2012-01-31 20:12:06 +01:00
|
|
|
namespace Kakoune
|
|
|
|
{
|
|
|
|
|
|
|
|
Editor::Editor(Buffer& buffer)
|
2012-11-04 23:39:25 +01:00
|
|
|
: m_buffer(&buffer),
|
2012-12-11 19:51:59 +01:00
|
|
|
m_edition_level(0),
|
|
|
|
m_selections(buffer)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2013-06-04 19:23:11 +02:00
|
|
|
m_selections.push_back(Selection({}, {}));
|
2013-03-15 18:48:59 +01:00
|
|
|
m_main_sel = 0;
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2013-06-03 18:58:09 +02:00
|
|
|
static void avoid_eol(const Buffer& buffer, BufferCoord& coord)
|
2013-05-24 18:49:25 +02:00
|
|
|
{
|
2013-06-03 18:58:09 +02:00
|
|
|
const auto column = coord.column;
|
2013-06-05 19:25:51 +02:00
|
|
|
const auto& line = buffer[coord.line];
|
|
|
|
if (column != 0 and column == line.length() - 1)
|
|
|
|
coord.column = line.byte_count_to(line.char_length() - 2);
|
2013-05-24 18:49:25 +02:00
|
|
|
}
|
|
|
|
|
2013-06-03 18:58:09 +02:00
|
|
|
static void avoid_eol(const Buffer& buffer, Range& sel)
|
2013-05-24 18:49:25 +02:00
|
|
|
{
|
2013-06-03 18:58:09 +02:00
|
|
|
avoid_eol(buffer, sel.first());
|
|
|
|
avoid_eol(buffer, sel.last());
|
2013-05-24 18:49:25 +02:00
|
|
|
}
|
|
|
|
|
2012-01-31 20:12:06 +01:00
|
|
|
void Editor::erase()
|
|
|
|
{
|
2012-02-08 00:41:10 +01:00
|
|
|
scoped_edition edition(*this);
|
2012-09-24 20:47:06 +02:00
|
|
|
for (auto& sel : m_selections)
|
2012-08-15 18:20:02 +02:00
|
|
|
{
|
2013-06-03 18:58:09 +02:00
|
|
|
Kakoune::erase(*m_buffer, sel);
|
|
|
|
avoid_eol(*m_buffer, sel);
|
2012-08-15 18:20:02 +02:00
|
|
|
}
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2013-06-06 19:39:53 +02:00
|
|
|
static BufferIterator prepare_insert(Buffer& buffer, const Selection& sel,
|
|
|
|
InsertMode mode)
|
2012-10-09 19:36:03 +02:00
|
|
|
{
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case InsertMode::Insert:
|
2013-06-06 19:39:53 +02:00
|
|
|
return buffer.iterator_at(sel.min());
|
2013-01-23 18:58:43 +01:00
|
|
|
case InsertMode::Replace:
|
2013-06-06 19:39:53 +02:00
|
|
|
return Kakoune::erase(buffer, sel);
|
2012-10-09 19:36:03 +02:00
|
|
|
case InsertMode::Append:
|
2012-11-26 19:23:50 +01:00
|
|
|
{
|
|
|
|
// special case for end of lines, append to current line instead
|
2013-06-06 19:39:53 +02:00
|
|
|
auto pos = buffer.iterator_at(sel.max());
|
|
|
|
return *pos == '\n' ? pos : utf8::next(pos);
|
2012-11-26 19:23:50 +01:00
|
|
|
}
|
2012-10-09 19:36:03 +02:00
|
|
|
case InsertMode::InsertAtLineBegin:
|
2013-06-06 19:39:53 +02:00
|
|
|
return buffer.iterator_at(sel.min().line);
|
2012-10-09 19:36:03 +02:00
|
|
|
case InsertMode::AppendAtLineEnd:
|
2013-06-06 19:39:53 +02:00
|
|
|
return buffer.iterator_at({sel.max().line, buffer[sel.max().line].length() - 1});
|
2012-11-26 19:23:50 +01:00
|
|
|
case InsertMode::InsertAtNextLineBegin:
|
2013-06-06 19:39:53 +02:00
|
|
|
return buffer.iterator_at(sel.max().line+1);
|
2012-10-09 19:36:03 +02:00
|
|
|
case InsertMode::OpenLineBelow:
|
2013-06-06 19:39:53 +02:00
|
|
|
return buffer.insert(buffer.iterator_at(sel.max().line + 1), "\n");
|
2012-10-09 19:36:03 +02:00
|
|
|
case InsertMode::OpenLineAbove:
|
2013-06-06 19:39:53 +02:00
|
|
|
return buffer.insert(buffer.iterator_at(sel.min().line), "\n");
|
2012-10-09 19:36:03 +02:00
|
|
|
}
|
2013-04-09 20:04:11 +02:00
|
|
|
kak_assert(false);
|
2013-06-03 18:58:09 +02:00
|
|
|
return {};
|
2012-10-09 19:36:03 +02:00
|
|
|
}
|
|
|
|
|
2013-02-26 14:06:25 +01:00
|
|
|
void Editor::insert(const String& str, InsertMode mode)
|
2012-02-10 00:47:55 +01:00
|
|
|
{
|
2012-10-09 19:25:20 +02:00
|
|
|
scoped_edition edition(*this);
|
2012-12-27 18:54:52 +01:00
|
|
|
|
2012-10-09 19:25:20 +02:00
|
|
|
for (auto& sel : m_selections)
|
2012-02-10 00:47:55 +01:00
|
|
|
{
|
2013-06-06 19:39:53 +02:00
|
|
|
auto pos = prepare_insert(*m_buffer, sel, mode);
|
|
|
|
pos = m_buffer->insert(pos, str);
|
|
|
|
if (mode == InsertMode::Replace and pos != m_buffer->end())
|
2012-12-27 18:54:52 +01:00
|
|
|
{
|
2013-06-06 19:39:53 +02:00
|
|
|
sel.first() = pos.coord();
|
2013-06-03 18:58:09 +02:00
|
|
|
sel.last() = str.empty() ?
|
2013-06-06 19:39:53 +02:00
|
|
|
pos.coord() : (pos + str.byte_count_to(str.char_length() - 1)).coord();
|
2012-12-27 18:54:52 +01:00
|
|
|
}
|
2013-06-03 18:58:09 +02:00
|
|
|
avoid_eol(*m_buffer, sel);
|
2012-02-10 00:47:55 +01:00
|
|
|
}
|
2013-04-03 19:22:12 +02:00
|
|
|
check_invariant();
|
2012-02-10 00:47:55 +01:00
|
|
|
}
|
|
|
|
|
2013-07-26 01:17:12 +02:00
|
|
|
void Editor::insert(memoryview<String> strings, InsertMode mode)
|
2012-02-10 00:47:55 +01:00
|
|
|
{
|
2012-10-09 19:25:20 +02:00
|
|
|
scoped_edition edition(*this);
|
2012-02-10 00:47:55 +01:00
|
|
|
if (strings.empty())
|
|
|
|
return;
|
|
|
|
|
2012-10-09 19:25:20 +02:00
|
|
|
for (size_t i = 0; i < selections().size(); ++i)
|
2012-02-10 00:47:55 +01:00
|
|
|
{
|
2012-12-12 14:21:50 +01:00
|
|
|
auto& sel = m_selections[i];
|
2013-06-06 19:39:53 +02:00
|
|
|
auto pos = prepare_insert(*m_buffer, sel, mode);
|
2012-12-27 18:54:52 +01:00
|
|
|
const String& str = strings[std::min(i, strings.size()-1)];
|
2013-06-06 19:39:53 +02:00
|
|
|
pos = m_buffer->insert(pos, str);
|
|
|
|
if (mode == InsertMode::Replace and pos != m_buffer->end())
|
2012-12-27 18:54:52 +01:00
|
|
|
{
|
2013-06-06 19:39:53 +02:00
|
|
|
sel.first() = pos.coord();
|
|
|
|
sel.last() = (str.empty() ?
|
|
|
|
pos : pos + str.byte_count_to(str.char_length() - 1)).coord();
|
2012-12-27 18:54:52 +01:00
|
|
|
}
|
2013-06-03 18:58:09 +02:00
|
|
|
avoid_eol(*m_buffer, sel);
|
2012-02-10 00:47:55 +01:00
|
|
|
}
|
2013-04-03 19:22:12 +02:00
|
|
|
check_invariant();
|
2012-02-10 00:47:55 +01:00
|
|
|
}
|
|
|
|
|
2012-03-08 22:23:29 +01:00
|
|
|
std::vector<String> Editor::selections_content() const
|
2012-02-10 00:47:55 +01:00
|
|
|
{
|
|
|
|
std::vector<String> contents;
|
2012-09-24 20:47:06 +02:00
|
|
|
for (auto& sel : m_selections)
|
2013-06-03 18:58:09 +02:00
|
|
|
contents.push_back(m_buffer->string(sel.min(), m_buffer->char_next(sel.max())));
|
2012-02-10 00:47:55 +01:00
|
|
|
return contents;
|
|
|
|
}
|
|
|
|
|
2013-01-02 14:25:28 +01:00
|
|
|
static bool compare_selections(const Selection& lhs, const Selection& rhs)
|
|
|
|
{
|
2013-05-24 14:25:50 +02:00
|
|
|
return lhs.min() < rhs.min();
|
2013-01-02 14:25:28 +01:00
|
|
|
}
|
|
|
|
|
2013-05-03 13:53:23 +02:00
|
|
|
template<typename OverlapsFunc>
|
|
|
|
void merge_overlapping(SelectionList& selections, size_t& main_selection,
|
|
|
|
OverlapsFunc overlaps)
|
2012-10-10 19:11:24 +02:00
|
|
|
{
|
2013-05-03 13:53:23 +02:00
|
|
|
kak_assert(std::is_sorted(selections.begin(), selections.end(), compare_selections));
|
2013-03-15 18:48:59 +01:00
|
|
|
for (size_t i = 0; i+1 < selections.size() and selections.size() > 1;)
|
2012-10-10 19:11:24 +02:00
|
|
|
{
|
2013-03-15 18:48:59 +01:00
|
|
|
if (overlaps(selections[i], selections[i+1]))
|
2012-10-10 19:11:24 +02:00
|
|
|
{
|
2013-03-15 18:48:59 +01:00
|
|
|
selections[i].merge_with(selections[i+1]);
|
|
|
|
selections.erase(selections.begin() + i + 1);
|
|
|
|
if (i + 1 <= main_selection)
|
|
|
|
--main_selection;
|
2012-10-10 19:11:24 +02:00
|
|
|
}
|
2012-12-13 18:45:32 +01:00
|
|
|
else
|
|
|
|
++i;
|
2012-10-10 19:11:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-03 13:53:23 +02:00
|
|
|
void sort_and_merge_overlapping(SelectionList& selections, size_t& main_selection)
|
|
|
|
{
|
|
|
|
if (selections.size() == 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const auto& main = selections[main_selection];
|
2013-05-24 14:25:50 +02:00
|
|
|
const auto main_begin = main.min();
|
2013-05-03 13:53:23 +02:00
|
|
|
main_selection = std::count_if(selections.begin(), selections.end(),
|
|
|
|
[&](const Selection& sel) {
|
2013-05-24 14:25:50 +02:00
|
|
|
auto begin = sel.min();
|
2013-05-03 13:53:23 +02:00
|
|
|
if (begin == main_begin)
|
|
|
|
return &sel < &main;
|
|
|
|
else
|
2013-05-24 14:25:50 +02:00
|
|
|
return begin < main_begin;
|
2013-05-03 13:53:23 +02:00
|
|
|
});
|
|
|
|
std::stable_sort(selections.begin(), selections.end(), compare_selections);
|
|
|
|
|
|
|
|
merge_overlapping(selections, main_selection, overlaps);
|
|
|
|
}
|
|
|
|
|
2013-07-26 00:44:00 +02:00
|
|
|
BufferCoord Editor::offset_coord(BufferCoord coord, CharCount offset)
|
2013-07-17 21:17:32 +02:00
|
|
|
{
|
|
|
|
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)};
|
|
|
|
}
|
|
|
|
|
2012-10-02 14:10:00 +02:00
|
|
|
void Editor::move_selections(CharCount offset, SelectMode mode)
|
|
|
|
{
|
2013-04-09 20:04:11 +02:00
|
|
|
kak_assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
|
2012-10-02 14:10:00 +02:00
|
|
|
for (auto& sel : m_selections)
|
|
|
|
{
|
2013-07-17 21:17:32 +02:00
|
|
|
auto last = offset_coord(sel.last(), offset);
|
2013-01-02 13:49:02 +01:00
|
|
|
sel.first() = mode == SelectMode::Extend ? sel.first() : last;
|
|
|
|
sel.last() = last;
|
2013-06-03 18:58:09 +02:00
|
|
|
avoid_eol(*m_buffer, sel);
|
2012-10-02 14:10:00 +02:00
|
|
|
}
|
2013-03-15 18:48:59 +01:00
|
|
|
sort_and_merge_overlapping(m_selections, m_main_sel);
|
2012-10-02 14:10:00 +02:00
|
|
|
}
|
|
|
|
|
2013-07-26 00:44:00 +02:00
|
|
|
BufferCoord Editor::offset_coord(BufferCoord coord, LineCount offset)
|
2013-07-17 21:17:32 +02:00
|
|
|
{
|
|
|
|
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)};
|
|
|
|
}
|
|
|
|
|
2012-10-02 14:10:00 +02:00
|
|
|
void Editor::move_selections(LineCount offset, SelectMode mode)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2013-04-09 20:04:11 +02:00
|
|
|
kak_assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
|
2012-09-24 20:47:06 +02:00
|
|
|
for (auto& sel : m_selections)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2013-07-17 21:17:32 +02:00
|
|
|
auto pos = offset_coord(sel.last(), offset);
|
2013-06-05 18:47:39 +02:00
|
|
|
sel.first() = mode == SelectMode::Extend ? sel.first() : pos;
|
|
|
|
sel.last() = pos;
|
2013-06-03 18:58:09 +02:00
|
|
|
avoid_eol(*m_buffer, sel);
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
2013-03-15 18:48:59 +01:00
|
|
|
sort_and_merge_overlapping(m_selections, m_main_sel);
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Editor::clear_selections()
|
|
|
|
{
|
2013-03-15 18:48:59 +01:00
|
|
|
auto& sel = m_selections[m_main_sel];
|
2013-01-03 18:47:02 +01:00
|
|
|
auto& pos = sel.last();
|
2013-06-06 14:17:31 +02:00
|
|
|
avoid_eol(*m_buffer, pos);
|
2013-01-03 18:47:02 +01:00
|
|
|
sel.first() = pos;
|
2012-01-31 20:12:06 +01:00
|
|
|
|
2013-03-15 18:48:59 +01:00
|
|
|
m_selections.erase(m_selections.begin(), m_selections.begin() + m_main_sel);
|
|
|
|
m_selections.erase(m_selections.begin() + 1, m_selections.end());
|
|
|
|
m_main_sel = 0;
|
2012-12-31 18:36:28 +01:00
|
|
|
check_invariant();
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2012-11-19 19:03:56 +01:00
|
|
|
void Editor::flip_selections()
|
|
|
|
{
|
|
|
|
for (auto& sel : m_selections)
|
2012-11-30 18:32:49 +01:00
|
|
|
std::swap(sel.first(), sel.last());
|
2012-12-31 18:36:28 +01:00
|
|
|
check_invariant();
|
2012-11-19 19:03:56 +01:00
|
|
|
}
|
|
|
|
|
2012-01-31 20:12:06 +01:00
|
|
|
void Editor::keep_selection(int index)
|
|
|
|
{
|
2012-09-24 20:47:06 +02:00
|
|
|
if (index < m_selections.size())
|
2013-03-15 18:48:59 +01:00
|
|
|
{
|
|
|
|
size_t real_index = (index + m_main_sel + 1) % m_selections.size();
|
|
|
|
m_selections = SelectionList{ std::move(m_selections[real_index]) };
|
|
|
|
m_main_sel = 0;
|
|
|
|
}
|
2012-12-31 18:36:28 +01:00
|
|
|
check_invariant();
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2012-05-29 13:15:43 +02:00
|
|
|
void Editor::remove_selection(int index)
|
|
|
|
{
|
2012-09-24 20:47:06 +02:00
|
|
|
if (m_selections.size() > 1 and index < m_selections.size())
|
2013-03-15 18:48:59 +01:00
|
|
|
{
|
|
|
|
size_t real_index = (index + m_main_sel + 1) % m_selections.size();
|
|
|
|
m_selections.erase(m_selections.begin() + real_index);
|
|
|
|
if (real_index <= m_main_sel)
|
2013-10-11 19:44:43 +02:00
|
|
|
m_main_sel = (m_main_sel > 0 ? m_main_sel
|
|
|
|
: m_selections.size()) - 1;
|
2013-03-15 18:48:59 +01:00
|
|
|
}
|
2012-12-31 18:36:28 +01:00
|
|
|
check_invariant();
|
2012-05-29 13:15:43 +02:00
|
|
|
}
|
|
|
|
|
2012-12-31 14:06:20 +01:00
|
|
|
void Editor::select(const Selection& selection, SelectMode mode)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2012-12-18 19:12:15 +01:00
|
|
|
if (mode == SelectMode::Replace)
|
2013-03-20 19:05:05 +01:00
|
|
|
{
|
2012-12-31 14:06:20 +01:00
|
|
|
m_selections = SelectionList{ selection };
|
2013-03-20 19:05:05 +01:00
|
|
|
m_main_sel = 0;
|
|
|
|
}
|
2012-12-18 19:12:15 +01:00
|
|
|
else if (mode == SelectMode::Extend)
|
|
|
|
{
|
2013-03-15 18:48:59 +01:00
|
|
|
m_selections[m_main_sel].merge_with(selection);
|
2013-05-14 13:58:41 +02:00
|
|
|
m_selections = SelectionList{ std::move(m_selections[m_main_sel]) };
|
|
|
|
m_main_sel = 0;
|
2012-12-18 19:12:15 +01:00
|
|
|
}
|
|
|
|
else if (mode == SelectMode::Append)
|
2012-12-31 14:06:20 +01:00
|
|
|
{
|
2013-03-15 18:48:59 +01:00
|
|
|
m_main_sel = m_selections.size();
|
2012-12-31 14:06:20 +01:00
|
|
|
m_selections.push_back(selection);
|
2013-03-15 18:48:59 +01:00
|
|
|
sort_and_merge_overlapping(m_selections, m_main_sel);
|
2012-12-31 14:06:20 +01:00
|
|
|
}
|
2013-01-03 14:00:31 +01:00
|
|
|
else
|
2013-04-09 20:04:11 +02:00
|
|
|
kak_assert(false);
|
2012-12-31 18:36:28 +01:00
|
|
|
check_invariant();
|
2012-09-24 20:47:06 +02:00
|
|
|
}
|
|
|
|
|
2012-11-30 18:32:49 +01:00
|
|
|
void Editor::select(SelectionList selections)
|
2012-09-24 20:47:06 +02:00
|
|
|
{
|
|
|
|
if (selections.empty())
|
|
|
|
throw runtime_error("no selections");
|
2012-12-12 14:21:50 +01:00
|
|
|
m_selections = std::move(selections);
|
2013-03-15 18:48:59 +01:00
|
|
|
m_main_sel = m_selections.size() - 1;
|
2012-12-31 18:36:28 +01:00
|
|
|
check_invariant();
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2012-09-07 14:29:29 +02:00
|
|
|
void Editor::select(const Selector& selector, SelectMode mode)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2012-10-10 13:57:52 +02:00
|
|
|
if (mode == SelectMode::Append)
|
|
|
|
{
|
2013-03-15 18:48:59 +01:00
|
|
|
auto& sel = m_selections[m_main_sel];
|
2013-06-01 14:22:57 +02:00
|
|
|
auto res = selector(*m_buffer, sel);
|
2012-11-30 18:32:49 +01:00
|
|
|
if (res.captures().empty())
|
|
|
|
res.captures() = sel.captures();
|
2013-03-15 18:48:59 +01:00
|
|
|
m_main_sel = m_selections.size();
|
2012-10-10 13:57:52 +02:00
|
|
|
m_selections.push_back(res);
|
|
|
|
}
|
2013-03-15 18:20:35 +01:00
|
|
|
else if (mode == SelectMode::ReplaceMain)
|
2013-01-03 14:00:31 +01:00
|
|
|
{
|
2013-03-15 18:48:59 +01:00
|
|
|
auto& sel = m_selections[m_main_sel];
|
2013-06-01 14:22:57 +02:00
|
|
|
auto res = selector(*m_buffer, sel);
|
2013-01-03 18:47:02 +01:00
|
|
|
sel.first() = res.first();
|
|
|
|
sel.last() = res.last();
|
|
|
|
if (not res.captures().empty())
|
|
|
|
sel.captures() = std::move(res.captures());
|
2013-01-03 14:00:31 +01:00
|
|
|
}
|
2012-10-10 19:11:24 +02:00
|
|
|
else
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2012-10-10 19:11:24 +02:00
|
|
|
for (auto& sel : m_selections)
|
|
|
|
{
|
2013-06-01 14:22:57 +02:00
|
|
|
auto res = selector(*m_buffer, sel);
|
2012-10-10 19:11:24 +02:00
|
|
|
if (mode == SelectMode::Extend)
|
2012-11-30 18:32:49 +01:00
|
|
|
sel.merge_with(res);
|
2012-10-10 19:11:24 +02:00
|
|
|
else
|
2013-01-03 18:47:02 +01:00
|
|
|
{
|
|
|
|
sel.first() = res.first();
|
|
|
|
sel.last() = res.last();
|
|
|
|
}
|
2012-11-30 18:32:49 +01:00
|
|
|
if (not res.captures().empty())
|
|
|
|
sel.captures() = std::move(res.captures());
|
2012-10-10 19:11:24 +02:00
|
|
|
}
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
2013-03-15 18:48:59 +01:00
|
|
|
sort_and_merge_overlapping(m_selections, m_main_sel);
|
2012-12-31 18:36:28 +01:00
|
|
|
check_invariant();
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
struct nothing_selected : public runtime_error
|
|
|
|
{
|
|
|
|
nothing_selected() : runtime_error("nothing was selected") {}
|
|
|
|
};
|
|
|
|
|
|
|
|
void Editor::multi_select(const MultiSelector& selector)
|
|
|
|
{
|
2012-11-30 18:32:49 +01:00
|
|
|
SelectionList new_selections;
|
2012-09-24 20:47:06 +02:00
|
|
|
for (auto& sel : m_selections)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2013-06-01 14:22:57 +02:00
|
|
|
SelectionList res = selector(*m_buffer, sel);
|
2013-02-28 18:51:58 +01:00
|
|
|
new_selections.reserve(new_selections.size() + res.size());
|
2012-11-30 18:32:49 +01:00
|
|
|
for (auto& new_sel : res)
|
2012-02-10 00:47:55 +01:00
|
|
|
{
|
2012-09-26 20:43:42 +02:00
|
|
|
// preserve captures when selectors captures nothing.
|
2012-11-30 18:32:49 +01:00
|
|
|
if (new_sel.captures().empty())
|
|
|
|
new_selections.emplace_back(new_sel.first(), new_sel.last(),
|
|
|
|
sel.captures());
|
2012-09-26 20:43:42 +02:00
|
|
|
else
|
2012-11-30 18:32:49 +01:00
|
|
|
new_selections.push_back(std::move(new_sel));
|
2012-02-10 00:47:55 +01:00
|
|
|
}
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
if (new_selections.empty())
|
|
|
|
throw nothing_selected();
|
2013-03-15 18:48:59 +01:00
|
|
|
m_main_sel = new_selections.size() - 1;
|
|
|
|
sort_and_merge_overlapping(new_selections, m_main_sel);
|
2012-12-12 14:21:50 +01:00
|
|
|
m_selections = std::move(new_selections);
|
2012-12-31 18:36:28 +01:00
|
|
|
check_invariant();
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2013-05-02 19:31:58 +02:00
|
|
|
class ModifiedRangesListener : public BufferChangeListener_AutoRegister
|
2012-07-16 21:53:00 +02:00
|
|
|
{
|
|
|
|
public:
|
2013-05-02 19:31:58 +02:00
|
|
|
ModifiedRangesListener(Buffer& buffer)
|
|
|
|
: BufferChangeListener_AutoRegister(buffer) {}
|
2012-07-16 21:53:00 +02:00
|
|
|
|
2013-07-26 00:44:00 +02:00
|
|
|
void on_insert(const Buffer& buffer, BufferCoord begin, BufferCoord end)
|
2012-07-16 21:53:00 +02:00
|
|
|
{
|
2013-06-01 00:48:46 +02:00
|
|
|
m_ranges.update_insert(buffer, begin, end);
|
2013-05-02 19:31:58 +02:00
|
|
|
auto it = std::upper_bound(m_ranges.begin(), m_ranges.end(), begin,
|
2013-07-26 00:44:00 +02:00
|
|
|
[](BufferCoord c, const Selection& sel)
|
2013-06-01 00:48:46 +02:00
|
|
|
{ return c < sel.min(); });
|
2013-06-04 19:23:11 +02:00
|
|
|
m_ranges.emplace(it, begin, buffer.char_prev(end));
|
2012-07-16 21:53:00 +02:00
|
|
|
}
|
|
|
|
|
2013-07-26 00:44:00 +02:00
|
|
|
void on_erase(const Buffer& buffer, BufferCoord begin, BufferCoord end)
|
2012-07-16 21:53:00 +02:00
|
|
|
{
|
2013-06-01 00:48:46 +02:00
|
|
|
m_ranges.update_erase(buffer, begin, end);
|
2013-06-04 19:23:11 +02:00
|
|
|
auto pos = std::min(begin, buffer.back_coord());
|
|
|
|
auto it = std::upper_bound(m_ranges.begin(), m_ranges.end(), pos,
|
2013-07-26 00:44:00 +02:00
|
|
|
[](BufferCoord c, const Selection& sel)
|
2013-06-01 00:48:46 +02:00
|
|
|
{ return c < sel.min(); });
|
2013-05-02 19:31:58 +02:00
|
|
|
m_ranges.emplace(it, pos, pos);
|
2012-07-16 21:53:00 +02:00
|
|
|
}
|
2013-05-02 19:31:58 +02:00
|
|
|
SelectionList& ranges() { return m_ranges; }
|
2012-07-16 21:53:00 +02:00
|
|
|
|
|
|
|
private:
|
2013-05-02 19:31:58 +02:00
|
|
|
SelectionList m_ranges;
|
2012-07-16 21:53:00 +02:00
|
|
|
};
|
|
|
|
|
2013-06-03 18:58:09 +02:00
|
|
|
inline bool touches(const Buffer& buffer, const Range& lhs, const Range& rhs)
|
2013-05-24 14:25:50 +02:00
|
|
|
{
|
2013-06-03 18:58:09 +02:00
|
|
|
return lhs.min() <= rhs.min() ? buffer.char_next(lhs.max()) >= rhs.min()
|
|
|
|
: lhs.min() <= buffer.char_next(rhs.max());
|
2013-05-24 14:25:50 +02:00
|
|
|
}
|
|
|
|
|
2012-01-31 20:12:06 +01:00
|
|
|
bool Editor::undo()
|
|
|
|
{
|
2013-06-03 18:58:09 +02:00
|
|
|
using namespace std::placeholders;
|
2013-05-02 19:31:58 +02:00
|
|
|
ModifiedRangesListener listener(buffer());
|
2012-11-04 23:39:25 +01:00
|
|
|
bool res = m_buffer->undo();
|
2013-05-02 19:31:58 +02:00
|
|
|
if (res and not listener.ranges().empty())
|
2013-03-15 18:48:59 +01:00
|
|
|
{
|
2013-05-02 19:31:58 +02:00
|
|
|
m_selections = std::move(listener.ranges());
|
|
|
|
m_main_sel = m_selections.size() - 1;
|
2013-06-03 18:58:09 +02:00
|
|
|
merge_overlapping(m_selections, m_main_sel, std::bind(touches, std::ref(buffer()), _1, _2));
|
2013-03-15 18:48:59 +01:00
|
|
|
}
|
2012-12-31 18:36:28 +01:00
|
|
|
check_invariant();
|
2012-07-16 21:53:00 +02:00
|
|
|
return res;
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Editor::redo()
|
|
|
|
{
|
2013-06-03 18:58:09 +02:00
|
|
|
using namespace std::placeholders;
|
2013-05-02 19:31:58 +02:00
|
|
|
ModifiedRangesListener listener(buffer());
|
2012-11-04 23:39:25 +01:00
|
|
|
bool res = m_buffer->redo();
|
2013-05-02 19:31:58 +02:00
|
|
|
if (res and not listener.ranges().empty())
|
2013-03-15 18:48:59 +01:00
|
|
|
{
|
2013-05-02 19:31:58 +02:00
|
|
|
m_selections = std::move(listener.ranges());
|
|
|
|
m_main_sel = m_selections.size() - 1;
|
2013-06-03 18:58:09 +02:00
|
|
|
merge_overlapping(m_selections, m_main_sel, std::bind(touches, std::ref(buffer()), _1, _2));
|
2013-03-15 18:48:59 +01:00
|
|
|
}
|
2012-12-31 18:36:28 +01:00
|
|
|
check_invariant();
|
2012-07-16 21:53:00 +02:00
|
|
|
return res;
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Editor::check_invariant() const
|
|
|
|
{
|
2013-02-27 19:02:01 +01:00
|
|
|
#ifdef KAK_DEBUG
|
2013-04-09 20:04:11 +02:00
|
|
|
kak_assert(not m_selections.empty());
|
|
|
|
kak_assert(m_main_sel < m_selections.size());
|
2012-12-12 14:21:50 +01:00
|
|
|
m_selections.check_invariant();
|
2013-04-03 19:22:12 +02:00
|
|
|
buffer().check_invariant();
|
2013-04-09 20:04:11 +02:00
|
|
|
kak_assert(std::is_sorted(m_selections.begin(), m_selections.end(), compare_selections));
|
2013-02-27 19:02:01 +01:00
|
|
|
#endif
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2012-02-08 00:41:10 +01:00
|
|
|
void Editor::begin_edition()
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2012-02-08 00:41:10 +01:00
|
|
|
++m_edition_level;
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2012-02-08 00:41:10 +01:00
|
|
|
void Editor::end_edition()
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2013-04-09 20:04:11 +02:00
|
|
|
kak_assert(m_edition_level > 0);
|
2012-02-08 00:41:10 +01:00
|
|
|
if (m_edition_level == 1)
|
2013-02-20 14:20:16 +01:00
|
|
|
m_buffer->commit_undo_group();
|
2012-02-08 00:41:10 +01:00
|
|
|
|
|
|
|
--m_edition_level;
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2012-09-26 14:22:24 +02:00
|
|
|
IncrementalInserter::IncrementalInserter(Editor& editor, InsertMode mode)
|
2012-07-16 21:21:56 +02:00
|
|
|
: m_editor(editor), m_edition(editor), m_mode(mode)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2012-11-04 23:39:25 +01:00
|
|
|
Buffer& buffer = *editor.m_buffer;
|
2012-01-31 20:12:06 +01:00
|
|
|
|
2012-09-24 20:47:06 +02:00
|
|
|
for (auto& sel : m_editor.m_selections)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2013-06-03 19:04:28 +02:00
|
|
|
BufferCoord first, last;
|
2012-01-31 20:12:06 +01:00
|
|
|
switch (mode)
|
|
|
|
{
|
2013-06-06 19:39:53 +02:00
|
|
|
case InsertMode::Insert:
|
|
|
|
first = sel.max();
|
|
|
|
last = sel.min();
|
|
|
|
break;
|
2013-01-23 18:58:43 +01:00
|
|
|
case InsertMode::Replace:
|
2013-06-06 19:39:53 +02:00
|
|
|
first = last = Kakoune::erase(buffer, sel).coord();
|
2013-01-23 18:58:43 +01:00
|
|
|
break;
|
2012-12-28 14:06:56 +01:00
|
|
|
case InsertMode::Append:
|
2013-06-03 19:04:28 +02:00
|
|
|
first = sel.min();
|
2013-06-06 19:39:53 +02:00
|
|
|
last = sel.max();
|
2012-12-28 14:06:56 +01:00
|
|
|
// special case for end of lines, append to current line instead
|
2013-06-05 18:41:02 +02:00
|
|
|
if (last.column != buffer[last.line].length() - 1)
|
2013-06-03 19:04:28 +02:00
|
|
|
last = buffer.char_next(last);
|
2012-12-28 14:06:56 +01:00
|
|
|
break;
|
2012-01-31 20:12:06 +01:00
|
|
|
|
2012-09-26 14:22:24 +02:00
|
|
|
case InsertMode::OpenLineBelow:
|
|
|
|
case InsertMode::AppendAtLineEnd:
|
2013-06-06 19:39:53 +02:00
|
|
|
first = last = BufferCoord{sel.max().line, buffer[sel.max().line].length() - 1};
|
2012-01-31 20:12:06 +01:00
|
|
|
break;
|
|
|
|
|
2012-09-26 14:22:24 +02:00
|
|
|
case InsertMode::OpenLineAbove:
|
|
|
|
case InsertMode::InsertAtLineBegin:
|
2013-06-04 19:23:11 +02:00
|
|
|
first = sel.min().line;
|
2012-09-26 14:22:24 +02:00
|
|
|
if (mode == InsertMode::OpenLineAbove)
|
2013-06-03 19:04:28 +02:00
|
|
|
first = buffer.char_prev(first);
|
2012-03-07 20:19:33 +01:00
|
|
|
else
|
|
|
|
{
|
2013-06-03 19:04:28 +02:00
|
|
|
auto first_non_blank = buffer.iterator_at(first);
|
2012-03-07 20:19:33 +01:00
|
|
|
while (*first_non_blank == ' ' or *first_non_blank == '\t')
|
|
|
|
++first_non_blank;
|
|
|
|
if (*first_non_blank != '\n')
|
2013-06-04 19:23:11 +02:00
|
|
|
first = first_non_blank.coord();
|
2012-03-07 20:19:33 +01:00
|
|
|
}
|
2012-07-16 21:21:56 +02:00
|
|
|
last = first;
|
2012-01-31 20:12:06 +01:00
|
|
|
break;
|
2013-02-07 13:37:22 +01:00
|
|
|
case InsertMode::InsertAtNextLineBegin:
|
2013-04-09 20:04:11 +02:00
|
|
|
kak_assert(false); // not implemented
|
2013-02-07 13:37:22 +01:00
|
|
|
break;
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
2013-06-03 19:04:28 +02:00
|
|
|
if (buffer.is_end(first))
|
|
|
|
first = buffer.char_prev(first);
|
|
|
|
if (buffer.is_end(last))
|
|
|
|
last = buffer.char_prev(last);
|
|
|
|
sel.first() = first;
|
|
|
|
sel.last() = last;
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
2012-09-26 14:22:24 +02:00
|
|
|
if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
|
2012-09-03 23:46:04 +02:00
|
|
|
{
|
2012-08-10 19:12:43 +02:00
|
|
|
insert("\n");
|
2012-09-26 14:22:24 +02:00
|
|
|
if (mode == InsertMode::OpenLineAbove)
|
2012-09-03 23:46:04 +02:00
|
|
|
{
|
2012-09-24 20:47:06 +02:00
|
|
|
for (auto& sel : m_editor.m_selections)
|
2012-09-03 23:46:04 +02:00
|
|
|
{
|
|
|
|
// special case, the --first line above did nothing, so we need to compensate now
|
2013-06-03 19:04:28 +02:00
|
|
|
if (sel.first() == buffer.char_next({0,0}))
|
|
|
|
sel.first() = sel.last() = BufferCoord{0,0};
|
2012-09-03 23:46:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-15 18:48:59 +01:00
|
|
|
sort_and_merge_overlapping(editor.m_selections, editor.m_main_sel);
|
2012-12-31 18:36:28 +01:00
|
|
|
editor.check_invariant();
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
IncrementalInserter::~IncrementalInserter()
|
|
|
|
{
|
2012-09-24 20:47:06 +02:00
|
|
|
for (auto& sel : m_editor.m_selections)
|
2012-08-27 14:26:16 +02:00
|
|
|
{
|
2013-06-03 18:58:09 +02:00
|
|
|
if (m_mode == InsertMode::Append and sel.last().column > 0)
|
|
|
|
sel.last() = m_editor.buffer().char_prev(sel.last());
|
|
|
|
avoid_eol(m_editor.buffer(), sel);
|
2012-08-27 14:26:16 +02:00
|
|
|
}
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2012-11-19 13:40:23 +01:00
|
|
|
void IncrementalInserter::insert(String content)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2013-06-06 19:39:53 +02:00
|
|
|
auto& buffer = m_editor.buffer();
|
2012-09-24 20:47:06 +02:00
|
|
|
for (auto& sel : m_editor.m_selections)
|
2012-08-10 19:12:43 +02:00
|
|
|
{
|
2012-11-30 18:32:49 +01:00
|
|
|
m_editor.filters()(buffer, sel, content);
|
2013-06-06 19:39:53 +02:00
|
|
|
buffer.insert(buffer.iterator_at(sel.last()), content);
|
2012-08-10 19:12:43 +02:00
|
|
|
}
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
2013-07-26 01:17:12 +02:00
|
|
|
void IncrementalInserter::insert(memoryview<String> strings)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2013-06-06 19:39:53 +02:00
|
|
|
auto& buffer = m_editor.buffer();
|
2012-11-12 13:40:07 +01:00
|
|
|
for (size_t i = 0; i < m_editor.m_selections.size(); ++i)
|
|
|
|
{
|
|
|
|
size_t index = std::min(i, strings.size()-1);
|
2013-06-06 19:39:53 +02:00
|
|
|
buffer.insert(buffer.iterator_at(m_editor.m_selections[i].last()),
|
|
|
|
strings[index]);
|
2012-11-12 13:40:07 +01:00
|
|
|
}
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void IncrementalInserter::erase()
|
|
|
|
{
|
2013-06-06 19:39:53 +02:00
|
|
|
auto& buffer = m_editor.buffer();
|
2012-09-24 20:47:06 +02:00
|
|
|
for (auto& sel : m_editor.m_selections)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2013-07-30 20:09:36 +02:00
|
|
|
if (sel.last() == BufferCoord{0,0})
|
|
|
|
continue;
|
2013-06-06 19:39:53 +02:00
|
|
|
auto pos = buffer.iterator_at(sel.last());
|
2013-07-30 20:09:36 +02:00
|
|
|
buffer.erase(utf8::previous(pos), pos);
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-26 19:38:07 +01:00
|
|
|
void IncrementalInserter::move_cursors(CharCount move)
|
2012-01-31 20:12:06 +01:00
|
|
|
{
|
2012-11-26 19:38:07 +01:00
|
|
|
m_editor.move_selections(move, SelectMode::Replace);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IncrementalInserter::move_cursors(LineCount move)
|
|
|
|
{
|
|
|
|
m_editor.move_selections(move, SelectMode::Replace);
|
2012-01-31 20:12:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|