commit 52cea73bf0e43483210cb94e5177989bc524a30c
parent 174e6af4e28e5dec7b1402de9b15174357898865
Author: lumidify <nobody@lumidify.org>
Date: Wed, 12 May 2021 21:47:17 +0200
Add initial support for deletion
Diffstat:
M | buffer.c | | | 275 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
M | buffer.h | | | 10 | ++++++++++ |
M | ledit.c | | | 342 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
3 files changed, 452 insertions(+), 175 deletions(-)
diff --git a/buffer.c b/buffer.c
@@ -138,8 +138,9 @@ init_line(ledit_buffer *buffer, ledit_line *line) {
line->parent_buffer = buffer;
line->layout = pango_layout_new(buffer->state->context);
pango_layout_set_width(line->layout, (buffer->state->w - 10) * PANGO_SCALE);
- pango_layout_set_font_description(line->layout, buffer->state->font);
- pango_layout_set_wrap(line->layout, PANGO_WRAP_WORD_CHAR);
+ pango_layout_set_font_description(line->layout, buffer->state->font);
+ pango_layout_set_wrap(line->layout, PANGO_WRAP_WORD_CHAR);
+ pango_layout_set_attributes(line->layout, basic_attrs);
line->text = NULL;
line->cap = line->len = 0;
line->cache_index = -1;
@@ -185,18 +186,27 @@ ledit_append_line(ledit_buffer *buffer, int line_index, int text_index) {
}
void
-ledit_delete_line_entry(ledit_buffer *buffer, int index) {
- g_object_unref(buffer->lines[index].layout);
- free(buffer->lines[index].text);
- if (index < buffer->lines_num - 1)
+ledit_delete_line_entries(ledit_buffer *buffer, int index1, int index2) {
+ for (int i = index1; i <= index2; i++) {
+ g_object_unref(buffer->lines[i].layout);
+ free(buffer->lines[i].text);
+ }
+ if (index2 < buffer->lines_num - 1) {
memmove(
- buffer->lines + index, buffer->lines + index + 1,
- (buffer->lines_num - index - 1) * sizeof(ledit_line)
+ buffer->lines + index1, buffer->lines + index2 + 1,
+ (buffer->lines_num - index2 - 1) * sizeof(ledit_line)
);
- buffer->lines_num--;
+ }
+ buffer->lines_num -= index2 - index1 + 1;
+ /* FIXME: avoid this by just subtracting the heights */
recalc_line_size_absolute(buffer);
}
+void
+ledit_delete_line_entry(ledit_buffer *buffer, int index) {
+ ledit_delete_line_entries(buffer, index, index);
+}
+
/* FIXME: use some sort of gap buffer (that would make this function
slightly more useful...) */
ledit_line *
@@ -270,3 +280,250 @@ ledit_delete_unicode_char(ledit_buffer *buffer, int line_index, int byte_index,
recalc_single_line_size(buffer, line_index);
return new_index;
}
+
+static void
+delete_line_section(ledit_buffer *buffer, int line, int start, int length) {
+ ledit_line *l = &buffer->lines[line];
+ memmove(l->text + start, l->text + start + length, l->len - start - length);
+ l->len -= length;
+ pango_layout_set_text(l->layout, l->text, l->len);
+ recalc_single_line_size(buffer, line);
+ l->dirty = 1;
+}
+
+void
+ledit_pos_to_x_softline(ledit_line *line, int pos, int *x_ret, int *softline_ret) {
+ pango_layout_index_to_line_x(line->layout, pos, 0, softline_ret, x_ret);
+ /* FIXME: do these lines need to be unref'd? */
+ PangoLayoutLine *pango_line = pango_layout_get_line_readonly(line->layout, *softline_ret);
+ /* add left margin to x position if line is aligned right */
+ if (pango_line->resolved_dir == PANGO_DIRECTION_RTL) {
+ PangoRectangle rect;
+ pango_layout_line_get_extents(pango_line, NULL, &rect);
+ *x_ret += (line->w * PANGO_SCALE - rect.width);
+ }
+ /* if in normal mode, change position to the middle of the
+ current rectangle so that moving around won't jump weirdly */
+ /* FIXME: also in visual? */
+ if (line->parent_buffer->state->mode == NORMAL) {
+ PangoRectangle rect;
+ pango_layout_index_to_pos(line->layout, pos, &rect);
+ *x_ret += rect.width / 2;
+ }
+}
+
+/* FIXME: change this to return int */
+void
+ledit_x_softline_to_pos(ledit_line *line, int x, int softline, int *pos_ret) {
+ int trailing = 0;
+ int x_relative = x;
+ PangoLayoutLine *pango_line =
+ pango_layout_get_line_readonly(line->layout, softline);
+ /* x is absolute, so the margin at the left needs to be subtracted */
+ if (pango_line->resolved_dir == PANGO_DIRECTION_RTL) {
+ PangoRectangle rect;
+ pango_layout_line_get_extents(pango_line, NULL, &rect);
+ x_relative -= (line->w * PANGO_SCALE - rect.width);
+ }
+ pango_layout_line_x_to_index(
+ pango_line, x_relative, pos_ret, &trailing
+ );
+ /* if in insert mode, snap to the nearest border between graphemes */
+ if (line->parent_buffer->state->mode == INSERT) {
+ while (trailing > 0) {
+ trailing--;
+ (*pos_ret)++;
+ /* utf8 stuff */
+ while (*pos_ret < line->len &&
+ ((line->text[*pos_ret] & 0xC0) == 0x80))
+ (*pos_ret)++;
+ }
+ }
+}
+
+/* FIXME: cursor jumps weirdly */
+/* FIXME: use at least somewhat sensible variable names */
+void
+ledit_delete_range(
+ ledit_buffer *buffer, int line_based,
+ int line_index1, int byte_index1,
+ int line_index2, int byte_index2,
+ int *new_line_ret, int *new_byte_ret) {
+ if (line_based) {
+ int x, softline1, softline2;
+ ledit_line *line1 = ledit_get_line(buffer, line_index1);
+ ledit_pos_to_x_softline(line1, byte_index1, &x, &softline1);
+ if (line_index1 == line_index2) {
+ int x_useless;
+ pango_layout_index_to_line_x(line1->layout, byte_index2, 0, &softline2, &x_useless);
+ int l1 = softline1 < softline2 ? softline1 : softline2;
+ int l2 = softline1 < softline2 ? softline2 : softline1;
+ int softlines = pango_layout_get_line_count(line1->layout);
+ PangoLayoutLine *pl1 = pango_layout_get_line_readonly(line1->layout, l1);
+ PangoLayoutLine *pl2 = pango_layout_get_line_readonly(line1->layout, l2);
+ /* don't delete entire line of it is the last one remaining */
+ if (l1 == 0 && l2 == softlines - 1 && buffer->lines_num > 1) {
+ ledit_delete_line_entry(buffer, line_index1);
+ /* note: line_index1 is now the index of the next
+ line since the current one was just deleted */
+ if (line_index1 < buffer->lines_num) {
+ *new_line_ret = line_index1;
+ ledit_x_softline_to_pos(
+ ledit_get_line(buffer, line_index1),
+ x, 0, new_byte_ret
+ );
+ } else {
+ /* note: logically, this must be >= 0 because
+ buffer->lines_num > 1 && line_index1 >= buffer->lines_num */
+ *new_line_ret = line_index1 - 1;
+ ledit_line *prevline = ledit_get_line(buffer, line_index1 - 1);
+ softlines = pango_layout_get_line_count(prevline->layout);
+ ledit_x_softline_to_pos(prevline, x, softlines - 1, new_byte_ret);
+ }
+ } else {
+ /* FIXME: sanity checks that the length is actually positive, etc. */
+ delete_line_section(
+ buffer, line_index1, pl1->start_index,
+ pl2->start_index + pl2->length - pl1->start_index
+ );
+ if (l2 == softlines - 1 && line_index1 < buffer->lines_num - 1) {
+ *new_line_ret = line_index1 + 1;
+ ledit_x_softline_to_pos(
+ ledit_get_line(buffer, line_index1 + 1),
+ x, 0, new_byte_ret
+ );
+ } else if (l2 < softlines - 1) {
+ *new_line_ret = line_index1;
+ ledit_x_softline_to_pos(
+ ledit_get_line(buffer, line_index1),
+ x, l1, new_byte_ret
+ );
+ } else if (l1 > 0) {
+ *new_line_ret = line_index1;
+ ledit_x_softline_to_pos(
+ ledit_get_line(buffer, line_index1),
+ x, l1 - 1, new_byte_ret
+ );
+ } else {
+ /* the line has been emptied and is the last line remaining */
+ *new_line_ret = 0;
+ *new_byte_ret = 0;
+ }
+ }
+ } else {
+ int x_useless, sl1, sl2;
+ int l1, l2, b1, b2;
+ if (line_index1 < line_index2) {
+ l1 = line_index1;
+ b1 = byte_index1;
+ l2 = line_index2;
+ b2 = byte_index2;
+ } else {
+ l1 = line_index2;
+ b1 = byte_index2;
+ l2 = line_index1;
+ b2 = byte_index1;
+ }
+ ledit_line *ll1 = ledit_get_line(buffer, l1);
+ ledit_line *ll2 = ledit_get_line(buffer, l2);
+ pango_layout_index_to_line_x(ll1->layout, b1, 0, &sl1, &x_useless);
+ pango_layout_index_to_line_x(ll2->layout, b2, 0, &sl2, &x_useless);
+ PangoLayoutLine *pl1 = pango_layout_get_line_readonly(ll1->layout, sl1);
+ PangoLayoutLine *pl2 = pango_layout_get_line_readonly(ll2->layout, sl2);
+ int softlines = pango_layout_get_line_count(ll2->layout);
+ if (sl1 == 0 && sl2 == softlines - 1) {
+ if (l1 == 0 && l2 == buffer->lines_num - 1) {
+ delete_line_section(buffer, l1, 0, ll1->len);
+ ledit_delete_line_entries(buffer, l1 + 1, l2);
+ *new_line_ret = 0;
+ *new_byte_ret = 0;
+ } else {
+ ledit_delete_line_entries(buffer, l1, l2);
+ if (l1 >= buffer->lines_num) {
+ *new_line_ret = buffer->lines_num - 1;
+ ledit_line *new_lline = ledit_get_line(buffer, *new_line_ret);
+ int new_softlines = pango_layout_get_line_count(new_lline->layout);
+ ledit_x_softline_to_pos(new_lline, x, new_softlines - 1, new_byte_ret);
+ } else {
+ *new_line_ret = l1;
+ ledit_x_softline_to_pos(
+ ledit_get_line(buffer, l1),
+ x, 0, new_byte_ret
+ );
+ }
+ }
+ } else if (sl1 == 0) {
+ delete_line_section(buffer, l2, 0, pl2->start_index + pl2->length);
+ ledit_delete_line_entries(buffer, l1, l2 - 1);
+ *new_line_ret = l1;
+ ledit_x_softline_to_pos(ledit_get_line(buffer, l1), x, 0, new_byte_ret);
+ } else if (sl2 == softlines - 1) {
+ delete_line_section(buffer, l1, pl1->start_index, ll1->len - pl1->start_index);
+ ledit_delete_line_entries(buffer, l1 + 1, l2);
+ if (l1 + 1 >= buffer->lines_num) {
+ *new_line_ret = buffer->lines_num - 1;
+ ledit_line *new_lline = ledit_get_line(buffer, *new_line_ret);
+ int new_softlines = pango_layout_get_line_count(new_lline->layout);
+ ledit_x_softline_to_pos(new_lline, x, new_softlines - 1, new_byte_ret);
+ } else {
+ *new_line_ret = l1 + 1;
+ ledit_x_softline_to_pos(
+ ledit_get_line(buffer, l1 + 1),
+ x, 0, new_byte_ret
+ );
+ }
+ } else {
+ /* FIXME: should this join the two lines? */
+ delete_line_section(buffer, l1, pl1->start_index, ll1->len - pl1->start_index);
+ delete_line_section(buffer, l2, 0, pl2->start_index + pl2->length);
+ if (l2 > l1 + 1)
+ ledit_delete_line_entries(buffer, l1 + 1, l2 - 1);
+ *new_line_ret = l1 + 1;
+ ledit_x_softline_to_pos(ledit_get_line(buffer, l1 + 1), x, 0, new_byte_ret);
+ }
+ }
+ } else {
+ if (line_index1 == line_index2) {
+ int b1, b2;
+ if (byte_index1 < byte_index2) {
+ b1 = byte_index1;
+ b2 = byte_index2;
+ } else {
+ b1 = byte_index2;
+ b2 = byte_index1;
+ }
+ delete_line_section(buffer, line_index1, b1, b2 - b1);
+ *new_line_ret = line_index1;
+ *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) {
+ l1 = line_index1;
+ b1 = byte_index1;
+ l2 = line_index2;
+ b2 = byte_index2;
+ } else {
+ l1 = line_index2;
+ b1 = byte_index2;
+ l2 = line_index1;
+ b2 = byte_index1;
+ }
+ ledit_line *line1 = ledit_get_line(buffer, l1);
+ ledit_line *line2 = ledit_get_line(buffer, l2);
+ line1->len = b1;
+ if (b2 > 0) {
+ ledit_insert_text(
+ buffer, l1, b1,
+ line2->text + b2,
+ line2->len - b2
+ );
+ }
+ *new_line_ret = l1;
+ *new_byte_ret = b1;
+ ledit_delete_line_entries(buffer, l1 + 1, l2);
+ }
+ }
+}
diff --git a/buffer.h b/buffer.h
@@ -1,5 +1,6 @@
typedef struct ledit_buffer ledit_buffer;
+/* FIXME: size_t for len, etc. */
typedef struct {
PangoLayout *layout;
char *text;
@@ -36,7 +37,16 @@ void ledit_wipe_line_cursor_attrs(ledit_buffer *buffer, int line);
void ledit_insert_text(ledit_buffer *buffer, int line_index, int index, char *text, int len);
void ledit_render_line(ledit_buffer *buffer, int line_index);
void ledit_append_line(ledit_buffer *buffer, int line_index, int text_index);
+void ledit_delete_line_entries(ledit_buffer *buffer, int index1, int index2);
void ledit_delete_line_entry(ledit_buffer *buffer, int index);
ledit_line *ledit_get_line(ledit_buffer *buffer, int index);
int ledit_line_visible(ledit_buffer *buffer, int index);
int ledit_delete_unicode_char(ledit_buffer *buffer, int line_index, int byte_index, int dir);
+void ledit_delete_range(
+ ledit_buffer *buffer, int line_based,
+ int line_index1, int byte_index1,
+ int line_index2, int byte_index2,
+ int *new_line_ret, int *new_byte_ret
+);
+void ledit_pos_to_x_softline(ledit_line *line, int pos, int *x_ret, int *softline_ret);
+void ledit_x_softline_to_pos(ledit_line *line, int x, int softline, int *pos_ret);
diff --git a/ledit.c b/ledit.c
@@ -31,24 +31,32 @@ enum key_type {
KEY_NONE = 0,
KEY_MISC = 1,
KEY_CHAR = 2,
- KEY_MOTION = 4,
- KEY_NUMBER = 8,
- KEY_NUMBERALLOWED = 16,
+ KEY_MOTION_CHAR = 4,
+ KEY_MOTION_LINE = 8,
+ KEY_MOTION = 4|8,
+ KEY_NUMBER = 16,
+ KEY_NUMBERALLOWED = 32,
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 */
+ 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 prev_keys; /* allowed previous keys */
enum key_type key_types; /* key types - used to determine if the key is allowed */
- void (*func)(void); /* callback function */
+ void (*func)(void); /* callback function */
};
struct key_stack_elem {
- enum key_type key; /* key type */
+ enum key_type key;
enum key_type followup; /* allowed keys to complete the keybinding */
- void (*func)(void); /* function to call if an allowed key is entered */
+ /* callback function that motion commands call to complete a command -
+ * line and char_pos already include the repetition stored in this stack
+ * element; type is the type of motion command (used to determine if
+ * the command should operate on lines or chars) */
+ void (*motion_cb)(int line, int char_pos, enum key_type type);
+ int count; /* number of repetitions */
int data1; /* misc. data 1 */
int data2; /* misc. data 2 */
};
@@ -63,12 +71,7 @@ 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 *push_key_stack(void);
static struct key_stack_elem *peek_key_stack(void);
static struct key_stack_elem *pop_key_stack(void);
void clear_key_stack(void);
@@ -109,11 +112,81 @@ static void push_6(void);
static void push_7(void);
static void push_8(void);
static void push_9(void);
+static void key_d(void);
+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
+key_d(void) {
+ int num = 0;
+ struct key_stack_elem *e = pop_key_stack();
+ if (e != NULL) {
+ if (e->key & KEY_NUMBER) {
+ num = e->count;
+ e = pop_key_stack();
+ }
+ /* FIXME: checking equality of the function pointer may be a bit risky */
+ if (e != NULL && e->motion_cb == &key_d_cb) {
+ 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);
+ }
+ clear_key_stack();
+ } else if (e != NULL) {
+ clear_key_stack();
+ }
+ }
+ if (e == NULL) {
+ e = push_key_stack();
+ e->key = KEY_MOTION; /* ? */
+ e->count = num;
+ e->motion_cb = &key_d_cb;
+ }
+}
+
+/* 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,
+ buffer->cur_line, buffer->cur_index,
+ line, char_pos,
+ &buffer->cur_line, &buffer->cur_index
+ );
+ ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index);
+}
+
+static void
key_x(void) {
struct key_stack_elem *e = pop_key_stack();
int num = 1;
@@ -121,7 +194,7 @@ key_x(void) {
if (e && !(e->key & KEY_NUMBER))
return;
if (e)
- num = e->data1;
+ num = e->count;
if (num <= 0)
num = 1;
printf("delete %d\n", num);
@@ -130,14 +203,16 @@ key_x(void) {
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);
+ if (!e || !(e->key & KEY_NUMBER)) {
+ e = push_key_stack();
+ e->key = KEY_NUMBER;
+ e->followup = KEY_NUMBER|KEY_NUMBERALLOWED;
+ }
/* FIXME: error checking */
- e->data1 *= 10;
- e->data1 += num;
+ e->count *= 10;
+ e->count += num;
}
-/* FIXME: CHANGE BEHAVIOR TO MOVEMENT */
static void
push_0(void) {
push_num(0);
@@ -198,11 +273,7 @@ main(int argc, char *argv[]) {
}
static struct key_stack_elem *
-push_key_stack(
- enum key_type key,
- enum key_type followup,
- void (*func)(void),
- int data1, int data2) {
+push_key_stack(void) {
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;
@@ -212,11 +283,12 @@ push_key_stack(
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;
+ e->key = KEY_NONE;
+ e->followup = KEY_NONE;
+ e->motion_cb = NULL;
+ e->count = 0;
+ e->data1 = 0;
+ e->data2 = 0;
key_stack.len++;
return &key_stack.stack[key_stack.len - 1];
}
@@ -757,21 +829,20 @@ move_cursor(int dir) {
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
+ buffer->cur_index, 0, dir,
+ &buffer->cur_index, &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--;
+ /* 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++;
}
- */
if (buffer->cur_index < 0)
buffer->cur_index = 0;
/* when in normal mode, the cursor cannot be at the very end
@@ -832,23 +903,10 @@ enter_insert(void) {
static void
cursor_down(void) {
- int lineno, x, trailing = 0;
+ int lineno, x;
ledit_line *cur_line = ledit_get_line(buffer, buffer->cur_line);
- pango_layout_index_to_line_x(
- cur_line->layout, buffer->cur_index, 0, &lineno, &x
- );
- PangoLayoutLine *cur_pango_line =
- pango_layout_get_line_readonly(cur_line->layout, lineno);
- if (cur_pango_line->resolved_dir == PANGO_DIRECTION_RTL) {
- PangoRectangle rect;
- pango_layout_line_get_extents(cur_pango_line, NULL, &rect);
- x += (cur_line->w * PANGO_SCALE - rect.width);
- }
- if (state.mode == NORMAL) {
- PangoRectangle pos;
- pango_layout_index_to_pos(cur_line->layout, buffer->cur_index, &pos);
- x += pos.width / 2;
- }
+ 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);
@@ -856,59 +914,21 @@ cursor_down(void) {
if (buffer->cur_line < buffer->lines_num - 1) {
buffer->cur_line++;
cur_line = ledit_get_line(buffer, buffer->cur_line);
- PangoLayoutLine *nextline =
- pango_layout_get_line_readonly(cur_line->layout, 0);
- if (nextline->resolved_dir == PANGO_DIRECTION_RTL) {
- PangoRectangle rect;
- pango_layout_line_get_extents(nextline, NULL, &rect);
- x -= (cur_line->w * PANGO_SCALE - rect.width);
- }
- pango_layout_line_x_to_index(
- nextline, x, &buffer->cur_index, &trailing
- );
- if (state.mode == INSERT)
- buffer->cur_index += trailing;
+ ledit_x_softline_to_pos(cur_line, x, 0, &buffer->cur_index);
}
} else {
/* move to the next soft line */
- PangoLayoutLine *nextline =
- pango_layout_get_line_readonly(cur_line->layout, lineno + 1);
- if (nextline->resolved_dir == PANGO_DIRECTION_RTL) {
- PangoRectangle rect;
- pango_layout_line_get_extents(nextline, NULL, &rect);
- x -= (cur_line->w * PANGO_SCALE - rect.width);
- }
- pango_layout_line_x_to_index(
- nextline, x, &buffer->cur_index, &trailing
- );
- if (state.mode == INSERT)
- buffer->cur_index += trailing;
+ 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);
}
static void
cursor_up(void) {
- int lineno, x, trailing = 0;
+ int lineno, x;
ledit_line *cur_line = ledit_get_line(buffer, buffer->cur_line);
- pango_layout_index_to_line_x(
- cur_line->layout, buffer->cur_index, 0, &lineno, &x
- );
- PangoLayoutLine *cur_pango_line =
- pango_layout_get_line_readonly(cur_line->layout, lineno);
- /* FIXME: do these lines need to be unref'd? */
- if (cur_pango_line->resolved_dir == PANGO_DIRECTION_RTL) {
- PangoRectangle rect;
- pango_layout_line_get_extents(cur_pango_line, NULL, &rect);
- /* FIXME: don't store w in each line because it is now the same for all */
- x += (cur_line->w * PANGO_SCALE - rect.width);
- }
- if (state.mode == NORMAL) {
- PangoRectangle pos;
- pango_layout_index_to_pos(cur_line->layout, buffer->cur_index, &pos);
- x += pos.width / 2;
- }
- /* FIXME: clean this up (if and else are very similar) */
+ 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 */
@@ -916,34 +936,11 @@ cursor_up(void) {
buffer->cur_line--;
cur_line = ledit_get_line(buffer, buffer->cur_line);
int maxlines = pango_layout_get_line_count(cur_line->layout);
- PangoLayoutLine *prevline =
- pango_layout_get_line_readonly(cur_line->layout, maxlines - 1);
- if (prevline->resolved_dir == PANGO_DIRECTION_RTL) {
- PangoRectangle rect;
- pango_layout_line_get_extents(prevline, NULL, &rect);
- x -= (cur_line->w * PANGO_SCALE - rect.width);
- }
- pango_layout_line_x_to_index(
- prevline, x, &buffer->cur_index, &trailing
- );
- /* FIXME: also in visual? */
- if (state.mode == INSERT)
- buffer->cur_index += trailing;
+ ledit_x_softline_to_pos(cur_line, x, maxlines - 1, &buffer->cur_index);
}
} else {
/* move to the previous soft line */
- PangoLayoutLine *prevline =
- pango_layout_get_line_readonly(cur_line->layout, lineno - 1);
- if (prevline->resolved_dir == PANGO_DIRECTION_RTL) {
- PangoRectangle rect;
- pango_layout_line_get_extents(prevline, NULL, &rect);
- x -= (cur_line->w * PANGO_SCALE - rect.width);
- }
- pango_layout_line_x_to_index(
- prevline, x, &buffer->cur_index, &trailing
- );
- if (state.mode == INSERT)
- buffer->cur_index += trailing;
+ 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);
}
@@ -955,57 +952,66 @@ cursor_to_beginning(void) {
}
static struct key keys_en[] = {
- {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}
+ {NULL, XK_BackSpace, INSERT, KEY_ANY, KEY_ANY, &backspace},
+ {NULL, XK_Left, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_left},
+ {NULL, XK_Right, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_right},
+ {NULL, XK_Up, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_up},
+ {NULL, XK_Down, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_down},
+ {NULL, XK_Return, INSERT, KEY_ANY, KEY_ANY, &return_key},
+ {NULL, XK_Delete, INSERT, KEY_ANY, KEY_ANY, &delete_key},
+ {NULL, XK_Escape, INSERT, KEY_ANY, KEY_ANY, &escape_key},
+ {"i", 0, NORMAL, KEY_ANY, KEY_ANY, &enter_insert},
+ {"h", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left},
+ {"l", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right},
+ {"j", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down},
+ {"k", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up},
+ {"0", 0, NORMAL, ~KEY_NUMBER, KEY_ANY, &cursor_to_beginning},
+ {"0", 0, NORMAL, KEY_NUMBER, KEY_NUMBER, &push_0},
+ {"1", 0, NORMAL, KEY_ANY, KEY_NUMBER, &push_1},
+ {"2", 0, NORMAL, KEY_ANY, KEY_NUMBER, &push_2},
+ {"3", 0, NORMAL, KEY_ANY, KEY_NUMBER, &push_3},
+ {"4", 0, NORMAL, KEY_ANY, KEY_NUMBER, &push_4},
+ {"5", 0, NORMAL, KEY_ANY, KEY_NUMBER, &push_5},
+ {"6", 0, NORMAL, KEY_ANY, KEY_NUMBER, &push_6},
+ {"7", 0, NORMAL, KEY_ANY, KEY_NUMBER, &push_7},
+ {"8", 0, NORMAL, KEY_ANY, KEY_NUMBER, &push_8},
+ {"9", 0, NORMAL, KEY_ANY, KEY_NUMBER, &push_9},
+ {"x", 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &key_x},
+ {"d", 0, NORMAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &key_d}
};
static struct key keys_ur[] = {
- {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}
+ {NULL, XK_BackSpace, INSERT, KEY_ANY, KEY_ANY, &backspace},
+ {NULL, XK_Left, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_left},
+ {NULL, XK_Right, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_right},
+ {NULL, XK_Up, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_up},
+ {NULL, XK_Down, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_down},
+ {NULL, XK_Return, INSERT, KEY_ANY, KEY_ANY, &return_key},
+ {NULL, XK_Delete, INSERT, KEY_ANY, KEY_ANY, &delete_key},
+ {NULL, XK_Escape, INSERT, KEY_ANY, KEY_ANY, &escape_key},
+ {"ی", 0, NORMAL, KEY_ANY, KEY_ANY, &enter_insert},
+ {"ح", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left},
+ {"ل", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right},
+ {"ج", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down},
+ {"ک", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up},
+ {"0", 0, NORMAL, KEY_ANY, KEY_ANY, &cursor_to_beginning}
};
static struct key keys_hi[] = {
- {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}
+ {NULL, XK_BackSpace, INSERT, KEY_ANY, KEY_ANY, &backspace},
+ {NULL, XK_Left, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_left},
+ {NULL, XK_Right, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_right},
+ {NULL, XK_Up, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_up},
+ {NULL, XK_Down, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_down},
+ {NULL, XK_Return, INSERT, KEY_ANY, KEY_ANY, &return_key},
+ {NULL, XK_Delete, INSERT, KEY_ANY, KEY_ANY, &delete_key},
+ {NULL, XK_Escape, INSERT, KEY_ANY, KEY_ANY, &escape_key},
+ {"ि", 0, NORMAL, KEY_ANY, KEY_ANY, &enter_insert},
+ {"ह", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left},
+ {"ल", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right},
+ {"ज", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down},
+ {"क", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up},
+ {"0", 0, NORMAL, KEY_ANY, KEY_ANY, &cursor_to_beginning}
};
#define LENGTH(X) (sizeof(X) / sizeof(X[0]))
@@ -1044,10 +1050,12 @@ key_press(XEvent event) {
state.xic, &event.xkey, buf, sizeof(buf), &sym, NULL
);
int found = 0;
+ struct key_stack_elem *e = peek_key_stack();
for (int i = 0; i < cur_keys->num_keys; i++) {
if (cur_keys->keys[i].text) {
if (n > 0 &&
(cur_keys->keys[i].modes & state.mode) &&
+ (!e || (e->key & cur_keys->keys[i].prev_keys)) &&
!strncmp(cur_keys->keys[i].text, buf, n)) {
cur_keys->keys[i].func();
found = 1;
@@ -1057,6 +1065,8 @@ key_press(XEvent event) {
cur_keys->keys[i].func();
found = 1;
}
+ if (found)
+ break;
}
if (state.mode == INSERT && !found && n > 0) {
ledit_insert_text(