Move insert/erase methods from normal.cc to member functions in SelectionList
It does look like the Editor class is attempting a sneaky comeback...
This commit is contained in:
parent
0a060b62a2
commit
b2621ca140
116
src/normal.cc
116
src/normal.cc
|
@ -22,86 +22,6 @@
|
|||
namespace Kakoune
|
||||
{
|
||||
|
||||
void erase(Buffer& buffer, SelectionList& selections)
|
||||
{
|
||||
for (auto& sel : reversed(selections))
|
||||
{
|
||||
erase(buffer, sel);
|
||||
}
|
||||
selections.update();
|
||||
selections.avoid_eol();
|
||||
buffer.check_invariant();
|
||||
}
|
||||
|
||||
template<InsertMode mode>
|
||||
BufferIterator prepare_insert(Buffer& buffer, const Selection& sel)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case InsertMode::Insert:
|
||||
return buffer.iterator_at(sel.min());
|
||||
case InsertMode::Replace:
|
||||
return Kakoune::erase(buffer, sel);
|
||||
case InsertMode::Append:
|
||||
{
|
||||
// special case for end of lines, append to current line instead
|
||||
auto pos = buffer.iterator_at(sel.max());
|
||||
return *pos == '\n' ? pos : utf8::next(pos);
|
||||
}
|
||||
case InsertMode::InsertAtLineBegin:
|
||||
return buffer.iterator_at(sel.min().line);
|
||||
case InsertMode::AppendAtLineEnd:
|
||||
return buffer.iterator_at({sel.max().line, buffer[sel.max().line].length() - 1});
|
||||
case InsertMode::InsertAtNextLineBegin:
|
||||
return buffer.iterator_at(sel.max().line+1);
|
||||
case InsertMode::OpenLineBelow:
|
||||
return buffer.insert(buffer.iterator_at(sel.max().line + 1), "\n");
|
||||
case InsertMode::OpenLineAbove:
|
||||
return buffer.insert(buffer.iterator_at(sel.min().line), "\n");
|
||||
}
|
||||
kak_assert(false);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<InsertMode mode>
|
||||
void insert(Buffer& buffer, SelectionList& selections, memoryview<String> strings)
|
||||
{
|
||||
if (strings.empty())
|
||||
return;
|
||||
|
||||
selections.update();
|
||||
for (size_t i = 0; i < selections.size(); ++i)
|
||||
{
|
||||
size_t index = selections.size() - 1 - i;
|
||||
auto& sel = selections[index];
|
||||
auto pos = prepare_insert<mode>(buffer, sel);
|
||||
const String& str = strings[std::min(index, strings.size()-1)];
|
||||
pos = buffer.insert(pos, str);
|
||||
if (mode == InsertMode::Replace)
|
||||
{
|
||||
if (pos == buffer.end())
|
||||
--pos;
|
||||
sel.anchor() = pos.coord();
|
||||
sel.cursor() = (str.empty() ?
|
||||
pos : pos + str.byte_count_to(str.char_length() - 1)).coord();
|
||||
|
||||
// update following selections
|
||||
auto changes = compute_modifications(buffer, selections.timestamp());
|
||||
for (size_t j = index+1; j < selections.size(); ++j)
|
||||
{
|
||||
auto& sel = selections[j];
|
||||
sel.anchor() = update_pos(changes, sel.anchor());
|
||||
sel.cursor() = update_pos(changes, sel.cursor());
|
||||
}
|
||||
selections.update_timestamp();
|
||||
}
|
||||
}
|
||||
selections.update();
|
||||
selections.avoid_eol();
|
||||
selections.check_invariant();
|
||||
buffer.check_invariant();
|
||||
}
|
||||
|
||||
using namespace std::placeholders;
|
||||
|
||||
enum class SelectMode
|
||||
|
@ -172,7 +92,7 @@ constexpr Select<mode, T> make_select(T func)
|
|||
}
|
||||
|
||||
template<SelectMode mode = SelectMode::Replace>
|
||||
void select_coord(const Buffer& buffer, ByteCoord coord, SelectionList& selections)
|
||||
void select_coord(Buffer& buffer, ByteCoord coord, SelectionList& selections)
|
||||
{
|
||||
coord = buffer.clamp(coord);
|
||||
if (mode == SelectMode::Replace)
|
||||
|
@ -405,7 +325,7 @@ void replace_with_char(Context& context, int)
|
|||
CharCount count = char_length(buffer, sel);
|
||||
strings.emplace_back(key.key, count);
|
||||
}
|
||||
insert<InsertMode::Replace>(buffer, selections, strings);
|
||||
selections.insert(strings, InsertMode::Replace);
|
||||
}, "replace with char", "enter char to replace with\n");
|
||||
}
|
||||
|
||||
|
@ -428,7 +348,7 @@ void for_each_char(Context& context, int)
|
|||
for (auto& c : sel)
|
||||
c = func(c);
|
||||
}
|
||||
insert<InsertMode::Replace>(context.buffer(), context.selections(), sels);
|
||||
context.selections().insert(sels, InsertMode::Replace);
|
||||
}
|
||||
|
||||
void command(Context& context, int)
|
||||
|
@ -493,7 +413,7 @@ void pipe(Context& context, int)
|
|||
strings.push_back(str);
|
||||
}
|
||||
ScopedEdition edition(context);
|
||||
insert<mode>(buffer, selections, strings);
|
||||
selections.insert(strings, mode);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -543,7 +463,7 @@ void erase_selections(Context& context, int)
|
|||
{
|
||||
RegisterManager::instance()['"'] = context.selections_content();
|
||||
ScopedEdition edition(context);
|
||||
erase(context.buffer(), context.selections());
|
||||
context.selections().erase();
|
||||
}
|
||||
|
||||
void cat_erase_selections(Context& context, int)
|
||||
|
@ -553,7 +473,7 @@ void cat_erase_selections(Context& context, int)
|
|||
for (auto& sel : sels)
|
||||
str += sel;
|
||||
RegisterManager::instance()['"'] = memoryview<String>(str);
|
||||
erase(context.buffer(), context.selections());
|
||||
context.selections().erase();
|
||||
}
|
||||
|
||||
|
||||
|
@ -587,10 +507,8 @@ void paste(Context& context, int)
|
|||
}
|
||||
}
|
||||
ScopedEdition edition(context);
|
||||
if (linewise)
|
||||
insert<adapt_for_linewise(mode)>(context.buffer(), context.selections(), strings);
|
||||
else
|
||||
insert<mode>(context.buffer(), context.selections(), strings);
|
||||
context.selections().insert(strings,
|
||||
linewise ? adapt_for_linewise(mode) : mode);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -717,7 +635,7 @@ void select_regex(Context& context, int)
|
|||
else
|
||||
RegisterManager::instance()['/'] = String{ex.str()};
|
||||
if (not ex.empty() and not ex.str().empty())
|
||||
select_all_matches(context.buffer(), context.selections(), ex);
|
||||
select_all_matches(context.selections(), ex);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -729,7 +647,7 @@ void split_regex(Context& context, int)
|
|||
else
|
||||
RegisterManager::instance()['/'] = String{ex.str()};
|
||||
if (not ex.empty() and not ex.str().empty())
|
||||
split_selections(context.buffer(), context.selections(), ex);
|
||||
split_selections(context.selections(), ex);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -775,7 +693,7 @@ void join_select_spaces(Context& context, int)
|
|||
return;
|
||||
context.selections() = selections;
|
||||
ScopedEdition edition(context);
|
||||
insert<InsertMode::Replace>(buffer, context.selections(), " "_str);
|
||||
context.selections().insert(" "_str, InsertMode::Replace);
|
||||
}
|
||||
|
||||
void join(Context& context, int param)
|
||||
|
@ -853,7 +771,7 @@ void indent(Context& context, int)
|
|||
{
|
||||
ScopedEdition edition(context);
|
||||
SelectionList selections{buffer, std::move(sels)};
|
||||
insert<InsertMode::Insert>(buffer, selections, indent);
|
||||
selections.insert(indent, InsertMode::Insert);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -898,7 +816,7 @@ void deindent(Context& context, int)
|
|||
{
|
||||
ScopedEdition edition(context);
|
||||
SelectionList selections{context.buffer(), std::move(sels)};
|
||||
erase(context.buffer(), selections);
|
||||
selections.erase();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1008,7 +926,7 @@ void rotate_selections_content(Context& context, int group)
|
|||
std::rotate(it, end-count, end);
|
||||
it = end;
|
||||
}
|
||||
insert<InsertMode::Replace>(context.buffer(), context.selections(), strings);
|
||||
context.selections().insert(strings, InsertMode::Replace);
|
||||
context.selections().rotate_main(count);
|
||||
}
|
||||
|
||||
|
@ -1236,7 +1154,7 @@ void spaces_to_tabs(Context& context, int ts)
|
|||
}
|
||||
}
|
||||
|
||||
static boost::optional<SelectionList> compute_modified_ranges(const Buffer& buffer, size_t timestamp)
|
||||
static boost::optional<SelectionList> compute_modified_ranges(Buffer& buffer, size_t timestamp)
|
||||
{
|
||||
std::vector<Selection> ranges;
|
||||
for (auto& change : buffer.changes_since(timestamp))
|
||||
|
@ -1402,12 +1320,12 @@ KeyMap keymap =
|
|||
|
||||
{ '.', repeat_last_insert },
|
||||
|
||||
{ '%', [](Context& context, int) { select_whole_buffer(context.buffer(), context.selections()); } },
|
||||
{ '%', [](Context& context, int) { select_whole_buffer(context.selections()); } },
|
||||
|
||||
{ ':', command },
|
||||
{ '|', pipe<InsertMode::Replace> },
|
||||
{ alt('|'), pipe<InsertMode::Append> },
|
||||
{ ' ', [](Context& context, int count) { if (count == 0) clear_selections(context.buffer(), context.selections());
|
||||
{ ' ', [](Context& context, int count) { if (count == 0) clear_selections(context.selections());
|
||||
else keep_selection(context.selections(), count-1); } },
|
||||
{ alt(' '), [](Context& context, int count) { if (count == 0) flip_selections(context.selections());
|
||||
else remove_selection(context.selections(), count-1); } },
|
||||
|
|
|
@ -11,18 +11,6 @@ namespace Kakoune
|
|||
|
||||
class Context;
|
||||
|
||||
enum class InsertMode : unsigned
|
||||
{
|
||||
Insert,
|
||||
Append,
|
||||
Replace,
|
||||
InsertAtLineBegin,
|
||||
InsertAtNextLineBegin,
|
||||
AppendAtLineEnd,
|
||||
OpenLineBelow,
|
||||
OpenLineAbove
|
||||
};
|
||||
|
||||
using KeyMap = std::unordered_map<Key, std::function<void (Context& context, int param)>>;
|
||||
extern KeyMap keymap;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "utf8.hh"
|
||||
#include "modification.hh"
|
||||
#include "buffer_utils.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
@ -102,24 +103,24 @@ struct UpdateErase
|
|||
|
||||
}
|
||||
|
||||
SelectionList::SelectionList(const Buffer& buffer, Selection s, size_t timestamp)
|
||||
SelectionList::SelectionList(Buffer& buffer, Selection s, size_t timestamp)
|
||||
: m_buffer(&buffer), m_selections({ s }), m_timestamp(timestamp)
|
||||
{
|
||||
check_invariant();
|
||||
}
|
||||
|
||||
SelectionList::SelectionList(const Buffer& buffer, Selection s)
|
||||
SelectionList::SelectionList(Buffer& buffer, Selection s)
|
||||
: SelectionList(buffer, s, buffer.timestamp())
|
||||
{}
|
||||
|
||||
SelectionList::SelectionList(const Buffer& buffer, std::vector<Selection> s, size_t timestamp)
|
||||
SelectionList::SelectionList(Buffer& buffer, std::vector<Selection> s, size_t timestamp)
|
||||
: m_buffer(&buffer), m_selections(std::move(s)), m_timestamp(timestamp)
|
||||
{
|
||||
kak_assert(size() > 0);
|
||||
check_invariant();
|
||||
}
|
||||
|
||||
SelectionList::SelectionList(const Buffer& buffer, std::vector<Selection> s)
|
||||
SelectionList::SelectionList(Buffer& buffer, std::vector<Selection> s)
|
||||
: SelectionList(buffer, std::move(s), buffer.timestamp())
|
||||
{}
|
||||
|
||||
|
@ -221,4 +222,83 @@ void SelectionList::avoid_eol()
|
|||
_avoid_eol(buffer(), sel);
|
||||
}
|
||||
|
||||
void SelectionList::erase()
|
||||
{
|
||||
for (auto& sel : reversed(m_selections))
|
||||
{
|
||||
Kakoune::erase(*m_buffer, sel);
|
||||
}
|
||||
update();
|
||||
avoid_eol();
|
||||
m_buffer->check_invariant();
|
||||
}
|
||||
|
||||
BufferIterator prepare_insert(Buffer& buffer, const Selection& sel, InsertMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case InsertMode::Insert:
|
||||
return buffer.iterator_at(sel.min());
|
||||
case InsertMode::Replace:
|
||||
return erase(buffer, sel);
|
||||
case InsertMode::Append:
|
||||
{
|
||||
// special case for end of lines, append to current line instead
|
||||
auto pos = buffer.iterator_at(sel.max());
|
||||
return *pos == '\n' ? pos : utf8::next(pos);
|
||||
}
|
||||
case InsertMode::InsertAtLineBegin:
|
||||
return buffer.iterator_at(sel.min().line);
|
||||
case InsertMode::AppendAtLineEnd:
|
||||
return buffer.iterator_at({sel.max().line, buffer[sel.max().line].length() - 1});
|
||||
case InsertMode::InsertAtNextLineBegin:
|
||||
return buffer.iterator_at(sel.max().line+1);
|
||||
case InsertMode::OpenLineBelow:
|
||||
return buffer.insert(buffer.iterator_at(sel.max().line + 1), "\n");
|
||||
case InsertMode::OpenLineAbove:
|
||||
return buffer.insert(buffer.iterator_at(sel.min().line), "\n");
|
||||
}
|
||||
kak_assert(false);
|
||||
return {};
|
||||
}
|
||||
|
||||
void SelectionList::insert(memoryview<String> strings, InsertMode mode)
|
||||
{
|
||||
if (strings.empty())
|
||||
return;
|
||||
|
||||
update();
|
||||
for (size_t i = 0; i < m_selections.size(); ++i)
|
||||
{
|
||||
size_t index = m_selections.size() - 1 - i;
|
||||
auto& sel = m_selections[index];
|
||||
auto pos = prepare_insert(*m_buffer, sel, mode);
|
||||
const String& str = strings[std::min(index, strings.size()-1)];
|
||||
pos = m_buffer->insert(pos, str);
|
||||
if (mode == InsertMode::Replace)
|
||||
{
|
||||
if (pos == m_buffer->end())
|
||||
--pos;
|
||||
sel.anchor() = pos.coord();
|
||||
sel.cursor() = (str.empty() ?
|
||||
pos : pos + str.byte_count_to(str.char_length() - 1)).coord();
|
||||
|
||||
// update following selections
|
||||
auto changes = compute_modifications(*m_buffer, timestamp());
|
||||
for (size_t j = index+1; j < m_selections.size(); ++j)
|
||||
{
|
||||
auto& sel = m_selections[j];
|
||||
sel.anchor() = update_pos(changes, sel.anchor());
|
||||
sel.cursor() = update_pos(changes, sel.cursor());
|
||||
}
|
||||
update_timestamp();
|
||||
}
|
||||
}
|
||||
update();
|
||||
avoid_eol();
|
||||
check_invariant();
|
||||
m_buffer->check_invariant();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -55,12 +55,24 @@ static bool compare_selections(const Selection& lhs, const Selection& rhs)
|
|||
return lhs.min() < rhs.min();
|
||||
}
|
||||
|
||||
enum class InsertMode : unsigned
|
||||
{
|
||||
Insert,
|
||||
Append,
|
||||
Replace,
|
||||
InsertAtLineBegin,
|
||||
InsertAtNextLineBegin,
|
||||
AppendAtLineEnd,
|
||||
OpenLineBelow,
|
||||
OpenLineAbove
|
||||
};
|
||||
|
||||
struct SelectionList
|
||||
{
|
||||
SelectionList(const Buffer& buffer, Selection s);
|
||||
SelectionList(const Buffer& buffer, Selection s, size_t timestamp);
|
||||
SelectionList(const Buffer& buffer, std::vector<Selection> s);
|
||||
SelectionList(const Buffer& buffer, std::vector<Selection> s, size_t timestamp);
|
||||
SelectionList(Buffer& buffer, Selection s);
|
||||
SelectionList(Buffer& buffer, Selection s, size_t timestamp);
|
||||
SelectionList(Buffer& buffer, std::vector<Selection> s);
|
||||
SelectionList(Buffer& buffer, std::vector<Selection> s, size_t timestamp);
|
||||
|
||||
void update();
|
||||
|
||||
|
@ -103,17 +115,7 @@ struct SelectionList
|
|||
const_iterator begin() const { return m_selections.begin(); }
|
||||
const_iterator end() const { return m_selections.end(); }
|
||||
|
||||
template<typename... Args>
|
||||
iterator insert(Args... args)
|
||||
{
|
||||
return m_selections.insert(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
iterator erase(Args... args)
|
||||
{
|
||||
return m_selections.erase(std::forward<Args>(args)...);
|
||||
}
|
||||
void remove(size_t index) { m_selections.erase(begin() + index); }
|
||||
|
||||
size_t size() const { return m_selections.size(); }
|
||||
|
||||
|
@ -140,22 +142,25 @@ struct SelectionList
|
|||
(*this)[i] = std::move((*this)[j]);
|
||||
}
|
||||
}
|
||||
erase(begin() + i + 1, end());
|
||||
m_selections.erase(begin() + i + 1, end());
|
||||
kak_assert(std::is_sorted(begin(), end(), compare_selections));
|
||||
}
|
||||
|
||||
void sort_and_merge_overlapping();
|
||||
|
||||
const Buffer& buffer() const { return *m_buffer; }
|
||||
Buffer& buffer() const { return *m_buffer; }
|
||||
|
||||
size_t timestamp() const { return m_timestamp; }
|
||||
void update_timestamp() { m_timestamp = m_buffer->timestamp(); }
|
||||
|
||||
void insert(memoryview<String> strings, InsertMode mode);
|
||||
void erase();
|
||||
|
||||
private:
|
||||
size_t m_main = 0;
|
||||
std::vector<Selection> m_selections;
|
||||
|
||||
safe_ptr<const Buffer> m_buffer;
|
||||
safe_ptr<Buffer> m_buffer;
|
||||
size_t m_timestamp;
|
||||
};
|
||||
|
||||
|
|
|
@ -429,15 +429,16 @@ Selection trim_partial_lines(const Buffer& buffer, const Selection& selection)
|
|||
return Selection(first.coord(), last.coord());
|
||||
}
|
||||
|
||||
void select_whole_buffer(const Buffer& buffer, SelectionList& selections)
|
||||
void select_whole_buffer(SelectionList& selections)
|
||||
{
|
||||
auto& buffer = selections.buffer();
|
||||
selections = SelectionList{ buffer, Selection({0,0}, buffer.back_coord()) };
|
||||
}
|
||||
|
||||
void select_all_matches(const Buffer& buffer, SelectionList& selections,
|
||||
const Regex& regex)
|
||||
void select_all_matches(SelectionList& selections, const Regex& regex)
|
||||
{
|
||||
std::vector<Selection> result;
|
||||
auto& buffer = selections.buffer();
|
||||
for (auto& sel : selections)
|
||||
{
|
||||
auto sel_end = utf8::next(buffer.iterator_at(sel.max()));
|
||||
|
@ -466,10 +467,10 @@ void select_all_matches(const Buffer& buffer, SelectionList& selections,
|
|||
selections = std::move(result);
|
||||
}
|
||||
|
||||
void split_selections(const Buffer& buffer, SelectionList& selections,
|
||||
const Regex& regex)
|
||||
void split_selections(SelectionList& selections, const Regex& regex)
|
||||
{
|
||||
std::vector<Selection> result;
|
||||
auto& buffer = selections.buffer();
|
||||
for (auto& sel : selections)
|
||||
{
|
||||
auto begin = buffer.iterator_at(sel.min());
|
||||
|
|
|
@ -9,14 +9,14 @@
|
|||
namespace Kakoune
|
||||
{
|
||||
|
||||
inline void clear_selections(const Buffer& buffer, SelectionList& selections)
|
||||
inline void clear_selections(SelectionList& selections)
|
||||
{
|
||||
auto& sel = selections.main();
|
||||
auto& pos = sel.cursor();
|
||||
sel.anchor() = pos;
|
||||
selections.avoid_eol();
|
||||
|
||||
selections = SelectionList{ buffer, std::move(sel) };
|
||||
selections = SelectionList{ selections.buffer(), std::move(sel) };
|
||||
}
|
||||
|
||||
inline void flip_selections(SelectionList& selections)
|
||||
|
@ -41,7 +41,7 @@ inline void remove_selection(SelectionList& selections, int index)
|
|||
if (selections.size() > 1 and index < selections.size())
|
||||
{
|
||||
size_t real_index = (index + selections.main_index() + 1) % selections.size();
|
||||
selections.erase(selections.begin() + real_index);
|
||||
selections.remove(real_index);
|
||||
size_t main_index = selections.main_index();
|
||||
if (real_index <= main_index)
|
||||
selections.set_main_index((main_index > 0 ? main_index
|
||||
|
@ -207,7 +207,7 @@ Selection select_whole_paragraph(const Buffer& buffer, const Selection& selectio
|
|||
Selection select_whole_indent(const Buffer& buffer, const Selection& selection,
|
||||
ObjectFlags flags);
|
||||
Selection select_whole_lines(const Buffer& buffer, const Selection& selection);
|
||||
void select_whole_buffer(const Buffer& buffer, SelectionList& selections);
|
||||
void select_whole_buffer(SelectionList& selections);
|
||||
Selection trim_partial_lines(const Buffer& buffer, const Selection& selection);
|
||||
|
||||
enum Direction { Forward, Backward };
|
||||
|
@ -266,10 +266,10 @@ Selection find_next_match(const Buffer& buffer, const Selection& sel, const Rege
|
|||
return {begin.coord(), end.coord(), std::move(captures)};
|
||||
}
|
||||
|
||||
void select_all_matches(const Buffer& buffer, SelectionList& selections,
|
||||
void select_all_matches(SelectionList& selections,
|
||||
const Regex& regex);
|
||||
|
||||
void split_selections(const Buffer& buffer, SelectionList& selections,
|
||||
void split_selections(SelectionList& selections,
|
||||
const Regex& separator_regex);
|
||||
|
||||
using CodepointPair = std::pair<Codepoint, Codepoint>;
|
||||
|
|
Loading…
Reference in New Issue
Block a user