summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2013-12-15 18:07:51 +0000
committerMaxime Coste <frrrwww@gmail.com>2013-12-15 20:23:02 +0000
commit7267b8281fbcc21d96bb8cb760d2a4e881b4d5e5 (patch)
tree74891181f3d7b078bb6e1f4424e0449d843ac626 /src
parente369b60258ba48eeeb53a91d15e6ae1a9bb6f10f (diff)
Move insert and erase to normal.cc, and move edition management to context
Diffstat (limited to 'src')
-rw-r--r--src/client_manager.cc2
-rw-r--r--src/commands.cc7
-rw-r--r--src/context.cc14
-rw-r--r--src/context.hh22
-rw-r--r--src/editor.cc97
-rw-r--r--src/editor.hh26
-rw-r--r--src/input_handler.cc35
-rw-r--r--src/normal.cc199
-rw-r--r--src/unit_tests.cc25
9 files changed, 200 insertions, 227 deletions
diff --git a/src/client_manager.cc b/src/client_manager.cc
index 946650f4..657e6d93 100644
--- a/src/client_manager.cc
+++ b/src/client_manager.cc
@@ -109,7 +109,7 @@ void ClientManager::ensure_no_client_uses_buffer(Buffer& buffer)
if (&client->context().buffer() != &buffer)
continue;
- if (client->context().editor().is_editing())
+ if (client->context().is_editing())
throw runtime_error("client '" + client->context().name() + "' is inserting in '" +
buffer.display_name() + '\'');
diff --git a/src/commands.cc b/src/commands.cc
index e0f9e535..7c692745 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -573,6 +573,11 @@ void context_wrap(CommandParameters params, Context& context, Func func)
DynamicSelectionList sels{editor.buffer(), editor.selections()};
auto restore_sels = on_scope_end([&]{ editor.selections() = std::move(sels); });
+ // We do not want this draft context to commit undo groups if the real one is
+ // going to commit the whole thing later
+ if (real_context->is_editing())
+ input_handler.context().disable_undo_handling();
+
if (parser.has_option("itersel"))
{
for (auto& sel : sels)
@@ -804,7 +809,7 @@ void exec_keys(const KeyList& keys, Context& context)
RegisterRestorer quote('"', context);
RegisterRestorer slash('/', context);
- scoped_edition edition(context.editor());
+ ScopedEdition edition(context);
for (auto& key : keys)
context.input_handler().handle_key(key);
diff --git a/src/context.cc b/src/context.cc
index 35e28731..6e94b174 100644
--- a/src/context.cc
+++ b/src/context.cc
@@ -187,4 +187,18 @@ const SelectionList& Context::selections() const
return editor().selections();
}
+void Context::begin_edition()
+{
+ ++m_edition_level;
+}
+
+void Context::end_edition()
+{
+ kak_assert(m_edition_level > 0);
+ if (m_edition_level == 1)
+ buffer().commit_undo_group();
+
+ --m_edition_level;
+}
+
}
diff --git a/src/context.hh b/src/context.hh
index cda7a812..58e7380c 100644
--- a/src/context.hh
+++ b/src/context.hh
@@ -70,7 +70,15 @@ public:
const String& name() const { return m_name; }
void set_name(String name) { m_name = std::move(name); }
+ bool is_editing() const { return m_edition_level!= 0; }
+ void disable_undo_handling() { ++m_edition_level; }
private:
+ void begin_edition();
+ void end_edition();
+ int m_edition_level = 0;
+
+ friend struct ScopedEdition;
+
safe_ptr<Editor> m_editor;
safe_ptr<InputHandler> m_input_handler;
safe_ptr<Client> m_client;
@@ -82,5 +90,19 @@ private:
JumpList::iterator m_current_jump = m_jump_list.begin();
};
+struct ScopedEdition
+{
+ ScopedEdition(Context& context)
+ : m_context(context)
+ { m_context.begin_edition(); }
+
+ ~ScopedEdition()
+ { m_context.end_edition(); }
+
+ Context& context() const { return m_context; }
+private:
+ Context& m_context;
+};
+
}
#endif // context_hh_INCLUDED
diff --git a/src/editor.cc b/src/editor.cc
index d7bf52e0..12c65096 100644
--- a/src/editor.cc
+++ b/src/editor.cc
@@ -13,92 +13,9 @@ namespace Kakoune
Editor::Editor(Buffer& buffer)
: m_buffer(&buffer),
- m_edition_level(0),
m_selections(buffer, {BufferCoord{}})
{}
-void Editor::erase()
-{
- scoped_edition edition(*this);
- for (auto& sel : m_selections)
- {
- Kakoune::erase(*m_buffer, sel);
- avoid_eol(*m_buffer, sel);
- }
-}
-
-static 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 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 {};
-}
-
-void Editor::insert(const String& str, InsertMode mode)
-{
- scoped_edition edition(*this);
-
- for (auto& sel : m_selections)
- {
- auto pos = prepare_insert(*m_buffer, sel, mode);
- pos = m_buffer->insert(pos, str);
- if (mode == InsertMode::Replace and pos != m_buffer->end())
- {
- sel.first() = pos.coord();
- sel.last() = str.empty() ?
- pos.coord() : (pos + str.byte_count_to(str.char_length() - 1)).coord();
- }
- avoid_eol(*m_buffer, sel);
- }
- check_invariant();
-}
-
-void Editor::insert(memoryview<String> strings, InsertMode mode)
-{
- scoped_edition edition(*this);
- if (strings.empty())
- return;
-
- for (size_t i = 0; i < selections().size(); ++i)
- {
- auto& sel = m_selections[i];
- auto pos = prepare_insert(*m_buffer, sel, mode);
- const String& str = strings[std::min(i, strings.size()-1)];
- pos = m_buffer->insert(pos, str);
- if (mode == InsertMode::Replace and pos != m_buffer->end())
- {
- sel.first() = pos.coord();
- sel.last() = (str.empty() ?
- pos : pos + str.byte_count_to(str.char_length() - 1)).coord();
- }
- avoid_eol(*m_buffer, sel);
- }
- check_invariant();
-}
-
std::vector<String> Editor::selections_content() const
{
std::vector<String> contents;
@@ -182,18 +99,4 @@ void Editor::check_invariant() const
#endif
}
-void Editor::begin_edition()
-{
- ++m_edition_level;
-}
-
-void Editor::end_edition()
-{
- kak_assert(m_edition_level > 0);
- if (m_edition_level == 1)
- m_buffer->commit_undo_group();
-
- --m_edition_level;
-}
-
}
diff --git a/src/editor.hh b/src/editor.hh
index 5a468279..d98feecc 100644
--- a/src/editor.hh
+++ b/src/editor.hh
@@ -38,13 +38,6 @@ public:
Buffer& buffer() const { return *m_buffer; }
- void erase();
-
- void insert(const String& string,
- InsertMode mode = InsertMode::Insert);
- void insert(memoryview<String> strings,
- InsertMode mode = InsertMode::Insert);
-
const SelectionList& selections() const { return m_selections; }
SelectionList& selections() { return m_selections; }
std::vector<String> selections_content() const;
@@ -52,14 +45,9 @@ public:
bool undo();
bool redo();
- bool is_editing() const { return m_edition_level!= 0; }
private:
friend struct scoped_edition;
friend class InputModes::Insert;
- void begin_edition();
- void end_edition();
-
- int m_edition_level;
void check_invariant() const;
@@ -67,20 +55,6 @@ private:
DynamicSelectionList m_selections;
};
-struct scoped_edition
-{
- scoped_edition(Editor& editor)
- : m_editor(editor)
- { m_editor.begin_edition(); }
-
- ~scoped_edition()
- { m_editor.end_edition(); }
-
- Editor& editor() const { return m_editor; }
-private:
- Editor& m_editor;
-};
-
}
#endif // editor_hh_INCLUDED
diff --git a/src/input_handler.cc b/src/input_handler.cc
index 1b8e16d7..03c9f497 100644
--- a/src/input_handler.cc
+++ b/src/input_handler.cc
@@ -873,7 +873,7 @@ public:
Insert(InputHandler& input_handler, InsertMode mode)
: InputMode(input_handler),
m_insert_mode(mode),
- m_edition(context().editor()),
+ m_edition(context()),
m_completer(context()),
m_idle_timer{Clock::now() + idle_timeout,
[this](Timer& timer) {
@@ -982,8 +982,8 @@ public:
private:
void erase() const
{
- auto& buffer = m_edition.editor().buffer();
- for (auto& sel : m_edition.editor().selections())
+ auto& buffer = context().buffer();
+ for (auto& sel : context().selections())
{
if (sel.last() == BufferCoord{0,0})
continue;
@@ -1007,8 +1007,8 @@ private:
void insert(memoryview<String> strings)
{
- auto& buffer = m_edition.editor().buffer();
- auto& selections = m_edition.editor().selections();
+ auto& buffer = context().buffer();
+ auto& selections = context().selections();
for (size_t i = 0; i < selections.size(); ++i)
{
size_t index = std::min(i, strings.size()-1);
@@ -1020,18 +1020,18 @@ private:
void insert(Codepoint key)
{
auto str = codepoint_to_str(key);
- auto& buffer = m_edition.editor().buffer();
- for (auto& sel : m_edition.editor().selections())
+ auto& buffer = context().buffer();
+ for (auto& sel : context().selections())
buffer.insert(buffer.iterator_at(sel.last()), str);
context().hooks().run_hook("InsertChar", str, context());
}
void prepare(InsertMode mode)
{
- Editor& editor = m_edition.editor();
- Buffer& buffer = editor.buffer();
+ SelectionList& selections = context().selections();
+ Buffer& buffer = context().buffer();
- for (auto& sel : editor.m_selections)
+ for (auto& sel : selections)
{
BufferCoord first, last;
switch (mode)
@@ -1087,7 +1087,7 @@ private:
insert('\n');
if (mode == InsertMode::OpenLineAbove)
{
- for (auto& sel : editor.m_selections)
+ for (auto& sel : selections)
{
// special case, the --first line above did nothing, so we need to compensate now
if (sel.first() == buffer.char_next({0,0}))
@@ -1095,24 +1095,25 @@ private:
}
}
}
- editor.m_selections.sort_and_merge_overlapping();
- editor.check_invariant();
+ selections.sort_and_merge_overlapping();
+ selections.check_invariant();
+ buffer.check_invariant();
}
void on_replaced() override
{
- for (auto& sel : m_edition.editor().m_selections)
+ for (auto& sel : context().selections())
{
if (m_insert_mode == InsertMode::Append and sel.last().column > 0)
- sel.last() = m_edition.editor().buffer().char_prev(sel.last());
- avoid_eol(m_edition.editor().buffer(), sel);
+ sel.last() = context().buffer().char_prev(sel.last());
+ avoid_eol(context().buffer(), sel);
}
}
enum class Mode { Default, Complete, InsertReg };
Mode m_mode = Mode::Default;
InsertMode m_insert_mode;
- scoped_edition m_edition;
+ ScopedEdition m_edition;
BufferCompleter m_completer;
Timer m_idle_timer;
};
diff --git a/src/normal.cc b/src/normal.cc
index aab5a029..1b922275 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -20,6 +20,89 @@
namespace Kakoune
{
+void erase(Buffer& buffer, SelectionList& selections)
+{
+ for (auto& sel : selections)
+ {
+ erase(buffer, sel);
+ avoid_eol(buffer, sel);
+ }
+ selections.check_invariant();
+ 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, const String& str)
+{
+ for (auto& sel : selections)
+ {
+ auto pos = prepare_insert<mode>(buffer, sel);
+ pos = buffer.insert(pos, str);
+ if (mode == InsertMode::Replace and pos != buffer.end())
+ {
+ sel.first() = pos.coord();
+ sel.last() = str.empty() ?
+ pos.coord() : (pos + str.byte_count_to(str.char_length() - 1)).coord();
+ }
+ avoid_eol(buffer, sel);
+ }
+ selections.check_invariant();
+ buffer.check_invariant();
+}
+
+template<InsertMode mode>
+void insert(Buffer& buffer, SelectionList& selections, memoryview<String> strings)
+{
+ if (strings.empty())
+ return;
+ for (size_t i = 0; i < selections.size(); ++i)
+ {
+ auto& sel = selections[i];
+ auto pos = prepare_insert<mode>(buffer, sel);
+ const String& str = strings[std::min(i, strings.size()-1)];
+ pos = buffer.insert(pos, str);
+ if (mode == InsertMode::Replace and pos != buffer.end())
+ {
+ sel.first() = pos.coord();
+ sel.last() = (str.empty() ?
+ pos : pos + str.byte_count_to(str.char_length() - 1)).coord();
+ }
+ avoid_eol(buffer, sel);
+ }
+ selections.check_invariant();
+ buffer.check_invariant();
+}
+
using namespace std::placeholders;
enum class SelectMode
@@ -98,12 +181,12 @@ void select_coord(BufferCoord coord, SelectionList& selections)
}
template<InsertMode mode>
-void insert(Context& context, int)
+void enter_insert_mode(Context& context, int)
{
context.input_handler().insert(mode);
}
-void repeat_insert(Context& context, int)
+void repeat_last_insert(Context& context, int)
{
context.input_handler().repeat_last_insert();
}
@@ -289,11 +372,11 @@ void replace_with_char(Context& context, int)
on_next_key_with_autoinfo(context, [](Key key, Context& context) {
if (not isprint(key.key))
return;
- Editor& editor = context.editor();
- SelectionList sels = context.selections();
- auto restore_sels = on_scope_end([&]{ context.selections() = std::move(sels); });
- select_all_matches(context.buffer(), context.selections(), Regex{"."});
- editor.insert(codepoint_to_str(key.key), InsertMode::Replace);
+ ScopedEdition edition(context);
+ Buffer& buffer = context.buffer();
+ SelectionList selections = context.selections();
+ select_all_matches(buffer, selections, Regex{"."});
+ insert<InsertMode::Replace>(buffer, selections, codepoint_to_str(key.key));
}, "replace with char", "enter char to replace with\n");
}
@@ -309,6 +392,7 @@ Codepoint swap_case(Codepoint cp)
template<Codepoint (*func)(Codepoint)>
void for_each_char(Context& context, int)
{
+ ScopedEdition edition(context);
Editor& editor = context.editor();
std::vector<String> sels = editor.selections_content();
for (auto& sel : sels)
@@ -316,7 +400,7 @@ void for_each_char(Context& context, int)
for (auto& c : sel)
c = func(c);
}
- editor.insert(sels, InsertMode::Replace);
+ insert<InsertMode::Replace>(context.buffer(), context.selections(), sels);
}
void command(Context& context, int)
@@ -350,11 +434,12 @@ void pipe(Context& context, int)
if (real_cmd.empty())
return;
- Editor& editor = context.editor();
+ Buffer& buffer = context.buffer();
+ SelectionList& selections = context.selections();
std::vector<String> strings;
- for (auto& sel : context.selections())
+ for (auto& sel : selections)
{
- auto str = content(context.buffer(), sel);
+ auto str = content(buffer, sel);
bool insert_eol = str.back() != '\n';
if (insert_eol)
str += '\n';
@@ -364,7 +449,8 @@ void pipe(Context& context, int)
str = str.substr(0, str.length()-1);
strings.push_back(str);
}
- editor.insert(strings, InsertMode::Replace);
+ ScopedEdition edition(context);
+ insert<InsertMode::Replace>(buffer, selections, strings);
});
}
@@ -505,43 +591,43 @@ void cat_yank(Context& context, int)
void erase_selections(Context& context, int)
{
RegisterManager::instance()['"'] = context.editor().selections_content();
- context.editor().erase();
+ ScopedEdition edition(context);
+ erase(context.buffer(), context.selections());
}
void change(Context& context, int param)
{
RegisterManager::instance()['"'] = context.editor().selections_content();
- insert<InsertMode::Replace>(context, param);
+ enter_insert_mode<InsertMode::Replace>(context, param);
}
-static InsertMode adapt_for_linewise(InsertMode mode)
+constexpr InsertMode adapt_for_linewise(InsertMode mode)
{
- if (mode == InsertMode::Append)
- return InsertMode::InsertAtNextLineBegin;
- if (mode == InsertMode::Insert)
- return InsertMode::InsertAtLineBegin;
- if (mode == InsertMode::Replace)
- return InsertMode::Replace;
-
- kak_assert(false);
- return InsertMode::Insert;
+ return ((mode == InsertMode::Append) ?
+ InsertMode::InsertAtNextLineBegin :
+ ((mode == InsertMode::Insert) ?
+ InsertMode::InsertAtLineBegin :
+ ((mode == InsertMode::Replace) ?
+ InsertMode::Replace : InsertMode::Insert)));
}
-template<InsertMode insert_mode>
+template<InsertMode mode>
void paste(Context& context, int)
{
- Editor& editor = context.editor();
auto strings = RegisterManager::instance()['"'].values(context);
- InsertMode mode = insert_mode;
+ bool linewise = false;
for (auto& str : strings)
{
if (not str.empty() and str.back() == '\n')
{
- mode = adapt_for_linewise(mode);
+ linewise = true;
break;
}
}
- editor.insert(strings, mode);
+ if (linewise)
+ insert<adapt_for_linewise(mode)>(context.buffer(), context.selections(), strings);
+ else
+ insert<mode>(context.buffer(), context.selections(), strings);
}
template<typename T>
@@ -619,17 +705,17 @@ void join_select_spaces(Context& context, int)
{
select(select_whole_lines)(context, 0);
select<SelectMode::Extend>(select_to_eol)(context, 0);
- auto& editor = context.editor();
auto& buffer = context.buffer();
auto& selections = context.selections();
- select_all_matches(buffer, context.selections(), Regex{"(\n\\h*)+"});
+ select_all_matches(buffer, selections, Regex{"(\n\\h*)+"});
// remove last end of line if selected
kak_assert(std::is_sorted(selections.begin(), selections.end(),
[](const Selection& lhs, const Selection& rhs)
{ return lhs.min() < rhs.min(); }));
if (not selections.empty() and selections.back().max() == buffer.back_coord())
selections.pop_back();
- editor.insert(" ", InsertMode::Replace);
+ ScopedEdition edition(context);
+ insert<InsertMode::Replace>(buffer, selections, " ");
}
void join(Context& context, int param)
@@ -666,21 +752,18 @@ void indent(Context& context, int)
CharCount indent_width = context.options()["indentwidth"].get<int>();
String indent = indent_width == 0 ? "\t" : String{' ', indent_width};
- auto& editor = context.editor();
auto& buffer = context.buffer();
- DynamicSelectionList sels{context.buffer(), context.selections()};
- auto restore_sels = on_scope_end([&]{ context.selections() = std::move(sels); });
- SelectionList res;
+ SelectionList sels;
for (auto& sel : context.selections())
{
for (auto line = sel.min().line; line < sel.max().line+1; ++line)
{
if (indent_empty or buffer[line].length() > 1)
- res.emplace_back(line, line);
+ sels.emplace_back(line, line);
}
}
- context.selections() = std::move(res);
- editor.insert(indent, InsertMode::Insert);
+ ScopedEdition edition(context);
+ insert<InsertMode::Insert>(buffer, sels, indent);
}
template<bool deindent_incomplete = true>
@@ -691,12 +774,8 @@ void deindent(Context& context, int)
if (indent_width == 0)
indent_width = tabstop;
- auto& editor = context.editor();
auto& buffer = context.buffer();
- DynamicSelectionList sels{context.buffer(), context.selections()};
- auto restore_sels = on_scope_end([&]{ context.selections() = std::move(sels); });
-
- SelectionList res;
+ SelectionList sels;
for (auto& sel : context.selections())
{
for (auto line = sel.min().line; line < sel.max().line+1; ++line)
@@ -713,19 +792,19 @@ void deindent(Context& context, int)
else
{
if (deindent_incomplete and width != 0)
- res.emplace_back(line, BufferCoord{line, column-1});
+ sels.emplace_back(line, BufferCoord{line, column-1});
break;
}
if (width == indent_width)
{
- res.emplace_back(line, BufferCoord{line, column});
+ sels.emplace_back(line, BufferCoord{line, column});
break;
}
}
}
}
- context.selections() = std::move(res);
- editor.erase();
+ ScopedEdition edition(context);
+ erase(context.buffer(), sels);
}
template<ObjectFlags flags, SelectMode mode = SelectMode::Replace>
@@ -827,8 +906,9 @@ void rotate_selections_content(Context& context, int count)
auto strings = editor.selections_content();
count = count % strings.size();
std::rotate(strings.begin(), strings.end()-count, strings.end());
- editor.insert(strings, InsertMode::Replace);
context.selections().rotate_main(count);
+ ScopedEdition edition(context);
+ insert<InsertMode::Replace>(context.buffer(), context.selections(), strings);
}
enum class SelectFlags
@@ -885,7 +965,7 @@ void replay_macro(Context& context, int count)
auto stop = on_scope_end([&]{ running_macros.erase(key.key); });
auto keys = parse_keys(reg_val[0]);
- scoped_edition edition(context.editor());
+ ScopedEdition edition(context);
do { exec_keys(keys, context); } while (--count > 0);
}
}
@@ -983,7 +1063,6 @@ void align(Context& context, int)
void align_indent(Context& context, int selection)
{
- auto& editor = context.editor();
auto& buffer = context.buffer();
auto& selections = context.selections();
std::vector<LineCount> lines;
@@ -1003,7 +1082,7 @@ void align_indent(Context& context, int selection)
++it;
const String indent{line.begin(), it};
- scoped_edition edition{editor};
+ ScopedEdition edition{context};
for (auto& l : lines)
{
auto& line = buffer[l];
@@ -1023,7 +1102,7 @@ public:
void operator() (Context& context, int count)
{
- scoped_edition edition(context.editor());
+ ScopedEdition edition(context);
do { m_func(context, 0); } while(--count > 0);
}
private:
@@ -1076,12 +1155,12 @@ KeyMap keymap =
{ 'd', erase_selections },
{ 'c', change },
- { 'i', insert<InsertMode::Insert> },
- { 'I', insert<InsertMode::InsertAtLineBegin> },
- { 'a', insert<InsertMode::Append> },
- { 'A', insert<InsertMode::AppendAtLineEnd> },
- { 'o', insert<InsertMode::OpenLineBelow> },
- { 'O', insert<InsertMode::OpenLineAbove> },
+ { 'i', enter_insert_mode<InsertMode::Insert> },
+ { 'I', enter_insert_mode<InsertMode::InsertAtLineBegin> },
+ { 'a', enter_insert_mode<InsertMode::Append> },
+ { 'A', enter_insert_mode<InsertMode::AppendAtLineEnd> },
+ { 'o', enter_insert_mode<InsertMode::OpenLineBelow> },
+ { 'O', enter_insert_mode<InsertMode::OpenLineAbove> },
{ 'r', replace_with_char },
{ 'g', goto_commands<SelectMode::Replace> },
@@ -1099,7 +1178,7 @@ KeyMap keymap =
{ 'S', split_regex },
{ alt('s'), split_lines },
- { '.', repeat_insert },
+ { '.', repeat_last_insert },
{ '%', [](Context& context, int) { select_whole_buffer(context.buffer(), context.selections()); } },
diff --git a/src/unit_tests.cc b/src/unit_tests.cc
index d3cda91d..8bd0c5fc 100644
--- a/src/unit_tests.cc
+++ b/src/unit_tests.cc
@@ -68,30 +68,6 @@ void test_undo_group_optimizer()
kak_assert(lines[i] == buffer[LineCount((int)i)]);
}
-void test_editor()
-{
- using namespace std::placeholders;
- Buffer buffer("test", Buffer::Flags::None, { "test\n", "\n", "youpi\n" });
- Editor editor(buffer);
-
- {
- scoped_edition edition{editor};
- select_whole_buffer(buffer, editor.selections());
- select_all_matches(buffer, editor.selections(), Regex{"\\n\\h*"});
- for (auto& sel : editor.selections())
- {
- kak_assert(buffer.byte_at(sel.min()) == '\n');
- erase(buffer, sel);
- }
- }
- editor.undo();
-
- Selection sel{ 2_line, buffer.back_coord() };
- editor.selections() = SelectionList{sel};
- editor.insert("",InsertMode::Replace);
- kak_assert(not buffer.is_end(editor.selections().main().first()));
-}
-
void test_utf8()
{
String str = "maïs mélange bientôt";
@@ -146,5 +122,4 @@ void run_unit_tests()
test_keys();
test_buffer();
test_undo_group_optimizer();
- test_editor();
}