Introduction
Introduction Statistics Contact Development Disclaimer Help
tImplement word movement commands - ledit - Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
Log
Files
Refs
README
LICENSE
---
commit 335e5d61cc5d4876fb7240543fb55afb55f00cfb
parent 657c25540c4b349068c4c24f82b6b5bb1f94c459
Author: lumidify <[email protected]>
Date: Fri, 5 Nov 2021 19:06:35 +0100
Implement word movement commands
Diffstat:
M buffer.c | 284 +++++++++++++++++++++++++++++…
M buffer.h | 9 +++++++++
M keys_basic.c | 56 +++++++++++++++++++++++++++++…
M keys_basic_config.h | 12 ++++++++++++
4 files changed, 361 insertions(+), 0 deletions(-)
---
diff --git a/buffer.c b/buffer.c
t@@ -866,6 +866,8 @@ ledit_buffer_copy_text_to_txtbuf(
int
ledit_line_prev_utf8(ledit_line *line, int index) {
+ if (index <= 0)
+ return 0;
int i = index - 1;
/* find valid utf8 char - this probably needs to be improved */
/* FIXME: don't go off end or beginning */
t@@ -876,12 +878,294 @@ ledit_line_prev_utf8(ledit_line *line, int index) {
int
ledit_line_next_utf8(ledit_line *line, int index) {
+ if (index >= line->len)
+ return line->len;
int i = index + 1;
while (i < line->len && ((LINE_CHAR(line, i) & 0xC0) == 0x80))
i++;
return i;
}
+/* Warning: this is very inefficient! */
+/* FIXME: at least attempt to be more efficient by starting from the beginning
+ or end based on approximately where in the line the byte is */
+static int
+line_byte_to_char(ledit_line *line, int byte) {
+ int c = 0;
+ int i = 0;
+ int b = byte > line->len ? line->len : byte; /* maybe not necessary */
+ while (i < b) {
+ c++;
+ i = ledit_line_next_utf8(line, i);
+ }
+ return c;
+}
+
+static int
+line_next_word(ledit_line *line, int byte, int char_index, int wrapped_line, i…
+ int c, nattrs;
+ if (char_index >= 0)
+ c = char_index;
+ else
+ c = line_byte_to_char(line, byte);
+ int cur_byte = wrapped_line ? byte : ledit_line_next_utf8(line, byte);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(line->layout, &nattrs);
+ for (int i = wrapped_line ? c : c + 1; i < nattrs; i++) {
+ if (attrs[i].is_word_start) {
+ if (char_ret)
+ *char_ret = i;
+ if (real_byte_ret)
+ *real_byte_ret = cur_byte;
+ return cur_byte;
+ }
+ cur_byte = ledit_line_next_utf8(line, cur_byte);
+ }
+ return -1;
+}
+
+static int
+line_prev_word(ledit_line *line, int byte, int char_index, int *char_ret) {
+ int c, nattrs;
+ if (char_index >= 0)
+ c = char_index;
+ else
+ c = line_byte_to_char(line, byte);
+ int cur_byte = ledit_line_prev_utf8(line, byte);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(line->layout, &nattrs);
+ if (c > nattrs)
+ return -1;
+ for (int i = c - 1; i >= 0; i--) {
+ if (attrs[i].is_word_start) {
+ if (char_ret)
+ *char_ret = i;
+ return cur_byte;
+ }
+ cur_byte = ledit_line_prev_utf8(line, cur_byte);
+ }
+ return -1;
+}
+
+static int
+line_prev_bigword(ledit_line *line, int byte, int char_index, int *char_ret) {
+ int c, nattrs;
+ if (char_index >= 0)
+ c = char_index;
+ else
+ c = line_byte_to_char(line, byte);
+ int cur_byte = ledit_line_prev_utf8(line, byte);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(line->layout, &nattrs);
+ int next_cursorb = byte;
+ int next_cursorc = c;
+ int found_word = 0;
+ for (int i = c - 1; i >= 0; i--) {
+ if (!found_word && !attrs[i].is_white) {
+ found_word = 1;
+ } else if (found_word && attrs[i].is_white) {
+ if (char_ret)
+ *char_ret = next_cursorc;
+ return next_cursorb;
+ }
+ if (found_word && c == 0) {
+ if (char_ret)
+ *char_ret = 0;
+ return 0;
+ }
+ if (attrs[i].is_cursor_position) {
+ next_cursorc = i;
+ next_cursorb = cur_byte;
+ }
+ cur_byte = ledit_line_prev_utf8(line, cur_byte);
+ }
+ return -1;
+}
+
+int
+line_next_bigword_end(ledit_line *line, int byte, int char_index, int wrapped_…
+ int c, nattrs;
+ if (char_index >= 0)
+ c = char_index;
+ else
+ c = line_byte_to_char(line, byte);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(line->layout, &nattrs);
+ int last_cursorb, last_cursorc;
+ if (wrapped_line) {
+ last_cursorb = byte;
+ last_cursorc = c;
+ } else {
+ last_cursorb = -1;
+ last_cursorc = -1;
+ }
+ int found_word = 0;
+ int cur_byte = byte;
+ for (int i = c; i < nattrs; i++) {
+ if (last_cursorb != -1 && !found_word && !attrs[i].is_white) {
+ found_word = 1;
+ } else if (found_word && attrs[i].is_white) {
+ if (char_ret)
+ *char_ret = last_cursorc;
+ if (real_byte_ret)
+ *real_byte_ret = cur_byte;
+ return last_cursorb;
+ }
+ if (attrs[i].is_cursor_position) {
+ last_cursorc = i;
+ last_cursorb = cur_byte;
+ }
+ cur_byte = ledit_line_next_utf8(line, cur_byte);
+ }
+ return -1;
+}
+
+static int
+line_next_word_end(ledit_line *line, int byte, int char_index, int wrapped_lin…
+ int c, nattrs;
+ if (char_index >= 0)
+ c = char_index;
+ else
+ c = line_byte_to_char(line, byte);
+ int cur_byte = ledit_line_next_utf8(line, byte);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(line->layout, &nattrs);
+ int last_cursorb, last_cursorc;
+ if (wrapped_line) {
+ last_cursorb = byte;
+ last_cursorc = c;
+ } else {
+ last_cursorb = -1;
+ last_cursorc = -1;
+ }
+ for (int i = c + 1; i < nattrs; i++) {
+ if (last_cursorb != -1 && attrs[i].is_word_end) {
+ if (char_ret)
+ *char_ret = last_cursorc;
+ if (real_byte_ret)
+ *real_byte_ret = cur_byte;
+ return last_cursorb;
+ }
+ if (attrs[i].is_cursor_position) {
+ last_cursorc = i;
+ last_cursorb = cur_byte;
+ }
+ cur_byte = ledit_line_next_utf8(line, cur_byte);
+ }
+ return -1;
+}
+
+static int
+line_next_bigword(ledit_line *line, int byte, int char_index, int wrapped_line…
+ int c, nattrs;
+ if (char_index >= 0)
+ c = char_index;
+ else
+ c = line_byte_to_char(line, byte);
+ int cur_byte = byte;
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(line->layout, &nattrs);
+ int found_ws = wrapped_line;
+ for (int i = c; i < nattrs; i++) {
+ if (!found_ws && attrs[i].is_white) {
+ found_ws = 1;
+ } else if (found_ws && !attrs[i].is_white) {
+ if (char_ret)
+ *char_ret = i;
+ if (real_byte_ret)
+ *real_byte_ret = cur_byte;
+ return cur_byte;
+ }
+ cur_byte = ledit_line_next_utf8(line, cur_byte);
+ }
+ return -1;
+}
+
+/* FIXME: document that word and bigword are a bit weird because word uses uni…
+
+#define GEN_NEXT_WORD(name, func) …
+void …
+ledit_buffer_next_##name( …
+ ledit_buffer *buffer, …
+ int line, int byte, int num_repeat, …
+ int *line_ret, int *byte_ret, int *real_byte_ret) { …
+ int cur_line = line; …
+ int cur_byte = byte; …
+ int cur_char = -1; …
+ int real_byte = -1; …
+ int wrapped_line; …
+ ledit_line *ll = ledit_buffer_get_line(buffer, cur_line); …
+ for (int i = 0; i < num_repeat; i++) { …
+ wrapped_line = 0; …
+ while ((cur_byte = func(ll, cur_byte, cur_char, wrapped_line, …
+ cur_line < buffer->lines_num - 1) { …
+ cur_line++; …
+ ll = ledit_buffer_get_line(buffer, cur_line); …
+ cur_byte = 0; …
+ wrapped_line = 1; …
+ } …
+ if (cur_byte == -1 && cur_line == buffer->lines_num - 1) …
+ break; …
+ } …
+ if (cur_byte == -1) { …
+ *line_ret = buffer->lines_num - 1; …
+ *byte_ret = ledit_buffer_get_legal_normal_pos(buffer, buffer->…
+ *real_byte_ret = ll->len; …
+ } else { …
+ *line_ret = cur_line; …
+ *byte_ret = cur_byte; …
+ *real_byte_ret = real_byte; …
+ } …
+}
+
+#define GEN_PREV_WORD(name, func) …
+void …
+ledit_buffer_prev_##name( …
+ ledit_buffer *buffer, …
+ int line, int byte, int num_repeat, …
+ int *line_ret, int *byte_ret, int *real_byte_ret) { …
+ int cur_line = line; …
+ int cur_byte = byte; …
+ int cur_char = -1; …
+ ledit_line *ll = ledit_buffer_get_line(buffer, cur_line); …
+ for (int i = 0; i < num_repeat; i++) { …
+ while ((cur_byte = func(ll, cur_byte, cur_char, &cur_char)) ==…
+ cur_line--; …
+ ll = ledit_buffer_get_line(buffer, cur_line); …
+ cur_byte = ll->len; …
+ } …
+ if (cur_byte == -1 && cur_line == 0) …
+ break; …
+ } …
+ if (cur_byte == -1) { …
+ *line_ret = 0; …
+ *byte_ret = 0; …
+ *real_byte_ret = 0; …
+ } else { …
+ *line_ret = cur_line; …
+ *byte_ret = cur_byte; …
+ *real_byte_ret = cur_byte; …
+ } …
+}
+
+GEN_NEXT_WORD(word, line_next_word)
+GEN_NEXT_WORD(word_end, line_next_word_end)
+GEN_NEXT_WORD(bigword, line_next_bigword)
+GEN_NEXT_WORD(bigword_end, line_next_bigword_end)
+GEN_PREV_WORD(word, line_prev_word)
+GEN_PREV_WORD(bigword, line_prev_bigword)
+
+/* FIXME: implement */
+/*
+int
+ledit_line_nearest_cursor_pos(ledit_line *line, int byte) {
+}
+
+void
+ledit_line_word_boundaries(ledit_line *line, int byte, int *start_ret, int *en…
+}
+*/
+
/* FIXME: no idea why this exists */
/*
static void
diff --git a/buffer.h b/buffer.h
t@@ -57,6 +57,15 @@ void ledit_pos_to_x_softline(ledit_line *line, int pos, int…
void ledit_x_softline_to_pos(ledit_line *line, int x, int softline, int *pos_r…
int ledit_line_next_utf8(ledit_line *line, int index);
int ledit_line_prev_utf8(ledit_line *line, int index);
+int ledit_line_byte_to_char(ledit_line *line, int byte);
+
+void ledit_buffer_next_word(ledit_buffer *buffer, int line, int byte, int num_…
+void ledit_buffer_next_word_end(ledit_buffer *buffer, int line, int byte, int …
+void ledit_buffer_next_bigword(ledit_buffer *buffer, int line, int byte, int n…
+void ledit_buffer_next_bigword_end(ledit_buffer *buffer, int line, int byte, i…
+void ledit_buffer_prev_word(ledit_buffer *buffer, int line, int byte, int num_…
+void ledit_buffer_prev_bigword(ledit_buffer *buffer, int line, int byte, int n…
+
size_t ledit_buffer_textlen(ledit_buffer *buffer, int line1, int byte1, int li…
void ledit_buffer_copy_text(ledit_buffer *buffer, char *dst, int line1, int by…
void ledit_buffer_copy_text_to_txtbuf(
diff --git a/keys_basic.c b/keys_basic.c
t@@ -1040,6 +1040,62 @@ move_to_eol(ledit_buffer *buffer, char *text, int len) {
return (struct action){ACTION_NONE, NULL};
}
+#define GEN_WORD_MOVEMENT(name, func) …
+static struct action …
+name(ledit_buffer *buffer, char *text, int len) { …
+ (void)text; …
+ (void)len; …
+ int num = 1; …
+ struct key_stack_elem *e = pop_key_stack(); …
+ if (e != NULL) { …
+ if (e->key & KEY_NUMBER) { …
+ num = e->count > 0 ? e->count : 1; …
+ e = pop_key_stack(); …
+ } …
+ if (e != NULL) …
+ num *= (e->count > 0 ? e->count : 1); …
+ } …
+ int new_line, new_index, new_real_index; …
+ func( …
+ buffer, …
+ buffer->cur_line, buffer->cur_index, num, …
+ &new_line, &new_index, &new_real_index …
+ ); …
+ if (e != NULL && e->motion_cb != NULL) { …
+ e->motion_cb(buffer, new_line, new_real_index, KEY_MOTION_CHAR…
+ } else { …
+ if (buffer->common->mode == VISUAL) { …
+ ledit_buffer_set_selection( …
+ buffer, …
+ buffer->sel.line1, buffer->sel.byte1, …
+ new_line, new_real_index …
+ ); …
+ buffer->cur_line = new_line; …
+ buffer->cur_index = new_real_index; …
+ } else { …
+ if (new_line != buffer->cur_line) …
+ ledit_buffer_wipe_line_cursor_attrs( …
+ buffer, buffer->cur_line …
+ ); …
+ buffer->cur_line = new_line; …
+ buffer->cur_index = new_index; …
+ ledit_buffer_set_line_cursor_attrs( …
+ buffer, buffer->cur_line, buffer->cur_index …
+ ); …
+ } …
+ discard_repetition_stack(); …
+ } …
+ clear_key_stack(); …
+ return (struct action){ACTION_NONE, NULL}; …
+}
+
+GEN_WORD_MOVEMENT(next_word, ledit_buffer_next_word)
+GEN_WORD_MOVEMENT(next_word_end, ledit_buffer_next_word_end)
+GEN_WORD_MOVEMENT(next_bigword, ledit_buffer_next_bigword)
+GEN_WORD_MOVEMENT(next_bigword_end, ledit_buffer_next_bigword_end)
+GEN_WORD_MOVEMENT(prev_word, ledit_buffer_prev_word)
+GEN_WORD_MOVEMENT(prev_bigword, ledit_buffer_prev_bigword)
+
static void
move_cursor_left_right(ledit_buffer *buffer, int dir, int allow_illegal_index)…
int num = 1;
diff --git a/keys_basic_config.h b/keys_basic_config.h
t@@ -70,6 +70,12 @@ static struct action change(ledit_buffer *buffer, char *tex…
static struct action move_to_eol(ledit_buffer *buffer, char *text, int len);
static struct action mark_line(ledit_buffer *buffer, char *text, int len);
static struct action jump_to_mark(ledit_buffer *buffer, char *text, int len);
+static struct action next_word(ledit_buffer *buffer, char *text, int len);
+static struct action next_word_end(ledit_buffer *buffer, char *text, int len);
+static struct action next_bigword(ledit_buffer *buffer, char *text, int len);
+static struct action next_bigword_end(ledit_buffer *buffer, char *text, int le…
+static struct action prev_word(ledit_buffer *buffer, char *text, int len);
+static struct action prev_bigword(ledit_buffer *buffer, char *text, int len);
/* FIXME: maybe sort these and use binary search
-> but that would mess with the catch-all keys */
t@@ -128,6 +134,12 @@ static struct key keys_en[] = {
{"d", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &scroll_lin…
{"u", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &scroll_lin…
{"$", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &move_to_eol},
+ {"w", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &next_word},
+ {"e", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &next_word_end…
+ {"W", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &next_bigword},
+ {"E", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &next_bigword_…
+ {"b", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &prev_word},
+ {"B", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &prev_bigword},
{"G", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &move_to_line},
{"p", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &paste_normal},
{"P", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &paste_normal_backwards},
You are viewing proxied material from lumidify.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.