Movement with new semantics fully completed

This commit is contained in:
Krzosa Karol
2024-08-04 07:35:55 +02:00
parent cfad821e8e
commit b68b80f317
4 changed files with 245 additions and 290 deletions

View File

@@ -1,128 +0,0 @@
const int DIR_RIGHT = 0;
const int DIR_LEFT = 1;
const int DIR_DOWN = 2;
const int DIR_UP = 3;
const int DIR_COUNT = 4;
const bool CTRL_PRESSED = true;
Int MoveOnWhitespaceBoundary(Buffer &buffer, Int pos, int direction) {
Assert(direction == DIR_RIGHT || direction == DIR_LEFT);
bool right = direction == DIR_RIGHT;
pos = Clamp(pos, (Int)0, buffer.len);
bool standing_on_whitespace = IsWhitespace(buffer.str[pos]);
bool standing_on_symbol = IsSymbol(buffer.str[pos]);
bool standing_on_word = !standing_on_whitespace && !standing_on_symbol;
bool seek_whitespace = standing_on_whitespace == false;
bool seek_word = standing_on_whitespace || standing_on_symbol;
bool seek_symbol = standing_on_whitespace || standing_on_word;
Int result = right ? buffer.len : 0;
Int delta = right ? 1 : -1;
Int prev_pos = pos;
for (Int i = pos; right ? i < buffer.len : i >= 0; i += delta) {
bool is_whitespace = IsWhitespace(buffer.str[i]);
bool is_symbol = IsSymbol(buffer.str[i]);
bool is_word = !is_whitespace && !is_symbol;
Int res = right ? i : prev_pos;
if (seek_word && is_word) {
result = res;
break;
}
if (seek_whitespace && is_whitespace) {
result = res;
break;
}
if (seek_symbol && is_symbol) {
result = res;
break;
}
prev_pos = i;
}
return result;
}
Int MoveOnWhitespaceBoundaryVertical(Buffer &buffer, Int pos, int direction) {
Assert(direction == DIR_UP || direction == DIR_DOWN);
bool up = direction == DIR_UP;
Int delta = up ? -1 : 1;
Int result = pos;
Int next_line = PosToLine(buffer, pos) + delta;
for (Int line = next_line; up ? line >= 0 : line < buffer.line_starts.len; line += delta) {
Range line_range = GetLineRange(buffer, line);
result = line_range.min;
bool whitespace_line = true;
for (Int i = line_range.min; i < line_range.max; i += 1) {
if (!IsWhitespace(buffer.str[i])) {
whitespace_line = false;
break;
}
}
if (whitespace_line) break;
}
return result;
}
Int MovePos(Buffer &buffer, Int pos, int direction, bool ctrl_pressed = false) {
Assert(direction >= 0 && direction <= 3);
if (ctrl_pressed) {
switch (direction) {
case DIR_RIGHT: return MoveOnWhitespaceBoundary(buffer, pos, direction);
case DIR_LEFT: return MoveOnWhitespaceBoundary(buffer, pos - 1, direction);
case DIR_DOWN: return MoveOnWhitespaceBoundaryVertical(buffer, pos, direction);
case DIR_UP: return MoveOnWhitespaceBoundaryVertical(buffer, pos, direction);
default: return pos;
}
} else {
switch (direction) {
case DIR_RIGHT: return Clamp(pos + 1, (Int)0, buffer.len);
case DIR_LEFT: return Clamp(pos - 1, (Int)0, buffer.len);
case DIR_DOWN: return OffsetByLine(&buffer, pos, 1);
case DIR_UP: return OffsetByLine(&buffer, pos, -1);
default: return pos;
}
}
}
Caret FindInBuffer(Buffer *buffer, String16 needle, Caret caret, bool find_next = false) {
Int pos = caret.range.min;
String16 medium = GetString(*buffer, {pos, INT64_MAX});
Caret result = {};
Int index = 0;
if (Seek(medium, needle, &index)) {
result = MakeCaret(pos + index + needle.len, pos + index);
} else {
medium = GetString(*buffer);
if (Seek(medium, needle, &index)) {
result = MakeCaret(index + needle.len, index);
}
}
if (find_next && AreEqual(result, caret)) {
caret.range.min = Clamp(*buffer, caret.range.min + 1);
caret.range.max = Clamp(*buffer, caret.range.max + 1);
result = FindInBuffer(buffer, needle, caret, false);
}
return result;
}
Array<Range> FindAllInBuffer(Allocator allocator, Buffer *buffer, String16 needle) {
Array<Range> result = {allocator};
String16 string_buffer = GetString(*buffer);
for (Int pos = 0;;) {
Int index = 0;
String16 medium = Skip(string_buffer, pos);
if (!Seek(medium, needle, &index)) {
break;
}
Add(&result, Rng(pos + index, pos + index + needle.len));
pos += needle.len;
}
return result;
}

View File

@@ -39,6 +39,14 @@ struct Event {
const char *text;
};
const int DIR_RIGHT = 0;
const int DIR_LEFT = 1;
const int DIR_DOWN = 2;
const int DIR_UP = 3;
const int DIR_COUNT = 4;
const bool CTRL_PRESSED = true;
bool SHIFT_PRESSED = true;
#define Press(KEY) (event.key == KEY)
#define Ctrl(KEY) (event.key == KEY && event.ctrl)
#define Shift(KEY) (event.key == KEY && event.shift)

View File

@@ -1,3 +1,152 @@
void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = false) {
Assert(direction == DIR_UP || direction == DIR_DOWN);
View &view = *GetActiveView(window);
Buffer *buffer = GetBuffer(view.active_buffer);
Rect2I visible_cells_rect = GetVisibleCells(window);
Int y = GetSize(visible_cells_rect).y - 2;
if (direction == DIR_UP) y = -y;
For(view.carets) {
XY xy = PosToXY(*buffer, GetFront(it));
if (direction == DIR_DOWN && xy.line == buffer->line_starts.len - 1) {
Range line_range = GetLineRange(*buffer, xy.line);
xy.col = line_range.max - line_range.min;
} else if (direction == DIR_UP && xy.line == 0) {
xy.col = 0;
}
xy.line += y;
Int pos = XYToPos(*buffer, xy);
if (shift) {
it = ChangeFront(it, pos);
} else {
it = MakeCaret(pos);
}
}
}
void Command_MoveCursorsToSide(View *view, int direction, bool shift = false) {
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
Buffer *buffer = GetBuffer(view->active_buffer);
For(view->carets) {
Int pos = GetFront(it);
if (direction == DIR_RIGHT) {
pos = GetLineEnd(buffer, pos);
} else {
pos = GetLineStart(buffer, pos);
}
if (shift) {
it = ChangeFront(it, pos);
} else {
it.range.max = it.range.min = pos;
}
}
}
Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool shift = false) {
Int front = GetFront(it);
Int range_size = GetSize(it.range);
switch (direction) {
case DIR_UP: {
if (ctrl && shift) {
Int pos = GetPrevEmptyLineStart(buffer, front);
it = ChangeFront(it, pos);
} else if (ctrl) {
Int pos = GetPrevEmptyLineStart(buffer, it.range.min);
it = MakeCaret(pos);
} else if (shift) {
Int pos = OffsetByLine(buffer, front, -1);
it = ChangeFront(it, pos);
} else {
if (range_size == 0) {
Int pos = OffsetByLine(buffer, it.range.min, -1);
it = MakeCaret(pos);
} else {
it = MakeCaret(it.range.min);
}
}
} break;
case DIR_DOWN: {
if (ctrl && shift) {
Int pos = GetNextEmptyLineStart(buffer, front);
it = ChangeFront(it, pos);
} else if (ctrl) {
Int pos = GetNextEmptyLineStart(buffer, it.range.max);
it = MakeCaret(pos);
} else if (shift) {
Int pos = OffsetByLine(buffer, front, 1);
it = ChangeFront(it, pos);
} else {
if (range_size == 0) {
Int pos = OffsetByLine(buffer, it.range.max, 1);
it = MakeCaret(pos);
} else {
it = MakeCaret(it.range.max);
}
}
} break;
case DIR_LEFT: {
if (ctrl && shift) {
Int pos = GetPrevWordStart(buffer, front);
it = ChangeFront(it, pos);
} else if (ctrl) {
if (range_size != 0 && front != it.range.min) {
it = MakeCaret(it.range.min);
} else {
Int pos = GetPrevWordStart(buffer, it.range.min);
it = MakeCaret(pos);
}
} else if (shift) {
Int pos = GetPrevChar(buffer, front);
it = ChangeFront(it, pos);
} else {
if (range_size == 0) {
Int pos = GetPrevChar(buffer, it.range.min);
it = MakeCaret(pos);
} else {
it = MakeCaret(it.range.min);
}
}
} break;
case DIR_RIGHT: {
if (ctrl && shift) {
Int pos = GetNextWordEnd(buffer, front);
it = ChangeFront(it, pos);
} else if (ctrl) {
if (range_size != 0 && front != it.range.max) {
it = MakeCaret(it.range.max);
} else {
Int pos = GetNextWordEnd(buffer, it.range.max);
it = MakeCaret(pos);
}
} else if (shift) {
Int pos = GetNextChar(buffer, front);
it = ChangeFront(it, pos);
} else {
if (range_size == 0) {
Int pos = GetNextChar(buffer, it.range.max);
it = MakeCaret(pos);
} else {
it = MakeCaret(it.range.max);
}
}
} break;
}
return it;
}
void Command_Move(View *view, int direction, bool ctrl = false, bool shift = false) {
Assert(direction < DIR_COUNT);
Buffer *buffer = GetBuffer(view->active_buffer);
For(view->carets) {
it = MoveCaret(buffer, it, direction, ctrl, shift);
}
}
void Command_Replace(View *view, String16 string) {
Buffer *buffer = GetBuffer(view->active_buffer);
Scratch scratch;
@@ -28,7 +177,7 @@ void Command_DuplicateLine(View *view, int direction) {
ApplyEdits(buffer, edits);
AfterEdit(buffer, &edits, &view->carets);
For(view->carets) it = MakeCaret(MovePos(*buffer, it.range.min, direction, false));
Command_Move(view, direction);
}
Int FindRangeByPos(Array<Range> &ranges, Int pos) {
@@ -177,90 +326,6 @@ void Command_KillSelectedLines(View *view) {
AfterEdit(buffer, &edits, &view->carets, KILL_SELECTION);
}
bool SHIFT_PRESSED = true;
void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = false) {
Assert(direction == DIR_UP || direction == DIR_DOWN);
View &view = *GetActiveView(window);
Buffer *buffer = GetBuffer(view.active_buffer);
Rect2I visible_cells_rect = GetVisibleCells(window);
Int y = GetSize(visible_cells_rect).y - 2;
if (direction == DIR_UP) y = -y;
For(view.carets) {
XY xy = PosToXY(*buffer, GetFront(it));
if (direction == DIR_DOWN && xy.line == buffer->line_starts.len - 1) {
Range line_range = GetLineRange(*buffer, xy.line);
xy.col = line_range.max - line_range.min;
} else if (direction == DIR_UP && xy.line == 0) {
xy.col = 0;
}
xy.line += y;
Int pos = XYToPos(*buffer, xy);
if (shift) {
it = ChangeFront(it, pos);
} else {
it = MakeCaret(pos);
}
}
}
void Command_MoveCursorsToSide(View *view, int direction, bool shift = false) {
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
Buffer *buffer = GetBuffer(view->active_buffer);
For(view->carets) {
Int pos = GetFront(it);
if (direction == DIR_RIGHT) {
pos = GetLineEnd(buffer, pos);
} else {
pos = GetLineStart(buffer, pos);
}
if (shift) {
it = ChangeFront(it, pos);
} else {
it.range.max = it.range.min = pos;
}
}
}
void Command_Move(View *view, int direction, bool ctrl = false, bool shift = false) {
Assert(direction < DIR_COUNT);
Buffer *buffer = GetBuffer(view->active_buffer);
For(view->carets) {
Int front = GetFront(it);
switch (direction) {
case DIR_UP: {
} break;
case DIR_DOWN: {
if (ctrl && shift) {
Int pos = GetNextEmptyLineStart(buffer, front);
it = ChangeFront(it, pos);
} else if (ctrl) {
Int pos = GetNextEmptyLineStart(buffer, it.range.max);
it = MakeCaret(pos);
} else if (shift) {
Int pos = OffsetByLine(buffer, front, 1);
it = ChangeFront(it, pos);
} else {
if (GetSize(it.range) == 0) {
Int pos = OffsetByLine(buffer, it.range.max, 1);
it = MakeCaret(pos);
} else {
it = MakeCaret(it.range.max);
}
}
} break;
case DIR_LEFT: {
} break;
case DIR_RIGHT: {
} break;
}
}
}
void Command_Delete(View *view, int direction, bool ctrl = false) {
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
Scratch scratch;
@@ -271,8 +336,7 @@ void Command_Delete(View *view, int direction, bool ctrl = false) {
// Select things to delete
For(view->carets) {
if (GetSize(it.range)) continue;
Int pos = MovePos(*buffer, it.range.min, direction, ctrl);
it = MakeCaret(pos, it.range.min);
it = MoveCaret(buffer, it, direction, ctrl, SHIFT_PRESSED);
}
MergeCarets(view);
@@ -306,17 +370,20 @@ void Command_CreateCursorVertical(View *_view, int direction) {
View &view = *_view;
Buffer *buffer = GetBuffer(view.active_buffer);
Int line_offset = direction == DIR_UP ? -1 : 1;
Scratch scratch;
Array<Caret> arr = {scratch};
For(view.carets) {
if (PosToLine(*buffer, it.range.min) == PosToLine(*buffer, it.range.max)) {
Int f = MovePos(*buffer, GetFront(it), direction);
Int b = MovePos(*buffer, GetBack(it), direction);
Int f = OffsetByLine(buffer, GetFront(it), line_offset);
Int b = OffsetByLine(buffer, GetBack(it), line_offset);
Add(&arr, MakeCaret(f, b));
} else {
Int pos = direction == DIR_UP ? it.range.min : it.range.max;
Int min = MovePos(*buffer, pos, direction);
Add(&arr, MakeCaret(min));
Int pos = direction == DIR_UP ? it.range.min : it.range.max;
Caret caret = MakeCaret(pos);
caret = MoveCaret(buffer, caret, direction);
Add(&arr, caret);
}
}
For(arr) Add(&view.carets, it);
@@ -391,6 +458,45 @@ void MergeCarets(View *view, Range *mouse_selection_anchor) {
Swap(&view->carets[first_caret_index], &view->carets[0]);
}
Caret FindInBuffer(Buffer *buffer, String16 needle, Caret caret, bool find_next = false) {
Int pos = caret.range.min;
String16 medium = GetString(*buffer, {pos, INT64_MAX});
Caret result = {};
Int index = 0;
if (Seek(medium, needle, &index)) {
result = MakeCaret(pos + index + needle.len, pos + index);
} else {
medium = GetString(*buffer);
if (Seek(medium, needle, &index)) {
result = MakeCaret(index + needle.len, index);
}
}
if (find_next && AreEqual(result, caret)) {
caret.range.min = Clamp(*buffer, caret.range.min + 1);
caret.range.max = Clamp(*buffer, caret.range.max + 1);
result = FindInBuffer(buffer, needle, caret, false);
}
return result;
}
Array<Range> FindAllInBuffer(Allocator allocator, Buffer *buffer, String16 needle) {
Array<Range> result = {allocator};
String16 string_buffer = GetString(*buffer);
for (Int pos = 0;;) {
Int index = 0;
String16 medium = Skip(string_buffer, pos);
if (!Seek(medium, needle, &index)) {
break;
}
Add(&result, Rng(pos + index, pos + index + needle.len));
pos += needle.len;
}
return result;
}
void WindowCommand(Event event, Window *window, View *view) {
ProfileFunction();
Buffer *buffer = GetBuffer(view->active_buffer);
@@ -409,33 +515,6 @@ void WindowCommand(Event event, Window *window, View *view) {
}
}
// Underline
if (event.ctrl) {
Caret caret = view->carets[0];
if (GetSize(caret.range) == 0) {
view->underline_pos[view->underline_count++] = caret.range.min;
Assert(view->underline_count <= 2);
}
{
Vec2I mouse = MouseVec2I();
Vec2I mworld = mouse - window->document_rect.min + view->scroll;
Vec2I pos = mworld / Vec2I{FontCharSpacing, FontLineSpacing};
XY xy = {(Int)(pos.x), (Int)(pos.y)};
Int p = XYToPosErrorOutOfBounds(*buffer, xy);
if (p != -1) {
view->underline_pos[view->underline_count++] = p;
Assert(view->underline_count <= 2);
if (Mouse(LEFT)) {
Range enclose = EncloseLoadWord(buffer, p);
String16 string = GetString(*buffer, enclose);
Open(string);
}
}
}
}
if (CtrlAlt(SDLK_DOWN)) {
Command_DuplicateLine(view, DIR_DOWN);
} else if (AltShift(SDLK_DOWN)) {
@@ -455,63 +534,33 @@ void WindowCommand(Event event, Window *window, View *view) {
} else if (AltShift(SDLK_UP)) {
Command_CreateCursorVertical(view, DIR_UP);
} else if (CtrlShift(SDLK_UP)) {
For(view->carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_UP, CTRL_PRESSED));
Command_Move(view, DIR_UP, CTRL_PRESSED, SHIFT_PRESSED);
} else if (Ctrl(SDLK_UP)) {
For(view->carets) it = MakeCaret(MovePos(*buffer, it.range.min, DIR_UP, CTRL_PRESSED));
Command_Move(view, DIR_UP, CTRL_PRESSED);
} else if (Shift(SDLK_UP)) {
For(view->carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_UP));
Command_Move(view, DIR_UP, false, SHIFT_PRESSED);
} else if (Press(SDLK_UP)) {
For(view->carets) {
if (GetSize(it.range) == 0) {
it = MakeCaret(MovePos(*buffer, it.range.min, DIR_UP));
} else {
it = MakeCaret(it.range.min);
}
}
Command_Move(view, DIR_UP);
}
if (CtrlShift(SDLK_LEFT)) {
For(view->carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_LEFT, true));
Command_Move(view, DIR_LEFT, CTRL_PRESSED, SHIFT_PRESSED);
} else if (Ctrl(SDLK_LEFT)) {
For(view->carets) {
if (GetSize(it.range) != 0 && GetFront(it) != it.range.min) {
it = MakeCaret(it.range.min);
} else {
it = MakeCaret(MovePos(*buffer, it.range.min, DIR_LEFT, true));
}
}
Command_Move(view, DIR_LEFT, CTRL_PRESSED);
} else if (Shift(SDLK_LEFT)) {
For(view->carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_LEFT, false));
Command_Move(view, DIR_LEFT, false, SHIFT_PRESSED);
} else if (Press(SDLK_LEFT)) {
For(view->carets) {
if (GetSize(it.range) == 0) {
it = MakeCaret(MovePos(*buffer, it.range.min, DIR_LEFT, false));
} else {
it = MakeCaret(it.range.min);
}
}
Command_Move(view, DIR_LEFT);
}
if (CtrlShift(SDLK_RIGHT)) {
For(view->carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_RIGHT, true));
Command_Move(view, DIR_RIGHT, CTRL_PRESSED, SHIFT_PRESSED);
} else if (Ctrl(SDLK_RIGHT)) {
For(view->carets) {
if (GetSize(it.range) != 0 && GetFront(it) != it.range.max) {
it = MakeCaret(it.range.max);
} else {
it = MakeCaret(MovePos(*buffer, it.range.max, DIR_RIGHT, true));
}
}
Command_Move(view, DIR_RIGHT, CTRL_PRESSED);
} else if (Shift(SDLK_RIGHT)) {
For(view->carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_RIGHT, false));
Command_Move(view, DIR_RIGHT, false, SHIFT_PRESSED);
} else if (Press(SDLK_RIGHT)) {
For(view->carets) {
if (GetSize(it.range) == 0) {
it = MakeCaret(MovePos(*buffer, it.range.max, DIR_RIGHT, false));
} else {
it = MakeCaret(it.range.max);
}
}
Command_Move(view, DIR_RIGHT);
}
if (CtrlShift(SDLK_Z)) {
@@ -718,6 +767,33 @@ void WindowCommand(Event event, Window *window, View *view) {
}
}
// Underline
if (event.ctrl) {
Caret caret = view->carets[0];
if (GetSize(caret.range) == 0) {
view->underline_pos[view->underline_count++] = caret.range.min;
Assert(view->underline_count <= 2);
}
{
Vec2I mouse = MouseVec2I();
Vec2I mworld = mouse - window->document_rect.min + view->scroll;
Vec2I pos = mworld / Vec2I{FontCharSpacing, FontLineSpacing};
XY xy = {(Int)(pos.x), (Int)(pos.y)};
Int p = XYToPosErrorOutOfBounds(*buffer, xy);
if (p != -1) {
view->underline_pos[view->underline_count++] = p;
Assert(view->underline_count <= 2);
if (Mouse(LEFT)) {
Range enclose = EncloseLoadWord(buffer, p);
String16 string = GetString(*buffer, enclose);
Open(string);
}
}
}
}
{
Vec2I mouse = MouseVec2I();

View File

@@ -26,7 +26,6 @@ int FullScreenPositionX, FullScreenPositionY;
#include "buffer_helpers.cpp"
#include "buffer.cpp"
#include "buffer_multi_cursor.cpp"
#include "buffer_ops.cpp"
#include "buffer_history.cpp"
#include "buffer_fuzzy_search.cpp"
#include "buffer_test_load.cpp"