summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2024-01-25 09:50:28 +0100
committerAlbert Cervin <albert@acervin.com>2024-01-25 09:50:28 +0100
commitb5397df84c53e12376dcbb977148f08bd6765525 (patch)
tree9e654ff6b4ff5f9be11f978cea22cbf8c88449e7
parentc27f5c5ed4bce91eaa50d7d1daa5335f186dcc36 (diff)
downloaddged-b5397df84c53e12376dcbb977148f08bd6765525.tar.gz
dged-b5397df84c53e12376dcbb977148f08bd6765525.tar.xz
dged-b5397df84c53e12376dcbb977148f08bd6765525.zip
Improve word navigation
Now behaves the way we want.
-rw-r--r--dged.nix2
-rw-r--r--src/dged/buffer.c118
-rw-r--r--src/main/cmds.c10
3 files changed, 109 insertions, 21 deletions
diff --git a/dged.nix b/dged.nix
index 53f0210..2427e2d 100644
--- a/dged.nix
+++ b/dged.nix
@@ -6,6 +6,7 @@
, bear
, lib
, doxygen
+, valgrind
}:
stdenv.mkDerivation {
name = "dged";
@@ -19,6 +20,7 @@ stdenv.mkDerivation {
clang-tools
bear
doxygen
+ valgrind
];
buildPhase = ''
diff --git a/src/dged/buffer.c b/src/dged/buffer.c
index 8e63e1f..8b1f69c 100644
--- a/src/dged/buffer.c
+++ b/src/dged/buffer.c
@@ -242,25 +242,65 @@ static void write_line(struct text_chunk *chunk, void *userdata) {
fputc('\n', file);
}
-static struct location find_next(struct buffer *buffer, struct location from,
- uint8_t chars[], uint32_t nchars,
- int direction) {
- struct text_chunk line = text_get_line(buffer->text, from.line);
- int64_t bytei = text_col_to_byteindex(buffer->text, from.line, from.col);
- while (bytei < line.nbytes && bytei > 0 &&
- (line.text[bytei] == ' ' || line.text[bytei] == '.')) {
- bytei += direction;
- }
-
- for (; bytei < line.nbytes && bytei > 0; bytei += direction) {
- uint8_t b = line.text[bytei];
- if (b == ' ' || b == '.') {
+static bool is_word_break(uint8_t c) {
+ return c == ' ' || c == '.' || c == '(' || c == ')';
+}
+
+static bool is_word_char(uint8_t c) { return !is_word_break(c); }
+
+struct match_result {
+ struct location at;
+ bool found;
+};
+
+static struct match_result find_next_in_line(struct buffer *buffer,
+ struct location start,
+ bool (*predicate)(uint8_t c)) {
+ struct text_chunk line = text_get_line(buffer->text, start.line);
+ bool found = false;
+
+ if (line.nbytes == 0) {
+ return (struct match_result){.at = start, .found = false};
+ }
+
+ uint32_t bytei = text_col_to_byteindex(buffer->text, start.line, start.col);
+ while (bytei < line.nbytes) {
+ if (predicate(line.text[bytei])) {
+ found = true;
+ break;
+ }
+ ++bytei;
+ }
+
+ uint32_t target_col = text_byteindex_to_col(buffer->text, start.line, bytei);
+ return (struct match_result){
+ .at = (struct location){.line = start.line, .col = target_col},
+ .found = found};
+}
+
+static struct match_result find_prev_in_line(struct buffer *buffer,
+ struct location start,
+ bool (*predicate)(uint8_t c)) {
+ struct text_chunk line = text_get_line(buffer->text, start.line);
+ bool found = false;
+
+ if (line.nbytes == 0) {
+ return (struct match_result){.at = start, .found = false};
+ }
+
+ uint32_t bytei = text_col_to_byteindex(buffer->text, start.line, start.col);
+ while (bytei > 0) {
+ if (predicate(line.text[bytei])) {
+ found = true;
break;
}
+ --bytei;
}
- uint32_t target_col = text_byteindex_to_col(buffer->text, from.line, bytei);
- return (struct location){.line = from.line, .col = target_col};
+ uint32_t target_col = text_byteindex_to_col(buffer->text, start.line, bytei);
+ return (struct match_result){
+ .at = (struct location){.line = start.line, .col = target_col},
+ .found = found};
}
static struct text_chunk *copy_region(struct buffer *buffer,
@@ -458,9 +498,36 @@ struct location buffer_previous_char(struct buffer *buffer,
struct location buffer_previous_word(struct buffer *buffer,
struct location dot) {
- moveh(buffer, -1, &dot);
- uint8_t chars[] = {' ', '.'};
- return find_next(buffer, dot, chars, 2, -1);
+
+ struct match_result res = find_prev_in_line(buffer, dot, is_word_break);
+ if (!res.found && res.at.col == dot.col) {
+ moveh(buffer, -1, &res.at);
+ return res.at;
+ }
+
+ // check if we got here from the middle of a word or not
+ uint32_t traveled = dot.col - res.at.col;
+
+ // if not, skip over another word
+ if (traveled <= 1) {
+ res = find_prev_in_line(buffer, res.at, is_word_char);
+ if (!res.found) {
+ moveh(buffer, -1, &res.at);
+ return res.at;
+ }
+
+ // at this point, we are at the end of the previous word
+ res = find_prev_in_line(buffer, res.at, is_word_break);
+ if (!res.found) {
+ return res.at;
+ } else {
+ moveh(buffer, 1, &res.at);
+ }
+ } else {
+ moveh(buffer, 1, &res.at);
+ }
+
+ return res.at;
}
struct location buffer_previous_line(struct buffer *buffer,
@@ -475,9 +542,18 @@ struct location buffer_next_char(struct buffer *buffer, struct location dot) {
}
struct location buffer_next_word(struct buffer *buffer, struct location dot) {
- moveh(buffer, 1, &dot);
- uint8_t chars[] = {' ', '.'};
- return find_next(buffer, dot, chars, 2, 1);
+ struct match_result res = find_next_in_line(buffer, dot, is_word_break);
+ if (!res.found) {
+ moveh(buffer, 1, &res.at);
+ return res.at;
+ }
+
+ res = find_next_in_line(buffer, res.at, is_word_char);
+ if (!res.found) {
+ moveh(buffer, 1, &res.at);
+ }
+
+ return res.at;
}
struct location buffer_next_line(struct buffer *buffer, struct location dot) {
diff --git a/src/main/cmds.c b/src/main/cmds.c
index 506054b..f12b4d4 100644
--- a/src/main/cmds.c
+++ b/src/main/cmds.c
@@ -229,6 +229,11 @@ static void find_file_comp_inserted() { minibuffer_execute(); }
static int32_t open_file(struct buffers *buffers, struct window *active_window,
const char *pth) {
+
+ if (active_window == minibuffer_window()) {
+ return 1;
+ }
+
struct stat sb = {0};
if (stat(pth, &sb) < 0 && errno != ENOENT) {
minibuffer_echo("stat on %s failed: %s", pth, strerror(errno));
@@ -387,6 +392,11 @@ static int32_t scroll_down_cmd(struct command_ctx ctx, int argc,
};
static int32_t goto_line(struct command_ctx ctx, int argc, const char *argv[]) {
+ // don't want to goto line in minibuffer
+ if (ctx.active_window == minibuffer_window()) {
+ return 0;
+ }
+
if (argc == 0) {
return minibuffer_prompt(ctx, "line: ");
}