Remove Editor::select methods, add a non-const selections getter

This commit is contained in:
Maxime Coste 2013-12-14 18:38:14 +00:00
parent 0c4d523b22
commit ce0e71aacb
10 changed files with 155 additions and 193 deletions

View File

@ -81,7 +81,7 @@ static void reload_buffer(Context& context, const String& filename)
if (not buf) if (not buf)
return; return;
Window& win = ClientManager::instance().get_unused_window_for_buffer(*buf); Window& win = ClientManager::instance().get_unused_window_for_buffer(*buf);
win.select(cursor_pos); win.selections() = SelectionList{cursor_pos};
win.set_position(view_pos); win.set_position(view_pos);
context.change_editor(win); context.change_editor(win);
context.print_status({ "'" + buf->display_name() + "' reloaded", context.print_status({ "'" + buf->display_name() + "' reloaded",

View File

@ -127,7 +127,7 @@ void edit(CommandParameters params, Context& context)
int column = param_count > 2 and not parser[2].empty() ? int column = param_count > 2 and not parser[2].empty() ?
std::max(0, str_to_int(parser[2]) - 1) : 0; std::max(0, str_to_int(parser[2]) - 1) : 0;
context.editor().select(context.buffer().clamp({ line, column })); context.editor().selections() = context.buffer().clamp({ line, column });
if (context.has_window()) if (context.has_window())
context.window().center_selection(); context.window().center_selection();
} }
@ -571,13 +571,13 @@ void context_wrap(CommandParameters params, Context& context, Func func)
Editor& editor = real_context->editor(); Editor& editor = real_context->editor();
InputHandler input_handler(editor, real_context->name()); InputHandler input_handler(editor, real_context->name());
DynamicSelectionList sels{editor.buffer(), editor.selections()}; DynamicSelectionList sels{editor.buffer(), editor.selections()};
auto restore_sels = on_scope_end([&]{ editor.select(sels); }); auto restore_sels = on_scope_end([&]{ editor.selections() = std::move(sels); });
if (parser.has_option("itersel")) if (parser.has_option("itersel"))
{ {
for (auto& sel : sels) for (auto& sel : sels)
{ {
editor.select(sel); editor.selections() = sel;
func(parser, input_handler.context()); func(parser, input_handler.context());
} }
} }

View File

@ -21,10 +21,8 @@ static Buffer& get_or_create_debug_buffer()
void write_debug(const String& str) void write_debug(const String& str)
{ {
Buffer& debug_buffer = get_or_create_debug_buffer(); Buffer& buffer = get_or_create_debug_buffer();
Editor editor(debug_buffer); buffer.insert(buffer.end(), str);
editor.select(debug_buffer.back_coord());
editor.insert(str + "\n");
} }
} }

View File

@ -14,7 +14,7 @@ namespace Kakoune
Editor::Editor(Buffer& buffer) Editor::Editor(Buffer& buffer)
: m_buffer(&buffer), : m_buffer(&buffer),
m_edition_level(0), m_edition_level(0),
m_selections(buffer, { {{},{}} }) m_selections(buffer, {BufferCoord{}})
{} {}
void Editor::erase() void Editor::erase()
@ -151,45 +151,6 @@ void Editor::move_selections(LineCount offset, SelectMode mode)
m_selections.sort_and_merge_overlapping(); m_selections.sort_and_merge_overlapping();
} }
void Editor::select(const Selection& selection, SelectMode mode)
{
if (mode == SelectMode::Replace)
m_selections = SelectionList{ selection };
else if (mode == SelectMode::Extend)
{
m_selections.main().merge_with(selection);
m_selections = SelectionList{ std::move(m_selections.main()) };
}
else if (mode == SelectMode::Append)
{
m_selections.push_back(selection);
m_selections.set_main_index(m_selections.size()-1);
m_selections.sort_and_merge_overlapping();
}
else
kak_assert(false);
check_invariant();
}
void Editor::select(SelectionList selections)
{
if (selections.empty())
throw runtime_error("no selections");
m_selections = std::move(selections);
check_invariant();
}
struct nothing_selected : public runtime_error
{
nothing_selected() : runtime_error("nothing was selected") {}
};
void Editor::select(const Selector& selector)
{
selector(*m_buffer, m_selections);
check_invariant();
}
class ModifiedRangesListener : public BufferChangeListener_AutoRegister class ModifiedRangesListener : public BufferChangeListener_AutoRegister
{ {
public: public:

View File

@ -57,16 +57,11 @@ public:
SelectMode mode = SelectMode::Replace); SelectMode mode = SelectMode::Replace);
void move_selections(CharCount move, void move_selections(CharCount move,
SelectMode mode = SelectMode::Replace); SelectMode mode = SelectMode::Replace);
void select(BufferCoord c, SelectMode mode = SelectMode::Replace)
{ select(Selection{ buffer().clamp(c) }, mode); }
void select(const Selection& sel,
SelectMode mode = SelectMode::Replace);
void select(SelectionList selections);
void select(const Selector& selector);
void rotate_selections(int count) { m_selections.rotate_main(count); } void rotate_selections(int count) { m_selections.rotate_main(count); }
const SelectionList& selections() const { return m_selections; } const SelectionList& selections() const { return m_selections; }
SelectionList& selections() { return m_selections; }
std::vector<String> selections_content() const; std::vector<String> selections_content() const;
bool undo(); bool undo();

View File

@ -30,8 +30,8 @@ public:
void operator() (Context& context, int) void operator() (Context& context, int)
{ {
context.editor().select([this](const Buffer& buffer, SelectionList& selections) auto& buffer = context.buffer();
{ auto& selections = context.editor().selections();
if (mode == SelectMode::Append) if (mode == SelectMode::Append)
{ {
auto& sel = selections.main(); auto& sel = selections.main();
@ -68,7 +68,6 @@ public:
} }
selections.sort_and_merge_overlapping(); selections.sort_and_merge_overlapping();
selections.check_invariant(); selections.check_invariant();
});
} }
private: private:
T m_func; T m_func;
@ -77,6 +76,18 @@ private:
template<SelectMode mode = SelectMode::Replace, typename T> template<SelectMode mode = SelectMode::Replace, typename T>
constexpr Select<mode, T> select(T func) { return Select<mode, T>(func); } constexpr Select<mode, T> select(T func) { return Select<mode, T>(func); }
template<SelectMode mode = SelectMode::Replace>
void select_coord(BufferCoord coord, SelectionList& selections)
{
if (mode == SelectMode::Replace)
selections = SelectionList { coord };
else if (mode == SelectMode::Extend)
{
for (auto& sel : selections)
sel.last() = coord;
selections.sort_and_merge_overlapping();
}
}
template<InsertMode mode> template<InsertMode mode>
void insert(Context& context, int) void insert(Context& context, int)
@ -119,7 +130,7 @@ void goto_commands(Context& context, int line)
if (line != 0) if (line != 0)
{ {
context.push_jump(); context.push_jump();
context.editor().select(BufferCoord{line - 1, 0}); select_coord<mode>(LineCount{line - 1}, context.editor().selections());
if (context.has_window()) if (context.has_window())
context.window().center_selection(); context.window().center_selection();
} }
@ -135,7 +146,7 @@ void goto_commands(Context& context, int line)
case 'g': case 'g':
case 'k': case 'k':
context.push_jump(); context.push_jump();
editor.select(BufferCoord{0,0}, mode); select_coord<mode>(BufferCoord{0,0}, context.editor().selections());
break; break;
case 'l': case 'l':
select<mode>(select_to_eol)(context, 0); select<mode>(select_to_eol)(context, 0);
@ -146,18 +157,18 @@ void goto_commands(Context& context, int line)
case 'j': case 'j':
{ {
context.push_jump(); context.push_jump();
editor.select({editor.buffer().line_count() - 1, 0}, mode); select_coord<mode>({editor.buffer().line_count() - 1, 0}, editor.selections());
break; break;
} }
case 'e': case 'e':
context.push_jump(); context.push_jump();
editor.select(editor.buffer().back_coord(), mode); select_coord<mode>(editor.buffer().back_coord(), editor.selections());
break; break;
case 't': case 't':
if (context.has_window()) if (context.has_window())
{ {
auto line = context.window().position().line; auto line = context.window().position().line;
editor.select({line, 0}, mode); select_coord<mode>(line, editor.selections());
} }
break; break;
case 'b': case 'b':
@ -165,7 +176,7 @@ void goto_commands(Context& context, int line)
{ {
auto& window = context.window(); auto& window = context.window();
auto line = window.position().line + window.dimensions().line - 1; auto line = window.position().line + window.dimensions().line - 1;
editor.select({line, 0}, mode); select_coord<mode>(line, editor.selections());
} }
break; break;
case 'c': case 'c':
@ -173,7 +184,7 @@ void goto_commands(Context& context, int line)
{ {
auto& window = context.window(); auto& window = context.window();
auto line = window.position().line + window.dimensions().line / 2; auto line = window.position().line + window.dimensions().line / 2;
editor.select({line, 0}, mode); select_coord<mode>(line, editor.selections());
} }
break; break;
case 'a': case 'a':
@ -273,8 +284,8 @@ void replace_with_char(Context& context, int)
return; return;
Editor& editor = context.editor(); Editor& editor = context.editor();
SelectionList sels = editor.selections(); SelectionList sels = editor.selections();
auto restore_sels = on_scope_end([&]{ editor.select(std::move(sels)); }); auto restore_sels = on_scope_end([&]{ editor.selections() = std::move(sels); });
editor.select(std::bind(select_all_matches, _1, _2, Regex{"."})); select_all_matches(editor.buffer(), editor.selections(), Regex{"."});
editor.insert(codepoint_to_str(key.key), InsertMode::Replace); editor.insert(codepoint_to_str(key.key), InsertMode::Replace);
}, "replace with char", "enter char to replace with\n"); }, "replace with char", "enter char to replace with\n");
} }
@ -359,7 +370,7 @@ void search(Context& context, int)
[selections](const String& str, PromptEvent event, Context& context) { [selections](const String& str, PromptEvent event, Context& context) {
try try
{ {
context.editor().select(selections); context.editor().selections() = selections;
if (event == PromptEvent::Abort) if (event == PromptEvent::Abort)
return; return;
@ -377,7 +388,7 @@ void search(Context& context, int)
else if (str.empty() or not context.options()["incsearch"].get<bool>()) else if (str.empty() or not context.options()["incsearch"].get<bool>())
return; return;
context.editor().select(std::bind(select_next_match<direction, mode>, _1, _2, ex)); select_next_match<direction, mode>(context.buffer(), context.editor().selections(), ex);
} }
catch (boost::regex_error& err) catch (boost::regex_error& err)
{ {
@ -388,7 +399,7 @@ void search(Context& context, int)
} }
catch (runtime_error&) catch (runtime_error&)
{ {
context.editor().select(selections); context.editor().selections() = selections;
// only validation should propagate errors, // only validation should propagate errors,
// incremental search should not. // incremental search should not.
if (event == PromptEvent::Validate) if (event == PromptEvent::Validate)
@ -407,7 +418,7 @@ void search_next(Context& context, int param)
{ {
Regex ex{str}; Regex ex{str};
do { do {
context.editor().select(std::bind(select_next_match<direction, mode>, _1, _2, ex)); select_next_match<direction, mode>(context.buffer(), context.editor().selections(), ex);
} while (--param > 0); } while (--param > 0);
} }
catch (boost::regex_error& err) catch (boost::regex_error& err)
@ -534,7 +545,7 @@ void select_regex(Context& context, int)
else else
RegisterManager::instance()['/'] = String{ex.str()}; RegisterManager::instance()['/'] = String{ex.str()};
if (not ex.empty() and not ex.str().empty()) if (not ex.empty() and not ex.str().empty())
context.editor().select(std::bind(select_all_matches, _1, _2, ex)); select_all_matches(context.buffer(), context.editor().selections(), ex);
}); });
} }
@ -546,14 +557,14 @@ void split_regex(Context& context, int)
else else
RegisterManager::instance()['/'] = String{ex.str()}; RegisterManager::instance()['/'] = String{ex.str()};
if (not ex.empty() and not ex.str().empty()) if (not ex.empty() and not ex.str().empty())
context.editor().select(std::bind(split_selection, _1, _2, ex)); split_selections(context.buffer(), context.editor().selections(), ex);
}); });
} }
void split_lines(Context& context, int) void split_lines(Context& context, int)
{ {
context.editor().select([](const Buffer& buffer, auto& selections = context.editor().selections();
SelectionList& selections) { auto& buffer = context.buffer();
SelectionList res; SelectionList res;
for (auto& sel : selections) for (auto& sel : selections)
{ {
@ -570,24 +581,22 @@ void split_lines(Context& context, int)
res.push_back({max.line, max}); res.push_back({max.line, max});
} }
selections = std::move(res); selections = std::move(res);
});
} }
void join_select_spaces(Context& context, int) void join_select_spaces(Context& context, int)
{ {
select(select_whole_lines)(context, 0); select(select_whole_lines)(context, 0);
select<SelectMode::Extend>(select_to_eol)(context, 0); select<SelectMode::Extend>(select_to_eol)(context, 0);
Editor& editor = context.editor(); auto& editor = context.editor();
editor.select([](const Buffer& buffer, SelectionList& sel) auto& buffer = context.buffer();
{ auto& selections = editor.selections();
select_all_matches(buffer, sel, Regex{"(\n\\h*)+"}); select_all_matches(buffer, editor.selections(), Regex{"(\n\\h*)+"});
// remove last end of line if selected // remove last end of line if selected
kak_assert(std::is_sorted(sel.begin(), sel.end(), kak_assert(std::is_sorted(selections.begin(), selections.end(),
[](const Selection& lhs, const Selection& rhs) [](const Selection& lhs, const Selection& rhs)
{ return lhs.min() < rhs.min(); })); { return lhs.min() < rhs.min(); }));
if (not sel.empty() and sel.back().max() == buffer.back_coord()) if (not selections.empty() and selections.back().max() == buffer.back_coord())
sel.pop_back(); selections.pop_back();
});
editor.insert(" ", InsertMode::Replace); editor.insert(" ", InsertMode::Replace);
} }
@ -595,7 +604,7 @@ void join(Context& context, int param)
{ {
Editor& editor = context.editor(); Editor& editor = context.editor();
DynamicSelectionList sels{editor.buffer(), editor.selections()}; DynamicSelectionList sels{editor.buffer(), editor.selections()};
auto restore_sels = on_scope_end([&]{ editor.select((SelectionList)std::move(sels)); }); auto restore_sels = on_scope_end([&]{ editor.selections() = std::move(sels); });
join_select_spaces(context, param); join_select_spaces(context, param);
} }
@ -617,7 +626,7 @@ void keep(Context& context, int)
} }
if (keep.empty()) if (keep.empty())
throw runtime_error("no selections remaining"); throw runtime_error("no selections remaining");
editor.select(std::move(keep)); editor.selections() = std::move(keep);
}); });
} }
@ -627,21 +636,20 @@ void indent(Context& context, int)
CharCount indent_width = context.options()["indentwidth"].get<int>(); CharCount indent_width = context.options()["indentwidth"].get<int>();
String indent = indent_width == 0 ? "\t" : String{' ', indent_width}; String indent = indent_width == 0 ? "\t" : String{' ', indent_width};
Editor& editor = context.editor(); auto& editor = context.editor();
auto& buffer = context.buffer();
DynamicSelectionList sels{editor.buffer(), editor.selections()}; DynamicSelectionList sels{editor.buffer(), editor.selections()};
auto restore_sels = on_scope_end([&]{ editor.select((SelectionList)std::move(sels)); }); auto restore_sels = on_scope_end([&]{ editor.selections() = std::move(sels); });
editor.select([&indent](const Buffer& buf, SelectionList& selections) {
SelectionList res; SelectionList res;
for (auto& sel : selections) for (auto& sel : editor.selections())
{ {
for (auto line = sel.min().line; line < sel.max().line+1; ++line) for (auto line = sel.min().line; line < sel.max().line+1; ++line)
{ {
if (indent_empty or buf[line].length() > 1) if (indent_empty or buffer[line].length() > 1)
res.emplace_back(line, line); res.emplace_back(line, line);
} }
} }
selections = std::move(res); editor.selections() = std::move(res);
});
editor.insert(indent, InsertMode::Insert); editor.insert(indent, InsertMode::Insert);
} }
@ -653,18 +661,18 @@ void deindent(Context& context, int)
if (indent_width == 0) if (indent_width == 0)
indent_width = tabstop; indent_width = tabstop;
Editor& editor = context.editor(); auto& editor = context.editor();
auto& buffer = context.buffer();
DynamicSelectionList sels{editor.buffer(), editor.selections()}; DynamicSelectionList sels{editor.buffer(), editor.selections()};
auto restore_sels = on_scope_end([&]{ editor.select((SelectionList)std::move(sels)); }); auto restore_sels = on_scope_end([&]{ editor.selections() = std::move(sels); });
editor.select([indent_width,tabstop](const Buffer& buf, SelectionList& selections) {
SelectionList res; SelectionList res;
for (auto& sel : selections) for (auto& sel : editor.selections())
{ {
for (auto line = sel.min().line; line < sel.max().line+1; ++line) for (auto line = sel.min().line; line < sel.max().line+1; ++line)
{ {
CharCount width = 0; CharCount width = 0;
auto& content = buf[line]; auto& content = buffer[line];
for (auto column = 0_byte; column < content.length(); ++column) for (auto column = 0_byte; column < content.length(); ++column)
{ {
const char c = content[column]; const char c = content[column];
@ -686,8 +694,7 @@ void deindent(Context& context, int)
} }
} }
} }
selections = std::move(res); editor.selections() = std::move(res);
});
editor.erase(); editor.erase();
} }
@ -773,7 +780,7 @@ void scroll(Context& context, int)
auto cursor_pos = utf8::advance(buffer.iterator_at(position.line), auto cursor_pos = utf8::advance(buffer.iterator_at(position.line),
buffer.iterator_at(position.line+1), buffer.iterator_at(position.line+1),
position.column); position.column);
window.select(cursor_pos.coord()); select_coord(cursor_pos.coord(), window.selections());
window.set_position(position); window.set_position(position);
} }
@ -868,7 +875,7 @@ void jump(Context& context, int)
auto& manager = ClientManager::instance(); auto& manager = ClientManager::instance();
context.change_editor(manager.get_unused_window_for_buffer(buffer)); context.change_editor(manager.get_unused_window_for_buffer(buffer));
} }
context.editor().select(SelectionList{ jump }); context.editor().selections() = jump;
} }
void save_selections(Context& context, int) void save_selections(Context& context, int)
@ -1051,14 +1058,14 @@ KeyMap keymap =
{ '.', repeat_insert }, { '.', repeat_insert },
{ '%', [](Context& context, int) { context.editor().select(select_whole_buffer); } }, { '%', [](Context& context, int) { select_whole_buffer(context.buffer(), context.editor().selections()); } },
{ ':', command }, { ':', command },
{ '|', pipe }, { '|', pipe },
{ ' ', [](Context& context, int count) { if (count == 0) context.editor().select(clear_selections); { ' ', [](Context& context, int count) { if (count == 0) clear_selections(context.buffer(), context.editor().selections());
else context.editor().select(std::bind(keep_selection, _1, _2, count-1)); } }, else keep_selection(context.editor().selections(), count-1); } },
{ alt(' '), [](Context& context, int count) { if (count == 0) context.editor().select(flip_selections); { alt(' '), [](Context& context, int count) { if (count == 0) flip_selections(context.editor().selections());
else context.editor().select(std::bind(remove_selection, _1, _2, count-1)); } }, else remove_selection(context.editor().selections(), count-1); } },
{ 'w', repeated(select<SelectMode::Replace>(select_to_next_word<Word>)) }, { 'w', repeated(select<SelectMode::Replace>(select_to_next_word<Word>)) },
{ 'e', repeated(select<SelectMode::Replace>(select_to_next_word_end<Word>)) }, { 'e', repeated(select<SelectMode::Replace>(select_to_next_word_end<Word>)) },
{ 'b', repeated(select<SelectMode::Replace>(select_to_previous_word<Word>)) }, { 'b', repeated(select<SelectMode::Replace>(select_to_previous_word<Word>)) },

View File

@ -94,6 +94,7 @@ static bool compare_selections(const Selection& lhs, const Selection& rhs)
struct SelectionList : std::vector<Selection> struct SelectionList : std::vector<Selection>
{ {
SelectionList() = default; SelectionList() = default;
SelectionList(BufferCoord c) : std::vector<Selection>{Selection{c,c}} {}
SelectionList(Selection s) : std::vector<Selection>{s} {} SelectionList(Selection s) : std::vector<Selection>{s} {}
void update_insert(const Buffer& buffer, BufferCoord begin, BufferCoord end); void update_insert(const Buffer& buffer, BufferCoord begin, BufferCoord end);

View File

@ -438,7 +438,7 @@ void select_all_matches(const Buffer& buffer, SelectionList& selections,
selections = std::move(result); selections = std::move(result);
} }
void split_selection(const Buffer& buffer, SelectionList& selections, void split_selections(const Buffer& buffer, SelectionList& selections,
const Regex& regex) const Regex& regex)
{ {
SelectionList result; SelectionList result;

View File

@ -19,14 +19,14 @@ inline void clear_selections(const Buffer& buffer, SelectionList& selections)
selections = SelectionList{ std::move(sel) }; selections = SelectionList{ std::move(sel) };
} }
inline void flip_selections(const Buffer&, SelectionList& selections) inline void flip_selections(SelectionList& selections)
{ {
for (auto& sel : selections) for (auto& sel : selections)
std::swap(sel.first(), sel.last()); std::swap(sel.first(), sel.last());
selections.check_invariant(); selections.check_invariant();
} }
inline void keep_selection(const Buffer&, SelectionList& selections, int index) inline void keep_selection(SelectionList& selections, int index)
{ {
if (index < selections.size()) if (index < selections.size())
{ {
@ -36,7 +36,7 @@ inline void keep_selection(const Buffer&, SelectionList& selections, int index)
selections.check_invariant(); selections.check_invariant();
} }
inline void remove_selection(const Buffer&, SelectionList& selections, int index) inline void remove_selection(SelectionList& selections, int index)
{ {
if (selections.size() > 1 and index < selections.size()) if (selections.size() > 1 and index < selections.size())
{ {
@ -282,7 +282,7 @@ void select_next_match(const Buffer& buffer, SelectionList& selections,
void select_all_matches(const Buffer& buffer, SelectionList& selections, void select_all_matches(const Buffer& buffer, SelectionList& selections,
const Regex& regex); const Regex& regex);
void split_selection(const Buffer& buffer, SelectionList& selections, void split_selections(const Buffer& buffer, SelectionList& selections,
const Regex& separator_regex); const Regex& separator_regex);
using CodepointPair = std::pair<Codepoint, Codepoint>; using CodepointPair = std::pair<Codepoint, Codepoint>;

View File

@ -76,8 +76,8 @@ void test_editor()
{ {
scoped_edition edition{editor}; scoped_edition edition{editor};
editor.select(select_whole_buffer); select_whole_buffer(buffer, editor.selections());
editor.select(std::bind(select_all_matches, _1, _2, Regex{"\\n\\h*"})); select_all_matches(buffer, editor.selections(), Regex{"\\n\\h*"});
for (auto& sel : editor.selections()) for (auto& sel : editor.selections())
{ {
kak_assert(buffer.byte_at(sel.min()) == '\n'); kak_assert(buffer.byte_at(sel.min()) == '\n');
@ -87,7 +87,7 @@ void test_editor()
editor.undo(); editor.undo();
Selection sel{ 2_line, buffer.back_coord() }; Selection sel{ 2_line, buffer.back_coord() };
editor.select(sel, SelectMode::Replace); editor.selections() = SelectionList{sel};
editor.insert("",InsertMode::Replace); editor.insert("",InsertMode::Replace);
kak_assert(not buffer.is_end(editor.selections().main().first())); kak_assert(not buffer.is_end(editor.selections().main().first()));
} }