Fix the line moving, really hard code ...
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
#define BUFFER_DEBUG 0
|
#define BUFFER_DEBUG DEBUG_BUILD
|
||||||
|
|
||||||
API Range MakeRange(Int a, Int b) {
|
API Range MakeRange(Int a, Int b) {
|
||||||
Range result = {Min(a, b), Max(a, b)};
|
Range result = {Min(a, b), Max(a, b)};
|
||||||
@@ -669,6 +669,9 @@ void UpdateLines(Buffer *buffer, Range range, String16 string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RawValidateLineStarts(Buffer *buffer) {
|
void RawValidateLineStarts(Buffer *buffer) {
|
||||||
|
if (buffer->no_line_starts) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Int line = 0;
|
Int line = 0;
|
||||||
for (Int i = 0; i < buffer->len; i += 1) {
|
for (Int i = 0; i < buffer->len; i += 1) {
|
||||||
Int l = PosToLine(buffer, i);
|
Int l = PosToLine(buffer, i);
|
||||||
@@ -795,7 +798,9 @@ void MergeSort(int64_t Count, T *First, T *Temp) {
|
|||||||
API void ApplyEditsMultiCursor(Buffer *buffer, Array<Edit> edits) {
|
API void ApplyEditsMultiCursor(Buffer *buffer, Array<Edit> edits) {
|
||||||
ProfileFunction();
|
ProfileFunction();
|
||||||
#if BUFFER_DEBUG
|
#if BUFFER_DEBUG
|
||||||
|
if (buffer->no_line_starts == false) {
|
||||||
Assert(buffer->line_starts.len);
|
Assert(buffer->line_starts.len);
|
||||||
|
}
|
||||||
Assert(edits.len);
|
Assert(edits.len);
|
||||||
For(edits) {
|
For(edits) {
|
||||||
Assert(it.range.min >= 0);
|
Assert(it.range.min >= 0);
|
||||||
@@ -1038,7 +1043,9 @@ API void AdjustCarets(Array<Edit> edits, Array<Caret> *carets) {
|
|||||||
for (Int i = 0; i < carets->len; i += 1) carets->data[i] = new_carets[i];
|
for (Int i = 0; i < carets->len; i += 1) carets->data[i] = new_carets[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
API void EndEdit(Buffer *buffer, Array<Edit> *edits, Array<Caret> *carets, bool kill_selection) {
|
constexpr bool EndEdit_KillSelection = true;
|
||||||
|
constexpr bool EndEdit_SkipFixingCaretsIWantToDoThatMyself = true;
|
||||||
|
API void EndEdit(Buffer *buffer, Array<Edit> *edits, Array<Caret> *carets, bool kill_selection, bool skip_fixing_carets_user_will_do_that_himself = false) {
|
||||||
ProfileFunction();
|
ProfileFunction();
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1068,6 +1075,7 @@ API void EndEdit(Buffer *buffer, Array<Edit> *edits, Array<Caret> *carets, bool
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (skip_fixing_carets_user_will_do_that_himself == false) {
|
||||||
// Adjust carets
|
// Adjust carets
|
||||||
// this one also moves the carets forward if they are aligned with edit
|
// this one also moves the carets forward if they are aligned with edit
|
||||||
//
|
//
|
||||||
@@ -1105,6 +1113,7 @@ API void EndEdit(Buffer *buffer, Array<Edit> *edits, Array<Caret> *carets, bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
// make sure overlapping edits won't happen.
|
// make sure overlapping edits won't happen.
|
||||||
@@ -1322,7 +1331,7 @@ void RunBufferTest() {
|
|||||||
AddEdit(&edits, {0, 7}, u"t");
|
AddEdit(&edits, {0, 7}, u"t");
|
||||||
AddEdit(&edits, {8, 9}, u"T");
|
AddEdit(&edits, {8, 9}, u"T");
|
||||||
AddEdit(&edits, GetBufferEndAsRange(&buffer), u"\nnewThing");
|
AddEdit(&edits, GetBufferEndAsRange(&buffer), u"\nnewThing");
|
||||||
EndEdit(&buffer, &edits, &carets, KILL_SELECTION);
|
EndEdit(&buffer, &edits, &carets, EndEdit_KillSelection);
|
||||||
String16 s = GetString(&buffer);
|
String16 s = GetString(&buffer);
|
||||||
Assert(s == u"t\nThings\nnewThing");
|
Assert(s == u"t\nThings\nnewThing");
|
||||||
DeinitBuffer(&buffer);
|
DeinitBuffer(&buffer);
|
||||||
@@ -1346,7 +1355,7 @@ void RunBufferTest() {
|
|||||||
AddEdit(&edits, {0, 7}, u"t");
|
AddEdit(&edits, {0, 7}, u"t");
|
||||||
AddEdit(&edits, {8, 9}, u"T");
|
AddEdit(&edits, {8, 9}, u"T");
|
||||||
AddEdit(&edits, GetBufferEndAsRange(&buffer), u"\nnewThing");
|
AddEdit(&edits, GetBufferEndAsRange(&buffer), u"\nnewThing");
|
||||||
EndEdit(&buffer, &edits, &carets, KILL_SELECTION);
|
EndEdit(&buffer, &edits, &carets, EndEdit_KillSelection);
|
||||||
String16 s = GetString(&buffer);
|
String16 s = GetString(&buffer);
|
||||||
Assert(s == u"t\nThings\nnewThing");
|
Assert(s == u"t\nThings\nnewThing");
|
||||||
Assert(buffer.line_starts.len == 0);
|
Assert(buffer.line_starts.len == 0);
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ void TrimWhitespace(Buffer *buffer, bool trim_lines_with_caret) {
|
|||||||
|
|
||||||
Array<Range> lines_to_skip_triming = {};
|
Array<Range> lines_to_skip_triming = {};
|
||||||
if (!trim_lines_with_caret) {
|
if (!trim_lines_with_caret) {
|
||||||
lines_to_skip_triming = GetSelectedLinesSorted(scratch, view);
|
lines_to_skip_triming = GetSelectedLinesSortedExclusive(scratch, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Int i = 0; i < buffer->line_starts.len; i += 1) {
|
for (Int i = 0; i < buffer->line_starts.len; i += 1) {
|
||||||
@@ -160,7 +160,7 @@ void TrimWhitespace(Buffer *buffer, bool trim_lines_with_caret) {
|
|||||||
AddEdit(&edits, whitespace_range, u"");
|
AddEdit(&edits, whitespace_range, u"");
|
||||||
}
|
}
|
||||||
|
|
||||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
EndEdit(buffer, &edits, &view->carets, !EndEdit_KillSelection);
|
||||||
view->update_scroll = false;
|
view->update_scroll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ void CMD_FormatSelection() {
|
|||||||
String16 string16 = {exec_result.buffer->str, exec_result.buffer->len};
|
String16 string16 = {exec_result.buffer->str, exec_result.buffer->len};
|
||||||
AddEdit(&edits, it.range, string16);
|
AddEdit(&edits, it.range, string16);
|
||||||
}
|
}
|
||||||
EndEdit(primary.buffer, &edits, &primary.view->carets, KILL_SELECTION);
|
EndEdit(primary.buffer, &edits, &primary.view->carets, EndEdit_KillSelection);
|
||||||
} RegisterCommand(CMD_FormatSelection, "", "");
|
} RegisterCommand(CMD_FormatSelection, "", "");
|
||||||
|
|
||||||
void CMD_KillProcess() {
|
void CMD_KillProcess() {
|
||||||
@@ -218,12 +218,14 @@ void CMD_KillProcess() {
|
|||||||
void CMD_MakeFontLarger() {
|
void CMD_MakeFontLarger() {
|
||||||
FontSize += 1;
|
FontSize += 1;
|
||||||
ReloadFont(PathToFont, (U32)FontSize);
|
ReloadFont(PathToFont, (U32)FontSize);
|
||||||
|
CMD_CenterView();
|
||||||
} RegisterCommand(CMD_MakeFontLarger, "ctrl-equals", "Increase the font size");
|
} RegisterCommand(CMD_MakeFontLarger, "ctrl-equals", "Increase the font size");
|
||||||
|
|
||||||
void CMD_MakeFontSmaller() {
|
void CMD_MakeFontSmaller() {
|
||||||
if (FontSize > 4) {
|
if (FontSize > 4) {
|
||||||
FontSize -= 1;
|
FontSize -= 1;
|
||||||
ReloadFont(PathToFont, (U32)FontSize);
|
ReloadFont(PathToFont, (U32)FontSize);
|
||||||
|
CMD_CenterView();
|
||||||
}
|
}
|
||||||
} RegisterCommand(CMD_MakeFontSmaller, "ctrl-minus", "Decrease the font size");
|
} RegisterCommand(CMD_MakeFontSmaller, "ctrl-minus", "Decrease the font size");
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ void ClipboardPaste(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, KILL_SELECTION);
|
EndEdit(buffer, &edits, &view->carets, EndEdit_KillSelection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ void ClipboardPaste(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, KILL_SELECTION);
|
EndEdit(buffer, &edits, &view->carets, EndEdit_KillSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMD_Paste() {
|
void CMD_Paste() {
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ bool SearchCaseSensitive = false;
|
|||||||
bool SearchWordBoundary = false;
|
bool SearchWordBoundary = false;
|
||||||
bool BreakOnError = false;
|
bool BreakOnError = false;
|
||||||
Int ErrorCount;
|
Int ErrorCount;
|
||||||
|
// String16 InitialScratchContent;
|
||||||
|
String16 InitialScratchContent = uR"==(0
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6)==";
|
||||||
|
|
||||||
Allocator SysAllocator = {SystemAllocatorProc};
|
Allocator SysAllocator = {SystemAllocatorProc};
|
||||||
String ConfigDir;
|
String ConfigDir;
|
||||||
@@ -32,6 +40,7 @@ Array<Buffer *> Buffers;
|
|||||||
View *LogView;
|
View *LogView;
|
||||||
Buffer *LogBuffer;
|
Buffer *LogBuffer;
|
||||||
|
|
||||||
|
// Replace with ref to null buffer?
|
||||||
BufferID NullBufferID;
|
BufferID NullBufferID;
|
||||||
ViewID NullViewID;
|
ViewID NullViewID;
|
||||||
WindowID NullWindowID;
|
WindowID NullWindowID;
|
||||||
|
|||||||
@@ -963,6 +963,9 @@ int main(int argc, char **argv)
|
|||||||
View *null_view = CreateView(null_buffer->id);
|
View *null_view = CreateView(null_buffer->id);
|
||||||
null_view->special = true;
|
null_view->special = true;
|
||||||
Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID);
|
Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID);
|
||||||
|
if (InitialScratchContent.len) {
|
||||||
|
RawAppend(null_buffer, InitialScratchContent);
|
||||||
|
}
|
||||||
|
|
||||||
Buffer *logs_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(ProjectDirectory, "logs", ""));
|
Buffer *logs_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(ProjectDirectory, "logs", ""));
|
||||||
logs_buffer->special = true;
|
logs_buffer->special = true;
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ struct ViewID { Int id; View *o; };
|
|||||||
struct WindowID { Int id; Window *o; };
|
struct WindowID { Int id; Window *o; };
|
||||||
union Range { struct { Int min; Int max; }; Int e[2]; };
|
union Range { struct { Int min; Int max; }; Int e[2]; };
|
||||||
struct Caret { union { Range range; Int pos[2]; }; Int ifront;};
|
struct Caret { union { Range range; Int pos[2]; }; Int ifront;};
|
||||||
struct XY { Int col; Int line; };
|
union XY {
|
||||||
|
struct {Int col; Int line;};
|
||||||
|
struct {Int x; Int y; };
|
||||||
|
};
|
||||||
typedef void Function();
|
typedef void Function();
|
||||||
|
|
||||||
struct FunctionData {
|
struct FunctionData {
|
||||||
@@ -314,7 +317,6 @@ constexpr int DIR_UP = 3;
|
|||||||
constexpr int DIR_COUNT = 4;
|
constexpr int DIR_COUNT = 4;
|
||||||
constexpr bool CTRL_PRESSED = true;
|
constexpr bool CTRL_PRESSED = true;
|
||||||
constexpr bool SHIFT_PRESS = true;
|
constexpr bool SHIFT_PRESS = true;
|
||||||
constexpr bool KILL_SELECTION = true;
|
|
||||||
constexpr Int LAST_LINE = INT64_MAX;
|
constexpr Int LAST_LINE = INT64_MAX;
|
||||||
|
|
||||||
BSet GetBSet(struct Window *window);
|
BSet GetBSet(struct Window *window);
|
||||||
|
|||||||
@@ -172,6 +172,34 @@ String GetIndentString8(Allocator allocator, Int indent_size) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Array<Range> GetSelectedLinesSortedExclusive(Allocator allocator, View *view) {
|
||||||
|
Scratch scratch(allocator);
|
||||||
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
|
Array<Caret> caret_copy = TightCopy(scratch, view->carets);
|
||||||
|
Array<Caret> temp = TightCopy(scratch, view->carets);
|
||||||
|
if (view->carets.len > 1) MergeSort(view->carets.len, caret_copy.data, temp.data);
|
||||||
|
|
||||||
|
Array<Range> result = {allocator};
|
||||||
|
For(caret_copy) {
|
||||||
|
Int min_line = PosToLine(buffer, it.range.min);
|
||||||
|
Int max_line = PosToLine(buffer, it.range.max);
|
||||||
|
Range line_range = {min_line, max_line + 1};
|
||||||
|
|
||||||
|
if (result.len == 0) {
|
||||||
|
Add(&result, line_range);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Range *last = GetLast(result);
|
||||||
|
if (AreOverlapping(*last, line_range)) {
|
||||||
|
last->max = Max(last->max, line_range.max);
|
||||||
|
} else {
|
||||||
|
Add(&result, line_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void IndentedNewLine(View *view) {
|
void IndentedNewLine(View *view) {
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
@@ -185,7 +213,7 @@ void IndentedNewLine(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, KILL_SELECTION);
|
EndEdit(buffer, &edits, &view->carets, EndEdit_KillSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARNING: Don't use in user facing stuff
|
// WARNING: Don't use in user facing stuff
|
||||||
@@ -399,52 +427,90 @@ void MoveCarets(View *view, int direction, bool ctrl = false, bool shift = false
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MoveCaretsLine(View *view, int direction) {
|
void MoveCaretsLine(View *view, int direction) {
|
||||||
|
// This is so hard...
|
||||||
|
// It's because of the corner cases in the implementation, would be nice to simplify this somehow
|
||||||
|
// but don't know how. The multiple carets constraints + not every line ends with new line make it into
|
||||||
|
// really tricky code.
|
||||||
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 {
|
|
||||||
XY front;
|
|
||||||
XY back;
|
|
||||||
};
|
|
||||||
|
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
|
||||||
MergeCarets(buffer, &view->carets);
|
|
||||||
|
// Save caret positions to fix them at end to the expected incremented by one positions
|
||||||
|
struct XYPair { XY front; XY back; };
|
||||||
Array<XYPair> saved_xy = {scratch};
|
Array<XYPair> saved_xy = {scratch};
|
||||||
For (view->carets) {
|
For (view->carets) {
|
||||||
Int eof_current = 0;
|
|
||||||
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 = Copy16(scratch, GetString(buffer, lines_to_move_range));
|
|
||||||
|
|
||||||
AddEdit(&edits, lines_to_move_range, {});
|
|
||||||
if (direction == DIR_DOWN) {
|
|
||||||
AddEdit(&edits, MakeRange(next_line_end), string);
|
|
||||||
} else {
|
|
||||||
AddEdit(&edits, MakeRange(prev_line_start), string);
|
|
||||||
}
|
|
||||||
|
|
||||||
Add(&saved_xy, {PosToXY(buffer, GetFront(it)), PosToXY(buffer, GetBack(it))});
|
Add(&saved_xy, {PosToXY(buffer, GetFront(it)), PosToXY(buffer, GetBack(it))});
|
||||||
}
|
}
|
||||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
|
||||||
|
|
||||||
Int line_offset = direction == DIR_UP ? -1 : +1;
|
Int line_offset = direction == DIR_UP ? -1 : +1;
|
||||||
|
int side_idx = direction == DIR_UP ? 0 : 1;
|
||||||
|
|
||||||
|
Array<Range> line_ranges = GetSelectedLinesSortedExclusive(scratch, view); // This is <min_line, max_line> not positions
|
||||||
|
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||||
|
MergeCarets(buffer, &view->carets);
|
||||||
|
ForItem (_lines, line_ranges) {
|
||||||
|
Range lines = {_lines.min, _lines.max - 1}; // inclusive
|
||||||
|
Int swap_line = lines.e[side_idx] + line_offset;
|
||||||
|
|
||||||
|
Range total_range = {};
|
||||||
|
{
|
||||||
|
Int total_min_line = 0;
|
||||||
|
Int total_max_line = 0;
|
||||||
|
if (direction == DIR_UP) {
|
||||||
|
total_min_line = swap_line;
|
||||||
|
total_max_line = lines.max;
|
||||||
|
if (total_min_line < 0) {
|
||||||
|
edits.len = 0;
|
||||||
|
saved_xy.len = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
total_min_line = lines.min;
|
||||||
|
total_max_line = swap_line;
|
||||||
|
if (total_max_line >= buffer->line_starts.len) {
|
||||||
|
edits.len = 0;
|
||||||
|
saved_xy.len = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Range arange = GetLineRange(buffer, total_min_line);
|
||||||
|
Range brange = GetLineRange(buffer, total_max_line);
|
||||||
|
total_range = {arange.min, brange.max};
|
||||||
|
}
|
||||||
|
|
||||||
|
String16 replacement_string = {};
|
||||||
|
{
|
||||||
|
Range selected_range_min = GetLineRange(buffer, lines.min);
|
||||||
|
Range selected_range_max = GetLineRange(buffer, lines.max);
|
||||||
|
Range swap_line_range = GetLineRange(buffer, swap_line);
|
||||||
|
String16 selected_string = GetString(buffer, {selected_range_min.min, selected_range_max.max});
|
||||||
|
String16 swap_string = GetString(buffer, swap_line_range);
|
||||||
|
if (direction == DIR_UP) {
|
||||||
|
bool ends_with_new_line = selected_string.len == 0 || (selected_string.len && selected_string[selected_string.len - 1] == u'\n');
|
||||||
|
bool doesnt_end_with_new_line_special_case = !ends_with_new_line;
|
||||||
|
if (doesnt_end_with_new_line_special_case) {
|
||||||
|
if (swap_string.len) swap_string.len -= 1;
|
||||||
|
selected_string = Concat(scratch, selected_string, u"\n");
|
||||||
|
}
|
||||||
|
replacement_string = Concat(scratch, selected_string, swap_string);
|
||||||
|
} else {
|
||||||
|
bool ends_with_new_line = swap_string.len == 0 || (swap_string.len && swap_string[swap_string.len - 1] == u'\n');
|
||||||
|
bool doesnt_end_with_new_line_special_case = !ends_with_new_line;
|
||||||
|
if (doesnt_end_with_new_line_special_case) {
|
||||||
|
if (selected_string.len) selected_string.len -= 1;
|
||||||
|
swap_string = Concat(scratch, swap_string, u"\n");
|
||||||
|
}
|
||||||
|
replacement_string = Concat(scratch, swap_string, selected_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddEdit(&edits, total_range, replacement_string);
|
||||||
|
}
|
||||||
|
EndEdit(buffer, &edits, &view->carets, EndEdit_KillSelection, EndEdit_SkipFixingCaretsIWantToDoThatMyself);
|
||||||
|
|
||||||
for (Int i = 0; i < saved_xy.len; i += 1) {
|
for (Int i = 0; i < saved_xy.len; i += 1) {
|
||||||
Caret &caret = view->carets[i];
|
Caret &caret = view->carets[i];
|
||||||
XYPair &xypair = saved_xy[i];
|
XYPair &xypair = saved_xy[i];
|
||||||
@@ -452,9 +518,10 @@ void MoveCaretsLine(View *view, int direction) {
|
|||||||
xypair.back.line += line_offset;
|
xypair.back.line += line_offset;
|
||||||
Int front = XYToPos(buffer, xypair.front);
|
Int front = XYToPos(buffer, xypair.front);
|
||||||
Int back = XYToPos(buffer, xypair.back);
|
Int back = XYToPos(buffer, xypair.back);
|
||||||
|
|
||||||
caret = MakeCaret(front, back);
|
caret = MakeCaret(front, back);
|
||||||
}
|
}
|
||||||
|
MergeCarets(buffer, &view->carets);
|
||||||
|
IF_DEBUG(AssertRanges(view->carets));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateCursorVertical(View *view, int direction) {
|
void CreateCursorVertical(View *view, int direction) {
|
||||||
@@ -514,7 +581,7 @@ void 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, true);
|
EndEdit(buffer, &edits, &view->carets, EndEdit_KillSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncloseSpace(View *view) {
|
void EncloseSpace(View *view) {
|
||||||
@@ -525,34 +592,6 @@ void EncloseSpace(View *view) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Array<Range> GetSelectedLinesSorted(Allocator allocator, View *view) {
|
|
||||||
Scratch scratch(allocator);
|
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
|
||||||
Array<Caret> caret_copy = TightCopy(scratch, view->carets);
|
|
||||||
Array<Caret> temp = TightCopy(scratch, view->carets);
|
|
||||||
if (view->carets.len > 1) MergeSort(view->carets.len, caret_copy.data, temp.data);
|
|
||||||
|
|
||||||
Array<Range> result = {allocator};
|
|
||||||
For(caret_copy) {
|
|
||||||
Int min_line = PosToLine(buffer, it.range.min);
|
|
||||||
Int max_line = PosToLine(buffer, it.range.max);
|
|
||||||
Range line_range = {min_line, max_line + 1};
|
|
||||||
|
|
||||||
if (result.len == 0) {
|
|
||||||
Add(&result, line_range);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Range *last = GetLast(result);
|
|
||||||
if (AreOverlapping(*last, line_range)) {
|
|
||||||
last->max = Max(last->max, line_range.max);
|
|
||||||
} else {
|
|
||||||
Add(&result, line_range);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IndentSelectedLines(View *view, bool shift = false) {
|
void IndentSelectedLines(View *view, bool shift = false) {
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
@@ -562,7 +601,7 @@ void IndentSelectedLines(View *view, bool shift = false) {
|
|||||||
|
|
||||||
char16_t indent_char = GetIndentChar();
|
char16_t indent_char = GetIndentChar();
|
||||||
String16 indent_string = GetIndentString(scratch, IndentSize);
|
String16 indent_string = GetIndentString(scratch, IndentSize);
|
||||||
Array<Range> line_ranges_to_indent = GetSelectedLinesSorted(scratch, view);
|
Array<Range> line_ranges_to_indent = GetSelectedLinesSortedExclusive(scratch, view);
|
||||||
For(line_ranges_to_indent) {
|
For(line_ranges_to_indent) {
|
||||||
for (Int i = it.min; i < it.max; i += 1) {
|
for (Int i = it.min; i < it.max; i += 1) {
|
||||||
Range pos_range_of_line = GetLineRange(buffer, i);
|
Range pos_range_of_line = GetLineRange(buffer, i);
|
||||||
@@ -580,7 +619,7 @@ void IndentSelectedLines(View *view, bool shift = false) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
EndEdit(buffer, &edits, &view->carets, !EndEdit_KillSelection);
|
||||||
view->update_scroll = false;
|
view->update_scroll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,7 +656,7 @@ Array<Edit> ReplaceEx(Allocator scratch, View *view, String16 string) {
|
|||||||
For(view->carets) {
|
For(view->carets) {
|
||||||
AddEdit(&edits, it.range, string);
|
AddEdit(&edits, it.range, string);
|
||||||
}
|
}
|
||||||
EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
|
EndEdit(buffer, &edits, &view->carets, EndEdit_KillSelection);
|
||||||
return edits;
|
return edits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,8 +685,9 @@ void DuplicateLine(View *view, int direction) {
|
|||||||
Int pos = direction == DIR_UP ? range.min : range.max;
|
Int pos = direction == DIR_UP ? range.min : range.max;
|
||||||
AddEdit(&edits, MakeRange(pos), string);
|
AddEdit(&edits, MakeRange(pos), string);
|
||||||
}
|
}
|
||||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
EndEdit(buffer, &edits, &view->carets, !EndEdit_KillSelection);
|
||||||
|
|
||||||
|
// Move carets now in the duplicate direction
|
||||||
Int coef = direction == DIR_UP ? -1 : 1;
|
Int coef = direction == DIR_UP ? -1 : 1;
|
||||||
for (Int i = 0; i < edits.len; i += 1) {
|
for (Int i = 0; i < edits.len; i += 1) {
|
||||||
Caret *caret = view->carets.data + i;
|
Caret *caret = view->carets.data + i;
|
||||||
|
|||||||
Reference in New Issue
Block a user