commit 3895a14f2fb3bcc35ba842e259074a67adddb8a1
parent 52cea73bf0e43483210cb94e5177989bc524a30c
Author: lumidify <nobody@lumidify.org>
Date: Thu, 13 May 2021 21:54:24 +0200
Add basic repetition and motion callback support to cursor movement keys
Diffstat:
M | buffer.c | | | 12 | +++++++++--- |
M | ledit.c | | | 249 | +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------- |
2 files changed, 171 insertions(+), 90 deletions(-)
diff --git a/buffer.c b/buffer.c
@@ -494,10 +494,16 @@ ledit_delete_range(
}
delete_line_section(buffer, line_index1, b1, b2 - b1);
*new_line_ret = line_index1;
+ ledit_line *ll = ledit_get_line(buffer, line_index1);
+ /* FIXME: where should this be done? */
+ /* FIXME: also do this below in the else statement */
+ if (buffer->state->mode == NORMAL && b1 == ll->len && b1 > 0) {
+ /* FIXME: use grapheme instead of character! */
+ b1 = ll->len - 1;
+ while (b1 > 0 && ((ll->text[b1] & 0xC0) == 0x80))
+ b1--;
+ }
*new_byte_ret = b1;
- /* FIXME: this needs to be checked by calling code to
- move cursor one back if in normal mode and at end
- of line */
} else {
int l1, l2, b1, b2;
if (line_index1 < line_index2) {
diff --git a/ledit.c b/ledit.c
@@ -91,9 +91,10 @@ static void resize_window(int w, int h);
static void backspace(void);
static void delete_key(void);
-static void move_cursor(int dir);
+static void move_cursor_left_right(int dir);
static void cursor_left(void);
static void cursor_right(void);
+static void move_cursor_up_down(int dir);
static void cursor_down(void);
static void cursor_up(void);
static void cursor_to_beginning(void);
@@ -117,6 +118,67 @@ static void key_d_cb(int line, int char_pos, enum key_type type);
static void change_keyboard(char *lang);
static void key_press(XEvent event);
+static void get_new_line_softline(
+ int cur_line, int cur_index, int movement,
+ int *new_line_ret, int *new_softline_ret
+);
+
+static void
+get_new_line_softline(
+ int cur_line, int cur_index, int movement,
+ int *new_line_ret, int *new_softline_ret) {
+ ledit_line *line = ledit_get_line(buffer, cur_line);
+ int x, softline;
+ pango_layout_index_to_line_x(line->layout, cur_index, 0, &softline, &x);
+ if (movement > 0) {
+ int softlines = pango_layout_get_line_count(line->layout);
+ if (softlines - softline > movement) {
+ *new_line_ret = cur_line;
+ *new_softline_ret = softline + movement;
+ } else {
+ movement -= (softlines - softline - 1);
+ int endline = cur_line + 1;
+ while (movement > 0 && endline < buffer->lines_num) {
+ line = ledit_get_line(buffer, endline);
+ softlines = pango_layout_get_line_count(line->layout);
+ movement -= softlines;
+ endline++;
+ }
+ endline--;
+ if (movement <= 0) {
+ *new_softline_ret = movement + softlines - 1;
+ } else {
+ *new_softline_ret = softlines - 1;
+ }
+ *new_line_ret = endline;
+ }
+ } else if (movement < 0) {
+ int softlines = 0;
+ if (softline + movement >= 0) {
+ *new_line_ret = cur_line;
+ *new_softline_ret = softline + movement;
+ } else {
+ movement += softline;
+ int endline = cur_line - 1;
+ while (movement < 0 && endline >= 0) {
+ line = ledit_get_line(buffer, endline);
+ softlines = pango_layout_get_line_count(line->layout);
+ movement += softlines;
+ endline--;
+ }
+ endline++;
+ if (movement >= 0) {
+ *new_softline_ret = movement;
+ } else {
+ *new_softline_ret = 0;
+ }
+ *new_line_ret = endline;
+ }
+ } else {
+ *new_line_ret = cur_line;
+ *new_softline_ret = softline;
+ }
+}
static void
key_d(void) {
@@ -132,33 +194,14 @@ key_d(void) {
int prevnum = e->count > 0 ? e->count : 1;
num = num > 0 ? num : 1;
int lines = num * prevnum;
-
- ledit_line *line = ledit_get_line(buffer, buffer->cur_line);
- int x, softline;
- pango_layout_index_to_line_x(line->layout, buffer->cur_index, 0, &softline, &x);
- int softlines = pango_layout_get_line_count(line->layout);
- if (softlines - softline >= lines) {
- PangoLayoutLine *l = pango_layout_get_line_readonly(line->layout, softline + lines - 1);
- e->motion_cb(buffer->cur_line, l->start_index, KEY_MOTION_LINE);
- } else {
- lines -= (softlines - softline);
- int endline = buffer->cur_line + 1;
- while (lines > 0 && endline < buffer->lines_num) {
- line = ledit_get_line(buffer, endline);
- softlines = pango_layout_get_line_count(line->layout);
- lines -= softlines;
- endline++;
- }
- endline--;
- int endsoftline = 0;
- if (lines <= 0) {
- endsoftline = lines + softlines - 1;
- } else {
- endsoftline = softlines - 1;
- }
- PangoLayoutLine *l = pango_layout_get_line_readonly(line->layout, endsoftline);
- e->motion_cb(endline, l->start_index, KEY_MOTION_LINE);
- }
+ int new_line, new_softline;
+ get_new_line_softline(
+ buffer->cur_line, buffer->cur_index, lines - 1,
+ &new_line, &new_softline
+ );
+ ledit_line *ll = ledit_get_line(buffer, new_line);
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layout, new_softline);
+ e->motion_cb(new_line, pl->start_index, KEY_MOTION_LINE);
clear_key_stack();
} else if (e != NULL) {
clear_key_stack();
@@ -175,7 +218,6 @@ key_d(void) {
/* FIXME: should this get number of lines to remove or actual end line? */
static void
key_d_cb(int line, int char_pos, enum key_type type) {
- printf("%d, %d\n", line, char_pos);
int line_based = type == KEY_MOTION_LINE ? 1 : 0;
ledit_delete_range(
buffer, line_based,
@@ -819,51 +861,79 @@ delete_key(void) {
ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index);
}
-/* FIXME: this comment needs to be implemented still */
-/* num is number of graphemes to move (see pango documentation) - negative
- * is left, positive is right */
static void
-move_cursor(int dir) {
+move_cursor_left_right(int dir) {
+ 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 : 0;
+ e = pop_key_stack();
+ }
+ if (e != NULL)
+ num *= (e->count > 0 ? e->count : 1);
+ }
+
/* FIXME: trailing */
- int trailing, last_index = buffer->cur_index;
+ int trailing = 0, tmp_index;
ledit_line *cur_line = ledit_get_line(buffer, buffer->cur_line);
- pango_layout_move_cursor_visually(
- cur_line->layout, TRUE,
- buffer->cur_index, 0, dir,
- &buffer->cur_index, &trailing
- );
+ int new_index = buffer->cur_index, last_index = buffer->cur_index;
+ while (num > 0) {
+ tmp_index = new_index;
+ pango_layout_move_cursor_visually(
+ cur_line->layout, TRUE,
+ new_index, trailing, dir,
+ &new_index, &trailing
+ );
+ /* for some reason, this is necessary */
+ if (new_index < 0)
+ new_index = 0;
+ else if (new_index > cur_line->len)
+ new_index = cur_line->len;
+ num--;
+ if (tmp_index != new_index)
+ last_index = tmp_index;
+ }
/* FIXME: Allow cursor to be at end of soft line */
/* we don't currently support a difference between the cursor being at
the end of a soft line and the beginning of the next line */
/* FIXME: spaces at end of softlines are weird in normal mode */
while (trailing > 0) {
trailing--;
- buffer->cur_index++;
- while (buffer->cur_index < cur_line->len &&
- ((cur_line->text[buffer->cur_index] & 0xC0) == 0x80))
- buffer->cur_index++;
+ new_index++;
+ while (new_index < cur_line->len &&
+ ((cur_line->text[new_index] & 0xC0) == 0x80))
+ new_index++;
}
- if (buffer->cur_index < 0)
- buffer->cur_index = 0;
+ if (new_index < 0)
+ new_index = 0;
/* when in normal mode, the cursor cannot be at the very end
of the line because it's always covering a character */
- if (buffer->cur_index >= cur_line->len) {
- if (state.mode == NORMAL)
- buffer->cur_index = last_index;
- else
- buffer->cur_index = cur_line->len;
+ if (new_index >= cur_line->len) {
+ if (state.mode == NORMAL && (e == NULL || e->motion_cb == NULL)) {
+ new_index = last_index;
+ } else {
+ /* FIXME: I guess this is unnecessary */
+ new_index = cur_line->len;
+ }
}
- ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index);
+ if (e != NULL & e->motion_cb != NULL) {
+ e->motion_cb(buffer->cur_line, new_index, KEY_MOTION_CHAR);
+ } else {
+ buffer->cur_index = new_index;
+ ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index);
+ }
+ clear_key_stack();
}
static void
cursor_left(void) {
- move_cursor(-1);
+ move_cursor_left_right(-1);
}
static void
cursor_right(void) {
- move_cursor(1);
+ move_cursor_left_right(1);
}
static void
@@ -901,48 +971,53 @@ enter_insert(void) {
ledit_wipe_line_cursor_attrs(buffer, buffer->cur_line);
}
+/* FIXME: Check if previous key allows motion command - or is this checked automatically before? */
static void
-cursor_down(void) {
- int lineno, x;
- ledit_line *cur_line = ledit_get_line(buffer, buffer->cur_line);
- ledit_pos_to_x_softline(cur_line, buffer->cur_index, &x, &lineno);
-
- int maxlines = pango_layout_get_line_count(cur_line->layout);
- if (lineno == maxlines - 1) {
- ledit_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- /* move to the next hard line */
- if (buffer->cur_line < buffer->lines_num - 1) {
- buffer->cur_line++;
- cur_line = ledit_get_line(buffer, buffer->cur_line);
- ledit_x_softline_to_pos(cur_line, x, 0, &buffer->cur_index);
+move_cursor_up_down(int dir) {
+ int new_line, new_softline;
+
+ 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 : 0;
+ e = pop_key_stack();
}
+ if (e != NULL)
+ num *= (e->count > 0 ? e->count : 1);
+ }
+ num *= dir;
+
+ get_new_line_softline(
+ buffer->cur_line, buffer->cur_index, num,
+ &new_line, &new_softline
+ );
+
+ ledit_line *cur_lline = ledit_get_line(buffer, buffer->cur_line);
+ ledit_line *new_lline = ledit_get_line(buffer, new_line);
+ if (e != NULL && e->motion_cb != NULL) {
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(new_lline->layout, new_softline);
+ e->motion_cb(new_line, pl->start_index, KEY_MOTION_LINE);
} else {
- /* move to the next soft line */
- ledit_x_softline_to_pos(cur_line, x, lineno + 1, &buffer->cur_index);
+ int lineno, x;
+ ledit_pos_to_x_softline(cur_lline, buffer->cur_index, &x, &lineno);
+ ledit_x_softline_to_pos(new_lline, x, new_softline, &buffer->cur_index);
+ if (buffer->cur_line != new_line)
+ ledit_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ buffer->cur_line = new_line;
+ ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index);
}
- ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index);
+ clear_key_stack();
+}
+
+static void
+cursor_down(void) {
+ move_cursor_up_down(1);
}
static void
cursor_up(void) {
- int lineno, x;
- ledit_line *cur_line = ledit_get_line(buffer, buffer->cur_line);
- ledit_pos_to_x_softline(cur_line, buffer->cur_index, &x, &lineno);
- buffer->trailing = 0;
- if (lineno == 0) {
- ledit_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- /* move to the previous hard line */
- if (buffer->cur_line > 0) {
- buffer->cur_line--;
- cur_line = ledit_get_line(buffer, buffer->cur_line);
- int maxlines = pango_layout_get_line_count(cur_line->layout);
- ledit_x_softline_to_pos(cur_line, x, maxlines - 1, &buffer->cur_index);
- }
- } else {
- /* move to the previous soft line */
- ledit_x_softline_to_pos(cur_line, x, lineno - 1, &buffer->cur_index);
- }
- ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index);
+ move_cursor_up_down(-1);
}
static void