Adding commands, BeforeEdit AfterEdit
This commit is contained in:
@@ -211,6 +211,8 @@ void MergeSort(int64_t Count, Edit *First, Edit *Temp) {
|
|||||||
void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
|
void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
|
||||||
Scratch scratch((Arena *)buffer->allocator.object);
|
Scratch scratch((Arena *)buffer->allocator.object);
|
||||||
|
|
||||||
|
// Figure out how much we insert and how much we delete so
|
||||||
|
// we can resize buffers properly if necessary
|
||||||
Assert(edits.len);
|
Assert(edits.len);
|
||||||
int64_t size_to_delete = 0;
|
int64_t size_to_delete = 0;
|
||||||
int64_t size_to_insert = 0;
|
int64_t size_to_insert = 0;
|
||||||
@@ -241,6 +243,7 @@ void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
|
|||||||
Array<Edit> edits_copy = edits.copy(scratch);
|
Array<Edit> edits_copy = edits.copy(scratch);
|
||||||
MergeSort(edits.len, edits_copy.data, edits.data);
|
MergeSort(edits.len, edits_copy.data, edits.data);
|
||||||
|
|
||||||
|
// Try resizing the buffers
|
||||||
int64_t len_offset = size_to_insert - size_to_delete;
|
int64_t len_offset = size_to_insert - size_to_delete;
|
||||||
int64_t allocated_size_required = Max((int64_t)0, len_offset);
|
int64_t allocated_size_required = Max((int64_t)0, len_offset);
|
||||||
if (buffer->len + allocated_size_required > buffer->cap) {
|
if (buffer->len + allocated_size_required > buffer->cap) {
|
||||||
@@ -257,6 +260,7 @@ void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
|
|||||||
buffer->cap = new_cap;
|
buffer->cap = new_cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Figure out what we need to write to the second buffer
|
||||||
int srci = buffer->bi;
|
int srci = buffer->bi;
|
||||||
int dsti = (buffer->bi + 1) % 2;
|
int dsti = (buffer->bi + 1) % 2;
|
||||||
|
|
||||||
@@ -293,12 +297,14 @@ void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
|
|||||||
writes.add({dest_range, source_string});
|
writes.add({dest_range, source_string});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure there are no gaps between ranges
|
||||||
#if DEBUG_BUILD
|
#if DEBUG_BUILD
|
||||||
for (int64_t i = 0; i < writes.len - 1; i += 1) {
|
for (int64_t i = 0; i < writes.len - 1; i += 1) {
|
||||||
Assert(writes[i].range.max == writes[i + 1].range.min);
|
Assert(writes[i].range.max == writes[i + 1].range.min);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Write to the second buffer
|
||||||
int64_t new_buffer_len = 0;
|
int64_t new_buffer_len = 0;
|
||||||
For(writes) {
|
For(writes) {
|
||||||
Assert(it.range.min >= 0);
|
Assert(it.range.min >= 0);
|
||||||
|
|||||||
@@ -103,7 +103,26 @@ int64_t MoveUp(Buffer &buffer, int64_t pos) {
|
|||||||
return new_pos;
|
return new_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateCursorsAfterEdit(Window *window, Array<Edit> edits) {
|
void BeforeEdit(Window *window) {
|
||||||
|
// Merge cursors that overlap, this needs to be handled before any edits to
|
||||||
|
// make sure overlapping edits won't happen.
|
||||||
|
for (int64_t cursor_i = 0; cursor_i < window->cursors.len; cursor_i += 1) {
|
||||||
|
Cursor &cursor = window->cursors[cursor_i];
|
||||||
|
IterRemove(window->cursors) {
|
||||||
|
IterRemovePrepare(window->cursors);
|
||||||
|
if (&cursor == &it) continue;
|
||||||
|
|
||||||
|
if (cursor.range.max >= it.range.min && cursor.range.max <= it.range.max) {
|
||||||
|
remove_item = true;
|
||||||
|
cursor.range.max = it.range.max;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AfterEdit(Window *window, Array<Edit> edits) {
|
||||||
|
// First offset all cursors by edits
|
||||||
ForItem(edit, edits) {
|
ForItem(edit, edits) {
|
||||||
int64_t remove_size = GetRangeSize(edit.range);
|
int64_t remove_size = GetRangeSize(edit.range);
|
||||||
int64_t insert_size = edit.string.len;
|
int64_t insert_size = edit.string.len;
|
||||||
@@ -194,7 +213,13 @@ int main() {
|
|||||||
if (IsKeyPressed(KEY_LEFT) || IsKeyPressedRepeat(KEY_LEFT)) {
|
if (IsKeyPressed(KEY_LEFT) || IsKeyPressedRepeat(KEY_LEFT)) {
|
||||||
For(focused_window->cursors) {
|
For(focused_window->cursors) {
|
||||||
if (IsKeyDown(KEY_LEFT_CONTROL)) {
|
if (IsKeyDown(KEY_LEFT_CONTROL)) {
|
||||||
|
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
||||||
|
int64_t front = GetFront(it);
|
||||||
|
front = Seek(focused_window->buffer, front, ITERATE_BACKWARD);
|
||||||
|
it = ChangeFront(it, front);
|
||||||
|
} else {
|
||||||
it.range.max = it.range.min = Seek(focused_window->buffer, it.range.min, ITERATE_BACKWARD);
|
it.range.max = it.range.min = Seek(focused_window->buffer, it.range.min, ITERATE_BACKWARD);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
||||||
int64_t front = GetFront(it);
|
int64_t front = GetFront(it);
|
||||||
@@ -213,7 +238,13 @@ int main() {
|
|||||||
if (IsKeyPressed(KEY_RIGHT) || IsKeyPressedRepeat(KEY_RIGHT)) {
|
if (IsKeyPressed(KEY_RIGHT) || IsKeyPressedRepeat(KEY_RIGHT)) {
|
||||||
For(focused_window->cursors) {
|
For(focused_window->cursors) {
|
||||||
if (IsKeyDown(KEY_LEFT_CONTROL)) {
|
if (IsKeyDown(KEY_LEFT_CONTROL)) {
|
||||||
|
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
||||||
|
int64_t front = GetFront(it);
|
||||||
|
front = Seek(focused_window->buffer, front, ITERATE_FORWARD);
|
||||||
|
it = ChangeFront(it, front);
|
||||||
|
} else {
|
||||||
it.range.max = it.range.min = Seek(focused_window->buffer, it.range.min, ITERATE_FORWARD);
|
it.range.max = it.range.min = Seek(focused_window->buffer, it.range.min, ITERATE_FORWARD);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
||||||
int64_t front = GetFront(it);
|
int64_t front = GetFront(it);
|
||||||
@@ -230,45 +261,75 @@ int main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (IsKeyPressed(KEY_DOWN) || IsKeyPressedRepeat(KEY_DOWN)) {
|
if (IsKeyPressed(KEY_DOWN) || IsKeyPressedRepeat(KEY_DOWN)) {
|
||||||
|
if (IsKeyDown(KEY_LEFT_SHIFT) && IsKeyDown(KEY_LEFT_ALT)) { // Default in VSCode seems to be Ctrl + Alt + down
|
||||||
|
For(focused_window->cursors) {
|
||||||
|
int64_t front = GetFront(it);
|
||||||
|
front = MoveDown(focused_window->buffer, front);
|
||||||
|
focused_window->cursors.add({front, front});
|
||||||
|
}
|
||||||
|
} else if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_LEFT_ALT)) { // Default in VSCode seems to be Shift + Alt + down
|
||||||
|
BeforeEdit(focused_window);
|
||||||
|
Array<Edit> edits = {FrameArena};
|
||||||
|
For(focused_window->cursors) {
|
||||||
|
int64_t front = GetFront(it);
|
||||||
|
Line line = FindLine(focused_window->buffer, front);
|
||||||
|
String string = GetString(focused_window->buffer, {line.range.min, line.range.max + 1});
|
||||||
|
AddEdit(&edits, {line.range.max + 1, line.range.max + 1}, string);
|
||||||
|
}
|
||||||
|
ApplyEdits(&focused_window->buffer, edits);
|
||||||
|
AfterEdit(focused_window, edits);
|
||||||
|
For(focused_window->cursors) {
|
||||||
|
it.range.max = it.range.min = MoveDown(focused_window->buffer, it.range.min);
|
||||||
|
}
|
||||||
|
} else if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
||||||
For(focused_window->cursors) {
|
For(focused_window->cursors) {
|
||||||
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
|
||||||
int64_t front = GetFront(it);
|
int64_t front = GetFront(it);
|
||||||
front = MoveDown(focused_window->buffer, front);
|
front = MoveDown(focused_window->buffer, front);
|
||||||
it = ChangeFront(it, front);
|
it = ChangeFront(it, front);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
For(focused_window->cursors) {
|
||||||
it.range.max = it.range.min = MoveDown(focused_window->buffer, it.range.min);
|
it.range.max = it.range.min = MoveDown(focused_window->buffer, it.range.min);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsKeyPressed(KEY_UP) || IsKeyPressedRepeat(KEY_UP)) {
|
if (IsKeyPressed(KEY_UP) || IsKeyPressedRepeat(KEY_UP)) {
|
||||||
|
if (IsKeyDown(KEY_LEFT_SHIFT) && IsKeyDown(KEY_LEFT_ALT)) { // Default in VSCode seems to be Ctrl + Alt + up
|
||||||
|
For(focused_window->cursors) {
|
||||||
|
int64_t front = GetFront(it);
|
||||||
|
front = MoveUp(focused_window->buffer, front);
|
||||||
|
focused_window->cursors.add({front, front});
|
||||||
|
}
|
||||||
|
} else if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_LEFT_ALT)) { // Default in VSCode seems to be Shift + Alt + up
|
||||||
|
BeforeEdit(focused_window);
|
||||||
|
Array<Edit> edits = {FrameArena};
|
||||||
|
For(focused_window->cursors) {
|
||||||
|
int64_t front = GetFront(it);
|
||||||
|
Line line = FindLine(focused_window->buffer, front);
|
||||||
|
String string = GetString(focused_window->buffer, {line.range.min, line.range.max + 1});
|
||||||
|
AddEdit(&edits, {line.range.min, line.range.min}, string);
|
||||||
|
}
|
||||||
|
ApplyEdits(&focused_window->buffer, edits);
|
||||||
|
AfterEdit(focused_window, edits);
|
||||||
|
For(focused_window->cursors) {
|
||||||
|
it.range.max = it.range.min = MoveUp(focused_window->buffer, it.range.min);
|
||||||
|
}
|
||||||
|
} else if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
||||||
For(focused_window->cursors) {
|
For(focused_window->cursors) {
|
||||||
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
|
||||||
int64_t front = GetFront(it);
|
int64_t front = GetFront(it);
|
||||||
front = MoveUp(focused_window->buffer, front);
|
front = MoveUp(focused_window->buffer, front);
|
||||||
it = ChangeFront(it, front);
|
it = ChangeFront(it, front);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
For(focused_window->cursors) {
|
||||||
it.range.max = it.range.min = MoveUp(focused_window->buffer, it.range.min);
|
it.range.max = it.range.min = MoveUp(focused_window->buffer, it.range.min);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge cursors that overlap, this needs to be handled before any edits to
|
|
||||||
// make sure overlapping edits won't happen.
|
|
||||||
for (int64_t cursor_i = 0; cursor_i < focused_window->cursors.len; cursor_i += 1) {
|
|
||||||
Cursor &cursor = focused_window->cursors[cursor_i];
|
|
||||||
IterRemove(focused_window->cursors) {
|
|
||||||
IterRemovePrepare(focused_window->cursors);
|
|
||||||
if (&cursor == &it) continue;
|
|
||||||
|
|
||||||
if (cursor.range.max >= it.range.min && cursor.range.max <= it.range.max) {
|
|
||||||
remove_item = true;
|
|
||||||
cursor.range.max = it.range.max;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsKeyPressed(KEY_BACKSPACE) || IsKeyPressedRepeat(KEY_BACKSPACE)) {
|
if (IsKeyPressed(KEY_BACKSPACE) || IsKeyPressedRepeat(KEY_BACKSPACE)) {
|
||||||
|
BeforeEdit(focused_window);
|
||||||
Array<Edit> edits = {FrameArena};
|
Array<Edit> edits = {FrameArena};
|
||||||
String string = {};
|
String string = {};
|
||||||
For(focused_window->cursors) {
|
For(focused_window->cursors) {
|
||||||
@@ -276,7 +337,7 @@ int main() {
|
|||||||
AddEdit(&edits, {pos, it.range.min}, string);
|
AddEdit(&edits, {pos, it.range.min}, string);
|
||||||
}
|
}
|
||||||
ApplyEdits(&focused_window->buffer, edits);
|
ApplyEdits(&focused_window->buffer, edits);
|
||||||
UpdateCursorsAfterEdit(focused_window, edits);
|
AfterEdit(focused_window, edits);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle user input
|
// Handle user input
|
||||||
@@ -290,12 +351,13 @@ int main() {
|
|||||||
string = {(char *)utf8.out_str, (int64_t)utf8.len};
|
string = {(char *)utf8.out_str, (int64_t)utf8.len};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BeforeEdit(focused_window);
|
||||||
Array<Edit> edits = {FrameArena};
|
Array<Edit> edits = {FrameArena};
|
||||||
For(focused_window->cursors) {
|
For(focused_window->cursors) {
|
||||||
AddEdit(&edits, it.range, string);
|
AddEdit(&edits, it.range, string);
|
||||||
}
|
}
|
||||||
ApplyEdits(&focused_window->buffer, edits);
|
ApplyEdits(&focused_window->buffer, edits);
|
||||||
UpdateCursorsAfterEdit(focused_window, edits);
|
AfterEdit(focused_window, edits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user