Introduction
Introduction Statistics Contact Development Disclaimer Help
tImprove bottom bar text input - 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 f46f28e4d372daa0353489d65a29078e69fe0376
parent a52f6845ba83e6df5d60d22844b1a2546ca97af1
Author: lumidify <[email protected]>
Date: Fri, 12 Nov 2021 23:31:39 +0100
Improve bottom bar text input
Diffstat:
M buffer.c | 9 +++++++++
M keys_basic.c | 4 +++-
M keys_command.c | 64 +++++++++++++++++++++++++++++…
M keys_command_config.h | 28 ++++++++++++++++++++++++++++
M undo.c | 12 ++++++++++++
M window.c | 123 +++++++++++++++++++++++++++++…
M window.h | 5 +++++
7 files changed, 233 insertions(+), 12 deletions(-)
---
diff --git a/buffer.c b/buffer.c
t@@ -2239,10 +2239,19 @@ ledit_buffer_redo(ledit_buffer *buffer) {
static void
paste_callback(void *data, char *text, int len) {
ledit_buffer *buffer = (ledit_buffer *)data;
+ txtbuf ins_buf = {.text = text, .len = len, .cap = len};
+ ledit_range cur_range, ins_range;
+ cur_range.line1 = ins_range.line1 = buffer->cur_line;
+ cur_range.byte1 = ins_range.byte1 = buffer->cur_index;
ledit_buffer_insert_text_with_newlines(
buffer, buffer->cur_line, buffer->cur_index,
text, len, &buffer->cur_line, &buffer->cur_index
);
+ cur_range.line2 = ins_range.line2 = buffer->cur_line;
+ cur_range.byte2 = ins_range.byte2 = buffer->cur_index;
+ ledit_push_undo_insert(
+ buffer->undo, &ins_buf, ins_range, cur_range, 1, buffer->common->m…
+ );
}
/* FIXME: guard against buffer being destroyed before paste callback is nulled…
diff --git a/keys_basic.c b/keys_basic.c
t@@ -421,7 +421,6 @@ insert_text(
int cur_line2, int cur_index2, int start_group) {
if (len < 0)
len = strlen(text);
- /* FIXME: this is kind of hacky... */
txtbuf ins_buf = {.text = text, .len = len, .cap = len};
ledit_range cur_range, del_range;
if (cur_line1 >= 0 && cur_index1 >= 0) {
t@@ -1804,6 +1803,7 @@ enter_commandedit(ledit_buffer *buffer, char *text, int …
(void)text;
(void)len;
ledit_window_set_bottom_bar_text(buffer->window, ":", -1);
+ ledit_window_set_bottom_bar_min_pos(buffer->window, 1);
ledit_window_set_bottom_bar_cursor(buffer->window, 1);
ledit_command_set_type(CMD_EDIT);
ledit_window_set_bottom_bar_text_shown(buffer->window, 1);
t@@ -1816,6 +1816,7 @@ enter_searchedit_forward(ledit_buffer *buffer, char *tex…
(void)text;
(void)len;
ledit_window_set_bottom_bar_text(buffer->window, "/", -1);
+ ledit_window_set_bottom_bar_min_pos(buffer->window, 1);
ledit_window_set_bottom_bar_cursor(buffer->window, 1);
ledit_command_set_type(CMD_EDITSEARCH);
ledit_window_set_bottom_bar_text_shown(buffer->window, 1);
t@@ -1828,6 +1829,7 @@ enter_searchedit_backward(ledit_buffer *buffer, char *te…
(void)text;
(void)len;
ledit_window_set_bottom_bar_text(buffer->window, "?", -1);
+ ledit_window_set_bottom_bar_min_pos(buffer->window, 1);
ledit_window_set_bottom_bar_cursor(buffer->window, 1);
ledit_command_set_type(CMD_EDITSEARCHB);
ledit_window_set_bottom_bar_text_shown(buffer->window, 1);
diff --git a/keys_command.c b/keys_command.c
t@@ -26,6 +26,8 @@
#include "keys_command.h"
#include "keys_command_config.h"
+/* FIXME: history for search and commands */
+
/* FIXME: THIS WON'T WORK WHEN THERE ARE MULTIPLE BUFFERS! */
/* this must first be set by caller before jumping to key handler */
static enum ledit_command_type cur_type;
t@@ -244,10 +246,57 @@ edit_insert_text(ledit_buffer *buffer, char *key_text, i…
}
static int
+edit_cursor_to_end(ledit_buffer *buffer, char *key_text, int len) {
+ (void)key_text;
+ (void)len;
+ ledit_window_bottom_bar_cursor_to_end(buffer->window);
+ return 1;
+}
+
+static int
+edit_cursor_to_beginning(ledit_buffer *buffer, char *key_text, int len) {
+ (void)key_text;
+ (void)len;
+ ledit_window_bottom_bar_cursor_to_beginning(buffer->window);
+ return 1;
+}
+
+static int
+edit_cursor_left(ledit_buffer *buffer, char *key_text, int len) {
+ (void)key_text;
+ (void)len;
+ ledit_window_move_bottom_bar_cursor(buffer->window, -1);
+ return 1;
+}
+
+static int
+edit_cursor_right(ledit_buffer *buffer, char *key_text, int len) {
+ (void)key_text;
+ (void)len;
+ ledit_window_move_bottom_bar_cursor(buffer->window, 1);
+ return 1;
+}
+
+static int
+edit_backspace(ledit_buffer *buffer, char *key_text, int len) {
+ (void)key_text;
+ (void)len;
+ ledit_window_delete_bottom_bar_char(buffer->window, -1);
+ return 1;
+}
+
+static int
+edit_delete(ledit_buffer *buffer, char *key_text, int len) {
+ (void)key_text;
+ (void)len;
+ ledit_window_delete_bottom_bar_char(buffer->window, 1);
+ return 1;
+}
+
+static int
edit_submit(ledit_buffer *buffer, char *key_text, int len) {
(void)key_text;
(void)len;
- ledit_buffer_set_mode(buffer, NORMAL);
ledit_window_set_bottom_bar_text_shown(buffer->window, 0);
/* FIXME: this is hacky */
return handle_cmd(buffer, ledit_window_get_bottom_bar_text(buffer->win…
t@@ -278,7 +327,6 @@ static int
editsearch_submit(ledit_buffer *buffer, char *key_text, int len) {
(void)key_text;
(void)len;
- ledit_buffer_set_mode(buffer, NORMAL);
ledit_window_set_bottom_bar_text_shown(buffer->window, 0);
ledit_set_search_forward(ledit_window_get_bottom_bar_text(buffer->wind…
search_next(buffer);
t@@ -289,13 +337,21 @@ static int
editsearchb_submit(ledit_buffer *buffer, char *key_text, int len) {
(void)key_text;
(void)len;
- ledit_buffer_set_mode(buffer, NORMAL);
ledit_window_set_bottom_bar_text_shown(buffer->window, 0);
ledit_set_search_backward(ledit_window_get_bottom_bar_text(buffer->win…
search_next(buffer);
return 0;
}
+static int
+edit_discard(ledit_buffer *buffer, char *key_text, int len) {
+ (void)buffer;
+ (void)key_text;
+ (void)len;
+ ledit_window_set_bottom_bar_text_shown(buffer->window, 0);
+ return 0;
+}
+
struct action
ledit_command_key_handler(ledit_buffer *buffer, XEvent *event, int lang_index)…
char buf[64];
t@@ -305,7 +361,7 @@ ledit_command_key_handler(ledit_buffer *buffer, XEvent *ev…
int num_keys = keys[lang_index].num_keys;
unsigned int key_state = event->xkey.state;
preprocess_key(buffer->window, event, &sym, buf, sizeof(buf), &n);
- int grabkey = 0;
+ int grabkey = 1;
for (int i = 0; i < num_keys; i++) {
if (cur_keys[i].text) {
if (n > 0 &&
diff --git a/keys_command_config.h b/keys_command_config.h
t@@ -3,9 +3,16 @@ static int substitute_yes_all(ledit_buffer *buffer, char *key…
static int substitute_no(ledit_buffer *buffer, char *key_text, int len);
static int substitute_no_all(ledit_buffer *buffer, char *key_text, int len);
static int edit_insert_text(ledit_buffer *buffer, char *key_text, int len);
+static int edit_cursor_left(ledit_buffer *buffer, char *key_text, int len);
+static int edit_cursor_right(ledit_buffer *buffer, char *key_text, int len);
+static int edit_cursor_to_end(ledit_buffer *buffer, char *key_text, int len);
+static int edit_cursor_to_beginning(ledit_buffer *buffer, char *key_text, int …
+static int edit_backspace(ledit_buffer *buffer, char *key_text, int len);
+static int edit_delete(ledit_buffer *buffer, char *key_text, int len);
static int edit_submit(ledit_buffer *buffer, char *key_text, int len);
static int editsearch_submit(ledit_buffer *buffer, char *key_text, int len);
static int editsearchb_submit(ledit_buffer *buffer, char *key_text, int len);
+static int edit_discard(ledit_buffer *buffer, char *key_text, int len);
struct key {
char *text; /* for keys that correspond…
t@@ -24,6 +31,27 @@ static struct key keys_en[] = {
{NULL, 0, XK_Return, CMD_EDIT, &edit_submit},
{NULL, 0, XK_Return, CMD_EDITSEARCH, &editsearch_submit},
{NULL, 0, XK_Return, CMD_EDITSEARCHB, &editsearchb_submit},
+ {NULL, 0, XK_Left, CMD_EDIT, &edit_cursor_left},
+ {NULL, 0, XK_Left, CMD_EDITSEARCH, &edit_cursor_left},
+ {NULL, 0, XK_Left, CMD_EDITSEARCHB, &edit_cursor_left},
+ {NULL, 0, XK_Right, CMD_EDIT, &edit_cursor_right},
+ {NULL, 0, XK_Right, CMD_EDITSEARCH, &edit_cursor_right},
+ {NULL, 0, XK_Right, CMD_EDITSEARCHB, &edit_cursor_right},
+ {NULL, 0, XK_BackSpace, CMD_EDIT, &edit_backspace},
+ {NULL, 0, XK_BackSpace, CMD_EDITSEARCH, &edit_backspace},
+ {NULL, 0, XK_BackSpace, CMD_EDITSEARCHB, &edit_backspace},
+ {NULL, 0, XK_Delete, CMD_EDIT, &edit_delete},
+ {NULL, 0, XK_Delete, CMD_EDITSEARCH, &edit_delete},
+ {NULL, 0, XK_Delete, CMD_EDITSEARCHB, &edit_delete},
+ {NULL, 0, XK_End, CMD_EDIT, &edit_cursor_to_end},
+ {NULL, 0, XK_End, CMD_EDITSEARCH, &edit_cursor_to_end},
+ {NULL, 0, XK_End, CMD_EDITSEARCHB, &edit_cursor_to_end},
+ {NULL, 0, XK_Home, CMD_EDIT, &edit_cursor_to_beginning},
+ {NULL, 0, XK_Home, CMD_EDITSEARCH, &edit_cursor_to_beginning},
+ {NULL, 0, XK_Home, CMD_EDITSEARCHB, &edit_cursor_to_beginning},
+ {NULL, 0, XK_Escape, CMD_EDIT, &edit_discard},
+ {NULL, 0, XK_Escape, CMD_EDITSEARCH, &edit_discard},
+ {NULL, 0, XK_Escape, CMD_EDITSEARCHB, &edit_discard},
{"", 0, 0, CMD_EDIT, &edit_insert_text},
{"", 0, 0, CMD_EDITSEARCH, &edit_insert_text},
{"", 0, 0, CMD_EDITSEARCHB, &edit_insert_text}
diff --git a/undo.c b/undo.c
t@@ -12,6 +12,18 @@
#include "cache.h"
#include "undo.h"
+/* FIXME: more sanity checks in case text is
+ inserted/deleted without adding to undo stack */
+/* FIXME: cursor positions can be a bit weird when
+ undo is used across different insert sessions in
+ insert mode - e.g. if some text is inserted, then
+ 'o' is used in normal mode to append a new line and
+ type some text, the cursor position at a certain
+ undo position will differ in insert mode depending
+ on whether it was reached with undo or redo since
+ 'o' saves the position at which it was pressed,
+ not the position of the last insert */
+
enum operation {
UNDO_INSERT,
UNDO_DELETE
diff --git a/window.c b/window.c
t@@ -18,12 +18,13 @@
#include "window.h"
#include "util.h"
+/* FIXME: Everything to do with the bottom bar is extremely hacky */
struct bottom_bar {
/* FIXME: encapsulate layout, width, draw a bit */
PangoLayout *mode;
ledit_draw *mode_draw;
int mode_w, mode_h;
- PangoLayout *ruler;
+ PangoLayout *ruler; /* not implemented yet */
ledit_draw *ruler_draw;
int ruler_w, ruler_h;
PangoLayout *line;
t@@ -32,6 +33,7 @@ struct bottom_bar {
char *line_text;
int line_alloc, line_len;
int line_cur_pos;
+ int min_pos; /* minimum position cursor can be at */
};
/* clipboard handling largely stolen from st (simple terminal) */
t@@ -72,7 +74,7 @@ recalc_text_size(ledit_window *window) {
void
ledit_window_insert_bottom_bar_text(ledit_window *window, char *text, int len)…
assert(len >= -1);
- assert(window->bb->line_cur_pos <= window->bb->line_alloc);
+ assert(window->bb->line_cur_pos <= window->bb->line_len);
if (len == -1)
len = strlen(text);
t@@ -102,6 +104,90 @@ ledit_window_insert_bottom_bar_text(ledit_window *window,…
}
void
+ledit_window_move_bottom_bar_cursor(ledit_window *window, int movement) {
+ assert(window->bb->line_cur_pos <= window->bb->line_len);
+ int trailing = 0;
+ int new_index = window->bb->line_cur_pos;
+ pango_layout_move_cursor_visually(
+ window->bb->line, TRUE,
+ new_index, trailing, movement,
+ &new_index, &trailing
+ );
+ while (trailing > 0) {
+ trailing--;
+ /* FIXME: move to common/util */
+ new_index++;
+ while (new_index < window->bb->line_len &&
+ (window->bb->line_text[new_index] & 0xC0) == 0x80)
+ new_index++;
+ }
+ if (new_index < window->bb->min_pos)
+ new_index = window->bb->min_pos;
+ if (new_index > window->bb->line_len)
+ new_index = window->bb->line_len;
+ window->bb->line_cur_pos = new_index;
+}
+
+void
+ledit_window_set_bottom_bar_min_pos(ledit_window *window, int pos) {
+ window->bb->min_pos = pos;
+}
+
+void
+ledit_window_bottom_bar_cursor_to_beginning(ledit_window *window) {
+ window->bb->line_cur_pos = window->bb->min_pos;
+}
+
+void
+ledit_window_bottom_bar_cursor_to_end(ledit_window *window) {
+ window->bb->line_cur_pos = window->bb->line_len;
+}
+
+/* FIXME: respect PangoLogAttr.backspace_deletes_character */
+void
+ledit_window_delete_bottom_bar_char(ledit_window *window, int dir) {
+ int byte = window->bb->line_cur_pos;
+ if (dir < 0) {
+ byte--;
+ while (byte > 0 &&
+ (window->bb->line_text[byte] & 0xC0) == 0x80) {
+ byte--;
+ }
+ if (byte < window->bb->min_pos)
+ byte = window->bb->min_pos;
+ memmove(
+ window->bb->line_text + byte,
+ window->bb->line_text + window->bb->line_cur_pos,
+ window->bb->line_len - window->bb->line_cur_pos
+ );
+ window->bb->line_len -= (window->bb->line_cur_pos - byte);
+ window->bb->line_cur_pos = byte;
+ } else if (dir > 0) {
+ byte++;
+ while (byte < window->bb->line_len &&
+ (window->bb->line_text[byte] & 0xC0) == 0x80) {
+ byte++;
+ }
+ if (byte >= window->bb->line_len)
+ byte = window->bb->line_len;
+ memmove(
+ window->bb->line_text + window->bb->line_cur_pos,
+ window->bb->line_text + byte,
+ window->bb->line_len - byte
+ );
+ window->bb->line_len -= (byte - window->bb->line_cur_pos);
+ }
+ /* FIXME: move to separate function */
+ window->bb->line_text[window->bb->line_len] = '\0';
+ pango_layout_set_text(window->bb->line, window->bb->line_text, window-…
+ pango_layout_get_pixel_size(window->bb->line, &window->bb->line_w, &wi…
+ ledit_draw_grow(window, window->bb->line_draw, window->bb->line_w, win…
+ XftDrawRect(window->bb->line_draw->xftdraw, &window->theme->text_bg, 0…
+ pango_xft_render_layout(window->bb->line_draw->xftdraw, &window->theme…
+ recalc_text_size(window);
+}
+
+void
ledit_window_set_bottom_bar_cursor(ledit_window *window, int byte_pos) {
/* FIXME: check if valid? */
window->bb->line_cur_pos = byte_pos;
t@@ -380,6 +466,7 @@ ledit_window_create(ledit_common *common, ledit_theme *the…
window->bb->line_text = NULL;
window->bb->line_alloc = window->bb->line_len = 0;
window->bb->line_cur_pos = 0;
+ window->bb->min_pos = 0;
window->bottom_text_shown = 0;
window->message_shown = 0;
t@@ -473,8 +560,16 @@ ledit_window_redraw(ledit_window *window) {
0, window->text_h,
window->w, window->h - window->text_h
);
- if (window->bottom_text_shown) {
- /* move input method position to cursor */
+ if (window->message_shown) {
+ XCopyArea(
+ window->common->dpy, window->bb->line_draw->pixmap,
+ window->drawable, window->gc,
+ 0, 0, window->bb->line_w, window->bb->line_h,
+ 0, window->text_h
+ );
+ } else if (window->bottom_text_shown) {
+ XSetForeground(window->common->dpy, window->gc, t->text_fg.pix…
+ /* move input method position to cursor and draw cursor */
PangoRectangle strong, weak;
pango_layout_get_cursor_pos(
window->bb->line, window->bb->line_cur_pos, &strong, &weak
t@@ -484,14 +579,28 @@ ledit_window_redraw(ledit_window *window) {
have to be moved out of the way anyways (fcitx just moves it
up a bit so it sort of works) */
xximspot(window, strong.x / PANGO_SCALE, window->h);
- }
- if (window->bottom_text_shown || window->message_shown) {
+ int x = 0;
+ int w = window->bb->line_w;
+ int cur_x = strong.x / PANGO_SCALE;
+ if (w > window->w) {
+ /* FIXME: try to keep some space on the edges */
+ x = (cur_x / window->w) * window->w;
+ w = window->w;
+ if (x + w > window->bb->line_w)
+ w = window->bb->line_w - x;
+ }
XCopyArea(
window->common->dpy, window->bb->line_draw->pixmap,
window->drawable, window->gc,
- 0, 0, window->bb->line_w, window->bb->line_h,
+ x, 0, w, window->bb->line_h,
0, window->text_h
);
+ XDrawLine(
+ window->common->dpy, window->drawable, window->gc,
+ cur_x - x, window->text_h + strong.y / PANGO_SCALE,
+ cur_x - x,
+ window->text_h + (strong.y + strong.height) / PANGO_SCALE
+ );
} else {
XCopyArea(
window->common->dpy, window->bb->mode_draw->pixmap,
diff --git a/window.h b/window.h
t@@ -46,6 +46,11 @@ void ledit_window_cleanup(void);
/* FIXME: this is a bit confusing because there's a difference between editable
text shown and non-editable message shown */
+void ledit_window_move_bottom_bar_cursor(ledit_window *window, int movement);
+void ledit_window_delete_bottom_bar_char(ledit_window *window, int dir);
+void ledit_window_bottom_bar_cursor_to_beginning(ledit_window *window);
+void ledit_window_bottom_bar_cursor_to_end(ledit_window *window);
+void ledit_window_set_bottom_bar_min_pos(ledit_window *window, int pos);
void ledit_window_set_bottom_bar_text_shown(ledit_window *window, int shown);
int ledit_window_bottom_bar_text_shown(ledit_window *window);
void ledit_window_set_bottom_bar_cursor(ledit_window *window, int byte_pos);
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.