Introduction
Introduction Statistics Contact Development Disclaimer Help
tAbstract text operations a bit - 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 0e379b0cf1ba991e2024b2541a9d5d4f80068d5b
parent e181351df92df2596bd48578667ce195f4cf34d0
Author: lumidify <[email protected]>
Date: Sat, 5 Jun 2021 20:16:59 +0200
Abstract text operations a bit
Diffstat:
M buffer.c | 128 ++++++++++++++++++++++++++---…
M buffer.h | 16 ++++++++++++++++
M ledit.c | 82 +++++++++--------------------…
3 files changed, 149 insertions(+), 77 deletions(-)
---
diff --git a/buffer.c b/buffer.c
t@@ -1,6 +1,7 @@
/* FIXME: shrink buffers when text length less than a fourth of the size */
#include <string.h>
+#include <assert.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
t@@ -101,6 +102,18 @@ ledit_wipe_line_cursor_attrs(ledit_buffer *buffer, int li…
}
void
+ledit_insert_text_from_line(
+ ledit_buffer *buffer,
+ int dst_line, int dst_index,
+ int src_line, int src_index, int src_len) {
+ assert(dst_line != src_line);
+ ledit_line *ll = ledit_get_line(buffer, src_line);
+ if (src_len == -1)
+ src_len = ll->len - src_index;
+ ledit_insert_text(buffer, dst_line, dst_index, ll->text, src_len);
+}
+
+void
ledit_insert_text(ledit_buffer *buffer, int line_index, int index, char *text,…
ledit_line *line = &buffer->lines[line_index];
if (len == -1)
t@@ -333,22 +346,109 @@ ledit_line_visible(ledit_buffer *buffer, int index) {
line->y_offset + line->h > buffer->display_offset;
}
+/* get needed length of text range, including newlines
+ * - NUL is not included
+ * - if the last range ends at the end of a line, the newline is *not* included
+ * - the range must be sorted already */
+size_t
+ledit_textlen(ledit_buffer *buffer, int line1, int byte1, int line2, int byte2…
+ assert(line1 < line2 || (line1 == line2 && byte1 <= byte2));
+ size_t len = 0;
+ ledit_line *ll = ledit_get_line(buffer, line1);
+ if (line1 == line2) {
+ len = byte2 - byte1;
+ } else {
+ /* + 1 for newline */
+ len = ll->len - byte1 + byte2 + 1;
+ for (int i = line1 + 1; i < line2; i++) {
+ ll = ledit_get_line(buffer, i);
+ len += ll->len + 1;
+ }
+ }
+ return len;
+}
+
+/* copy text range into given buffer
+ * - dst is null-terminated
+ * - dst must be large enough to contain the text and NUL
+ * - the range must be sorted already */
+void
+ledit_copy_text(ledit_buffer *buffer, char *dst, int line1, int byte1, int lin…
+ assert(line1 < line2 || (line1 == line2 && byte1 <= byte2));
+ ledit_line *ll1 = ledit_get_line(buffer, line1);
+ ledit_line *ll2 = ledit_get_line(buffer, line2);
+ if (line1 == line2) {
+ memcpy(dst, ll1->text + byte1, byte2 - byte1);
+ dst[byte2 - byte1] = '\0';
+ } else {
+ size_t cur_pos = 0;
+ memcpy(dst, ll1->text + byte1, ll1->len - byte1);
+ cur_pos += ll1->len - byte1;
+ dst[cur_pos] = '\n';
+ cur_pos++;
+ for (int i = line1 + 1; i < line2; i++) {
+ ledit_line *ll = ledit_get_line(buffer, i);
+ memcpy(dst + cur_pos, ll->text, ll->len);
+ cur_pos += ll->len;
+ dst[cur_pos] = '\n';
+ cur_pos++;
+ }
+ memcpy(dst + cur_pos, ll2->text, byte2);
+ cur_pos += byte2;
+ dst[cur_pos] = '\0';
+ }
+}
+
+/* copy text range into given buffer and resize it if necessary
+ * - *dst is reallocated and *alloc adjusted if the text doesn't fit
+ * - *dst is null-terminated
+ * - the range must be sorted already
+ * - returns the length of the text, not including the NUL */
+size_t
+ledit_copy_text_with_resize(
+ ledit_buffer *buffer,
+ char **dst, size_t *alloc,
+ int line1, int byte1,
+ int line2, int byte2) {
+ assert(line1 < line2 || (line1 == line2 && byte1 <= byte2));
+ size_t len = ledit_textlen(buffer, line1, byte1, line2, byte2);
+ /* len + 1 because of nul */
+ if (len + 1 > *alloc) {
+ *alloc = *alloc * 2 > len + 1 ? *alloc * 2 : len + 1;
+ *dst = ledit_realloc(*dst, *alloc);
+ }
+ ledit_copy_text(buffer, *dst, line1, byte1, line2, byte2);
+ return len;
+}
+
+int
+ledit_prev_utf8(ledit_line *line, int index) {
+ int i = index - 1;
+ /* find valid utf8 char - this probably needs to be improved */
+ while (i > 0 && ((line->text[i] & 0xC0) == 0x80))
+ i--;
+ return i;
+}
+
+int
+ledit_next_utf8(ledit_line *line, int index) {
+ int i = index + 1;
+ while (i < line->len && ((line->text[i] & 0xC0) == 0x80))
+ i++;
+ return i;
+}
+
int
ledit_delete_unicode_char(ledit_buffer *buffer, int line_index, int byte_index…
ledit_line *l = ledit_get_line(buffer, line_index);
int new_index = byte_index;
if (dir < 0) {
- int i = byte_index - 1;
- /* find valid utf8 char - this probably needs to be improved */
- while (i > 0 && ((l->text[i] & 0xC0) == 0x80))
- i--;
+ int i = ledit_prev_utf8(l, byte_index);
memmove(l->text + i, l->text + byte_index, l->len - byte_index…
l->len -= byte_index - i;
new_index = i;
} else {
- int i = byte_index + 1;
- while (i < l->len && ((l->text[i] & 0xC0) == 0x80))
- i++;
+ int i = ledit_next_utf8(l, byte_index);
memmove(l->text + byte_index, l->text + i, l->len - i);
l->len -= i - byte_index;
}
t@@ -410,11 +510,7 @@ ledit_x_softline_to_pos(ledit_line *line, int x, int soft…
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)++;
+ *pos_ret = ledit_next_utf8(line, *pos_ret);
}
}
}
t@@ -429,14 +525,10 @@ ledit_get_legal_normal_pos(ledit_buffer *buffer, int lin…
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--;
+ ret = ledit_prev_utf8(final_line, ret);
while (ret > 0 && cur > 0 && !attrs[cur].is_cursor_position) {
cur--;
- ret--;
- while (ret > 0 && ((final_line->text[ret] & 0xC0) == 0…
- ret--;
+ ret = ledit_prev_utf8(final_line, ret);
}
}
return ret;
diff --git a/buffer.h b/buffer.h
t@@ -66,3 +66,19 @@ void ledit_delete_range(
);
void ledit_pos_to_x_softline(ledit_line *line, int pos, int *x_ret, int *softl…
void ledit_x_softline_to_pos(ledit_line *line, int x, int softline, int *pos_r…
+int ledit_next_utf8(ledit_line *line, int index);
+int ledit_prev_utf8(ledit_line *line, int index);
+size_t ledit_textlen(ledit_buffer *buffer, int line1, int byte1, int line2, in…
+void ledit_copy_text(ledit_buffer *buffer, char *dst, int line1, int byte1, in…
+size_t ledit_copy_text_with_resize(
+ ledit_buffer *buffer,
+ char **dst, size_t *alloc,
+ int line1, int byte1,
+ int line2, int byte2
+);
+void
+ledit_insert_text_from_line(
+ ledit_buffer *buffer,
+ int dst_line, int dst_index,
+ int src_line, int src_index, int src_len
+);
diff --git a/ledit.c b/ledit.c
t@@ -707,7 +707,7 @@ mainloop(void) {
fprintf(stderr, "XKB not supported.");
exit(1);
}
- printf("XKB (%d.%d) supported.\n", major, minor);
+ /*printf("XKB (%d.%d) supported.\n", major, minor);*/
/* This should select the events when the keyboard mapping changes.
* When e.g. 'setxkbmap us' is executed, two events are sent, but I
* haven't figured out how to change that. When the xkb layout
t@@ -821,10 +821,12 @@ setup(int argc, char *argv[]) {
/* based on http://wili.cc/blog/xdbe.html */
int major, minor;
if (XdbeQueryExtension(state.dpy, &major, &minor)) {
+ /*
printf(
"Xdbe (%d.%d) supported, using double buffering.\n",
major, minor
);
+ */
int num_screens = 1;
Drawable screens[] = { DefaultRootWindow(state.dpy) };
XdbeScreenVisualInfo *info = XdbeGetVisualInfo(
t@@ -1116,12 +1118,9 @@ xy_to_line_byte(int x, int y, int *line_ret, int *byte_…
x * PANGO_SCALE, (int)(pos - h) * PANGO_SCALE,
&index, &trailing
);
- /* FIXME: make this a separate, reusable function */
while (trailing > 0) {
trailing--;
- index++;
- while (index < line->len && ((line->text[index…
- index++;
+ index = ledit_next_utf8(line, index);
}
*line_ret = i;
*byte_ret = index;
t@@ -1153,45 +1152,10 @@ sort_selection(int *line1, int *byte1, int *line2, int…
/* lines and bytes need to be sorted already! */
static void
copy_selection_to_x_primary(int line1, int byte1, int line2, int byte2) {
- size_t len = 0;
- ledit_line *ll1 = ledit_get_line(buffer, line1);
- ledit_line *ll2 = ledit_get_line(buffer, line2);
- if (line1 == line2) {
- len = byte2 - byte1;
- } else {
- /* + 1 for newline */
- len = ll1->len - byte1 + byte2 + 1;
- for (int i = line1 + 1; i < line2; i++) {
- ledit_line *ll = ledit_get_line(buffer, i);
- len += ll->len + 1;
- }
- }
- len += 1; /* nul */
- if (len > xsel.primary_alloc) {
- /* FIXME: maybe allocate a bit more */
- xsel.primary = ledit_realloc(xsel.primary, len);
- xsel.primary_alloc = len;
- }
- if (line1 == line2) {
- memcpy(xsel.primary, ll1->text + byte1, byte2 - byte1);
- xsel.primary[byte2 - byte1] = '\0';
- } else {
- size_t cur_pos = 0;
- memcpy(xsel.primary, ll1->text + byte1, ll1->len - byte1);
- cur_pos += ll1->len - byte1;
- xsel.primary[cur_pos] = '\n';
- cur_pos++;
- for (int i = line1 + 1; i < line2; i++) {
- ledit_line *ll = ledit_get_line(buffer, i);
- memcpy(xsel.primary + cur_pos, ll->text, ll->len);
- cur_pos += ll->len;
- xsel.primary[cur_pos] = '\n';
- cur_pos++;
- }
- memcpy(xsel.primary + cur_pos, ll2->text, byte2);
- cur_pos += byte2;
- xsel.primary[cur_pos] = '\0';
- }
+ (void)ledit_copy_text_with_resize(
+ buffer, &xsel.primary, &xsel.primary_alloc,
+ line1, byte1, line2, byte2
+ );
XSetSelectionOwner(state.dpy, XA_PRIMARY, state.win, CurrentTime);
/*
FIXME
t@@ -1378,12 +1342,10 @@ backspace(void) {
} 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…
int old_len = l1->len;
- ledit_insert_text_with_newlines(
- buffer, buffer->cur_line - 1,
- l1->len, l2->text, l2->len,
- NULL, NULL
+ ledit_insert_text_from_line(
+ buffer, buffer->cur_line - 1, l1->len,
+ buffer->cur_line, 0, -1
);
ledit_delete_line_entry(buffer, buffer->cur_line);
buffer->cur_line--;
t@@ -1404,14 +1366,10 @@ delete_key(void) {
/* 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
- );
int old_len = cur_line->len;
- ledit_insert_text_with_newlines(
+ ledit_insert_text_from_line(
buffer, buffer->cur_line, cur_line->len,
- next_line->text, next_line->len,
- NULL, NULL
+ buffer->cur_line + 1, 0, -1
);
ledit_delete_line_entry(buffer, buffer->cur_line + 1);
buffer->cur_index = old_len;
t@@ -1463,10 +1421,7 @@ move_cursor_left_right(int dir) {
/* FIXME: spaces at end of softlines are weird in normal mode */
while (trailing > 0) {
trailing--;
- new_index++;
- while (new_index < cur_line->len &&
- ((cur_line->text[new_index] & 0xC0) == 0x80))
- new_index++;
+ new_index = ledit_next_utf8(cur_line, new_index);
}
if (new_index < 0)
new_index = 0;
t@@ -1725,6 +1680,14 @@ end_lineedit(void) {
}
}
+static void
+show_line(void) {
+ int len = snprintf(NULL, 0, "Line %d of %d", buffer->cur_line + 1, buf…
+ char *str = ledit_malloc(len + 1);
+ snprintf(str, len + 1, "Line %d of %d", buffer->cur_line + 1, buffer->…
+ show_message(str, len);
+}
+
/* FIXME: maybe sort these and use binary search */
static struct key keys_en[] = {
{NULL, 0, XK_BackSpace, INSERT, KEY_ANY, KEY_ANY, &backspace},
t@@ -1757,6 +1720,7 @@ static struct key keys_en[] = {
{"o", 0, 0, VISUAL, KEY_ANY, KEY_ANY, &switch_selection_end},
{"c", ControlMask, 0, INSERT|VISUAL, KEY_ANY, KEY_ANY, &clipcopy},
{"v", ControlMask, 0, INSERT, KEY_ANY, KEY_ANY, &clippaste},
+ {"g", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &show_line},
{":", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &enter_commandedit},
{"?", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &enter_searchedit_backwa…
{"/", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &enter_searchedit_forwar…
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.