Introduction
Introduction Statistics Contact Development Disclaimer Help
tAdd visual mode and make current keys work with it - 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 413b7e3a74968e128ede783a25145dc5aea70c99
parent 10a6b45de3f15406bb82817a1bf28c79d492145f
Author: lumidify <[email protected]>
Date: Sun, 16 May 2021 20:26:05 +0200
Add visual mode and make current keys work with it
Diffstat:
M buffer.c | 45 +++++++++++++++++------------…
M buffer.h | 1 +
M ledit.c | 240 ++++++++++++++++++++++-------…
3 files changed, 195 insertions(+), 91 deletions(-)
---
diff --git a/buffer.c b/buffer.c
t@@ -360,7 +360,29 @@ ledit_x_softline_to_pos(ledit_line *line, int x, int soft…
}
}
-/* FIXME: cursor jumps weirdly */
+int
+ledit_get_legal_normal_pos(ledit_buffer *buffer, int line, int pos) {
+ /* move back one grapheme if at end of line */
+ int ret = pos;
+ ledit_line *final_line = ledit_get_line(buffer, line);
+ if (pos == final_line->len && pos > 0) {
+ int nattrs;
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(final_line->layout, &n…
+ int cur = nattrs - 2;
+ ret--;
+ while (ret > 0 && ((final_line->text[ret] & 0xC0) == 0x80))
+ ret--;
+ while (ret > 0 && cur > 0 && !attrs[cur].is_cursor_position) {
+ cur--;
+ ret--;
+ while (ret > 0 && ((final_line->text[ret] & 0xC0) == 0…
+ ret--;
+ }
+ }
+ return ret;
+}
+
/* FIXME: use at least somewhat sensible variable names */
void
ledit_delete_range(
t@@ -541,24 +563,7 @@ ledit_delete_range(
*new_byte_ret = b1;
ledit_delete_line_entries(buffer, l1 + 1, l2);
}
- /* move back one grapheme if at end of line and in normal mode…
- ledit_line *final_line = ledit_get_line(buffer, *new_line_ret);
- if (buffer->state->mode == NORMAL &&
- *new_byte_ret == final_line->len &&
- *new_byte_ret > 0) {
- int nattrs;
- const PangoLogAttr *attrs =
- pango_layout_get_log_attrs_readonly(final_line->la…
- int cur = nattrs - 2;
- (*new_byte_ret)--;
- while (*new_byte_ret > 0 && ((final_line->text[*new_by…
- (*new_byte_ret)--;
- while (*new_byte_ret > 0 && cur > 0 && !attrs[cur].is_…
- cur--;
- (*new_byte_ret)--;
- while (*new_byte_ret > 0 && ((final_line->text…
- (*new_byte_ret)--;
- }
- }
+ if (buffer->state->mode == NORMAL)
+ *new_byte_ret = ledit_get_legal_normal_pos(buffer, *ne…
}
}
diff --git a/buffer.h b/buffer.h
t@@ -51,6 +51,7 @@ 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_i…
+int ledit_get_legal_normal_pos(ledit_buffer *buffer, int line, int pos);
void ledit_delete_range(
ledit_buffer *buffer, int line_based,
int line_index1, int byte_index1,
diff --git a/ledit.c b/ledit.c
t@@ -180,39 +180,63 @@ get_new_line_softline(
}
}
+static int
+delete_selection(void) {
+ if (buffer->sel.line1 != buffer->sel.line2 || buffer->sel.byte1 != buf…
+ ledit_delete_range(
+ buffer, 0,
+ buffer->sel.line1, buffer->sel.byte1,
+ buffer->sel.line2, buffer->sel.byte2,
+ &buffer->cur_line, &buffer->cur_index
+ );
+ buffer->sel.line1 = buffer->sel.line2 = -1;
+ buffer->sel.byte1 = buffer->sel.byte2 = -1;
+ ledit_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ return 1;
+ }
+ return 0;
+}
+
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();
+ if (delete_selection()) {
+ state.mode = NORMAL;
+ buffer->cur_index = ledit_get_legal_normal_pos(buffer, buffer-…
+ ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->…
+ clear_key_stack();
+ } else {
+ 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 ma…
+ 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;
+ int new_line, new_softline;
+ get_new_line_softline(
+ buffer->cur_line, buffer->cur_index, lines…
+ &new_line, &new_softline
+ );
+ ledit_line *ll = ledit_get_line(buffer, new_li…
+ PangoLayoutLine *pl = pango_layout_get_line_re…
+ e->motion_cb(new_line, pl->start_index, KEY_MO…
+ clear_key_stack();
+ } else if (e != NULL) {
+ clear_key_stack();
+ }
}
- /* FIXME: checking equality of the function pointer may be a b…
- 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;
- 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(l…
- e->motion_cb(new_line, pl->start_index, KEY_MOTION_LIN…
- 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;
}
}
- 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? */
t@@ -239,7 +263,6 @@ key_x(void) {
num = e->count;
if (num <= 0)
num = 1;
- printf("delete %d\n", num);
}
static void
t@@ -680,7 +703,7 @@ redraw(void) {
strong.x / PANGO_SCALE, cursor_y,
10, strong.height / PANGO_SCALE
);
- } else if (state.mode == INSERT) {
+ } else if (state.mode == INSERT || state.mode == VISUAL) {
XDrawLine(
state.dpy, state.drawable, state.gc,
strong.x / PANGO_SCALE, cursor_y,
t@@ -825,6 +848,12 @@ button_press(XEvent *event) {
int l, b;
xy_to_line_byte(x, y, &l, &b);
set_selection(l, b, l, b);
+ if (state.mode == NORMAL) {
+ ledit_wipe_line_cursor_attrs(buffer, b…
+ state.mode = VISUAL;
+ }
+ buffer->cur_line = l;
+ buffer->cur_index = b;
state.selecting = 1;
return 1;
}
t@@ -872,6 +901,8 @@ drag_motion(XEvent *event) {
int y = event->xbutton.y >= 0 ? event->xbutton.y : 0;
xy_to_line_byte(event->xbutton.x, y, &l, &b);
set_selection(buffer->sel.line1, buffer->sel.byte1, l, b);
+ buffer->cur_line = l;
+ buffer->cur_index = b;
return 1;
}
return 0;
t@@ -922,7 +953,9 @@ resize_window(int w, int h) {
static void
backspace(void) {
- if (buffer->cur_index == 0) {
+ if (delete_selection()) {
+ /* NOP */
+ } else if (buffer->cur_index == 0) {
if (buffer->cur_line != 0) {
ledit_line *l1 = ledit_get_line(buffer, buffer->cur_li…
ledit_line *l2 = ledit_get_line(buffer, buffer->cur_li…
t@@ -946,7 +979,9 @@ backspace(void) {
static void
delete_key(void) {
ledit_line *cur_line = ledit_get_line(buffer, buffer->cur_line);
- if (buffer->cur_index == cur_line->len) {
+ if (delete_selection()) {
+ /* NOP */
+ } else if (buffer->cur_index == cur_line->len) {
if (buffer->cur_line != buffer->lines_num - 1) {
ledit_line *next_line = ledit_get_line(
buffer, buffer->cur_line + 1
t@@ -1027,7 +1062,15 @@ move_cursor_left_right(int dir) {
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->…
+ if (state.mode == VISUAL) {
+ set_selection(buffer->sel.line1, buffer->sel.byte1, bu…
+ } else if (state.mode == INSERT &&
+ (buffer->sel.line1 != buffer->sel.line2 ||
+ buffer->sel.byte1 != buffer->sel.byte2)) {
+ set_selection(buffer->cur_line, new_index, buffer->cur…
+ } else if (state.mode == NORMAL) {
+ ledit_set_line_cursor_attrs(buffer, buffer->cur_line, …
+ }
}
clear_key_stack();
}
t@@ -1044,6 +1087,7 @@ cursor_right(void) {
static void
return_key(void) {
+ delete_selection();
ledit_append_line(buffer, buffer->cur_line, buffer->cur_index);
/* FIXME: these aren't needed, right? This only works in insert mode
* anyways, so there's nothing to wipe */
t@@ -1055,27 +1099,36 @@ return_key(void) {
static void
escape_key(void) {
- state.mode = NORMAL;
- clear_key_stack();
- PangoDirection dir = PANGO_DIRECTION_RTL;
- int tmp_index = buffer->cur_index;
- ledit_line *cur_line = ledit_get_line(buffer, buffer->cur_line);
- if (buffer->cur_index >= cur_line->len)
- tmp_index--;
- if (tmp_index >= 0)
- dir = pango_layout_get_direction(cur_line->layout, tmp_index);
- if (dir == PANGO_DIRECTION_RTL || dir == PANGO_DIRECTION_WEAK_RTL) {
- cursor_right();
+ clear_key_stack(); /* just in case... */
+ if (state.mode == INSERT &&
+ (buffer->sel.line1 != buffer->sel.line2 ||
+ buffer->sel.byte1 != buffer->sel.byte2)) {
+ state.mode = VISUAL;
} else {
- cursor_left();
+ state.mode = NORMAL;
+ clear_key_stack();
+ PangoDirection dir = PANGO_DIRECTION_RTL;
+ int tmp_index = buffer->cur_index;
+ ledit_line *cur_line = ledit_get_line(buffer, buffer->cur_line…
+ if (buffer->cur_index >= cur_line->len)
+ tmp_index--;
+ if (tmp_index >= 0)
+ dir = pango_layout_get_direction(cur_line->layout, tmp…
+ if (dir == PANGO_DIRECTION_RTL || dir == PANGO_DIRECTION_WEAK_…
+ cursor_right();
+ } else {
+ cursor_left();
+ }
+ ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->…
}
- ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_inde…
}
static void
enter_insert(void) {
+ if (state.mode == NORMAL)
+ ledit_wipe_line_cursor_attrs(buffer, buffer->cur_line);
state.mode = INSERT;
- ledit_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ clear_key_stack();
}
/* FIXME: Check if previous key allows motion command - or is this checked aut…
t@@ -1112,7 +1165,16 @@ move_cursor_up_down(int dir) {
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->…
+
+ if (state.mode == VISUAL) {
+ set_selection(buffer->sel.line1, buffer->sel.byte1, bu…
+ } else if (state.mode == INSERT &&
+ (buffer->sel.line1 != buffer->sel.line2 ||
+ buffer->sel.byte1 != buffer->sel.byte2)) {
+ set_selection(buffer->cur_line, buffer->cur_index, buf…
+ } else if (state.mode == NORMAL) {
+ ledit_set_line_cursor_attrs(buffer, buffer->cur_line, …
+ }
}
clear_key_stack();
}
t@@ -1129,37 +1191,72 @@ cursor_up(void) {
static void
cursor_to_beginning(void) {
- buffer->cur_index = 0;
- ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_inde…
+ struct key_stack_elem *e = pop_key_stack();
+ /* FIXME: error when no callback? */
+ if (e != NULL & e->motion_cb != NULL) {
+ e->motion_cb(buffer->cur_line, 0, KEY_MOTION_CHAR);
+ } else {
+ buffer->cur_index = 0;
+ if (state.mode == VISUAL) {
+ set_selection(
+ buffer->sel.line1, buffer->sel.byte1,
+ buffer->cur_line, buffer->cur_index
+ );
+ } else {
+ ledit_set_line_cursor_attrs(
+ buffer, buffer->cur_line, buffer->cur_index
+ );
+ }
+ }
+ clear_key_stack();
+}
+
+static void
+enter_visual(void) {
+ state.mode = VISUAL;
+ buffer->sel.line1 = buffer->sel.line2 = buffer->cur_line;
+ buffer->sel.byte1 = buffer->sel.byte2 = buffer->cur_index;
+ ledit_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ clear_key_stack(); /* FIXME: error if not empty? */
+}
+
+static void
+switch_selection_end(void) {
+ swap(&buffer->sel.line1, &buffer->sel.line2);
+ swap(&buffer->sel.byte1, &buffer->sel.byte2);
+ buffer->cur_line = buffer->sel.line2;
+ buffer->cur_index = buffer->sel.byte2;
}
static struct key keys_en[] = {
{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_Left, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_left},
+ {NULL, XK_Right, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_right…
+ {NULL, XK_Up, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_up},
+ {NULL, XK_Down, VISUAL|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_lef…
- {"l", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_rig…
- {"j", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_dow…
- {"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},
+ {NULL, XK_Escape, VISUAL|INSERT, KEY_ANY, KEY_ANY, &escape_key},
+ {"i", 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &enter_insert},
+ {"h", 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cur…
+ {"l", 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cur…
+ {"j", 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cur…
+ {"k", 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cur…
+ {"0", 0, NORMAL|VISUAL, ~KEY_NUMBER, KEY_ANY, &cursor_to_beginning},
+ {"0", 0, NORMAL|VISUAL, KEY_NUMBER, KEY_NUMBER, &push_0},
+ {"1", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_1},
+ {"2", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_2},
+ {"3", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_3},
+ {"4", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_4},
+ {"5", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_5},
+ {"6", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_6},
+ {"7", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_7},
+ {"8", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_8},
+ {"9", 0, NORMAL|VISUAL, 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}
+ {"d", 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &key_d…
+ {"v", 0, NORMAL, KEY_ANY, KEY_ANY, &enter_visual},
+ {"o", 0, VISUAL, KEY_ANY, KEY_ANY, &switch_selection_end},
};
static struct key keys_ur[] = {
t@@ -1251,6 +1348,7 @@ key_press(XEvent event) {
break;
}
if (state.mode == INSERT && !found && n > 0) {
+ delete_selection();
ledit_insert_text(
buffer, buffer->cur_line, buffer->cur_index, buf, n
);
You are viewing proxied material from lumidify.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.