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 174e6af4e28e5dec7b1402de9b15174357898865
parent 593315dc549190dd7ed38194fce885cae741c216
Author: lumidify <nobody@lumidify.org>
Date:   Sat, 24 Apr 2021 19:28:21 +0200

Start implementing more complex commands

Diffstat:
Mbuffer.c | 2++
Mbuffer.h | 2++
Mledit.c | 287+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
3 files changed, 240 insertions(+), 51 deletions(-)

diff --git a/buffer.c b/buffer.c @@ -31,6 +31,8 @@ ledit_create_buffer(ledit_common_state *state) { buffer->cur_line = 0; buffer->cur_index = 0; buffer->trailing = 0; + buffer->trailing_bytes = 0; + buffer->end_of_soft_line = 0; buffer->total_height = 0; buffer->display_offset = 0; ledit_append_line(buffer, -1, -1); diff --git a/buffer.h b/buffer.h @@ -22,6 +22,8 @@ struct ledit_buffer { int cur_index; /* current byte index in line */ int trailing; /* used by pango for determining if index is at * beginning or end of character */ + int trailing_bytes; /* same thing, but with bytes instead of utf8 characters */ + int end_of_soft_line; /* used to handle special behavior at end end of soft line */ long total_height; /* total pixel height of all lines */ double display_offset; /* current pixel offset of viewport - this * is a double to make scrolling smoother */ diff --git a/ledit.c b/ledit.c @@ -1,3 +1,4 @@ +/* FIXME: Use PANGO_PIXELS() */ /* FIXME: Fix cursor movement, especially buffer->trailing and writing at end of line */ /* FIXME: horizontal scrolling (also need cache to avoid too large pixmaps) */ /* FIXME: sort out types for indices (currently just int, but that might overflow) */ @@ -26,16 +27,52 @@ #include "buffer.h" #include "cache.h" +enum key_type { + KEY_NONE = 0, + KEY_MISC = 1, + KEY_CHAR = 2, + KEY_MOTION = 4, + KEY_NUMBER = 8, + KEY_NUMBERALLOWED = 16, + KEY_ANY = 0xFF +}; + struct key { char *text; /* for keys that correspond with text */ KeySym keysym; /* for other keys, e.g. arrow keys */ enum ledit_mode modes; /* modes in which this keybinding is functional */ + enum key_type key_types; /* key types - used to determine if the key is allowed */ void (*func)(void); /* callback function */ }; +struct key_stack_elem { + enum key_type key; /* key type */ + enum key_type followup; /* allowed keys to complete the keybinding */ + void (*func)(void); /* function to call if an allowed key is entered */ + int data1; /* misc. data 1 */ + int data2; /* misc. data 2 */ +}; + +static struct { + size_t len, alloc; + struct key_stack_elem *stack; +} key_stack; + static ledit_common_state state; static ledit_buffer *buffer; +/* TODO: protect against overflow, especially on repeating commands */ + +static struct key_stack_elem *push_key_stack( + enum key_type key, + enum key_type followup, + void (*func)(void), + int data1, int data2 +); +static struct key_stack_elem *peek_key_stack(void); +static struct key_stack_elem *pop_key_stack(void); +void clear_key_stack(void); + static void set_scroll_pos(double pos); static void get_scroll_pos_height(double *pos, double *height); static void resize_window(int w, int h); @@ -54,16 +91,103 @@ static void delete_key(void); static void move_cursor(int dir); static void cursor_left(void); static void cursor_right(void); +static void cursor_down(void); +static void cursor_up(void); +static void cursor_to_beginning(void); static void return_key(void); static void escape_key(void); -static void i_key(void); -static void line_down(void); -static void line_up(void); -static void zero_key(void); +static void enter_insert(void); +static void key_x(void); +static void push_num(int num); +static void push_0(void); +static void push_1(void); +static void push_2(void); +static void push_3(void); +static void push_4(void); +static void push_5(void); +static void push_6(void); +static void push_7(void); +static void push_8(void); +static void push_9(void); static void change_keyboard(char *lang); static void key_press(XEvent event); +static void +key_x(void) { + struct key_stack_elem *e = pop_key_stack(); + int num = 1; + clear_key_stack(); + if (e && !(e->key & KEY_NUMBER)) + return; + if (e) + num = e->data1; + if (num <= 0) + num = 1; + printf("delete %d\n", num); +} + +static void +push_num(int num) { + struct key_stack_elem *e = peek_key_stack(); + if (!e || !(e->key & KEY_NUMBER)) + e = push_key_stack(KEY_NUMBER, KEY_NUMBERALLOWED, NULL, 0, 0); + /* FIXME: error checking */ + e->data1 *= 10; + e->data1 += num; +} + +/* FIXME: CHANGE BEHAVIOR TO MOVEMENT */ +static void +push_0(void) { + push_num(0); +} + +static void +push_1(void) { + push_num(1); +} + +static void +push_2(void) { + push_num(2); +} + +static void +push_3(void) { + push_num(3); +} + +static void +push_4(void) { + push_num(4); +} + +static void +push_5(void) { + push_num(5); +} + +static void +push_6(void) { + push_num(6); +} + +static void +push_7(void) { + push_num(7); +} + +static void +push_8(void) { + push_num(8); +} + +static void +push_9(void) { + push_num(9); +} + int main(int argc, char *argv[]) { setup(argc, argv); @@ -73,6 +197,53 @@ main(int argc, char *argv[]) { return 0; } +static struct key_stack_elem * +push_key_stack( + enum key_type key, + enum key_type followup, + void (*func)(void), + int data1, int data2) { + struct key_stack_elem *e; + if (key_stack.len >= key_stack.alloc) { + size_t new_alloc = key_stack.alloc > 0 ? key_stack.alloc * 2 : 4; + key_stack.stack = ledit_realloc( + key_stack.stack, new_alloc * sizeof(struct key_stack_elem) + ); + key_stack.alloc = new_alloc; + } + e = &key_stack.stack[key_stack.len]; + e->key = key; + e->followup = followup; + e->func = func; + e->data1 = data1; + e->data2 = data2; + key_stack.len++; + return &key_stack.stack[key_stack.len - 1]; +} + +/* Note: for peek and pop, the returned element is only valid + * until the next element is pushed */ +static struct key_stack_elem * +peek_key_stack(void) { + if (key_stack.len > 0) + return &key_stack.stack[key_stack.len - 1]; + return NULL; +} + +static struct key_stack_elem * +pop_key_stack(void) { + if (key_stack.len > 0) { + key_stack.len--; + return &key_stack.stack[key_stack.len]; + } + return NULL; +} + +void +clear_key_stack(void) { + key_stack.len = 0; +} + static void get_scroll_pos_height(double *pos, double *height) { *height = ((double)state.h / buffer->total_height) * state.h; @@ -316,6 +487,10 @@ setup(int argc, char *argv[]) { ledit_init_cache(&state); buffer = ledit_create_buffer(&state); + + key_stack.len = key_stack.alloc = 0; + key_stack.stack = NULL; + redraw(); } @@ -572,17 +747,23 @@ 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) { - int last_index = buffer->cur_index; + /* FIXME: trailing */ + int trailing, last_index = buffer->cur_index; ledit_line *cur_line = ledit_get_line(buffer, buffer->cur_line); pango_layout_move_cursor_visually( cur_line->layout, TRUE, buffer->cur_index, buffer->trailing, dir, &buffer->cur_index, &buffer->trailing ); + /* 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 */ + /* while (buffer->trailing > 0) { buffer->trailing--; buffer->cur_index++; @@ -590,6 +771,7 @@ move_cursor(int dir) { ((cur_line->text[buffer->cur_index] & 0xC0) == 0x80)) buffer->cur_index++; } + */ if (buffer->cur_index < 0) buffer->cur_index = 0; /* when in normal mode, the cursor cannot be at the very end @@ -643,13 +825,13 @@ escape_key(void) { } static void -i_key(void) { +enter_insert(void) { state.mode = INSERT; ledit_wipe_line_cursor_attrs(buffer, buffer->cur_line); } static void -line_down(void) { +cursor_down(void) { int lineno, x, trailing = 0; ledit_line *cur_line = ledit_get_line(buffer, buffer->cur_line); pango_layout_index_to_line_x( @@ -706,7 +888,7 @@ line_down(void) { } static void -line_up(void) { +cursor_up(void) { int lineno, x, trailing = 0; ledit_line *cur_line = ledit_get_line(buffer, buffer->cur_line); pango_layout_index_to_line_x( @@ -767,60 +949,63 @@ line_up(void) { } static void -zero_key(void) { +cursor_to_beginning(void) { buffer->cur_index = 0; ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index); } static struct key keys_en[] = { - {NULL, XK_BackSpace, INSERT, &backspace}, - {NULL, XK_Left, INSERT|NORMAL, &cursor_left}, - {NULL, XK_Right, INSERT|NORMAL, &cursor_right}, - {NULL, XK_Up, INSERT|NORMAL, &line_up}, - {NULL, XK_Down, INSERT|NORMAL, &line_down}, - {NULL, XK_Return, INSERT, &return_key}, - {NULL, XK_Delete, INSERT, &delete_key}, - {NULL, XK_Escape, INSERT, &escape_key}, - {"i", 0, NORMAL, &i_key}, - {"h", 0, NORMAL, &cursor_left}, - {"l", 0, NORMAL, &cursor_right}, - {"j", 0, NORMAL, &line_down}, - {"k", 0, NORMAL, &line_up}, - {"0", 0, NORMAL, &zero_key} + {NULL, XK_BackSpace, INSERT, KEY_ANY, &backspace}, + {NULL, XK_Left, INSERT|NORMAL, KEY_ANY, &cursor_left}, + {NULL, XK_Right, INSERT|NORMAL, KEY_ANY, &cursor_right}, + {NULL, XK_Up, INSERT|NORMAL, KEY_ANY, &cursor_up}, + {NULL, XK_Down, INSERT|NORMAL, KEY_ANY, &cursor_down}, + {NULL, XK_Return, INSERT, KEY_ANY, &return_key}, + {NULL, XK_Delete, INSERT, KEY_ANY, &delete_key}, + {NULL, XK_Escape, INSERT, KEY_ANY, &escape_key}, + {"i", 0, NORMAL, KEY_ANY, &enter_insert}, + {"h", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left}, + {"l", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right}, + {"j", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down}, + {"k", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up}, + {"0", 0, NORMAL, KEY_ANY, &cursor_to_beginning}, + {"1", 0, NORMAL, KEY_NUMBER, &push_1}, + {"2", 0, NORMAL, KEY_NUMBER, &push_2}, + {"x", 0, NORMAL, KEY_NUMBERALLOWED, &key_x} }; static struct key keys_ur[] = { - {NULL, XK_BackSpace, INSERT, &backspace}, - {NULL, XK_Left, INSERT|NORMAL, &cursor_left}, - {NULL, XK_Right, INSERT|NORMAL, &cursor_right}, - {NULL, XK_Up, INSERT|NORMAL, &line_up}, - {NULL, XK_Down, INSERT|NORMAL, &line_down}, - {NULL, XK_Return, INSERT, &return_key}, - {NULL, XK_Delete, INSERT, &delete_key}, - {NULL, XK_Escape, INSERT, &escape_key}, - {"ی", 0, NORMAL, &i_key}, - {"ح", 0, NORMAL, &cursor_left}, - {"ل", 0, NORMAL, &cursor_right}, - {"ج", 0, NORMAL, &line_down}, - {"ک", 0, NORMAL, &line_up}, - {"0", 0, NORMAL, &zero_key} + {NULL, XK_BackSpace, INSERT, KEY_ANY, &backspace}, + {NULL, XK_Left, INSERT|NORMAL, KEY_ANY, &cursor_left}, + {NULL, XK_Right, INSERT|NORMAL, KEY_ANY, &cursor_right}, + {NULL, XK_Up, INSERT|NORMAL, KEY_ANY, &cursor_up}, + {NULL, XK_Down, INSERT|NORMAL, KEY_ANY, &cursor_down}, + {NULL, XK_Return, INSERT, KEY_ANY, &return_key}, + {NULL, XK_Delete, INSERT, KEY_ANY, &delete_key}, + {NULL, XK_Escape, INSERT, KEY_ANY, &escape_key}, + {"ی", 0, NORMAL, KEY_ANY, &enter_insert}, + {"ح", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left}, + {"ل", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right}, + {"ج", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down}, + {"ک", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up}, + {"0", 0, NORMAL, KEY_ANY, &cursor_to_beginning} }; static struct key keys_hi[] = { - {NULL, XK_BackSpace, INSERT, &backspace}, - {NULL, XK_Left, INSERT|NORMAL, &cursor_left}, - {NULL, XK_Right, INSERT|NORMAL, &cursor_right}, - {NULL, XK_Up, INSERT|NORMAL, &line_up}, - {NULL, XK_Down, INSERT|NORMAL, &line_down}, - {NULL, XK_Return, INSERT, &return_key}, - {NULL, XK_Delete, INSERT, &delete_key}, - {NULL, XK_Escape, INSERT, &escape_key}, - {"ि", 0, NORMAL, &i_key}, - {"ह", 0, NORMAL, &cursor_left}, - {"ल", 0, NORMAL, &cursor_right}, - {"ज", 0, NORMAL, &line_down}, - {"क", 0, NORMAL, &line_up}, - {"0", 0, NORMAL, &zero_key} + {NULL, XK_BackSpace, INSERT, KEY_ANY, &backspace}, + {NULL, XK_Left, INSERT|NORMAL, KEY_ANY, &cursor_left}, + {NULL, XK_Right, INSERT|NORMAL, KEY_ANY, &cursor_right}, + {NULL, XK_Up, INSERT|NORMAL, KEY_ANY, &cursor_up}, + {NULL, XK_Down, INSERT|NORMAL, KEY_ANY, &cursor_down}, + {NULL, XK_Return, INSERT, KEY_ANY, &return_key}, + {NULL, XK_Delete, INSERT, KEY_ANY, &delete_key}, + {NULL, XK_Escape, INSERT, KEY_ANY, &escape_key}, + {"ि", 0, NORMAL, KEY_ANY, &enter_insert}, + {"ह", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left}, + {"ल", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right}, + {"ज", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down}, + {"क", 0, NORMAL, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up}, + {"0", 0, NORMAL, KEY_ANY, &cursor_to_beginning} }; #define LENGTH(X) (sizeof(X) / sizeof(X[0]))