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 1619b579fa72a45217ceeab062cd5dc6c9961a37
parent bf406bf2c7ad5025890a061780823576b65a67d7
Author: lumidify <nobody@lumidify.org>
Date:   Fri, 29 Oct 2021 21:03:27 +0200

Add Ctrl-f and Ctrl-b for scrolling whole screens at a time

Diffstat:
Mbuffer.c | 33++++++++++++++++++++++-----------
Mbuffer.h | 6+++++-
Mkeys_basic.c | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mkeys_basic_config.h | 4++++
Mwindow.c | 2++
5 files changed, 107 insertions(+), 12 deletions(-)

diff --git a/buffer.c b/buffer.c @@ -1363,16 +1363,25 @@ ledit_buffer_resize_textview(ledit_buffer *buffer) { } ledit_window_set_scroll_max(buffer->window, buffer->total_height); if (buffer->display_offset > 0 && - buffer->display_offset + text_h >= buffer->total_height) { - buffer->display_offset = buffer->total_height - text_h; - if (buffer->display_offset < 0) - buffer->display_offset = 0; - ledit_window_set_scroll_pos(buffer->window, buffer->display_offset); + buffer->display_offset + text_h > buffer->total_height) { + ledit_buffer_scroll(buffer, buffer->total_height - text_h); } } void -ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int *line_ret, int *byte_ret) { +ledit_buffer_scroll(ledit_buffer *buffer, long new_offset) { + int text_w, text_h; + ledit_window_get_textview_size(buffer->window, &text_w, &text_h); + if (new_offset + text_h > buffer->total_height) + new_offset = buffer->total_height - text_h; + if (new_offset < 0) + new_offset = 0; + buffer->display_offset = new_offset; + ledit_window_set_scroll_pos(buffer->window, buffer->display_offset); +} + +void +ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int snap_to_nearest, int *line_ret, int *byte_ret) { /* FIXME: store current line offset to speed this up */ /* FIXME: use y_offset in lines */ long h = 0; @@ -1386,9 +1395,11 @@ ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int *line_ret, int *by x * PANGO_SCALE, (int)(pos - h) * PANGO_SCALE, &index, &trailing ); - while (trailing > 0) { - trailing--; - index = ledit_line_next_utf8(line, index); + if (snap_to_nearest) { + while (trailing > 0) { + trailing--; + index = ledit_line_next_utf8(line, index); + } } *line_ret = i; *byte_ret = index; @@ -1509,7 +1520,7 @@ ledit_buffer_button_handler(void *data, XEvent *event) { int y = event->xbutton.y; switch (event->type) { case ButtonPress: - ledit_xy_to_line_byte(buffer, x, y, &l, &b); + ledit_xy_to_line_byte(buffer, x, y, 1, &l, &b); ledit_buffer_set_selection(buffer, l, b, l, b); if (buffer->common->mode == NORMAL) { ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); @@ -1528,7 +1539,7 @@ ledit_buffer_button_handler(void *data, XEvent *event) { case MotionNotify: if (buffer->selecting) { y = y >= 0 ? y : 0; - ledit_xy_to_line_byte(buffer, x, y, &l, &b); + ledit_xy_to_line_byte(buffer, x, y, 1, &l, &b); ledit_buffer_set_selection(buffer, buffer->sel.line1, buffer->sel.byte1, l, b); buffer->cur_line = l; buffer->cur_index = b; diff --git a/buffer.h b/buffer.h @@ -128,7 +128,10 @@ void ledit_buffer_insert_text_from_line( ); void ledit_buffer_resize_width(ledit_buffer *buffer, int width); -void ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int *line_ret, int *byte_ret); +/* x and y are in pixels, if snap_to_nearest is nonzero, the returned byte + is at the nearest grapheme boundary, if it is zero, the byte is always + the beginning of the grapheme under the position */ +void ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int snap_to_nearest, int *line_ret, int *byte_ret); void ledit_buffer_ensure_cursor_shown(ledit_buffer *buffer); void ledit_buffer_scroll_handler(void *buffer, long pos); void ledit_buffer_button_handler(void *data, XEvent *event); @@ -140,3 +143,4 @@ void ledit_buffer_set_mode(ledit_buffer *buffer, enum ledit_mode mode); void ledit_buffer_paste_clipboard(ledit_buffer *buffer); void ledit_buffer_paste_primary(ledit_buffer *buffer); void ledit_buffer_resize_textview(ledit_buffer *buffer); +void ledit_buffer_scroll(ledit_buffer *buffer, long new_offset); diff --git a/keys_basic.c b/keys_basic.c @@ -343,6 +343,79 @@ delete_selection(ledit_buffer *buffer) { return 0; } +/* get the number of times a command should be repeated, or -1 if anything + invalid was on the stack - this is for commands that just take a repeat + count and nothin else (cursor movement keys are different because they + can use other elements on the key stack to, for instance, call a callback + as is done for deletion */ +static int +get_key_repeat(void) { + int num = 1; + struct key_stack_elem *e = pop_key_stack(); + if (e != NULL) { + if (e->key & KEY_NUMBER) { + /* FIXME: why did I do this? */ + num = e->count > 0 ? e->count : 0; + e = pop_key_stack(); + } + if (e != NULL) { + /* the key was not a number, or there was another + element under it on the stack -> error */ + num = -1; + } + } + clear_key_stack(); + return num; +} + +/* movement is multiplied to the window height and added to the display offset + the cursor is moved to the top if movement is upwards, to the bottom otherwise */ +static void +move_screen(ledit_buffer *buffer, int movement) { + int w, h; + ledit_window_get_textview_size(buffer->window, &w, &h); + long total = movement * (long)h; + ledit_buffer_scroll(buffer, buffer->display_offset + total); + ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); + /* try to keep current x position of cursor */ + ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line); + int x, softline; + /* FIXME: properly document what uses PANGO_SCALE and what not */ + ledit_pos_to_x_softline(ll, buffer->cur_index, &x, &softline); + /* if movement is up, move cursor to top, else to bottom of current screen */ + ledit_xy_to_line_byte( + buffer, x / PANGO_SCALE, movement < 0 ? 0 : h, 0, + &buffer->cur_line, &buffer->cur_index + ); + ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index); +} + +static struct action +screen_up(ledit_buffer *buffer, char *text, int len) { + (void)text; + (void)len; + int repeat = get_key_repeat(); + if (repeat >= 0) + move_screen(buffer, -repeat); + else + ledit_window_show_message(buffer->window, "Invalid key", -1); + discard_repetition_stack(); + return (struct action){ACTION_NONE, NULL}; +} + +static struct action +screen_down(ledit_buffer *buffer, char *text, int len) { + (void)text; + (void)len; + int repeat = get_key_repeat(); + if (repeat >= 0) + move_screen(buffer, repeat); + else + ledit_window_show_message(buffer->window, "Invalid key", -1); + discard_repetition_stack(); + return (struct action){ACTION_NONE, NULL}; +} + static struct action key_d(ledit_buffer *buffer, char *text, int len) { (void)text; @@ -665,6 +738,7 @@ return_key(ledit_buffer *buffer, char *text, int len) { return (struct action){ACTION_NONE, NULL}; } +/* FIXME: Is this illegal due to different licenses? */ /* FIXME: Check earliest version of other used functions to get minimum pango version for ledit as a whole */ /* FIXME: This is just copied from the newer version of pango. It *seems* like diff --git a/keys_basic_config.h b/keys_basic_config.h @@ -57,6 +57,8 @@ static struct action undo(ledit_buffer *buffer, char *text, int len); static struct action redo(ledit_buffer *buffer, char *text, int len); static struct action insert_mode_insert_text(ledit_buffer *buffer, char *text, int len); static struct action repeat_command(ledit_buffer *buffer, char *text, int len); +static struct action screen_up(ledit_buffer *buffer, char *text, int len); +static struct action screen_down(ledit_buffer *buffer, char *text, int len); /* FIXME: maybe sort these and use binary search -> but that would mess with the catch-all keys */ @@ -102,6 +104,8 @@ static struct key keys_en[] = { {".", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &repeat_command}, /* FIXME: only allow after finished key sequence */ {"z", ControlMask, 0, INSERT, KEY_ANY, KEY_ANY, &undo}, {"y", ControlMask, 0, INSERT, KEY_ANY, KEY_ANY, &redo}, + {"b", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &screen_up}, + {"f", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &screen_down}, {"", 0, 0, INSERT, KEY_ANY, KEY_ANY, &insert_mode_insert_text} }; diff --git a/window.c b/window.c @@ -415,6 +415,8 @@ ledit_window_create(ledit_common *common, ledit_theme *theme) { void ledit_window_destroy(ledit_window *window) { /* FIXME: cleanup everything else */ + /* FIXME: This doesn't seem to be correct - g_object_unref sometimes + causes segfault */ pango_font_description_free(window->font); g_object_unref(window->fontmap); g_object_unref(window->context);