Insert: Do not move end of line on open line (o/O)

Change the logic of open line commands so that if a selection lies
on the end of line character of the line from which we open a new
line, that selection does not move.

If we have two clients, A and B, with B's cursor on the eol character
of line L, and A hits `o` while on line L, B's cursor should stay
on the same (logical) line. Previous behaviour would make B's cursor
jump on the newly inserted line.
This commit is contained in:
Maxime Coste 2018-03-04 10:28:35 +11:00
parent 850f561096
commit 2fd42fe5fc
11 changed files with 50 additions and 27 deletions

View File

@ -1314,19 +1314,6 @@ private:
SelectionList& selections = context().selections();
Buffer& buffer = context().buffer();
auto duplicate_selections = [](SelectionList& sels, int count) {
count = count > 0 ? count : 1;
Vector<Selection> new_sels;
new_sels.reserve(count * sels.size());
for (auto& sel : sels)
for (int i = 0; i < count; ++i)
new_sels.push_back(sel);
size_t new_main = sels.main_index() * count + count - 1;
sels = SelectionList{sels.buffer(), std::move(new_sels)};
sels.set_main_index(new_main);
};
switch (mode)
{
case InsertMode::Insert:
@ -1351,22 +1338,41 @@ private:
sel.set({sel.max().line, buffer[sel.max().line].length() - 1});
break;
case InsertMode::OpenLineBelow:
for (auto& sel : selections)
sel.set({sel.max().line, buffer[sel.max().line].length() - 1});
duplicate_selections(selections, count);
insert('\n');
break;
case InsertMode::OpenLineAbove:
for (auto& sel : selections)
sel.set({sel.min().line});
duplicate_selections(selections, count);
// Do not use insert method here as we need to fixup selection
// before running the InsertChar hook.
selections.insert("\n"_str, InsertMode::InsertCursor);
for (auto& sel : selections) // fixup selection positions
sel.set({sel.cursor().line - 1});
{
Vector<Selection> new_sels;
count = count > 0 ? count : 1;
LineCount inserted_count = 0;
for (auto sel : selections)
{
buffer.insert(sel.max().line + inserted_count + 1,
String{'\n', CharCount{count}});
for (int i = 0; i < count; ++i)
new_sels.push_back({sel.max().line + inserted_count + i + 1});
inserted_count += count;
}
selections.set(std::move(new_sels),
selections.main_index() * count + count - 1);
context().hooks().run_hook("InsertChar", "\n", context());
break;
}
case InsertMode::OpenLineAbove:
{
Vector<Selection> new_sels;
count = count > 0 ? count : 1;
LineCount inserted_count = 0;
for (auto sel : selections)
{
buffer.insert(sel.min().line + inserted_count,
String{'\n', CharCount{count}});
for (int i = 0; i < count; ++i)
new_sels.push_back({sel.max().line + inserted_count + i});
inserted_count += count;
}
selections.set(std::move(new_sels),
selections.main_index() * count + count - 1);
context().hooks().run_hook("InsertChar", "\n", context());
break;
}
case InsertMode::InsertAtLineBegin:
for (auto& sel : selections)
{

View File

@ -0,0 +1 @@
3Obar<esc>

View File

@ -0,0 +1 @@
foo

View File

@ -0,0 +1,4 @@
bar
bar
bar
foo

View File

@ -0,0 +1 @@
3obar<esc>

View File

@ -0,0 +1 @@
foo

View File

@ -0,0 +1,4 @@
foo
bar
bar
bar

View File

@ -0,0 +1 @@
x;:exec -draft o<ret>

View File

@ -0,0 +1 @@
foo

View File

@ -0,0 +1,2 @@
foo

View File

@ -0,0 +1 @@
1.4,1.4