Improving basic commands

This commit is contained in:
krzosa
2025-05-02 12:02:13 +02:00
parent fd8a319b18
commit d7908bee54
9 changed files with 126 additions and 90 deletions

View File

@@ -249,6 +249,14 @@ String16 Copy16(Allocator allocator, char16_t *string) {
return Copy(allocator, s); return Copy(allocator, s);
} }
String16 Concat(Allocator allocator, String16 a, String16 b) {
char16_t *str = AllocArray(allocator, char16_t, a.len + b.len + 1);
MemoryCopy(str, a.data, a.len * 2);
MemoryCopy(str + a.len, b.data, b.len * 2);
str[a.len + b.len] = 0;
return {str, a.len + b.len};
}
void NormalizePathInPlace(String16 s) { void NormalizePathInPlace(String16 s) {
for (int64_t i = 0; i < s.len; i++) { for (int64_t i = 0; i < s.len; i++) {
if (s.data[i] == u'\\') if (s.data[i] == u'\\')
@@ -304,3 +312,4 @@ String16 SkipWhitespace(String16 *string) {
} }
return begin; return begin;
} }

View File

@@ -404,10 +404,10 @@ Int GetFullLineStart(Buffer *buffer, Int pos) {
return range.min; return range.min;
} }
Int GetFullLineEnd(Buffer *buffer, Int pos) { Int GetFullLineEnd(Buffer *buffer, Int pos, Int *eof = NULL) {
pos = Clamp(pos, (Int)0, buffer->len); pos = Clamp(pos, (Int)0, buffer->len);
Int line = PosToLine(buffer, pos); Int line = PosToLine(buffer, pos);
Range range = GetLineRange(buffer, line); Range range = GetLineRange(buffer, line, eof);
return range.max; return range.max;
} }
@@ -1018,14 +1018,6 @@ void UndoEdit(Buffer *buffer, Array<Caret> *carets) {
Dealloc(&entry.edits); Dealloc(&entry.edits);
} }
void RawApplyEdits(Buffer *buffer, Array<Edit> &edits) {
ProfileFunction();
Assert(buffer->edit_phase == 1);
buffer->edit_phase += 1;
SaveHistoryBeforeApplyEdits(buffer, &buffer->undo_stack, edits);
ApplyEditsMultiCursor(buffer, edits);
}
void DeallocHistoryEntries(Array<HistoryEntry> *entries) { void DeallocHistoryEntries(Array<HistoryEntry> *entries) {
For(*entries) { For(*entries) {
Dealloc(&it.carets); Dealloc(&it.carets);
@@ -1093,7 +1085,19 @@ void AdjustCarets(Array<Edit> edits, Array<Caret> *carets) {
void EndEdit(Buffer *buffer, Array<Edit> *edits, Array<Caret> *carets, bool kill_selection) { void EndEdit(Buffer *buffer, Array<Edit> *edits, Array<Caret> *carets, bool kill_selection) {
ProfileFunction(); ProfileFunction();
RawApplyEdits(buffer, *edits);
{
Assert(buffer->edit_phase == 1);
buffer->edit_phase += 1;
if (edits->len) {
SaveHistoryBeforeApplyEdits(buffer, &buffer->undo_stack, *edits);
ApplyEditsMultiCursor(buffer, *edits);
} else {
HistoryEntry entry = Pop(&buffer->undo_stack);
Dealloc(&entry.carets);
Assert(entry.edits.len == 0);
}
}
Assert(buffer->edit_phase == 2); Assert(buffer->edit_phase == 2);
buffer->edit_phase -= 2; buffer->edit_phase -= 2;

View File

@@ -52,7 +52,7 @@ enum {
void SaveCaretHistoryBeforeBeginEdit(Buffer *buffer, Array<Caret> &carets); void SaveCaretHistoryBeforeBeginEdit(Buffer *buffer, Array<Caret> &carets);
Array<Edit> BeginEdit(Allocator allocator, Buffer *buffer, Array<Caret> &carets); Array<Edit> BeginEdit(Allocator allocator, Buffer *buffer, Array<Caret> &carets);
void EndEdit(Buffer *buffer, Array<Edit> *edits, Array<Caret> *carets, bool kill_selection = true); void EndEdit(Buffer *buffer, Array<Edit> *edits, Array<Caret> *carets, bool kill_selection);
void AddEdit(Array<Edit> *e, Range range, String16 string); void AddEdit(Array<Edit> *e, Range range, String16 string);
// Merge carets that overlap, this needs to be handled before any edits to // Merge carets that overlap, this needs to be handled before any edits to

View File

@@ -234,6 +234,8 @@ void ReportWarningf(const char *fmt, ...) {
void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = false) { void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = false) {
Assert(direction == DIR_UP || direction == DIR_DOWN); Assert(direction == DIR_UP || direction == DIR_DOWN);
BSet set = GetBSet(window); BSet set = GetBSet(window);
CheckpointBeforeGoto(window);
Rect2I visible_cells_rect = GetVisibleCells(window); Rect2I visible_cells_rect = GetVisibleCells(window);
Int y = GetSize(visible_cells_rect).y - 2; Int y = GetSize(visible_cells_rect).y - 2;
@@ -388,6 +390,7 @@ void Command_MoveLine(View *view, int direction) {
Assert(direction == DIR_DOWN || direction == DIR_UP); Assert(direction == DIR_DOWN || direction == DIR_UP);
Scratch scratch; Scratch scratch;
// @todo: this doesn't work well at the end of buffer
struct XYPair { struct XYPair {
XY front; XY front;
XY back; XY back;
@@ -398,26 +401,36 @@ void Command_MoveLine(View *view, int direction) {
MergeCarets(buffer, &view->carets); MergeCarets(buffer, &view->carets);
Array<XYPair> saved_xy = {scratch}; Array<XYPair> saved_xy = {scratch};
For(view->carets) { For(view->carets) {
Add(&saved_xy, {PosToXY(buffer, GetFront(it)), PosToXY(buffer, GetBack(it))}); Int eof_current = 0;
Range lines_to_move_range = {GetFullLineStart(buffer, it.range.min), GetFullLineEnd(buffer, it.range.max)}; Range lines_to_move_range = {GetFullLineStart(buffer, it.range.min), GetFullLineEnd(buffer, it.range.max, &eof_current)};
if (lines_to_move_range.min == 0 && direction == DIR_UP) {
continue;
}
Int eof = 0;
Int next_line_start = lines_to_move_range.max;
Int next_line_end = GetFullLineEnd(buffer, next_line_start, &eof);
Int prev_line_end = lines_to_move_range.min - 1;
Int prev_line_start = GetFullLineStart(buffer, prev_line_end);
if (direction == DIR_DOWN && eof) {
continue;
} else if (direction == DIR_UP && eof_current) {
continue;
}
String16 string = Copy(scratch, GetString(buffer, lines_to_move_range));
String16 string = GetString(buffer, lines_to_move_range);
string = Copy(scratch, string);
AddEdit(&edits, lines_to_move_range, {}); AddEdit(&edits, lines_to_move_range, {});
// @todo: GetPrevLine, GetNextLine, GetNextFull
// GetPrevLineStart, GetNextLineEnd
if (direction == DIR_DOWN) { if (direction == DIR_DOWN) {
Int next_line_start = lines_to_move_range.max;
Int next_line_end = GetFullLineEnd(buffer, next_line_start);
AddEdit(&edits, Rng(next_line_end), string); AddEdit(&edits, Rng(next_line_end), string);
} else { } else {
Int prev_line_end = lines_to_move_range.min - 1;
Int prev_line_start = GetFullLineStart(buffer, prev_line_end);
AddEdit(&edits, Rng(prev_line_start), string); AddEdit(&edits, Rng(prev_line_start), string);
} }
Add(&saved_xy, {PosToXY(buffer, GetFront(it)), PosToXY(buffer, GetBack(it))});
} }
EndEdit(buffer, &edits, &view->carets); EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
Int line_offset = direction == DIR_UP ? -1 : +1; Int line_offset = direction == DIR_UP ? -1 : +1;
for (Int i = 0; i < saved_xy.len; i += 1) { for (Int i = 0; i < saved_xy.len; i += 1) {
@@ -437,7 +450,7 @@ Array<Edit> Command_ReplaceEx(Allocator scratch, View *view, String16 string) {
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets); Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
MergeCarets(buffer, &view->carets); MergeCarets(buffer, &view->carets);
For(view->carets) AddEdit(&edits, it.range, string); For(view->carets) AddEdit(&edits, it.range, string);
EndEdit(buffer, &edits, &view->carets); EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
return edits; return edits;
} }
@@ -452,20 +465,37 @@ void Command_DuplicateLine(View *view, int direction) {
Buffer *buffer = GetBuffer(view->active_buffer); Buffer *buffer = GetBuffer(view->active_buffer);
BeginEdit(scratch, buffer, view->carets); BeginEdit(scratch, buffer, view->carets);
For(view->carets) it = MakeCaret(GetFront(it));
MergeCarets(buffer, &view->carets); MergeCarets(buffer, &view->carets);
Array<Edit> edits = {scratch}; Array<Edit> edits = {scratch};
For(view->carets) { For(view->carets) {
Int line = PosToLine(buffer, it.range.min); Int eof = 0;
Range range = GetLineRange(buffer, line); Range range = {};
range.max = GetFullLineEnd(buffer, it.range.max, &eof);
range.min = GetFullLineStart(buffer, it.range.min);
range.min -= Clamp(eof, (Int)0, buffer->len);
String16 string = Copy(scratch, GetString(buffer, range)); String16 string = Copy(scratch, GetString(buffer, range));
Int pos = direction == DIR_UP ? range.min : range.max;
Int pos = direction == DIR_UP ? range.min : range.max;
AddEdit(&edits, Rng(pos), string); AddEdit(&edits, Rng(pos), string);
} }
EndEdit(buffer, &edits, &view->carets); EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
Command_Move(view, direction); Int coef = direction == DIR_UP ? -1 : 1;
for (Int i = 0; i < edits.len; i += 1) {
Edit *edit = edits.data + i;
Caret *caret = view->carets.data + i;
XY xymin = PosToXY(buffer, caret->range.min);
XY xymax = PosToXY(buffer, caret->range.max);
Int line_count = xymax.line - xymin.line + 1;
xymin.line += coef * line_count;
xymax.line += coef * line_count;
caret->range.min = XYToPos(buffer, xymin);
caret->range.max = XYToPos(buffer, xymax);
}
} }
Array<Range> GetSelectedLinesSorted(Allocator allocator, View *view) { Array<Range> GetSelectedLinesSorted(Allocator allocator, View *view) {
@@ -618,28 +648,15 @@ void SaveBuffer(View *view) {
void Command_KillSelectedLines(View *view) { void Command_KillSelectedLines(View *view) {
Scratch scratch; Scratch scratch;
Buffer *buffer = GetBuffer(view->active_buffer); Buffer *buffer = GetBuffer(view->active_buffer);
SaveCaretHistoryBeforeBeginEdit(buffer, view->carets);
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets); For (view->carets) {
MergeCarets(buffer, &view->carets); Int eof = 0;
it.range.max = GetFullLineEnd(buffer, it.range.max, &eof);
Array<Range> lines = GetSelectedLinesSorted(scratch, view); it.range.min = GetFullLineStart(buffer, it.range.min);
For(lines) { it.range.min -= Clamp(eof, (Int)0, buffer->len);
Range add_range = GetLineRange(buffer, it.min);
for (Int i = it.min + 1; i < it.max; i += 1) {
Range line_range = GetLineRange(buffer, i);
add_range.max = Max(line_range.max, add_range.max);
}
AddEdit(&edits, add_range, u"");
} }
Command_Replace(view, u"");
For(view->carets) {
Int line = PosToLine(buffer, it.range.min);
Range range = GetLineRange(buffer, line);
it.range.min = it.range.max = range.min;
}
EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
} }
void Command_Delete(View *view, int direction, bool ctrl = false) { void Command_Delete(View *view, int direction, bool ctrl = false) {
@@ -675,7 +692,7 @@ void Command_Delete(View *view, int direction, bool ctrl = false) {
MergeCarets(buffer, &view->carets); MergeCarets(buffer, &view->carets);
For(view->carets) AddEdit(&edits, it.range, {}); For(view->carets) AddEdit(&edits, it.range, {});
EndEdit(buffer, &edits, &view->carets); EndEdit(buffer, &edits, &view->carets, true);
} }
void Command_SelectAll(View *view, String16 needle) { void Command_SelectAll(View *view, String16 needle) {
@@ -782,7 +799,7 @@ void Command_IdentedNewLine(View *view) {
String16 string16 = ToString16(scratch, string); String16 string16 = ToString16(scratch, string);
AddEdit(&edits, it.range, string16); AddEdit(&edits, it.range, string16);
} }
EndEdit(buffer, &edits, &view->carets); EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
} }
void Command_Find(View *seek_view, String16 needle, bool forward = true) { void Command_Find(View *seek_view, String16 needle, bool forward = true) {

View File

@@ -219,9 +219,11 @@ void OnCommand(Event event) {
Assert(DocumentSelected.id == -1); Assert(DocumentSelected.id == -1);
BSet active = GetActiveSet(); BSet active = GetActiveSet();
bool mouse_in_document = CheckCollisionPointRec(mouse, active.window->document_rect); bool mouse_in_document = CheckCollisionPointRec(mouse, active.window->document_rect);
bool mouse_in_line_numbers = CheckCollisionPointRec(mouse, active.window->line_numbers_rect); bool mouse_in_line_numbers = CheckCollisionPointRec(mouse, active.window->line_numbers_rect);
if (mouse_in_document || mouse_in_line_numbers) { if (mouse_in_document || mouse_in_line_numbers) {
CheckpointBeforeGoto(active.window);
DocumentSelected = active.window->id; DocumentSelected = active.window->id;
Int p = ScreenSpaceToBufferPos(active.window, active.view, active.buffer, mouse); Int p = ScreenSpaceToBufferPos(active.window, active.view, active.buffer, mouse);
@@ -511,12 +513,7 @@ void OnCommand(Event event) {
} }
if (CtrlPress(SDLK_PERIOD)) { if (CtrlPress(SDLK_PERIOD)) {
String string = main.buffer->name; Command_Open(ChopLastSlash(main.buffer->name));
String right_part = CutLastSlash(&string);
if (StartsWith(right_part, "/+")) {
CutLastSlash(&string);
}
Command_Open(string);
} }
if (CtrlPress(SDLK_T)) { if (CtrlPress(SDLK_T)) {
@@ -528,19 +525,7 @@ void OnCommand(Event event) {
} }
if (CtrlShiftPress(SDLK_Q)) { if (CtrlPress(SDLK_Q)) {
Scratch scratch;
Caret caret = active.view->carets[0];
Range range = caret.range;
if (GetSize(caret.range) == 0) range = EncloseLoadWord(active.buffer, GetFront(caret));
String16 string = NormalizePath(scratch, GetString(active.buffer, range));
String16 right_part = CutLastSlash(&string);
if (right_part.len > 1 && right_part.data[1] == u'+') {
CutLastSlash(&string);
}
Command_Open(string);
} else if (CtrlPress(SDLK_Q)) {
Caret caret = active.view->carets[0]; Caret caret = active.view->carets[0];
Range range = caret.range; Range range = caret.range;
if (GetSize(caret.range) == 0) range = EncloseLoadWord(active.buffer, GetFront(caret)); if (GetSize(caret.range) == 0) range = EncloseLoadWord(active.buffer, GetFront(caret));

View File

@@ -66,7 +66,7 @@ void Command_Paste(View *view) {
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets); Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
MergeCarets(buffer, &view->carets); MergeCarets(buffer, &view->carets);
For(view->carets) AddEdit(&edits, it.range, string); For(view->carets) AddEdit(&edits, it.range, string);
EndEdit(buffer, &edits, &view->carets); EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
return; return;
} }
@@ -78,5 +78,5 @@ void Command_Paste(View *view) {
Caret &it = view->carets[i]; Caret &it = view->carets[i];
AddEdit(&edits, it.range, string); AddEdit(&edits, it.range, string);
} }
EndEdit(buffer, &edits, &view->carets); EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
} }

View File

@@ -51,22 +51,27 @@ View *Command_ExecHidden(String buffer_name, String cmd, String working_dir) {
// ActiveWindow = set.window->id; // ActiveWindow = set.window->id;
// } // }
void Command_Exec(String cmd, String working_dir) { BSet Command_BeginConsoleJump() {
BSet main = GetActiveMainSet(); BSet main = GetActiveMainSet();
CheckpointBeforeGoto(main.window); CheckpointBeforeGoto(main.window);
main.buffer = GetBuffer(NullBufferID);
main.view = WindowOpenBufferView(main.window, main.buffer->name);
return main;
}
Buffer *buffer = GetBuffer(NullBufferID); void Command_EndConsoleJump(BSet main) {
View *view = WindowOpenBufferView(main.window, buffer->name); Int pos = XYToPos(main.buffer, {0, main.buffer->line_starts.len - 1});
Exec(view->id, true, cmd, working_dir); main.view->carets[0] = MakeCaret(pos);
Int pos = XYToPos(buffer, {0, buffer->line_starts.len - 1});
view->carets[0] = MakeCaret(pos);
UpdateScroll(main.window, true); UpdateScroll(main.window, true);
main.window->active_view = view->id;
ActiveWindow = main.window->id; ActiveWindow = main.window->id;
} }
void Command_Exec(String cmd, String working_dir) {
BSet set = Command_BeginConsoleJump();
Exec(set.view->id, true, cmd, working_dir);
Command_EndConsoleJump(set);
}
void Command_Open(String path) { void Command_Open(String path) {
Scratch scratch; Scratch scratch;
@@ -88,12 +93,21 @@ void Command_Open(String path) {
String col_string = FieldString(LuaState, "col"); String col_string = FieldString(LuaState, "col");
Int col = strtoll(col_string.data, NULL, 10); Int col = strtoll(col_string.data, NULL, 10);
CheckpointBeforeGoto(main.window); if (IsDir(file_path)) {
View *view = WindowOpenBufferView(main.window, file_path); BSet set = Command_BeginConsoleJump();
Buffer *buffer = GetBuffer(view->active_buffer); Command_Appendf(set.view, "%.*s..\n", FmtString(file_path));
if (line != -1 && col != -1) { for (FileIter it = IterateFiles(scratch, file_path); IsValid(it); Advance(&it)) {
Int pos = XYToPos(buffer, {col - 1, line - 1}); Command_Appendf(set.view, "%.*s\n", FmtString(it.absolute_path));
view->carets[0] = MakeCaret(pos); }
Command_EndConsoleJump(set);
} else {
CheckpointBeforeGoto(main.window);
View *view = WindowOpenBufferView(main.window, file_path);
Buffer *buffer = GetBuffer(view->active_buffer);
if (line != -1 && col != -1) {
Int pos = XYToPos(buffer, {col - 1, line - 1});
view->carets[0] = MakeCaret(pos);
}
} }
UpdateScroll(main.window, true); UpdateScroll(main.window, true);
ActiveWindow = main.window->id; ActiveWindow = main.window->id;

View File

@@ -255,6 +255,10 @@ String Command_GetDir() {
} }
Int ConvertUTF8ToUTF16UnixLine(String string, char16_t *buffer, Int buffer_cap) { Int ConvertUTF8ToUTF16UnixLine(String string, char16_t *buffer, Int buffer_cap) {
if (string.len == 0) {
return 0;
}
Int buffer_len = 0; Int buffer_len = 0;
Assert(buffer_cap > string.len * 2); Assert(buffer_cap > string.len * 2);
for (Int i = 0; i < string.len;) { for (Int i = 0; i < string.len;) {

View File

@@ -96,6 +96,9 @@ void Command_Append(View *view, String string, bool scroll_to_end_if_curs
Array<Edit> Command_ReplaceEx(Allocator scratch, View *view, String16 string); Array<Edit> Command_ReplaceEx(Allocator scratch, View *view, String16 string);
void Command_ReplaceWithoutMovingCarets(View *view, Range range, String16 string); void Command_ReplaceWithoutMovingCarets(View *view, Range range, String16 string);
void Command_Copy(View *view);
void Command_Paste(View *view);
void ReportConsolef(const char *fmt, ...); void ReportConsolef(const char *fmt, ...);
void ReportErrorf(const char *fmt, ...); void ReportErrorf(const char *fmt, ...);
void ReportWarningf(const char *fmt, ...); void ReportWarningf(const char *fmt, ...);