commit 174e6af4e28e5dec7b1402de9b15174357898865
parent 593315dc549190dd7ed38194fce885cae741c216
Author: lumidify <nobody@lumidify.org>
Date: Sat, 24 Apr 2021 19:28:21 +0200
Start implementing more complex commands
Diffstat:
M | buffer.c | | | 2 | ++ |
M | buffer.h | | | 2 | ++ |
M | ledit.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]))