Introduction
Introduction Statistics Contact Development Disclaimer Help
tImplement Ctrl-e and Ctrl-y - 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 00de6deacf3f962dbf3b3d89926fe69798ad2893
parent 4f2001a6c39e051d22db3d88377e5de414aac97d
Author: lumidify <[email protected]>
Date: Sun, 31 Oct 2021 21:36:43 +0100
Implement Ctrl-e and Ctrl-y
Diffstat:
M buffer.c | 128 +++++++++++++++++++++++++++++…
M buffer.h | 3 +++
M keys.c | 7 +------
M keys.h | 8 +++++++-
M keys_basic.c | 62 +++++++++++++++++++++++++++++…
M keys_basic_config.h | 6 +++++-
6 files changed, 200 insertions(+), 14 deletions(-)
---
diff --git a/buffer.c b/buffer.c
t@@ -987,6 +987,7 @@ ledit_x_softline_to_pos(ledit_line *line, int x, int softl…
pango_line, x_relative, pos_ret, &trailing
);
/* if in insert mode, snap to the nearest border between graphemes */
+ /* FIXME: add parameter for this instead of checking mode */
if (line->parent_buffer->common->mode == INSERT) {
while (trailing > 0) {
trailing--;
t@@ -1380,6 +1381,101 @@ ledit_buffer_scroll(ledit_buffer *buffer, long new_off…
ledit_window_set_scroll_pos(buffer->window, buffer->display_offset);
}
+/* FIXME: there's gotta be a better/more efficient way to do this... */
+void
+ledit_buffer_get_nearest_legal_pos(
+ ledit_buffer *buffer,
+ int line, int byte,
+ /*int snap_to_nearest, int snap_middle, FIXME: take these parameters */
+ int *line_ret, int *byte_ret) {
+ PangoRectangle strong, weak;
+ int text_w, text_h;
+ int x, sl_useless;
+ ledit_window_get_textview_size(buffer->window, &text_w, &text_h);
+ ledit_line *lline = ledit_buffer_get_line(buffer, line);
+ pango_layout_get_cursor_pos(
+ lline->layout, byte, &strong, &weak
+ );
+ ledit_pos_to_x_softline(lline, byte, &x, &sl_useless);
+ long cursor_y = strong.y / PANGO_SCALE + lline->y_offset;
+ PangoRectangle ink, log;
+ if (cursor_y < buffer->display_offset) {
+ /* search for the hard line covering the top of the screen */
+ int hline = line;
+ while (lline->y_offset + lline->h <= buffer->display_offset &&…
+ lline = ledit_buffer_get_line(buffer, ++hline);
+ }
+ /* the current hard line is now the one at the very top of the…
+ int num_sl = pango_layout_get_line_count(lline->layout);
+ int cur_y_off = 0;
+ int sl_index = -1;
+ PangoLayoutLine *sl;
+ /* search for first soft line completely on-screen */
+ for (int i = 0; i < num_sl; i++) {
+ sl = pango_layout_get_line_readonly(lline->layout, i);
+ if (cur_y_off + lline->y_offset >= buffer->display_off…
+ sl_index = i;
+ break;
+ }
+ pango_layout_line_get_pixel_extents(sl, &ink, &log);
+ cur_y_off += log.height;
+ }
+ if (sl_index >= 0) {
+ /* we found the correct soft line */
+ *line_ret = hline;
+ ledit_x_softline_to_pos(lline, x, sl_index, byte_ret);
+ } else if (hline < buffer->lines_num - 1) {
+ /* need to move to next hard line */
+ *line_ret = hline + 1;
+ lline = ledit_buffer_get_line(buffer, hline + 1);
+ ledit_x_softline_to_pos(lline, x, 0, byte_ret);
+ } else {
+ /* no idea if this can happen, but just fail and use
+ the last soft line of the last hard line */
+ *line_ret = hline;
+ ledit_x_softline_to_pos(lline, x, num_sl - 1, byte_ret…
+ }
+ } else if (cursor_y + strong.height / PANGO_SCALE >
+ buffer->display_offset + text_h) {
+ /* search for the hard line covering the bottom of the screen …
+ int hline = line;
+ while (lline->y_offset > buffer->display_offset + text_h && hl…
+ lline = ledit_buffer_get_line(buffer, --hline);
+ }
+ /* the current hard line is now the one at the very bottom of …
+ int num_sl = pango_layout_get_line_count(lline->layout);
+ int cur_y_off = 0;
+ int sl_index = -1;
+ PangoLayoutLine *sl;
+ /* search for last soft line completely on-screen */
+ for (int i = num_sl - 1; i >= 0; i--) {
+ sl = pango_layout_get_line_readonly(lline->layout, i);
+ if (lline->y_offset + lline->h - cur_y_off < buffer->d…
+ sl_index = i;
+ break;
+ }
+ pango_layout_line_get_pixel_extents(sl, &ink, &log);
+ cur_y_off += log.height;
+ }
+ if (sl_index >= 0) {
+ /* we found the correct soft line */
+ *line_ret = hline;
+ ledit_x_softline_to_pos(lline, x, sl_index, byte_ret);
+ } else if (hline > 0) {
+ /* need to move to previous hard line */
+ *line_ret = hline - 1;
+ lline = ledit_buffer_get_line(buffer, hline - 1);
+ num_sl = pango_layout_get_line_count(lline->layout);
+ ledit_x_softline_to_pos(lline, x, num_sl - 1, byte_ret…
+ } else {
+ /* no idea if this can happen, but just fail and use
+ the first soft line of the first hard line */
+ *line_ret = hline;
+ ledit_x_softline_to_pos(lline, x, 0, byte_ret);
+ }
+ }
+}
+
void
ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int snap_to_nearest,…
/* FIXME: store current line offset to speed this up */
t@@ -1390,6 +1486,7 @@ ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y…
ledit_line *line = ledit_buffer_get_line(buffer, i);
if ((h <= pos && h + line->h > pos) || i == buffer->lines_num …
int index, trailing;
+ /* FIXME: what if i == buffer->lines_num - 1 but pos -…
pango_layout_xy_to_index(
line->layout,
x * PANGO_SCALE, (int)(pos - h) * PANGO_SCALE,
t@@ -1409,6 +1506,31 @@ ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int …
}
}
+static void
+scroll_to_pos(ledit_buffer *buffer, int line, int byte, int top) {
+ PangoRectangle strong, weak;
+ int text_w, text_h;
+ ledit_window_get_textview_size(buffer->window, &text_w, &text_h);
+ ledit_line *ll = ledit_buffer_get_line(buffer, line);
+ pango_layout_get_cursor_pos(ll->layout, byte, &strong, &weak);
+ long cursor_y = strong.y / PANGO_SCALE + ll->y_offset;
+ if (top) {
+ ledit_buffer_scroll(buffer, cursor_y);
+ } else {
+ ledit_buffer_scroll(buffer, cursor_y - text_h + strong.height …
+ }
+}
+
+void
+ledit_buffer_scroll_to_pos_top(ledit_buffer *buffer, int line, int byte) {
+ scroll_to_pos(buffer, line, byte, 1);
+}
+
+void
+ledit_buffer_scroll_to_pos_bottom(ledit_buffer *buffer, int line, int byte) {
+ scroll_to_pos(buffer, line, byte, 0);
+}
+
void
ledit_buffer_ensure_cursor_shown(ledit_buffer *buffer) {
PangoRectangle strong, weak;
t@@ -1420,13 +1542,11 @@ ledit_buffer_ensure_cursor_shown(ledit_buffer *buffer)…
);
long cursor_y = strong.y / PANGO_SCALE + line->y_offset;
if (cursor_y < buffer->display_offset) {
- buffer->display_offset = cursor_y;
+ ledit_buffer_scroll(buffer, cursor_y);
} else if (cursor_y + strong.height / PANGO_SCALE >
buffer->display_offset + text_h) {
- buffer->display_offset =
- cursor_y - text_h + strong.height / PANGO_SCALE;
+ ledit_buffer_scroll(buffer, cursor_y - text_h + strong.height …
}
- ledit_window_set_scroll_pos(buffer->window, buffer->display_offset);
}
static void
diff --git a/buffer.h b/buffer.h
t@@ -131,6 +131,7 @@ void ledit_buffer_resize_width(ledit_buffer *buffer, int w…
is at the nearest grapheme boundary, if it is zero, the byte is always
the beginning of the grapheme under the position */
void ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int snap_to_nea…
+void ledit_buffer_get_nearest_legal_pos(ledit_buffer *buffer, int line, int by…
void ledit_buffer_ensure_cursor_shown(ledit_buffer *buffer);
void ledit_buffer_scroll_handler(void *buffer, long pos);
void ledit_buffer_button_handler(void *data, XEvent *event);
t@@ -143,3 +144,5 @@ void ledit_buffer_paste_clipboard(ledit_buffer *buffer);
void ledit_buffer_paste_primary(ledit_buffer *buffer);
void ledit_buffer_resize_textview(ledit_buffer *buffer);
void ledit_buffer_scroll(ledit_buffer *buffer, long new_offset);
+void ledit_buffer_scroll_to_pos_top(ledit_buffer *buffer, int line, int byte);
+void ledit_buffer_scroll_to_pos_bottom(ledit_buffer *buffer, int line, int byt…
diff --git a/keys.c b/keys.c
t@@ -14,12 +14,7 @@
#include "window.h"
#include "keys.h"
-static char *key_langs[] = {
- "English (US)",
- "German",
- "Urdu (Pakistan)",
- "Hindi (Bolnagri)"
-};
+KEY_LANGS;
int
get_language_index(char *lang) {
diff --git a/keys.h b/keys.h
t@@ -1,6 +1,12 @@
#define LENGTH(X) (sizeof(X) / sizeof(X[0]))
-/* IMPORTANT: Also edit key_langs in keys.c when changing languages! */
+#define KEY_LANGS \
+static char *key_langs[] = { \
+ "English (US)", \
+ "German", \
+ "Urdu (Pakistan)", \
+ "Hindi (Bolnagri)" \
+}
#define GEN_KEY_ARRAY(key_struct, en, de, ur, hi) \
static struct { \
diff --git a/keys_basic.c b/keys_basic.c
t@@ -368,6 +368,62 @@ get_key_repeat(void) {
return num;
}
+static void
+scroll_with_cursor(ledit_buffer *buffer, int movement) {
+ PangoRectangle strong, weak;
+ ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line);
+ pango_layout_get_cursor_pos(ll->layout, buffer->cur_index, &strong, &w…
+ int pix_movement = movement * (strong.height / PANGO_SCALE);
+ ledit_buffer_scroll(buffer, buffer->display_offset + pix_movement);
+ int old_line = buffer->cur_line;
+ int old_index = buffer->cur_index;
+ ledit_buffer_get_nearest_legal_pos(
+ buffer, old_line, old_index,
+ &buffer->cur_line, &buffer->cur_index
+ );
+ if (old_line != buffer->cur_line || old_index != buffer->cur_index) {
+ ledit_buffer_wipe_line_cursor_attrs(buffer, old_line);
+ /* if cursor is at top or bottom of screen, snap it to the
+ very edge to avoid it looking weird */
+ if (movement > 0) {
+ ledit_buffer_scroll_to_pos_top(
+ buffer, buffer->cur_line, buffer->cur_index
+ );
+ } else {
+ ledit_buffer_scroll_to_pos_bottom(
+ buffer, buffer->cur_line, buffer->cur_index
+ );
+ }
+ }
+ ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+}
+
+static struct action
+scroll_with_cursor_up(ledit_buffer *buffer, char *text, int len) {
+ (void)text;
+ (void)len;
+ int repeat = get_key_repeat();
+ if (repeat >= 0)
+ scroll_with_cursor(buffer, -repeat);
+ else
+ ledit_window_show_message(buffer->window, "Invalid key", -1);
+ discard_repetition_stack();
+ return (struct action){ACTION_NONE, NULL};
+}
+
+static struct action
+scroll_with_cursor_down(ledit_buffer *buffer, char *text, int len) {
+ (void)text;
+ (void)len;
+ int repeat = get_key_repeat();
+ if (repeat >= 0)
+ scroll_with_cursor(buffer, repeat);
+ else
+ ledit_window_show_message(buffer->window, "Invalid key", -1);
+ discard_repetition_stack();
+ return (struct action){ACTION_NONE, NULL};
+}
+
/* movement is multiplied with the window height and the result is added to th…
the cursor is moved to the bottom if movement is upwards, to the top otherw…
(unless the screen is already at the very top or bottom - then it is the ot…
t@@ -378,8 +434,10 @@ move_screen(ledit_buffer *buffer, int movement) {
/* FIXME: overflow */
long total = movement * (long)h;
/* new pixel position of cursor */
- /* FIXME: in certain cases, just using h as the y position could make …
- move slightly further down than a screen once ensure_cursor_shown i…
+ /* Note: this usually causes at least part of a line of overlap
+ because ensure_cursor_shown scrolls back a bit if the line
+ isn't completely shown (this behavior could be changed using
+ ledit_buffer_get_nearest_legal_pos) */
int y = movement > 0 ? 0 : h;
if (buffer->display_offset + total < 0)
y = 0;
diff --git a/keys_basic_config.h b/keys_basic_config.h
t@@ -59,6 +59,8 @@ static struct action insert_mode_insert_text(ledit_buffer *b…
static struct action repeat_command(ledit_buffer *buffer, char *text, int len);
static struct action screen_up(ledit_buffer *buffer, char *text, int len);
static struct action screen_down(ledit_buffer *buffer, char *text, int len);
+static struct action scroll_with_cursor_up(ledit_buffer *buffer, char *text, i…
+static struct action scroll_with_cursor_down(ledit_buffer *buffer, char *text,…
/* FIXME: maybe sort these and use binary search
-> but that would mess with the catch-all keys */
t@@ -103,9 +105,11 @@ static struct key keys_en[] = {
{"U", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &redo},
{".", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &repeat_command}, /* FIXME: onl…
{"z", ControlMask, 0, INSERT, KEY_ANY, KEY_ANY, &undo},
- {"y", ControlMask, 0, INSERT, KEY_ANY, KEY_ANY, &redo},
+ {"y", ControlMask, 0, INSERT, KEY_ANY, KEY_ANY, &redo}, /* FIXME: thi…
{"b", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &screen_up},
{"f", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &screen_dow…
+ {"e", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &scroll_wit…
+ {"y", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &scroll_wit…
{"", 0, 0, INSERT, KEY_ANY, KEY_ANY, &insert_mode_insert_text}
};
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.