Remove IncrementalInserter and move it's code to InputModes::Insert

This commit is contained in:
Maxime Coste 2013-10-30 08:46:15 +00:00
parent 3e1bb777ce
commit 3e12507636
4 changed files with 145 additions and 192 deletions

View File

@ -850,7 +850,8 @@ class Insert : public InputMode
public: public:
Insert(Client& client, InsertMode mode) Insert(Client& client, InsertMode mode)
: InputMode(client), : InputMode(client),
m_inserter(context().editor(), mode), m_insert_mode(mode),
m_edition(context().editor()),
m_completer(context()), m_completer(context()),
m_idle_timer{Clock::now() + idle_timeout, m_idle_timer{Clock::now() + idle_timeout,
[this](Timer& timer) { [this](Timer& timer) {
@ -861,6 +862,7 @@ public:
last_insert().first = mode; last_insert().first = mode;
last_insert().second.clear(); last_insert().second.clear();
context().hooks().run_hook("InsertBegin", "", context()); context().hooks().run_hook("InsertBegin", "", context());
prepare(m_insert_mode);
} }
void on_key(Key key) override void on_key(Key key) override
@ -869,7 +871,7 @@ public:
if (m_mode == Mode::InsertReg) if (m_mode == Mode::InsertReg)
{ {
if (key.modifiers == Key::Modifiers::None) if (key.modifiers == Key::Modifiers::None)
m_inserter.insert(RegisterManager::instance()[key.key].values(context())); insert(RegisterManager::instance()[key.key].values(context()));
m_mode = Mode::Default; m_mode = Mode::Default;
return; return;
} }
@ -896,38 +898,35 @@ public:
reset_normal_mode(); reset_normal_mode();
} }
else if (key == Key::Backspace) else if (key == Key::Backspace)
m_inserter.erase(); erase();
else if (key == Key::Left) else if (key == Key::Left)
{ {
m_inserter.move_cursors(-1_char); m_edition.editor().move_selections(-1_char, SelectMode::Replace);
moved = true; moved = true;
} }
else if (key == Key::Right) else if (key == Key::Right)
{ {
m_inserter.move_cursors(1_char); m_edition.editor().move_selections(1_char, SelectMode::Replace);
moved = true; moved = true;
} }
else if (key == Key::Up) else if (key == Key::Up)
{ {
m_inserter.move_cursors(-1_line); m_edition.editor().move_selections(-1_line, SelectMode::Replace);
moved = true; moved = true;
} }
else if (key == Key::Down) else if (key == Key::Down)
{ {
m_inserter.move_cursors(1_line); m_edition.editor().move_selections(1_line, SelectMode::Replace);
moved = true; moved = true;
} }
else if (key.modifiers == Key::Modifiers::None) else if (key.modifiers == Key::Modifiers::None)
{ insert(key.key);
m_inserter.insert(codepoint_to_str(key.key));
context().hooks().run_hook("InsertKey", key_to_str(key), context());
}
else if (key == ctrl('r')) else if (key == ctrl('r'))
m_mode = Mode::InsertReg; m_mode = Mode::InsertReg;
else if ( key == ctrl('m')) else if ( key == ctrl('m'))
m_inserter.insert(String() + '\n'); insert('\n');
else if ( key == ctrl('i')) else if ( key == ctrl('i'))
m_inserter.insert(String() + '\t'); insert('\t');
else if ( key == ctrl('n')) else if ( key == ctrl('n'))
{ {
m_completer.select(1); m_completer.select(1);
@ -957,11 +956,131 @@ public:
KeymapMode keymap_mode() const override { return KeymapMode::Insert; } KeymapMode keymap_mode() const override { return KeymapMode::Insert; }
private: private:
void erase() const
{
auto& buffer = m_edition.editor().buffer();
for (auto& sel : m_edition.editor().selections())
{
if (sel.last() == BufferCoord{0,0})
continue;
auto pos = buffer.iterator_at(sel.last());
buffer.erase(utf8::previous(pos), pos);
}
}
void insert(memoryview<String> strings)
{
auto& buffer = m_edition.editor().buffer();
auto& selections = m_edition.editor().selections();
for (size_t i = 0; i < selections.size(); ++i)
{
size_t index = std::min(i, strings.size()-1);
buffer.insert(buffer.iterator_at(selections[i].last()),
strings[index]);
}
}
void insert(Codepoint key)
{
auto& buffer = m_edition.editor().buffer();
for (auto& sel : m_edition.editor().m_selections)
{
auto content = codepoint_to_str(key);
m_edition.editor().filters()(buffer, sel, content);
buffer.insert(buffer.iterator_at(sel.last()), content);
}
context().hooks().run_hook("InsertKey", codepoint_to_str(key), context());
}
void prepare(InsertMode mode)
{
Editor& editor = m_edition.editor();
Buffer& buffer = editor.buffer();
for (auto& sel : editor.m_selections)
{
BufferCoord first, last;
switch (mode)
{
case InsertMode::Insert:
first = sel.max();
last = sel.min();
break;
case InsertMode::Replace:
first = last = Kakoune::erase(buffer, sel).coord();
break;
case InsertMode::Append:
first = sel.min();
last = sel.max();
// special case for end of lines, append to current line instead
if (last.column != buffer[last.line].length() - 1)
last = buffer.char_next(last);
break;
case InsertMode::OpenLineBelow:
case InsertMode::AppendAtLineEnd:
first = last = BufferCoord{sel.max().line, buffer[sel.max().line].length() - 1};
break;
case InsertMode::OpenLineAbove:
case InsertMode::InsertAtLineBegin:
first = sel.min().line;
if (mode == InsertMode::OpenLineAbove)
first = buffer.char_prev(first);
else
{
auto first_non_blank = buffer.iterator_at(first);
while (*first_non_blank == ' ' or *first_non_blank == '\t')
++first_non_blank;
if (*first_non_blank != '\n')
first = first_non_blank.coord();
}
last = first;
break;
case InsertMode::InsertAtNextLineBegin:
kak_assert(false); // not implemented
break;
}
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;
}
if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
{
insert('\n');
if (mode == InsertMode::OpenLineAbove)
{
for (auto& sel : editor.m_selections)
{
// special case, the --first line above did nothing, so we need to compensate now
if (sel.first() == buffer.char_next({0,0}))
sel.first() = sel.last() = BufferCoord{0,0};
}
}
}
sort_and_merge_overlapping(editor.m_selections, editor.m_main_sel);
editor.check_invariant();
}
void on_replaced() override
{
for (auto& sel : m_edition.editor().m_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);
}
}
enum class Mode { Default, Complete, InsertReg }; enum class Mode { Default, Complete, InsertReg };
Mode m_mode = Mode::Default; Mode m_mode = Mode::Default;
IncrementalInserter m_inserter; InsertMode m_insert_mode;
BufferCompleter m_completer; scoped_edition m_edition;
Timer m_idle_timer; BufferCompleter m_completer;
Timer m_idle_timer;
}; };
} }

View File

@ -20,7 +20,7 @@ Editor::Editor(Buffer& buffer)
m_main_sel = 0; m_main_sel = 0;
} }
static void avoid_eol(const Buffer& buffer, BufferCoord& coord) void avoid_eol(const Buffer& buffer, BufferCoord& coord)
{ {
const auto column = coord.column; const auto column = coord.column;
const auto& line = buffer[coord.line]; const auto& line = buffer[coord.line];
@ -28,7 +28,7 @@ static void avoid_eol(const Buffer& buffer, BufferCoord& coord)
coord.column = line.byte_count_to(line.char_length() - 2); coord.column = line.byte_count_to(line.char_length() - 2);
} }
static void avoid_eol(const Buffer& buffer, Range& sel) void avoid_eol(const Buffer& buffer, Range& sel)
{ {
avoid_eol(buffer, sel.first()); avoid_eol(buffer, sel.first());
avoid_eol(buffer, sel.last()); avoid_eol(buffer, sel.last());
@ -450,130 +450,4 @@ void Editor::end_edition()
--m_edition_level; --m_edition_level;
} }
IncrementalInserter::IncrementalInserter(Editor& editor, InsertMode mode)
: m_editor(editor), m_edition(editor), m_mode(mode)
{
Buffer& buffer = *editor.m_buffer;
for (auto& sel : m_editor.m_selections)
{
BufferCoord first, last;
switch (mode)
{
case InsertMode::Insert:
first = sel.max();
last = sel.min();
break;
case InsertMode::Replace:
first = last = Kakoune::erase(buffer, sel).coord();
break;
case InsertMode::Append:
first = sel.min();
last = sel.max();
// special case for end of lines, append to current line instead
if (last.column != buffer[last.line].length() - 1)
last = buffer.char_next(last);
break;
case InsertMode::OpenLineBelow:
case InsertMode::AppendAtLineEnd:
first = last = BufferCoord{sel.max().line, buffer[sel.max().line].length() - 1};
break;
case InsertMode::OpenLineAbove:
case InsertMode::InsertAtLineBegin:
first = sel.min().line;
if (mode == InsertMode::OpenLineAbove)
first = buffer.char_prev(first);
else
{
auto first_non_blank = buffer.iterator_at(first);
while (*first_non_blank == ' ' or *first_non_blank == '\t')
++first_non_blank;
if (*first_non_blank != '\n')
first = first_non_blank.coord();
}
last = first;
break;
case InsertMode::InsertAtNextLineBegin:
kak_assert(false); // not implemented
break;
}
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;
}
if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
{
insert("\n");
if (mode == InsertMode::OpenLineAbove)
{
for (auto& sel : m_editor.m_selections)
{
// special case, the --first line above did nothing, so we need to compensate now
if (sel.first() == buffer.char_next({0,0}))
sel.first() = sel.last() = BufferCoord{0,0};
}
}
}
sort_and_merge_overlapping(editor.m_selections, editor.m_main_sel);
editor.check_invariant();
}
IncrementalInserter::~IncrementalInserter()
{
for (auto& sel : m_editor.m_selections)
{
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);
}
}
void IncrementalInserter::insert(String content)
{
auto& buffer = m_editor.buffer();
for (auto& sel : m_editor.m_selections)
{
m_editor.filters()(buffer, sel, content);
buffer.insert(buffer.iterator_at(sel.last()), content);
}
}
void IncrementalInserter::insert(memoryview<String> strings)
{
auto& buffer = m_editor.buffer();
for (size_t i = 0; i < m_editor.m_selections.size(); ++i)
{
size_t index = std::min(i, strings.size()-1);
buffer.insert(buffer.iterator_at(m_editor.m_selections[i].last()),
strings[index]);
}
}
void IncrementalInserter::erase()
{
auto& buffer = m_editor.buffer();
for (auto& sel : m_editor.m_selections)
{
if (sel.last() == BufferCoord{0,0})
continue;
auto pos = buffer.iterator_at(sel.last());
buffer.erase(utf8::previous(pos), pos);
}
}
void IncrementalInserter::move_cursors(CharCount move)
{
m_editor.move_selections(move, SelectMode::Replace);
}
void IncrementalInserter::move_cursors(LineCount move)
{
m_editor.move_selections(move, SelectMode::Replace);
}
} }

View File

@ -9,6 +9,8 @@
namespace Kakoune namespace Kakoune
{ {
namespace InputModes { class Insert; }
class Register; class Register;
enum class SelectMode enum class SelectMode
@ -88,6 +90,7 @@ public:
bool is_editing() const { return m_edition_level!= 0; } bool is_editing() const { return m_edition_level!= 0; }
private: private:
friend struct scoped_edition; friend struct scoped_edition;
friend class InputModes::Insert;
void begin_edition(); void begin_edition();
void end_edition(); void end_edition();
@ -98,8 +101,6 @@ private:
void check_invariant() const; void check_invariant() const;
friend class IncrementalInserter;
safe_ptr<Buffer> m_buffer; safe_ptr<Buffer> m_buffer;
DynamicSelectionList m_selections; DynamicSelectionList m_selections;
size_t m_main_sel; size_t m_main_sel;
@ -114,31 +115,15 @@ struct scoped_edition
~scoped_edition() ~scoped_edition()
{ m_editor.end_edition(); } { m_editor.end_edition(); }
Editor& editor() const { return m_editor; }
private: private:
Editor& m_editor; Editor& m_editor;
}; };
// An IncrementalInserter manage insert mode void avoid_eol(const Buffer& buffer, BufferCoord& coord);
class IncrementalInserter void avoid_eol(const Buffer& buffer, Range& sel);
{ void sort_and_merge_overlapping(SelectionList& selections, size_t& main_selection);
public:
IncrementalInserter(Editor& editor, InsertMode mode = InsertMode::Insert);
~IncrementalInserter();
void insert(String content);
void insert(memoryview<String> strings);
void erase();
void move_cursors(CharCount move);
void move_cursors(LineCount move);
Buffer& buffer() const { return m_editor.buffer(); }
Editor& editor() const { return m_editor; }
private:
InsertMode m_mode;
Editor& m_editor;
scoped_edition m_edition;
};
} }

View File

@ -92,30 +92,6 @@ void test_editor()
kak_assert(not buffer.is_end(editor.main_selection().first())); kak_assert(not buffer.is_end(editor.main_selection().first()));
} }
void test_incremental_inserter()
{
Buffer buffer("test", Buffer::Flags::None, { "test\n", "\n", "yoüpi\n", "matin\n" });
Editor editor(buffer);
editor.select({0,0});
{
IncrementalInserter inserter(editor, InsertMode::OpenLineAbove);
kak_assert(editor.is_editing());
kak_assert(editor.selections().size() == 1);
kak_assert(editor.selections().front().first() == BufferCoord{0 COMMA 0});
kak_assert(editor.selections().front().last() == BufferCoord{0 COMMA 0});
kak_assert(*buffer.begin() == L'\n');
}
// check utf-8 erase
editor.select({3,4});
{
IncrementalInserter inserter(editor, InsertMode::Insert);
inserter.erase();
kak_assert(editor.selections().back().last() == BufferCoord{3 COMMA 2});
}
kak_assert(not editor.is_editing());
}
void test_utf8() void test_utf8()
{ {
String str = "maïs mélange bientôt"; String str = "maïs mélange bientôt";
@ -171,5 +147,4 @@ void run_unit_tests()
test_buffer(); test_buffer();
test_undo_group_optimizer(); test_undo_group_optimizer();
test_editor(); test_editor();
test_incremental_inserter();
} }