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 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:
Mbuffer.c | 12+++++++++---
Mledit.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