buffer_ops.cpp unify MoveOnWhitespaceBoundary
This commit is contained in:
154
src/text_editor/buffer_ops.cpp
Normal file
154
src/text_editor/buffer_ops.cpp
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
const int DIR_RIGHT = 0;
|
||||||
|
const int DIR_LEFT = 1;
|
||||||
|
const int DIR_DOWN = 2;
|
||||||
|
const int DIR_UP = 3;
|
||||||
|
|
||||||
|
const bool CTRL_PRESSED = true;
|
||||||
|
|
||||||
|
Int MoveOnWhitespaceBoundary(Buffer &buffer, Int pos, int direction) {
|
||||||
|
Assert(direction == DIR_RIGHT || direction == DIR_LEFT);
|
||||||
|
|
||||||
|
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 = direction == DIR_RIGHT ? buffer.len : 0;
|
||||||
|
Int delta = direction == DIR_RIGHT ? 1 : -1;
|
||||||
|
Int prev_pos = pos;
|
||||||
|
for (Int i = pos; direction == DIR_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 r = direction == DIR_RIGHT ? i : prev_pos;
|
||||||
|
if (seek_word && is_word) {
|
||||||
|
result = r;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (seek_whitespace && is_whitespace) {
|
||||||
|
result = r;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (seek_symbol && is_symbol) {
|
||||||
|
result = r;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev_pos = i;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int MoveOnWhitespaceBoundaryDown(Buffer &buffer, Int pos) {
|
||||||
|
Int result = pos;
|
||||||
|
Int next_line = PosToLine(buffer, pos) + 1;
|
||||||
|
for (Int line = next_line; line < buffer.line_starts.len; line += 1) {
|
||||||
|
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 MoveOnWhitespaceBoundaryUp(Buffer &buffer, Int pos) {
|
||||||
|
Int result = pos;
|
||||||
|
Int next_line = PosToLine(buffer, pos) - 1;
|
||||||
|
for (Int line = next_line; line >= 0; line -= 1) {
|
||||||
|
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 MovePosByXY(Buffer &buffer, Int pos, XY offset) {
|
||||||
|
XY xy = PosToXY(buffer, pos);
|
||||||
|
Int result = XYToPosWithoutNL(buffer, {xy.col + offset.col, xy.line + offset.line});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int MovePos(Buffer &buffer, Int pos, int direction, bool ctrl_pressed = false) {
|
||||||
|
ProfileFunction();
|
||||||
|
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 MoveOnWhitespaceBoundaryDown(buffer, pos);
|
||||||
|
case DIR_UP: return MoveOnWhitespaceBoundaryUp(buffer, pos);
|
||||||
|
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 MovePosByXY(buffer, pos, {0, 1});
|
||||||
|
case DIR_UP: return MovePosByXY(buffer, pos, {0, -1});
|
||||||
|
default: return pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Range EncloseWord(Buffer &buffer, Int pos) {
|
||||||
|
Range result = {};
|
||||||
|
result.min = MoveOnWhitespaceBoundary(buffer, pos, DIR_LEFT);
|
||||||
|
result.max = MoveOnWhitespaceBoundary(buffer, pos, DIR_RIGHT);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -53,189 +53,6 @@ struct Event {
|
|||||||
#define Mouse(x) (event.kind == EVENT_MOUSE_##x)
|
#define Mouse(x) (event.kind == EVENT_MOUSE_##x)
|
||||||
#define MousePress() (Mouse(LEFT) || Mouse(RIGHT) || Mouse(MIDDLE))
|
#define MousePress() (Mouse(LEFT) || Mouse(RIGHT) || Mouse(MIDDLE))
|
||||||
|
|
||||||
Int MoveOnWhitespaceBoundaryForward(Buffer &buffer, Int pos) {
|
|
||||||
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 = buffer.len;
|
|
||||||
Int prev_pos = pos;
|
|
||||||
for (Int i = pos; i < buffer.len; i += 1) {
|
|
||||||
bool is_whitespace = IsWhitespace(buffer.str[i]);
|
|
||||||
bool is_symbol = IsSymbol(buffer.str[i]);
|
|
||||||
bool is_word = !is_whitespace && !is_symbol;
|
|
||||||
if (seek_word && is_word) {
|
|
||||||
result = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (seek_whitespace && is_whitespace) {
|
|
||||||
result = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (seek_symbol && is_symbol) {
|
|
||||||
result = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prev_pos = i;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Int MoveOnWhitespaceBoundaryBackward(Buffer &buffer, Int pos) {
|
|
||||||
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 = 0;
|
|
||||||
Int prev_pos = pos;
|
|
||||||
for (Int i = pos; i >= 0; i -= 1) {
|
|
||||||
bool is_whitespace = IsWhitespace(buffer.str[i]);
|
|
||||||
bool is_symbol = IsSymbol(buffer.str[i]);
|
|
||||||
bool is_word = !is_whitespace && !is_symbol;
|
|
||||||
if (seek_word && is_word) {
|
|
||||||
result = prev_pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (seek_whitespace && is_whitespace) {
|
|
||||||
result = prev_pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (seek_symbol && is_symbol) {
|
|
||||||
result = prev_pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prev_pos = i;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Int MoveOnWhitespaceBoundaryDown(Buffer &buffer, Int pos) {
|
|
||||||
Int result = pos;
|
|
||||||
Int next_line = PosToLine(buffer, pos) + 1;
|
|
||||||
for (Int line = next_line; line < buffer.line_starts.len; line += 1) {
|
|
||||||
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 MoveOnWhitespaceBoundaryUp(Buffer &buffer, Int pos) {
|
|
||||||
Int result = pos;
|
|
||||||
Int next_line = PosToLine(buffer, pos) - 1;
|
|
||||||
for (Int line = next_line; line >= 0; line -= 1) {
|
|
||||||
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 MovePosByXY(Buffer &buffer, Int pos, XY offset) {
|
|
||||||
XY xy = PosToXY(buffer, pos);
|
|
||||||
Int result = XYToPosWithoutNL(buffer, {xy.col + offset.col, xy.line + offset.line});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int DIR_RIGHT = 0;
|
|
||||||
const int DIR_LEFT = 1;
|
|
||||||
const int DIR_DOWN = 2;
|
|
||||||
const int DIR_UP = 3;
|
|
||||||
|
|
||||||
const bool CTRL_PRESSED = true;
|
|
||||||
|
|
||||||
Int MovePos(Buffer &buffer, Int pos, int direction, bool ctrl_pressed = false) {
|
|
||||||
ProfileFunction();
|
|
||||||
Assert(direction >= 0 && direction <= 3);
|
|
||||||
if (ctrl_pressed) {
|
|
||||||
switch (direction) {
|
|
||||||
case DIR_RIGHT: return MoveOnWhitespaceBoundaryForward(buffer, pos);
|
|
||||||
case DIR_LEFT: return MoveOnWhitespaceBoundaryBackward(buffer, pos);
|
|
||||||
case DIR_DOWN: return MoveOnWhitespaceBoundaryDown(buffer, pos);
|
|
||||||
case DIR_UP: return MoveOnWhitespaceBoundaryUp(buffer, pos);
|
|
||||||
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 MovePosByXY(buffer, pos, {0, 1});
|
|
||||||
case DIR_UP: return MovePosByXY(buffer, pos, {0, -1});
|
|
||||||
default: return pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Range EncloseWord(Buffer &buffer, Int pos) {
|
|
||||||
Range result = {};
|
|
||||||
result.min = MoveOnWhitespaceBoundaryBackward(buffer, pos);
|
|
||||||
result.max = MoveOnWhitespaceBoundaryForward(buffer, pos);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ToggleFullscreen() {
|
void ToggleFullscreen() {
|
||||||
if (IsInFullscreen) {
|
if (IsInFullscreen) {
|
||||||
SDL_SetWindowSize(SDLWindow, FullScreenSizeX, FullScreenSizeY);
|
SDL_SetWindowSize(SDLWindow, FullScreenSizeX, FullScreenSizeY);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ int FullScreenPositionX, FullScreenPositionY;
|
|||||||
#include "buffer_helpers.cpp"
|
#include "buffer_helpers.cpp"
|
||||||
#include "buffer.cpp"
|
#include "buffer.cpp"
|
||||||
#include "buffer_multi_cursor.cpp"
|
#include "buffer_multi_cursor.cpp"
|
||||||
|
#include "buffer_ops.cpp"
|
||||||
#include "buffer_history.cpp"
|
#include "buffer_history.cpp"
|
||||||
#include "buffer_fuzzy_search.cpp"
|
#include "buffer_fuzzy_search.cpp"
|
||||||
#include "buffer_test_load.cpp"
|
#include "buffer_test_load.cpp"
|
||||||
|
|||||||
@@ -2,7 +2,12 @@
|
|||||||
- page up and down should also scroll and leave you in exactly same scroll
|
- page up and down should also scroll and leave you in exactly same scroll
|
||||||
- I think the way sublime text and we display line highlights is confusing with multiple cursors (line highlight can be confused with selection)
|
- I think the way sublime text and we display line highlights is confusing with multiple cursors (line highlight can be confused with selection)
|
||||||
- don't trim lines with cursor or selection on it
|
- don't trim lines with cursor or selection on it
|
||||||
|
- fix history of ctrl + enter
|
||||||
|
|
||||||
|
- option trim trailing whitespace before save and dont' trim on cursor
|
||||||
|
- improve cursor movement, it's too clunky, too much stopping
|
||||||
|
- kill selected lines
|
||||||
|
- better enclosures
|
||||||
- search backwards
|
- search backwards
|
||||||
- load selected string or auto enclosed word when midclick?, ctrl + click, ctrl + e?
|
- load selected string or auto enclosed word when midclick?, ctrl + click, ctrl + e?
|
||||||
- experiment with using multiple cursors to select command and it's input
|
- experiment with using multiple cursors to select command and it's input
|
||||||
|
|||||||
Reference in New Issue
Block a user