Introduction
Introduction Statistics Contact Development Disclaimer Help
tAdd support for multiple views - 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 9bdc877acf81ae270c68cacad2e70b9860f0832e
parent 6c98800389dc02e20954a157675ac67fb02b7f8c
Author: lumidify <[email protected]>
Date: Sun, 28 Nov 2021 21:06:33 +0100
Add support for multiple views
Warning: There are still a lot of bugs.
Diffstat:
M IDEAS | 6 +++---
M Makefile | 6 ++++--
A QUIRKS | 9 +++++++++
A TODO | 2 ++
M buffer.c | 2267 ++++-------------------------…
M buffer.h | 418 ++++++++++++++++++++---------…
M cache.c | 94 +++++++++++++++--------------…
M cache.h | 66 +++++++++++++++++------------…
A cleanup.h | 3 +++
M common.h | 9 ++++-----
M keys_basic.c | 1483 +++++++++++++++--------------…
M keys_basic.h | 3 +--
M keys_basic_config.h | 160 ++++++++++++++++-------------…
M keys_command.c | 232 +++++++++++++++++------------…
M keys_command.h | 17 +++--------------
M keys_command_config.h | 32 ++++++++++++++++-------------…
M ledit.c | 196 ++++++++++-------------------…
A macros.h | 10 ++++++++++
M memory.c | 114 +++++++++++++++++++++++++++++…
M memory.h | 32 +++++++++++++++++++++++++++++…
M pango-compat.c | 8 ++++++--
M pango-compat.h | 5 +++--
M search.c | 74 ++++++++++++++++-------------…
M search.h | 4 ++--
M undo.c | 32 +++++++++++++++++++++++------…
M undo.h | 8 ++++----
M util.h | 2 ++
A view.c | 2096 +++++++++++++++++++++++++++++…
A view.h | 158 +++++++++++++++++++++++++++++…
M window.c | 179 +++++++++++++++++++++++++----…
M window.h | 37 +++++++++++++++++++++++++----…
31 files changed, 4305 insertions(+), 3457 deletions(-)
---
diff --git a/IDEAS b/IDEAS
t@@ -1,5 +1,5 @@
-* Important: use less memory (maybe don't keep all pango layouts around
- all the time)
-* allow editing same file in multiple places at same time (like in acme)
+* draw cursor as outline rectangle when window not active
+* implement '!' command by just opening a separate terminal
+* basic macros
* add different (more basic) text backend
* https://drewdevault.com/2021/06/27/You-cant-capture-the-nuance.html
diff --git a/Makefile b/Makefile
t@@ -11,6 +11,7 @@ MAN1 = ${BIN:=.1}
OBJ = \
buffer.o \
+ view.o \
cache.o \
keys.o \
keys_basic.o \
t@@ -26,8 +27,8 @@ OBJ = \
pango-compat.o
HDR = \
- action.h \
buffer.h \
+ view.h \
cache.h \
common.h \
keys.h \
t@@ -40,6 +41,7 @@ HDR = \
undo.h \
util.h \
window.h \
+ cleanup.h \
pango-compat.h
CFLAGS_LEDIT = -g -Wall -Wextra -D_POSIX_C_SOURCE=200809L `pkg-config --cflags…
t@@ -47,7 +49,7 @@ LDFLAGS_LEDIT = ${LDFLAGS} `pkg-config --libs x11 xkbfile pa…
all: ${BIN}
-ledit.o : config.h
+ledit.o window.o : config.h
theme.o : theme_config.h
keys_basic.o : keys_basic_config.h
keys_command.o : keys_command_config.h
diff --git a/QUIRKS b/QUIRKS
t@@ -0,0 +1,9 @@
+* Undo with multiple views:
+ Since a new mode group is started each time insert is entered, when text
+ is typed in one view in insert, then in another view, and then again in
+ the first one, the last two inserts will be undone in one go since both
+ views were in insert already. I'm not sure how to make this more logical,
+ though.
+ Maybe it could be "improved" by also saving view in undo stack, but that
+ would cause problems because views can be added and removed, and it would
+ maybe not even be more logical.
diff --git a/TODO b/TODO
t@@ -0,0 +1,2 @@
+* Load file in background so text is already shown while still
+ loading the rest of a big file.
diff --git a/buffer.c b/buffer.c
t@@ -1,12 +1,14 @@
/* FIXME: shrink buffers when text length less than a fourth of the size */
-/* FIXME: also cache PangoLayouts since keeping them around isn't really of mu…
/* FIXME: handle all undo within buffer to keep it consistent */
+/* FIXME: maybe use separate unicode grapheme library so all functions
+ that need grapheme boundaries can be included here instead of in the views …
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
+#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
t@@ -34,52 +36,45 @@
* normalized. This is a bit ugly, but oh well.
*/
-static PangoAttrList *basic_attrs = NULL;
+/*
+ * Note: "line gap buffer" refers to the gap buffer containing
+ * all lines, not to the gap buffer of the text in one line.
+ */
-/*static void err_text_dirty(ledit_buffer *buffer, int line);*/
-static void move_text_gap(ledit_line *line, int index);
-static void resize_and_move_text_gap(ledit_line *line, int min_size, int index…
-static char *strchr_len(char *text, char c, long len);
-static void init_line(ledit_buffer *buffer, ledit_line *line);
-static void delete_line_section_base(ledit_buffer *buffer, int line, int start…
-static void swap(int *a, int *b);
-static void copy_selection_to_x_primary(ledit_buffer *buffer, int line1, int b…
+/*
+ * Move the gap of a line so it is at byte position 'index'
+ */
+static void move_text_gap(ledit_line *line, size_t index);
/*
- * Assign a cache index to line and set text and highlight of the pango layout.
+ * Move the gap of the line gap buffer to 'index'.
*/
-static void set_pango_text_and_highlight(ledit_buffer *buffer, int line);
+static void move_line_gap(ledit_buffer *buffer, size_t index);
/*
- * Get the pango layout for line.
- * This first assigns a cache index (by calling set_pango_text_and_highlight).
+ * Resize the line so it can hold at least 'min_size' bytes and move the gap
+ * to byte position 'index'.
*/
-static PangoLayout *get_pango_layout(ledit_buffer *buffer, int line);
+static void resize_and_move_text_gap(ledit_line *line, size_t min_size, size_t…
/*
- * Get an attribute list for a text highlight between the given range.
+ * Resize the line gap buffer so it can hold at least 'min_size' lines and
+ * move the gap to line at position 'index'.
*/
-static PangoAttrList *get_pango_attributes(ledit_buffer *buffer, int start_byt…
+static void resize_and_move_line_gap(ledit_buffer *buffer, size_t min_size, si…
/*
- * Set the attributes for a PangoLayout belonging to the given line index.
- * If the line is part of the buffer's selection, the selection is set.
- * If that is not the case but cursor_index is set for the line, the character
- * at that position is highlighted (this is used for the normal mode cursor).
- * Otherwise, the default attributes (basic_attrs) are set.
+ * Similar to strchr, but the length of the text is given separately
*/
-static void set_line_layout_attrs(ledit_buffer *buffer, int line, PangoLayout …
+static char *strchr_len(char *text, char c, size_t len);
-static int line_visible_callback(void *data, int line);
-static void set_pixmap_line_helper(void *data, int line, int index);
-static void set_layout_line_helper(void *data, int line, int index);
+/*
+ * Initialize a line with default values for its struct members.
+ */
+static void init_line(ledit_buffer *buffer, ledit_line *line);
-void
-ledit_buffer_set_mode(ledit_buffer *buffer, enum ledit_mode mode) {
- buffer->common->mode = mode;
- ledit_window_set_mode(buffer->window, mode);
- ledit_change_mode_group(buffer->undo);
-}
+static void marklist_destroy(ledit_buffer_marklist *marklist);
+static ledit_buffer_marklist *marklist_create(void);
static void
marklist_destroy(ledit_buffer_marklist *marklist) {
t@@ -91,7 +86,7 @@ marklist_destroy(ledit_buffer_marklist *marklist) {
}
void
-ledit_buffer_insert_mark(ledit_buffer *buffer, char *mark, int len, int line, …
+ledit_buffer_insert_mark(ledit_buffer *buffer, char *mark, size_t len, size_t …
ledit_buffer_marklist *marklist = buffer->marklist;
for (size_t i = 0; i < marklist->len; i++) {
if (!strncmp(mark, marklist->marks[i].text, len)) {
t@@ -123,51 +118,89 @@ marklist_create(void) {
}
ledit_buffer *
-ledit_buffer_create(ledit_common *common, ledit_theme *theme, ledit_window *wi…
- if (basic_attrs == NULL) {
- basic_attrs = pango_attr_list_new();
- #if PANGO_VERSION_CHECK(1, 44, 0)
- PangoAttribute *no_hyphens = pango_attr_insert_hyphens_new(FAL…
- pango_attr_list_insert(basic_attrs, no_hyphens);
- #endif
- }
-
+ledit_buffer_create(ledit_common *common) {
ledit_buffer *buffer = ledit_malloc(sizeof(ledit_buffer));
- buffer->cache = cache_create(common->dpy);
+ buffer->common = common;
buffer->undo = ledit_undo_stack_create();
- buffer->theme = theme;
buffer->marklist = marklist_create();
- ledit_window_set_scroll_callback(window, &ledit_buffer_scroll_handler,…
- ledit_window_set_button_callback(window, &ledit_buffer_button_handler,…
- buffer->common = common;
- buffer->window = window;
- buffer->lines = NULL;
buffer->filename = NULL;
+ buffer->lines = NULL;
buffer->lines_num = 0;
buffer->lines_cap = 0;
- buffer->selecting = 0;
- buffer->cur_line = 0;
- buffer->cur_index = 0;
- /* FIXME: trailing currently not used */
- buffer->trailing = 0;
- buffer->trailing_bytes = 0;
- buffer->end_of_soft_line = 0;
- buffer->total_height = 0;
- buffer->display_offset = 0;
- buffer->sel.line1 = buffer->sel.byte1 = -1;
- buffer->sel.line2 = buffer->sel.byte2 = -1;
-
- ledit_buffer_append_line_base(buffer, -1, -1);
- ledit_buffer_recalc_all_lines(buffer);
+ buffer->lines_gap = 0;
+ buffer->views = NULL;
+ buffer->views_num = 0;
+ buffer->hard_line_based = 1;
+
+ /* add one empty line to buffer */
+ resize_and_move_line_gap(buffer, 1, 0);
+ buffer->lines_num++;
+ buffer->lines_gap++;
+ ledit_line *ll = ledit_buffer_get_line(buffer, 0);
+ init_line(buffer, ll);
return buffer;
}
+static void
+set_view_hard_line_text(ledit_buffer *buffer, ledit_view *view) {
+ char *text = buffer->hard_line_based ? "|HL" : "|SL";
+ ledit_window_set_mode_extra_text(view->window, text);
+}
+
+void
+ledit_buffer_set_hard_line_based(ledit_buffer *buffer, int hl) {
+ buffer->hard_line_based = hl;
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ set_view_hard_line_text(buffer, buffer->views[i]);
+ }
+}
+
+void
+ledit_buffer_add_view(ledit_buffer *buffer, ledit_theme *theme, enum ledit_mod…
+ size_t new_num = buffer->views_num + 1;
+ if (new_num <= buffer->views_num)
+ err_overflow();
+ buffer->views = ledit_reallocarray(buffer->views, new_num, sizeof(ledi…
+ buffer->views[buffer->views_num] = view_create(buffer, theme, mode, li…
+ set_view_hard_line_text(buffer, buffer->views[buffer->views_num]);
+ buffer->views_num = new_num;
+}
+
+/* FIXME: error checking */
+void
+ledit_buffer_remove_view(ledit_buffer *buffer, ledit_view *view) {
+ size_t i = 0;
+ int found = 0;
+ for (; i < buffer->views_num; i++) {
+ if (buffer->views[i] == view) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ view_destroy(buffer->views[i]);
+ memmove(
+ buffer->views + i,
+ buffer->views + i + 1,
+ (buffer->views_num - i - 1) * sizeof(ledit_view *)
+ );
+ ledit_reallocarray(buffer->views, --buffer->views_num, sizeof(…
+ }
+}
+
+void
+ledit_buffer_recalc_all_views_from_line(ledit_buffer *buffer, size_t line) {
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_recalc_from_line(buffer->views[i], line);
+ }
+}
+
/* FIXME: don't generate extra blank line at end! */
/* WARNING: errstr must be copied as soon as possible! */
int
-ledit_buffer_load_file(ledit_buffer *buffer, char *filename, int line, char **…
+ledit_buffer_load_file(ledit_buffer *buffer, char *filename, size_t line, char…
long len;
int off = 0;
ledit_line *ll;
t@@ -224,7 +257,7 @@ ledit_buffer_write_to_file(ledit_buffer *buffer, char *fil…
file = fopen(filename, "w");
if (!file) goto error;
clearerr(file);
- for (int i = 0; i < buffer->lines_num; i++) {
+ for (size_t i = 0; i < buffer->lines_num; i++) {
ll = ledit_buffer_get_line(buffer, i);
ledit_buffer_normalize_line(ll);
if (fprintf(file, "%s\n", ll->text) < 0) goto errorclose;
t@@ -245,11 +278,10 @@ errorclose:
void
ledit_buffer_destroy(ledit_buffer *buffer) {
ledit_line *l;
- for (int i = 0; i < buffer->lines_num; i++) {
+ for (size_t i = 0; i < buffer->lines_num; i++) {
l = ledit_buffer_get_line(buffer, i);
free(l->text);
}
- cache_destroy(buffer->cache);
ledit_undo_stack_destroy(buffer->undo);
free(buffer->lines);
if (buffer->filename)
t@@ -259,12 +291,6 @@ ledit_buffer_destroy(ledit_buffer *buffer) {
}
void
-ledit_buffer_cleanup(void) {
- if (basic_attrs)
- pango_attr_list_unref(basic_attrs);
-}
-
-void
ledit_buffer_normalize_line(ledit_line *line) {
if (line->gap < line->len) {
memmove(
t@@ -275,122 +301,17 @@ ledit_buffer_normalize_line(ledit_line *line) {
line->gap = line->len;
}
/* FIXME: check if enough space, just to be sure */
+ assert(line->len < line->cap);
line->text[line->len] = '\0';
}
-#if 0
-static void
-err_text_dirty(ledit_buffer *buffer, int line) {
- fprintf(
- stderr,
- "WARNING: Line had text_dirty or h_dirty attribute "
- "set when rendering. Fix your code!\n"
- );
- ledit_buffer_recalc_from_line(buffer, line);
-}
-#endif
-
-#if 0
-static void
-set_line_selection(ledit_buffer *buffer, int line, int start_byte, int end_byt…
- ledit_line *l = ledit_buffer_get_line(buffer, line);
- if (l->text_dirty)
- err_text_dirty(buffer, line);
- /* FIXME: Are these guaranteed to be range 0-65535? */
- XRenderColor fg = buffer->theme->text_fg.color;
- XRenderColor bg = buffer->theme->text_bg.color;
- PangoAttribute *attr0 = pango_attr_background_new(fg.red, fg.green, fg…
- PangoAttribute *attr1 = pango_attr_foreground_new(bg.red, bg.green, bg…
- attr0->start_index = start_byte;
- attr0->end_index = end_byte;
- attr1->start_index = start_byte;
- attr1->end_index = end_byte;
- PangoAttrList *list = pango_attr_list_new();
- pango_attr_list_insert(list, attr0);
- pango_attr_list_insert(list, attr1);
- #if PANGO_VERSION_CHECK(1, 44, 0)
- PangoAttribute *attr2 = pango_attr_insert_hyphens_new(FALSE);
- pango_attr_list_insert(list, attr2);
- #endif
- pango_layout_set_attributes(l->layout, list);
- pango_attr_list_unref(list);
- l->dirty = 1;
-}
-#endif
-
-static PangoAttrList *
-get_pango_attributes(ledit_buffer *buffer, int start_byte, int end_byte) {
- XRenderColor fg = buffer->theme->text_fg.color;
- XRenderColor bg = buffer->theme->text_bg.color;
- PangoAttribute *attr0 = pango_attr_background_new(fg.red, fg.green, fg…
- PangoAttribute *attr1 = pango_attr_foreground_new(bg.red, bg.green, bg…
- attr0->start_index = start_byte;
- attr0->end_index = end_byte;
- attr1->start_index = start_byte;
- attr1->end_index = end_byte;
- PangoAttrList *list = pango_attr_list_new();
- pango_attr_list_insert(list, attr0);
- pango_attr_list_insert(list, attr1);
- #if PANGO_VERSION_CHECK(1, 44, 0)
- PangoAttribute *attr2 = pango_attr_insert_hyphens_new(FALSE);
- pango_attr_list_insert(list, attr2);
- #endif
- return list;
-}
-
-/* this takes layout directly to possibly avoid infinite recursion */
-static void
-set_line_layout_attrs(ledit_buffer *buffer, int line, PangoLayout *layout) {
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- ledit_range sel = ll->parent_buffer->sel;
- PangoAttrList *list = NULL;
- if (sel.line1 < line && sel.line2 > line) {
- list = get_pango_attributes(buffer, 0, ll->len);
- } else if (sel.line1 == line && sel.line2 == line) {
- int start = sel.byte1, end = sel.byte2;
- if (start > end)
- swap(&start, &end);
- list = get_pango_attributes(buffer, start, end);
- } else if (sel.line1 == line && sel.line2 > line) {
- list = get_pango_attributes(buffer, sel.byte1, ll->len);
- } else if (sel.line1 < line && sel.line2 == line) {
- list = get_pango_attributes(buffer, 0, sel.byte2);
- } else if (ll->cursor_index >= 0 && ll->cursor_index < ll->len) {
- /* FIXME: does just adding one really do the right thing? */
- list = get_pango_attributes(buffer, ll->cursor_index, ll->curs…
- }
- if (list != NULL) {
- pango_layout_set_attributes(layout, list);
- pango_attr_list_unref(list);
- } else {
- pango_layout_set_attributes(layout, basic_attrs);
- }
- ll->highlight_dirty = 0;
-}
-
-void
-ledit_buffer_set_line_cursor_attrs(ledit_buffer *buffer, int line, int index) {
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- ll->cursor_index = index;
- ll->highlight_dirty = 1;
- ll->dirty = 1;
-}
-
-void
-ledit_buffer_wipe_line_cursor_attrs(ledit_buffer *buffer, int line) {
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- ll->cursor_index = -1;
- ll->highlight_dirty = 1;
- ll->dirty = 1;
-}
-
/* FIXME: To simplify this a bit, maybe just copy text to txtbuf first and
then insert it in one go instead of having this complex logic */
void
ledit_buffer_insert_text_from_line(
ledit_buffer *buffer,
- int dst_line, int dst_index,
- int src_line, int src_index, int src_len,
+ size_t dst_line, size_t dst_index,
+ size_t src_line, size_t src_index, size_t src_len,
txtbuf *text_ret) {
ledit_buffer_insert_text_from_line_base(
buffer, dst_line, dst_index, src_line, src_index, src_len, text_ret
t@@ -398,19 +319,17 @@ ledit_buffer_insert_text_from_line(
ledit_buffer_recalc_line(buffer, dst_line);
}
-/* FIXME: check if there can be bugs when a newline is inserted in some way ot…
+/* FIXME: check if there can be bugs when a newline is inserted in some way
other than pasting or pressing enter */
void
ledit_buffer_insert_text_from_line_base(
ledit_buffer *buffer,
- int dst_line, int dst_index,
- int src_line, int src_index, int src_len,
+ size_t dst_line, size_t dst_index,
+ size_t src_line, size_t src_index, size_t src_len,
txtbuf *text_ret) {
assert(dst_line != src_line);
ledit_line *ll = ledit_buffer_get_line(buffer, src_line);
- if (src_len == -1)
- src_len = ll->len - src_index;
if (text_ret != NULL) {
txtbuf_grow(text_ret, src_len);
text_ret->len = src_len;
t@@ -467,91 +386,66 @@ ledit_buffer_insert_text_from_line_base(
}
}
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_notify_insert_text(buffer->views[i], dst_line, dst_index,…
+ }
}
static void
-move_text_gap(ledit_line *line, int index) {
- if (index > line->gap) {
- /* move piece between end of original gap and
- index to beginning of original gap */
- memmove(
- line->text + line->gap,
- line->text + line->gap + line->cap - line->len,
- index - line->gap
- );
- } else if (index < line->gap) {
- /* move piece between index and original gap to
- end of original gap */
- memmove(
- line->text + index + line->cap - line->len,
- line->text + index,
- line->gap - index
- );
- }
- line->gap = index;
+move_text_gap(ledit_line *line, size_t index) {
+ /* yes, I know sizeof(char) == 1 anyways */
+ move_gap(
+ line->text, sizeof(char), index,
+ line->gap, line->cap, line->len,
+ &line->gap
+ );
+}
+
+static void
+move_line_gap(ledit_buffer *buffer, size_t index) {
+ move_gap(
+ buffer->lines, sizeof(ledit_line), index,
+ buffer->lines_gap, buffer->lines_cap, buffer->lines_num,
+ &buffer->lines_gap
+ );
}
-/* This is almost certainly premature optimization and maybe
- not optimization at all. */
/* FIXME: add "final" versions of the functions that include the
normalization, i.e. if they have to move the gap anyways, they
just move it to the end */
+
static void
-resize_and_move_text_gap(ledit_line *line, int min_size, int index) {
- int gap_size = line->cap - line->len;
- /* FIXME: read up on what the best values are here */
- line->cap = line->cap * 2 > min_size ? line->cap * 2 : min_size;
- line->text = ledit_realloc(line->text, line->cap);
- if (index > line->gap) {
- /* move piece between end of original gap and index to
- beginning of original gap */
- memmove(
- line->text + line->gap,
- line->text + line->gap + gap_size,
- index - line->gap
- );
- /* move piece after index to end of buffer */
- memmove(
- line->text + line->cap - (line->len - index),
- line->text + index + gap_size,
- line->len - index
- );
- } else if (index < line->gap) {
- /* move piece after original gap to end of buffer */
- memmove(
- line->text + line->cap - (line->len - line->gap),
- line->text + line->gap + gap_size,
- line->len - line->gap
- );
- /* move piece between index and original gap to end */
- memmove(
- line->text + line->cap - line->len + index,
- line->text + index,
- line->gap - index
- );
- } else {
- /* move piece after original gap to end of buffer */
- memmove(
- line->text + line->cap - (line->len - line->gap),
- line->text + line->gap + gap_size,
- line->len - line->gap
- );
- }
- line->gap = index;
+resize_and_move_text_gap(ledit_line *line, size_t min_size, size_t index) {
+ /* yes, I know sizeof(char) == 1 anyways */
+ line->text = resize_and_move_gap(
+ line->text, sizeof(char),
+ line->gap, line->cap, line->len,
+ min_size, index,
+ &line->gap, &line->cap
+ );
+}
+
+static void
+resize_and_move_line_gap(ledit_buffer *buffer, size_t min_size, size_t index) {
+ buffer->lines = resize_and_move_gap(
+ buffer->lines, sizeof(ledit_line),
+ buffer->lines_gap, buffer->lines_cap, buffer->lines_num,
+ min_size, index,
+ &buffer->lines_gap, &buffer->lines_cap
+ );
}
void
-ledit_buffer_insert_text(ledit_buffer *buffer, int line_index, int index, char…
+ledit_buffer_insert_text(ledit_buffer *buffer, size_t line_index, size_t index…
ledit_buffer_insert_text_base(buffer, line_index, index, text, len);
ledit_buffer_recalc_line(buffer, line_index);
}
void
-ledit_buffer_insert_text_base(ledit_buffer *buffer, int line_index, int index,…
- ledit_line *line = &buffer->lines[line_index];
- if (len == -1)
- len = strlen(text);
+ledit_buffer_insert_text_base(ledit_buffer *buffer, size_t line_index, size_t …
+ ledit_line *line = ledit_buffer_get_line(buffer, line_index);
/* \0 is not included in line->len */
+ /* FIXME: this if should be redundant now because resize_and_move... i…
if (line->len + len + 1 > line->cap || line->text == NULL)
resize_and_move_text_gap(line, line->len + len + 1, index);
else
t@@ -560,24 +454,15 @@ ledit_buffer_insert_text_base(ledit_buffer *buffer, int …
memcpy(line->text + index, text, len);
line->gap += len;
line->len += len;
- line->dirty = 1;
- line->text_dirty = 1;
- line->h_dirty = 1;
-}
-
-/* FIXME: implement this - if it is known that this is the last insertion,
- move gap to end immediately if the gap needs to be enlarged anyways to
- avoid another copy before rendering */
-/*
-void
-ledit_buffer_insert_text_final(ledit_buffer *buffer, int line_index, int index…
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_notify_insert_text(buffer->views[i], line_index, index, l…
+ }
}
-*/
/* FIXME: this isn't optimized like the standard version, but whatever */
static char *
-strchr_len(char *text, char c, long len) {
- for (long i = 0; i < len; i++) {
+strchr_len(char *text, char c, size_t len) {
+ for (size_t i = 0; i < len; i++) {
if (text[i] == c)
return text + i;
}
t@@ -585,23 +470,16 @@ strchr_len(char *text, char c, long len) {
}
/* FIXME: make these functions that call recalc* also be final as described ab…
-/* FIXME: Sort out integer types.
- -> len is long here mainly because that's what ftell(3) returns and it sort…
- makes sense since a file can be very long (although ledit probably won't wo…
- with such long files anyways). The individual lines have to use int anyways
- because of pango.
- Maybe len isn't needed anyways? It might be possible to enforce that text
- just always has to be null-terminated. */
void
ledit_buffer_insert_text_with_newlines(
ledit_buffer *buffer,
- int line_index, int index,
- char *text, long len,
- int *end_line_ret, int *end_char_ret) {
- int end;
+ size_t line_index, size_t index,
+ char *text, size_t len,
+ size_t *end_line_ret, size_t *end_byte_ret) {
+ size_t end;
ledit_buffer_insert_text_with_newlines_base(
buffer, line_index, index, text, len,
- &end, end_char_ret
+ &end, end_byte_ret
);
if (end_line_ret)
*end_line_ret = end;
t@@ -611,23 +489,22 @@ ledit_buffer_insert_text_with_newlines(
ledit_buffer_recalc_from_line(buffer, line_index);
}
-/* FIXME: Check for integer overflow when casting to int */
+/* FIXME: also look for \r */
void
ledit_buffer_insert_text_with_newlines_base(
ledit_buffer *buffer,
- int line_index, int index,
- char *text, long len,
- int *end_line_ret, int *end_char_ret) {
- if (len == -1)
- len = strlen(text);
- long rem_len = len;
+ size_t line_index, size_t index,
+ char *text, size_t len,
+ size_t *end_line_ret, size_t *end_byte_ret) {
+ size_t rem_len = len;
char *cur, *last = text;
- int cur_line = line_index;
- int cur_index = index;
+ size_t cur_line = line_index;
+ size_t cur_index = index;
/* FIXME: strchr_len isn't really needed when the lines are normalized…
while ((cur = strchr_len(last, '\n', rem_len)) != NULL) {
- /* FIXME: inefficient because there's no gap buffer yet */
- ledit_buffer_append_line_base(buffer, cur_line, cur_index);
+ /* FIXME: this is probably inefficient, but I don't have time …
+ think about it right now */
+ ledit_buffer_append_line_base(buffer, cur_line, cur_index, 1);
ledit_buffer_insert_text_base(buffer, cur_line, cur_index, las…
cur_index = 0;
cur_line++;
t@@ -638,256 +515,122 @@ ledit_buffer_insert_text_with_newlines_base(
ledit_buffer_insert_text_base(buffer, cur_line, cur_index, last, text …
if (end_line_ret)
*end_line_ret = cur_line;
- if (end_char_ret)
- *end_char_ret = cur_index + text + len - last;
-}
-
-/* FIXME: is this even needed? */
-static int
-line_visible_callback(void *data, int line) {
- return ledit_buffer_line_visible((ledit_buffer*)data, line);
-}
-
-/* FIXME: standardize variable names (line/line_index, etc.) */
-void
-ledit_buffer_render_line(ledit_buffer *buffer, int line_index) {
- /* FIXME: check for <= 0 on size */
- ledit_line *ll = ledit_buffer_get_line(buffer, line_index);
- assert(!ll->h_dirty); /* FIXME */
- PangoLayout *layout = get_pango_layout(buffer, line_index);
- if (ll->cache_pixmap_index == -1) {
- cache_assign_pixmap_index(
- buffer->cache, line_index, buffer,
- &line_visible_callback, &set_pixmap_line_helper
- );
- }
- cache_pixmap *pix = cache_get_pixmap(buffer->cache, ll->cache_pixmap_i…
- /* FIXME: sensible default pixmap sizes here */
- if (pix->pixmap == None || pix->draw == NULL) {
- pix->pixmap = XCreatePixmap(
- buffer->common->dpy, buffer->window->drawable,
- ll->w + 10, ll->h + 10, buffer->common->depth
- );
- pix->w = ll->w + 10;
- pix->h = ll->h + 10;
- pix->draw = XftDrawCreate(
- buffer->common->dpy, pix->pixmap,
- buffer->common->vis, buffer->common->cm
- );
- } else if (pix->w < ll->w || pix->h < ll->h) {
- int new_w = ll->w > pix->w ? ll->w + 10 : pix->w + 10;
- int new_h = ll->h > pix->h ? ll->h + 10 : pix->h + 10;
- XFreePixmap(buffer->common->dpy, pix->pixmap);
- pix->pixmap = XCreatePixmap(
- buffer->common->dpy, buffer->window->drawable,
- new_w, new_h, buffer->common->depth
- );
- pix->w = new_w;
- pix->h = new_h;
- XftDrawChange(pix->draw, pix->pixmap);
- }
- XftDrawRect(pix->draw, &buffer->theme->text_bg, 0, 0, ll->w, ll->h);
- pango_xft_render_layout(pix->draw, &buffer->theme->text_fg, layout, 0,…
- ll->dirty = 0;
+ if (end_byte_ret)
+ *end_byte_ret = cur_index + text + len - last;
}
static void
init_line(ledit_buffer *buffer, ledit_line *line) {
- int text_w, text_h;
line->parent_buffer = buffer;
- ledit_window_get_textview_size(buffer->window, &text_w, &text_h);
line->gap = 0;
line->cap = 2; /* arbitrary */
line->text = ledit_malloc(line->cap);
line->text[0] = '\0';
line->len = 0;
- line->cache_pixmap_index = -1;
- line->cache_layout_index = -1;
- line->dirty = 1;
- line->text_dirty = 1;
- line->highlight_dirty = 1;
- line->h_dirty = 1;
- line->w = line->h = 0;
- line->cursor_index = -1;
- line->softlines = 1;
- line->w = text_w;
- line->h = 0;
- line->y_offset = 0;
}
void
-ledit_buffer_append_line(ledit_buffer *buffer, int line_index, int text_index)…
- ledit_buffer_append_line_base(buffer, line_index, text_index);
+ledit_buffer_append_line(ledit_buffer *buffer, size_t line_index, size_t text_…
+ ledit_buffer_append_line_base(buffer, line_index, text_index, break_te…
ledit_buffer_recalc_from_line(buffer, line_index);
}
/* FIXME: error checking (index out of bounds, etc.) */
void
-ledit_buffer_append_line_base(ledit_buffer *buffer, int line_index, int text_i…
- if (buffer->lines_num >= buffer->lines_cap) {
- buffer->lines_cap *= 2;
- if (buffer->lines_cap == 0)
- buffer->lines_cap = 2;
- buffer->lines = ledit_realloc(
- buffer->lines, buffer->lines_cap * sizeof(ledit_line)
- );
- }
- memmove(
- buffer->lines + line_index + 2,
- buffer->lines + line_index + 1,
- (buffer->lines_num - (line_index + 1)) * sizeof(ledit_line)
- );
+ledit_buffer_append_line_base(ledit_buffer *buffer, size_t line_index, size_t …
+ size_t new_len = buffer->lines_num + 1;
+ if (new_len <= buffer->lines_num)
+ err_overflow();
+ size_t insert_index = line_index + 1;
+ if (insert_index <= line_index)
+ err_overflow();
+ resize_and_move_line_gap(buffer, new_len, insert_index);
buffer->lines_num++;
+ buffer->lines_gap++;
ledit_line *new_l = ledit_buffer_get_line(buffer, line_index + 1);
init_line(buffer, new_l);
- if (text_index != -1) {
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_notify_append_line(buffer->views[i], line_index);
+ }
+ if (break_text) {
ledit_line *l = ledit_buffer_get_line(buffer, line_index);
ledit_buffer_insert_text_from_line_base(
buffer, line_index + 1, 0,
- line_index, text_index, -1, NULL
+ line_index, text_index, l->len - text_index, NULL
);
- delete_line_section_base(
+ ledit_buffer_delete_line_section_base(
buffer, line_index,
text_index, l->len - text_index
);
}
}
-/* this is very weird and ugly with the recalc */
+/* FIXME: set offset to 0 when recalculating first line? */
void
-ledit_buffer_delete_line_entries(ledit_buffer *buffer, int index1, int index2)…
+ledit_buffer_delete_line_entries(ledit_buffer *buffer, size_t index1, size_t i…
ledit_buffer_delete_line_entries_base(buffer, index1, index2);
ledit_buffer_recalc_from_line(buffer, index1 > 0 ? index1 - 1 : 0);
}
-static void
-set_pixmap_line_helper(void *data, int line, int index) {
- ledit_line *ll = ledit_buffer_get_line((ledit_buffer *)data, line);
- ll->cache_pixmap_index = index;
-}
-
-static void
-set_layout_line_helper(void *data, int line, int index) {
- ledit_line *ll = ledit_buffer_get_line((ledit_buffer *)data, line);
- ll->cache_layout_index = index;
-}
-
/* IMPORTANT: ledit_buffer_recalc_from_line needs to be called sometime after …
void
-ledit_buffer_delete_line_entries_base(ledit_buffer *buffer, int index1, int in…
+ledit_buffer_delete_line_entries_base(ledit_buffer *buffer, size_t index1, siz…
ledit_line *l;
- /* FIXME: make sure this is always true */
- /* FIXME: Ummm... what is that assert supposed to do? */
+ assert (index2 >= index1);
+ /* it isn't allowed to delete all lines */
assert(index2 - index1 != buffer->lines_num);
- cache_invalidate_from_line(
- buffer->cache, index1, buffer,
- &set_pixmap_line_helper, &set_layout_line_helper
- );
- for (int i = index1; i <= index2; i++) {
+ for (size_t i = index1; i <= index2; i++) {
l = ledit_buffer_get_line(buffer, i);
free(l->text);
}
- /* FIXME: gap buffer */
- if (index2 < buffer->lines_num - 1) {
- memmove(
- buffer->lines + index1, buffer->lines + index2 + 1,
- (buffer->lines_num - index2 - 1) * sizeof(ledit_line)
- );
- }
+ move_line_gap(buffer, index1);
buffer->lines_num -= index2 - index1 + 1;
- /* force a recalc of the lines */
- if (index1 == 0) {
- l = ledit_buffer_get_line(buffer, 0);
- l->y_offset = 0;
- l->h_dirty = 1;
- } else {
- l = ledit_buffer_get_line(buffer, index1 - 1);
- l->h_dirty = 1;
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_notify_delete_lines(buffer->views[i], index1, index2);
}
}
void
-ledit_buffer_delete_line_entry(ledit_buffer *buffer, int index) {
+ledit_buffer_delete_line_entry(ledit_buffer *buffer, size_t index) {
ledit_buffer_delete_line_entries(buffer, index, index);
}
void
-ledit_buffer_delete_line_entry_base(ledit_buffer *buffer, int index) {
+ledit_buffer_delete_line_entry_base(ledit_buffer *buffer, size_t index) {
ledit_buffer_delete_line_entries_base(buffer, index, index);
}
-/* FIXME: use some sort of gap buffer (that would make this function
- slightly more useful...) */
ledit_line *
-ledit_buffer_get_line(ledit_buffer *buffer, int index) {
- assert(index >= 0 && index < buffer->lines_num);
- return &buffer->lines[index];
+ledit_buffer_get_line(ledit_buffer *buffer, size_t index) {
+ assert(index < buffer->lines_num);
+ return index < buffer->lines_gap ?
+ &buffer->lines[index] :
+ &buffer->lines[index + buffer->lines_cap - buffer->lines_num];
}
-/* set text of pango layout if dirty and recalculate height of line
- * - if height hasn't changed, nothing further is done
- * - if height has changed, offset of all following lines is changed */
void
-ledit_buffer_recalc_line(ledit_buffer *buffer, int line) {
- ledit_line *l = ledit_buffer_get_line(buffer, line);
- if (l->text_dirty)
- set_pango_text_and_highlight(buffer, line);
-
- /* if height changed, set height of current line
- * and adjust offsets of all lines following it */
- if (l->h_dirty) {
- l->h_dirty = 0;
- long off = l->y_offset + l->h;
- for (int i = line + 1; i < buffer->lines_num; i++) {
- l = ledit_buffer_get_line(buffer, i);
- l->y_offset = off;
- off += l->h;
- }
- buffer->total_height = off;
+ledit_buffer_recalc_line(ledit_buffer *buffer, size_t line) {
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_recalc_line(buffer->views[i], line);
}
}
-/* set text of pango layout and recalculate height
- * and offset for all lines starting at 'line' */
void
-ledit_buffer_recalc_from_line(ledit_buffer *buffer, int line) {
- ledit_line *l = ledit_buffer_get_line(buffer, line);
- long off = l->y_offset;
- for (int i = line; i < buffer->lines_num; i++) {
- l = ledit_buffer_get_line(buffer, i);
- if (l->text_dirty)
- set_pango_text_and_highlight(buffer, i);
- l->h_dirty = 0;
- l->y_offset = off;
- off += l->h;
+ledit_buffer_recalc_from_line(ledit_buffer *buffer, size_t line) {
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_recalc_from_line(buffer->views[i], line);
}
- buffer->total_height = off;
}
-/* short for 'ledit_buffer_recalc_from_line' starting at line 0 */
void
ledit_buffer_recalc_all_lines(ledit_buffer *buffer) {
- /* force first line to offset 0, just in case */
- ledit_line *l = ledit_buffer_get_line(buffer, 0);
- l->y_offset = 0;
- ledit_buffer_recalc_from_line(buffer, 0);
-}
-
-int
-ledit_buffer_line_visible(ledit_buffer *buffer, int index) {
- int text_w, text_h;
- ledit_window_get_textview_size(buffer->window, &text_w, &text_h);
- ledit_line *l = ledit_buffer_get_line(buffer, index);
- return l->y_offset < buffer->display_offset + text_h &&
- l->y_offset + l->h > buffer->display_offset;
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_recalc_all_lines(buffer->views[i]);
+ }
}
-/* 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_buffer_textlen(ledit_buffer *buffer, int line1, int byte1, int line2, in…
+ledit_buffer_textlen(ledit_buffer *buffer, size_t line1, size_t byte1, size_t …
assert(line1 < line2 || (line1 == line2 && byte1 <= byte2));
size_t len = 0;
ledit_line *ll = ledit_buffer_get_line(buffer, line1);
t@@ -896,7 +639,7 @@ ledit_buffer_textlen(ledit_buffer *buffer, int line1, int …
} else {
/* + 1 for newline */
len = ll->len - byte1 + byte2 + 1;
- for (int i = line1 + 1; i < line2; i++) {
+ for (size_t i = line1 + 1; i < line2; i++) {
ll = ledit_buffer_get_line(buffer, i);
len += ll->len + 1;
}
t@@ -910,10 +653,6 @@ ledit_buffer_textlen(ledit_buffer *buffer, int line1, int…
only done when it is re-rendered (and thus normalized because
of pango's requirements). If a more efficient rendering
backend is added, it would be good to optimize this, though. */
-/* 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_buffer_copy_text(ledit_buffer *buffer, char *dst, int line1, int byte1, …
assert(line1 < line2 || (line1 == line2 && byte1 <= byte2));
t@@ -944,17 +683,12 @@ ledit_buffer_copy_text(ledit_buffer *buffer, char *dst, …
}
}
-/* 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 */
void
ledit_buffer_copy_text_to_txtbuf(
ledit_buffer *buffer,
txtbuf *buf,
- int line1, int byte1,
- int line2, int byte2) {
+ size_t line1, size_t byte1,
+ size_t line2, size_t byte2) {
assert(line1 < line2 || (line1 == line2 && byte1 <= byte2));
size_t len = ledit_buffer_textlen(buffer, line1, byte1, line2, byte2);
txtbuf_grow(buf, len + 1);
t@@ -965,11 +699,11 @@ ledit_buffer_copy_text_to_txtbuf(
/* get char with logical index i from line */
#define LINE_CHAR(line, i) ((i) < (line)->gap ? (line)->text[i] : (line)->text…
-int
-ledit_line_prev_utf8(ledit_line *line, int index) {
+size_t
+ledit_line_prev_utf8(ledit_line *line, size_t index) {
if (index <= 0)
return 0;
- int i = index - 1;
+ size_t i = index - 1;
/* find valid utf8 char - this probably needs to be improved */
/* FIXME: don't go off end or beginning */
while (i > 0 && ((LINE_CHAR(line, i) & 0xC0) == 0x80))
t@@ -977,11 +711,11 @@ ledit_line_prev_utf8(ledit_line *line, int index) {
return i;
}
-int
-ledit_line_next_utf8(ledit_line *line, int index) {
+size_t
+ledit_line_next_utf8(ledit_line *line, size_t index) {
if (index >= line->len)
return line->len;
- int i = index + 1;
+ size_t i = index + 1;
while (i < line->len && ((LINE_CHAR(line, i) & 0xC0) == 0x80))
i++;
return i;
t@@ -990,11 +724,11 @@ ledit_line_next_utf8(ledit_line *line, int index) {
/* Warning: this is very inefficient! */
/* FIXME: at least attempt to be more efficient by starting from the beginning
or end based on approximately where in the line the byte is */
-static int
-line_byte_to_char(ledit_line *line, int byte) {
- int c = 0;
- int i = 0;
- int b = byte > line->len ? line->len : byte; /* maybe not necessary */
+size_t
+line_byte_to_char(ledit_line *line, size_t byte) {
+ size_t c = 0;
+ size_t i = 0;
+ size_t b = byte > line->len ? line->len : byte; /* maybe not necessary…
while (i < b) {
c++;
i = ledit_line_next_utf8(line, i);
t@@ -1002,466 +736,8 @@ line_byte_to_char(ledit_line *line, int byte) {
return c;
}
-int
-ledit_buffer_next_cursor_pos(ledit_buffer *buffer, int line, int byte, int num…
- int nattrs;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- int c = line_byte_to_char(ll, byte);
- int cur_byte = byte;
- PangoLayout *layout = get_pango_layout(buffer, line);
- const PangoLogAttr *attrs =
- pango_layout_get_log_attrs_readonly(layout, &nattrs);
- for (int i = 0; i < num; i++) {
- cur_byte = ledit_line_next_utf8(ll, byte);
- for (c++; c < nattrs; c++) {
- if (attrs[c].is_cursor_position)
- break;
- cur_byte = ledit_line_next_utf8(ll, cur_byte);
- }
- if (cur_byte >= ll->len)
- break;
- }
- return cur_byte <= ll->len ? cur_byte : ll->len;
-}
-
-int
-ledit_buffer_prev_cursor_pos(ledit_buffer *buffer, int line, int byte, int num…
- int nattrs;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- int c = line_byte_to_char(ll, byte);
- int cur_byte = byte;
- PangoLayout *layout = get_pango_layout(buffer, line);
- const PangoLogAttr *attrs =
- pango_layout_get_log_attrs_readonly(layout, &nattrs);
- for (int i = 0; i < num; i++) {
- cur_byte = ledit_line_prev_utf8(ll, cur_byte);
- for (c--; c >= 0; c--) {
- if (attrs[c].is_cursor_position)
- break;
- cur_byte = ledit_line_prev_utf8(ll, cur_byte);
- }
- if (cur_byte <= 0)
- break;
- }
- return cur_byte > 0 ? cur_byte : 0;
-}
-
-static int
-line_next_word(ledit_buffer *buffer, int line, int byte, int char_index, int w…
- int c, nattrs;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- if (char_index >= 0)
- c = char_index;
- else
- c = line_byte_to_char(ll, byte);
- int cur_byte = wrapped_line ? byte : ledit_line_next_utf8(ll, byte);
- PangoLayout *layout = get_pango_layout(buffer, line);
- const PangoLogAttr *attrs =
- pango_layout_get_log_attrs_readonly(layout, &nattrs);
- for (int i = wrapped_line ? c : c + 1; i < nattrs; i++) {
- if (attrs[i].is_word_start) {
- if (char_ret)
- *char_ret = i;
- if (real_byte_ret)
- *real_byte_ret = cur_byte;
- return cur_byte;
- }
- cur_byte = ledit_line_next_utf8(ll, cur_byte);
- }
- return -1;
-}
-
-static int
-line_prev_word(ledit_buffer *buffer, int line, int byte, int char_index, int *…
- int c, nattrs;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- if (char_index >= 0)
- c = char_index;
- else
- c = line_byte_to_char(ll, byte);
- int cur_byte = ledit_line_prev_utf8(ll, byte);
- PangoLayout *layout = get_pango_layout(buffer, line);
- const PangoLogAttr *attrs =
- pango_layout_get_log_attrs_readonly(layout, &nattrs);
- if (c > nattrs)
- return -1;
- for (int i = c - 1; i >= 0; i--) {
- if (attrs[i].is_word_start) {
- if (char_ret)
- *char_ret = i;
- return cur_byte;
- }
- cur_byte = ledit_line_prev_utf8(ll, cur_byte);
- }
- return -1;
-}
-
-static int
-line_prev_bigword(ledit_buffer *buffer, int line, int byte, int char_index, in…
- int c, nattrs;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- if (char_index >= 0)
- c = char_index;
- else
- c = line_byte_to_char(ll, byte);
- int cur_byte = ledit_line_prev_utf8(ll, byte);
- PangoLayout *layout = get_pango_layout(buffer, line);
- const PangoLogAttr *attrs =
- pango_layout_get_log_attrs_readonly(layout, &nattrs);
- int next_cursorb = byte;
- int next_cursorc = c;
- int found_word = 0;
- for (int i = c - 1; i >= 0; i--) {
- if (!found_word && !attrs[i].is_white) {
- found_word = 1;
- } else if (found_word && attrs[i].is_white) {
- if (char_ret)
- *char_ret = next_cursorc;
- return next_cursorb;
- }
- if (found_word && c == 0) {
- if (char_ret)
- *char_ret = 0;
- return 0;
- }
- if (attrs[i].is_cursor_position) {
- next_cursorc = i;
- next_cursorb = cur_byte;
- }
- cur_byte = ledit_line_prev_utf8(ll, cur_byte);
- }
- return -1;
-}
-
-int
-line_next_bigword_end(ledit_buffer *buffer, int line, int byte, int char_index…
- int c, nattrs;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- if (char_index >= 0)
- c = char_index;
- else
- c = line_byte_to_char(ll, byte);
- PangoLayout *layout = get_pango_layout(buffer, line);
- const PangoLogAttr *attrs =
- pango_layout_get_log_attrs_readonly(layout, &nattrs);
- int last_cursorb, last_cursorc;
- if (wrapped_line) {
- last_cursorb = byte;
- last_cursorc = c;
- } else {
- last_cursorb = -1;
- last_cursorc = -1;
- }
- int found_word = 0;
- int cur_byte = byte;
- for (int i = c; i < nattrs; i++) {
- if (last_cursorb != -1 && !found_word && !attrs[i].is_white) {
- found_word = 1;
- } else if (found_word && attrs[i].is_white) {
- if (char_ret)
- *char_ret = last_cursorc;
- if (real_byte_ret)
- *real_byte_ret = cur_byte;
- return last_cursorb;
- }
- if (attrs[i].is_cursor_position) {
- last_cursorc = i;
- last_cursorb = cur_byte;
- }
- cur_byte = ledit_line_next_utf8(ll, cur_byte);
- }
- return -1;
-}
-
-static int
-line_next_word_end(ledit_buffer *buffer, int line, int byte, int char_index, i…
- int c, nattrs;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- if (char_index >= 0)
- c = char_index;
- else
- c = line_byte_to_char(ll, byte);
- int cur_byte = ledit_line_next_utf8(ll, byte);
- PangoLayout *layout = get_pango_layout(buffer, line);
- const PangoLogAttr *attrs =
- pango_layout_get_log_attrs_readonly(layout, &nattrs);
- int last_cursorb, last_cursorc;
- if (wrapped_line) {
- last_cursorb = byte;
- last_cursorc = c;
- } else {
- last_cursorb = -1;
- last_cursorc = -1;
- }
- for (int i = c + 1; i < nattrs; i++) {
- if (last_cursorb != -1 && attrs[i].is_word_end) {
- if (char_ret)
- *char_ret = last_cursorc;
- if (real_byte_ret)
- *real_byte_ret = cur_byte;
- return last_cursorb;
- }
- if (attrs[i].is_cursor_position) {
- last_cursorc = i;
- last_cursorb = cur_byte;
- }
- cur_byte = ledit_line_next_utf8(ll, cur_byte);
- }
- return -1;
-}
-
-static int
-line_next_bigword(ledit_buffer *buffer, int line, int byte, int char_index, in…
- int c, nattrs;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- if (char_index >= 0)
- c = char_index;
- else
- c = line_byte_to_char(ll, byte);
- int cur_byte = byte;
- PangoLayout *layout = get_pango_layout(buffer, line);
- const PangoLogAttr *attrs =
- pango_layout_get_log_attrs_readonly(layout, &nattrs);
- int found_ws = wrapped_line;
- for (int i = c; i < nattrs; i++) {
- if (!found_ws && attrs[i].is_white) {
- found_ws = 1;
- } else if (found_ws && !attrs[i].is_white) {
- if (char_ret)
- *char_ret = i;
- if (real_byte_ret)
- *real_byte_ret = cur_byte;
- return cur_byte;
- }
- cur_byte = ledit_line_next_utf8(ll, cur_byte);
- }
- return -1;
-}
-
-int
-ledit_line_next_non_whitespace(ledit_buffer *buffer, int line, int byte) {
- int c, nattrs;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- c = line_byte_to_char(ll, byte);
- int cur_byte = byte;
- PangoLayout *layout = get_pango_layout(buffer, line);
- const PangoLogAttr *attrs =
- pango_layout_get_log_attrs_readonly(layout, &nattrs);
- for (; c < nattrs; c++) {
- if (!attrs[c].is_white)
- return cur_byte;
- cur_byte = ledit_line_next_utf8(ll, cur_byte);
- }
- return ll->len;
-}
-
-/* FIXME: document that word and bigword are a bit weird because word uses uni…
-
-#define GEN_NEXT_WORD(name, func) …
-void …
-ledit_buffer_next_##name( …
- ledit_buffer *buffer, …
- int line, int byte, int num_repeat, …
- int *line_ret, int *byte_ret, int *real_byte_ret) { …
- int cur_line = line; …
- int cur_byte = byte; …
- int cur_char = -1; …
- int real_byte = -1; …
- int wrapped_line; …
- for (int i = 0; i < num_repeat; i++) { …
- wrapped_line = 0; …
- while ((cur_byte = func(buffer, cur_line, cur_byte, cur_char, …
- wrapped_line, &cur_char, &real_byte)) == -1 && …
- cur_line < buffer->lines_num - 1) { …
- cur_line++; …
- cur_byte = 0; …
- wrapped_line = 1; …
- } …
- if (cur_byte == -1 && cur_line == buffer->lines_num - 1) …
- break; …
- } …
- if (cur_byte == -1) { …
- *line_ret = buffer->lines_num - 1; …
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->lines_n…
- *byte_ret = ledit_buffer_get_legal_normal_pos(buffer, buffer->…
- *real_byte_ret = ll->len; …
- } else { …
- *line_ret = cur_line; …
- *byte_ret = cur_byte; …
- *real_byte_ret = real_byte; …
- } …
-}
-
-#define GEN_PREV_WORD(name, func) …
-void …
-ledit_buffer_prev_##name( …
- ledit_buffer *buffer, …
- int line, int byte, int num_repeat, …
- int *line_ret, int *byte_ret, int *real_byte_ret) { …
- int cur_line = line; …
- int cur_byte = byte; …
- int cur_char = -1; …
- ledit_line *ll = ledit_buffer_get_line(buffer, cur_line); …
- for (int i = 0; i < num_repeat; i++) { …
- while ((cur_byte = func(buffer, cur_line, cur_byte, cur_char, …
- &cur_char)) == -1 && cur_line > 0) { …
- cur_line--; …
- ll = ledit_buffer_get_line(buffer, cur_line); …
- cur_byte = ll->len; …
- } …
- if (cur_byte == -1 && cur_line == 0) …
- break; …
- } …
- if (cur_byte == -1) { …
- *line_ret = 0; …
- *byte_ret = 0; …
- *real_byte_ret = 0; …
- } else { …
- *line_ret = cur_line; …
- *byte_ret = cur_byte; …
- *real_byte_ret = cur_byte; …
- } …
-}
-
-GEN_NEXT_WORD(word, line_next_word)
-GEN_NEXT_WORD(word_end, line_next_word_end)
-GEN_NEXT_WORD(bigword, line_next_bigword)
-GEN_NEXT_WORD(bigword_end, line_next_bigword_end)
-GEN_PREV_WORD(word, line_prev_word)
-GEN_PREV_WORD(bigword, line_prev_bigword)
-
-void
-ledit_buffer_get_pos_softline_bounds(
- ledit_buffer *buffer, int line, int pos,
- int *start_byte_ret, int *end_byte_ret) {
- assert(line >= 0 && line < buffer->lines_num);
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- assert(pos >= 0 && pos <= ll->len);
- PangoLayout *layout = get_pango_layout(buffer, line);
- int x, sli;
- pango_layout_index_to_line_x(layout, pos, 0, &sli, &x);
- PangoLayoutLine *pl = pango_layout_get_line_readonly(layout, sli);
- *start_byte_ret = pl->start_index;
- *end_byte_ret = pl->start_index + pl->length;
-}
-
-void
-ledit_buffer_get_softline_bounds(
- ledit_buffer *buffer, int line, int softline,
- int *start_byte_ret, int *end_byte_ret) {
- assert(line >= 0 && line < buffer->lines_num);
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- PangoLayout *layout = get_pango_layout(buffer, line);
- assert(softline < ll->softlines);
- PangoLayoutLine *pl = pango_layout_get_line_readonly(layout, softline);
- *start_byte_ret = pl->start_index;
- *end_byte_ret = pl->start_index + pl->length;
-}
-
-int
-ledit_buffer_get_softline_count(ledit_buffer *buffer, int line) {
- assert(line >= 0 && line < buffer->lines_num);
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- if (ll->text_dirty)
- set_pango_text_and_highlight(buffer, line);
- return ll->softlines;
-}
-
-int
-ledit_buffer_pos_to_softline(ledit_buffer *buffer, int line, int pos) {
- assert(line >= 0 && line < buffer->lines_num);
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- assert(pos >= 0 && pos <= ll->len);
- PangoLayout *layout = get_pango_layout(buffer, line);
- int x, sli;
- pango_layout_index_to_line_x(layout, pos, 0, &sli, &x);
- return sli;
-}
-
-void
-ledit_buffer_get_cursor_pixel_pos(ledit_buffer *buffer, int line, int pos, int…
- assert(line >= 0 && line < buffer->lines_num);
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- assert(pos >= 0 && pos <= ll->len);
- PangoLayout *layout = get_pango_layout(buffer, line);
- PangoRectangle strong, weak;
- pango_layout_get_cursor_pos(layout, 0, &strong, &weak);
- *x_ret = strong.x / PANGO_SCALE;
- *y_ret = strong.y / PANGO_SCALE;
- *h_ret = strong.height / PANGO_SCALE;
-}
-
-/* prev_index_ret is used instead of just calling get_legal_normal_pos
- because weird things happen otherwise
- -> in certain cases, this is still weird because prev_index_ret sometimes
- is not at the end of the line, but this is the best I could come up
- with for now */
-int
-ledit_buffer_move_cursor_visually(ledit_buffer *buffer, int line, int pos, int…
- /* FIXME: trailing */
- int trailing = 0, tmp_index;
- ledit_line *cur_line = ledit_buffer_get_line(buffer, line);
- PangoLayout *layout = get_pango_layout(buffer, line);
- int new_index = pos, last_index = pos;
- int dir = 1;
- int num = movement;
- if (movement < 0) {
- dir = -1;
- num = -movement;
- }
- while (num > 0) {
- tmp_index = new_index;
- pango_layout_move_cursor_visually(
- layout, TRUE,
- new_index, trailing, dir,
- &new_index, &trailing
- );
- /* for some reason, this is necessary */
- if (new_index < 0)
- new_index = 0;
- else if (new_index > cur_line->len)
- new_index = cur_line->len;
- num--;
- if (tmp_index != new_index)
- last_index = tmp_index;
- }
- /* 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 */
- /* FIXME: spaces at end of softlines are weird in normal mode */
- while (trailing > 0) {
- trailing--;
- new_index = ledit_line_next_utf8(cur_line, new_index);
- }
- if (new_index < 0)
- new_index = 0;
- if (prev_index_ret)
- *prev_index_ret = last_index;
- return new_index;
-}
-
-/* FIXME: implement */
-/*
-int
-ledit_line_nearest_cursor_pos(ledit_line *line, int byte) {
-}
-
void
-ledit_line_word_boundaries(ledit_line *line, int byte, int *start_ret, int *en…
-}
-*/
-
-/* FIXME: no idea why this exists */
-/*
-static void
-delete_line_section(ledit_buffer *buffer, int line, int start, int length) {
- delete_line_section_base(buffer, line, start, length);
- ledit_buffer_recalc_line(buffer, line);
-}
-*/
-
-static void
-delete_line_section_base(ledit_buffer *buffer, int line, int start, int length…
+ledit_buffer_delete_line_section_base(ledit_buffer *buffer, size_t line, size_…
ledit_line *l = ledit_buffer_get_line(buffer, line);
if (start <= l->gap && start + length >= l->gap) {
l->gap = start;
t@@ -1480,1092 +756,29 @@ delete_line_section_base(ledit_buffer *buffer, int li…
);
}
l->len -= length;
- l->dirty = 1;
- l->text_dirty = 1;
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_notify_delete_text(buffer->views[i], line, start, length);
+ }
}
-int
-ledit_buffer_delete_unicode_char(ledit_buffer *buffer, int line_index, int byt…
- int new_index = ledit_buffer_delete_unicode_char_base(buffer, line_ind…
+size_t
+ledit_buffer_delete_unicode_char(ledit_buffer *buffer, size_t line_index, size…
+ size_t new_index = ledit_buffer_delete_unicode_char_base(buffer, line_…
ledit_buffer_recalc_line(buffer, line_index);
return new_index;
}
-int
-ledit_buffer_delete_unicode_char_base(ledit_buffer *buffer, int line_index, in…
+size_t
+ledit_buffer_delete_unicode_char_base(ledit_buffer *buffer, size_t line_index,…
ledit_line *l = ledit_buffer_get_line(buffer, line_index);
- int new_index = byte_index;
+ size_t new_index = byte_index;
if (dir < 0) {
- int i = ledit_line_prev_utf8(l, byte_index);
- delete_line_section_base(buffer, line_index, i, byte_index - i…
+ size_t i = ledit_line_prev_utf8(l, byte_index);
+ ledit_buffer_delete_line_section_base(buffer, line_index, i, b…
new_index = i;
} else {
- int i = ledit_line_next_utf8(l, byte_index);
- delete_line_section_base(buffer, line_index, byte_index, i - b…
+ size_t i = ledit_line_next_utf8(l, byte_index);
+ ledit_buffer_delete_line_section_base(buffer, line_index, byte…
}
return new_index;
}
-
-static void
-set_pango_text_and_highlight(ledit_buffer *buffer, int line) {
- cache_layout *cl;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- int old_index = ll->cache_layout_index;
- if (ll->cache_layout_index < 0) {
- cache_assign_layout_index(
- ll->parent_buffer->cache, line,
- ll->parent_buffer, &set_layout_line_helper
- );
- assert(ll->cache_layout_index >= 0);
- cl = cache_get_layout(ll->parent_buffer->cache, ll->cache_layo…
- if (cl->layout == NULL) {
- cl->layout = pango_layout_new(ll->parent_buffer->windo…
- pango_layout_set_font_description(cl->layout, buffer->…
- pango_layout_set_wrap(cl->layout, PANGO_WRAP_WORD_CHAR…
- }
- } else {
- cl = cache_get_layout(ll->parent_buffer->cache, ll->cache_layo…
- }
- if (ll->text_dirty || old_index < 0) {
- ledit_buffer_normalize_line(ll);
- pango_layout_set_text(cl->layout, ll->text, ll->len);
- set_line_layout_attrs(buffer, line, cl->layout);
- /* FIXME: is this guard necessary? */
- ll->softlines = ll->len > 0 ? pango_layout_get_line_count(cl->…
- pango_layout_set_width(cl->layout, ll->w * PANGO_SCALE);
- int w, h;
- pango_layout_get_pixel_size(cl->layout, &w, &h);
- if (h != ll->h) {
- ll->h = h;
- ll->h_dirty = 1;
- }
- ll->text_dirty = 0;
- ll->dirty = 1;
- } else if (ll->highlight_dirty) {
- set_line_layout_attrs(buffer, line, cl->layout);
- }
- ll->highlight_dirty = 0;
-}
-
-static PangoLayout *
-get_pango_layout(ledit_buffer *buffer, int line) {
- set_pango_text_and_highlight(buffer, line);
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- cache_layout *cl = cache_get_layout(
- ll->parent_buffer->cache, ll->cache_layout_index
- );
- return cl->layout;
-}
-
-void
-ledit_pos_to_x_softline(ledit_buffer *buffer, int line, int pos, int *x_ret, i…
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- PangoLayout *layout = get_pango_layout(buffer, line);
- pango_layout_index_to_line_x(layout, pos, 0, softline_ret, x_ret);
- /* FIXME: do these lines need to be unref'd? */
- PangoLayoutLine *pango_line = pango_layout_get_line_readonly(layout, *…
- /* 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 += (ll->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? */
- /* FIXME: this is too much magic for my taste */
- if (ll->parent_buffer->common->mode == NORMAL) {
- PangoRectangle rect;
- pango_layout_index_to_pos(layout, pos, &rect);
- *x_ret += rect.width / 2;
- }
-}
-
-/* FIXME: change this to return int */
-void
-ledit_x_softline_to_pos(ledit_buffer *buffer, int line, int x, int softline, i…
- int trailing = 0;
- int x_relative = x;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
- PangoLayout *layout = get_pango_layout(buffer, line);
- PangoLayoutLine *pango_line =
- pango_layout_get_line_readonly(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 -= (ll->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 */
- /* FIXME: add parameter for this instead of checking mode */
- if (ll->parent_buffer->common->mode == INSERT) {
- while (trailing > 0) {
- trailing--;
- *pos_ret = ledit_line_next_utf8(ll, *pos_ret);
- }
- }
-}
-
-int
-ledit_buffer_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 *ll = ledit_buffer_get_line(buffer, line);
- if (pos == ll->len && pos > 0) {
- int nattrs;
- PangoLayout *layout = get_pango_layout(buffer, line);
- const PangoLogAttr *attrs =
- pango_layout_get_log_attrs_readonly(layout, &nattrs);
- int cur = nattrs - 2;
- ret = ledit_line_prev_utf8(ll, ret);
- while (ret > 0 && cur > 0 && !attrs[cur].is_cursor_position) {
- cur--;
- ret = ledit_line_prev_utf8(ll, ret);
- }
- }
- return ret;
-}
-
-void
-ledit_buffer_delete_range(
- ledit_buffer *buffer, enum delete_mode delmode,
- int line_index1, int byte_index1,
- int line_index2, int byte_index2,
- int *new_line_ret, int *new_byte_ret,
- ledit_range *final_range_ret, txtbuf *text_ret) {
- ledit_buffer_delete_range_base(
- buffer, delmode,
- line_index1, byte_index1,
- line_index2, byte_index2,
- new_line_ret, new_byte_ret,
- final_range_ret, text_ret
- );
- /* need to start recalculating one line before in case first
- line was deleted and offset is now wrong */
- int min = line_index1 < line_index2 ? line_index1 : line_index2;
- ledit_buffer_recalc_from_line(buffer, min > 0 ? min - 1 : min);
-}
-
-/* Note: line_index* and byte_index* don't need to be sorted */
-/* line_index1, byte_index1 are used as the cursor position in order
- to determine the new cursor position */
-/* FIXME: use at least somewhat sensible variable names */
-/* FIXME: I once noticed a bug where using 'dG' to delete to the end of
- the file caused a line index way larger than buffer->lines_num to be
- given, but I couldn't reproduce this bug */
-void
-ledit_buffer_delete_range_base(
- ledit_buffer *buffer, enum delete_mode delmode,
- int line_index1, int byte_index1,
- int line_index2, int byte_index2,
- int *new_line_ret, int *new_byte_ret,
- ledit_range *final_range_ret, txtbuf *text_ret) {
- /* FIXME: Oh boy, this is nasty */
- /* range line x, range byte x */
- int rgl1 = 0, rgb1 = 0, rgl2 = 0, rgb2 = 0;
- int new_line = 0, new_byte = 0;
- assert(line_index1 >= 0);
- assert(line_index2 >= 0);
- assert(line_index1 < buffer->lines_num);
- assert(line_index2 < buffer->lines_num);
- /* FIXME: could this be simplified by just calculating the range and t…
- the non-line-based version? */
- if (delmode == DELETE_HARDLINE) {
- int x, sl_useless;
- int l1 = line_index1, l2 = line_index2;
- if (line_index1 > line_index2) {
- l1 = line_index2;
- l2 = line_index1;
- }
- int dell1 = l1, dell2 = l2;
- ledit_line *ll = ledit_buffer_get_line(buffer, line_index1);
- ledit_pos_to_x_softline(buffer, line_index1, byte_index1, &x, …
- if (l1 > 0 && l2 < buffer->lines_num - 1) {
- rgl1 = l1;
- rgb1 = 0;
- rgl2 = l2 + 1;
- rgb2 = 0;
- } else if (l1 > 0) {
- rgl1 = l1 - 1;
- ll = ledit_buffer_get_line(buffer, rgl1);
- rgb1 = ll->len;
- rgl2 = l2;
- ll = ledit_buffer_get_line(buffer, rgl2);
- rgb2 = ll->len;
- } else if (l2 < buffer->lines_num - 1) {
- rgl1 = l1;
- rgb1 = 0;
- rgl2 = l2 + 1;
- rgb2 = 0;
- } else {
- rgl1 = l1;
- rgb1 = 0;
- rgl2 = l2;
- ll = ledit_buffer_get_line(buffer, rgl2);
- rgb2 = ll->len;
- }
- if (text_ret) {
- ledit_buffer_copy_text_to_txtbuf(
- buffer, text_ret,
- rgl1, rgb1, rgl2, rgb2
- );
- }
- /* default is dell1 = l1, dell2 = l2 */
- if (l2 < buffer->lines_num - 1) {
- new_line = l1;
- ledit_x_softline_to_pos(
- buffer, l2 + 1,
- x, 0, &new_byte
- );
- } else if (l1 > 0) {
- new_line = l1 - 1;
- ledit_x_softline_to_pos(
- buffer, l1 - 1,
- x, 0, &new_byte
- );
- } else {
- dell1 = l1 + 1;
- dell2 = l2;
- new_line = l1;
- new_byte = 0;
- /* happens when all lines are deleted, so one line has…
- ll = ledit_buffer_get_line(buffer, l1);
- delete_line_section_base(
- buffer, l1, 0, ll->len
- );
- }
- if (dell1 <= dell2) {
- ledit_buffer_delete_line_entries_base(buffer, dell1, d…
- }
- } else if (delmode == DELETE_SOFTLINE) {
- int x, softline1, softline2;
- ledit_line *line1 = ledit_buffer_get_line(buffer, line_index1);
- ledit_pos_to_x_softline(buffer, line_index1, byte_index1, &x, …
- if (line_index1 == line_index2) {
- int x_useless;
- PangoLayout *layout = get_pango_layout(buffer, line_in…
- pango_layout_index_to_line_x(layout, byte_index2, 0, &…
- int l1 = softline1 < softline2 ? softline1 : softline2;
- int l2 = softline1 < softline2 ? softline2 : softline1;
- PangoLayoutLine *pl1 = pango_layout_get_line_readonly(…
- PangoLayoutLine *pl2 = pango_layout_get_line_readonly(…
- /* don't delete entire line if it is the last one rema…
- if (l1 == 0 && l2 == line1->softlines - 1 && buffer->l…
- if (line_index1 < buffer->lines_num - 1) {
- /* cursor can be moved to next hard li…
- new_line = line_index1;
- ledit_x_softline_to_pos(
- buffer, line_index1 + 1,
- x, 0, &new_byte
- );
- rgl1 = line_index1;
- rgb1 = 0;
- rgl2 = line_index1 + 1;
- rgb2 = 0;
- } else {
- /* cursor has to be be moved to previo…
- because last line in buffer is dele…
- /* note: logically, line_index1 - 1 mu…
- buffer->lines_num > 1 && line_index…
- new_line = line_index1 - 1;
- ledit_line *prevline = ledit_buffer_ge…
- if (prevline->text_dirty)
- set_pango_text_and_highlight(b…
- ledit_x_softline_to_pos(buffer, new_li…
- rgl1 = line_index1 - 1;
- rgb1 = prevline->len;
- rgl2 = line_index1;
- rgb2 = line1->len;
- }
- if (text_ret) {
- ledit_buffer_copy_text_to_txtbuf(
- buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- ledit_buffer_delete_line_entry_base(buffer, li…
- } else {
- assert(pl2->start_index + pl2->length - pl1->s…
- rgl1 = rgl2 = line_index1;
- rgb1 = pl1->start_index;
- rgb2 = pl2->start_index + pl2->length;
- if (text_ret) {
- ledit_buffer_copy_text_to_txtbuf(
- buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- delete_line_section_base(
- buffer, line_index1, rgb1, rgb2 - rgb1
- );
- if (l2 == line1->softlines - 1 && line_index1 …
- new_line = line_index1 + 1;
- ledit_x_softline_to_pos(
- buffer, line_index1 + 1,
- x, 0, &new_byte
- );
- } else if (l2 < line1->softlines - 1) {
- new_line = line_index1;
- ledit_x_softline_to_pos(
- buffer, line_index1,
- x, l1, &new_byte
- );
- } else if (l1 > 0) {
- new_line = line_index1;
- ledit_x_softline_to_pos(
- buffer, line_index1,
- x, l1 - 1, &new_byte
- );
- } else {
- /* the line has been emptied and is th…
- new_line = 0;
- new_byte = 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_buffer_get_line(buffer, l1);
- ledit_line *ll2 = ledit_buffer_get_line(buffer, l2);
- PangoLayout *layout1 = get_pango_layout(buffer, l1);
- PangoLayout *layout2 = get_pango_layout(buffer, l2);
- pango_layout_index_to_line_x(layout1, b1, 0, &sl1, &x_…
- pango_layout_index_to_line_x(layout2, b2, 0, &sl2, &x_…
- PangoLayoutLine *pl1 = pango_layout_get_line_readonly(…
- PangoLayoutLine *pl2 = pango_layout_get_line_readonly(…
- if (sl1 == 0 && sl2 == ll2->softlines - 1) {
- if (l1 == 0 && l2 == buffer->lines_num - 1) {
- rgl1 = l1;
- rgl2 = l2;
- rgb1 = 0;
- rgb2 = ll2->len;
- if (text_ret) {
- ledit_buffer_copy_text_to_txtb…
- buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- delete_line_section_base(buffer, l1, 0…
- ledit_buffer_delete_line_entries_base(…
- new_line = 0;
- new_byte = 0;
- } else {
- if (l2 == buffer->lines_num - 1) {
- new_line = l1 - 1;
- ledit_line *new_lline = ledit_…
- if (new_lline->text_dirty)
- set_pango_text_and_hig…
- ledit_x_softline_to_pos(buffer…
- rgl1 = l1 - 1;
- rgb1 = new_lline->len;
- rgl2 = l2;
- rgb2 = ll2->len;
- } else {
- new_line = l1;
- ledit_x_softline_to_pos(
- buffer, l2 + 1, x, 0, &new…
- );
- rgl1 = l1;
- rgb1 = 0;
- rgl2 = l2 + 1;
- rgb2 = 0;
- }
- if (text_ret) {
- ledit_buffer_copy_text_to_txtb…
- buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- ledit_buffer_delete_line_entries_base(…
- }
- } else if (sl1 == 0) {
- rgl1 = l1;
- rgb1 = 0;
- rgl2 = l2;
- rgb2 = pl2->start_index + pl2->length;
- if (text_ret) {
- ledit_buffer_copy_text_to_txtbuf(
- buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- delete_line_section_base(buffer, l2, 0, pl2->s…
- new_line = l1;
- ledit_x_softline_to_pos(buffer, l2, x, 0, &new…
- ledit_buffer_delete_line_entries_base(buffer, …
- } else if (sl2 == ll2->softlines - 1) {
- rgl1 = l1;
- rgb1 = pl1->start_index;
- rgl2 = l2;
- rgb2 = ll2->len;
- if (l2 + 1 == buffer->lines_num) {
- new_line = l1;
- ledit_x_softline_to_pos(buffer, l1, x,…
- } else {
- new_line = l1 + 1;
- ledit_x_softline_to_pos(
- buffer, l2 + 1,
- x, 0, &new_byte
- );
- }
- if (text_ret) {
- ledit_buffer_copy_text_to_txtbuf(
- buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- delete_line_section_base(buffer, l1, pl1->star…
- ledit_buffer_delete_line_entries_base(buffer, …
- } else {
- /* FIXME: this could be made nicer by just usi…
- delete all in one go at the end */
- rgl1 = l1;
- rgb1 = pl1->start_index;
- rgl2 = l2;
- rgb2 = pl2->start_index + pl2->length;
- if (text_ret) {
- ledit_buffer_copy_text_to_txtbuf(
- buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- delete_line_section_base(buffer, l1, pl1->star…
- ledit_buffer_insert_text_from_line_base(
- buffer,
- l1, pl1->start_index,
- l2, pl2->start_index + pl2->length,
- ll2->len - (pl2->start_index + pl2->length…
- );
- ledit_buffer_delete_line_entries_base(buffer, …
- new_line = l1;
- set_pango_text_and_highlight(buffer, l1);
- /* it's technically possible that the remainin…
- second line is so small that it doesn't gen…
- softline, so there needs to be a special ca…
- a bit weird because the cursor will seem to…
- same line, but it now includes the rest of …
- (FIXME: this is probably not the best thing…
- ledit_x_softline_to_pos(
- buffer, l1, x, sl1 + 1 < ll1->softlines ? …
- );
- }
- }
- } else {
- if (line_index1 == line_index2) {
- rgl1 = rgl2 = line_index1;
- if (byte_index1 < byte_index2) {
- rgb1 = byte_index1;
- rgb2 = byte_index2;
- } else {
- rgb1 = byte_index2;
- rgb2 = byte_index1;
- }
- if (text_ret) {
- ledit_buffer_copy_text_to_txtbuf(
- buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- delete_line_section_base(buffer, line_index1, rgb1, rg…
- new_line = line_index1;
- new_byte = rgb1;
- } else {
- if (line_index1 < line_index2) {
- rgl1 = line_index1;
- rgb1 = byte_index1;
- rgl2 = line_index2;
- rgb2 = byte_index2;
- } else {
- rgl1 = line_index2;
- rgb1 = byte_index2;
- rgl2 = line_index1;
- rgb2 = byte_index1;
- }
- if (text_ret) {
- ledit_buffer_copy_text_to_txtbuf(
- buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- ledit_line *line1 = ledit_buffer_get_line(buffer, rgl1…
- ledit_line *line2 = ledit_buffer_get_line(buffer, rgl2…
- delete_line_section_base(buffer, rgl1, rgb1, line1->le…
- ledit_buffer_insert_text_from_line_base(
- buffer, rgl1, rgb1, rgl2, rgb2, line2->len - rgb2,…
- );
- new_line = rgl1;
- new_byte = rgb1;
- ledit_buffer_delete_line_entries_base(buffer, rgl1 + 1…
- }
- if (buffer->common->mode == NORMAL)
- new_byte = ledit_buffer_get_legal_normal_pos(buffer, n…
- }
- if (final_range_ret) {
- final_range_ret->line1 = rgl1;
- final_range_ret->byte1 = rgb1;
- final_range_ret->line2 = rgl2;
- final_range_ret->byte2 = rgb2;
- }
- if (new_line_ret)
- *new_line_ret = new_line;
- if (new_byte_ret)
- *new_byte_ret = new_byte;
-}
-
-/* FIXME: any way to make this more efficient? */
-void
-ledit_buffer_resize_textview(ledit_buffer *buffer) {
- buffer->total_height = 0;
- int text_w, text_h;
- ledit_window_get_textview_size(buffer->window, &text_w, &text_h);
- for (int i = 0; i < buffer->lines_num; i++) {
- ledit_line *line = ledit_buffer_get_line(buffer, i);
- line->w = text_w;
- line->text_dirty = 1;
- set_pango_text_and_highlight(buffer, i);
- line->y_offset = buffer->total_height;
- line->dirty = 1;
- line->h_dirty = 0;
- buffer->total_height += line->h;
- }
- ledit_window_set_scroll_max(buffer->window, buffer->total_height);
- if (buffer->display_offset > 0 &&
- buffer->display_offset + text_h > buffer->total_height) {
- ledit_buffer_scroll(buffer, buffer->total_height - text_h);
- }
-}
-
-void
-ledit_buffer_scroll(ledit_buffer *buffer, long new_offset) {
- int text_w, text_h;
- ledit_window_get_textview_size(buffer->window, &text_w, &text_h);
- if (new_offset + text_h > buffer->total_height)
- new_offset = buffer->total_height - text_h;
- if (new_offset < 0)
- new_offset = 0;
- buffer->display_offset = new_offset;
- ledit_window_set_scroll_pos(buffer->window, buffer->display_offset);
-}
-
-/* FIXME: there's gotta be a better/more efficient way to do this... */
-/* FIXME: make sure h_dirty is not set here */
-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);
- PangoLayout *layout = get_pango_layout(buffer, line);
- pango_layout_get_cursor_pos(layout, byte, &strong, &weak);
- ledit_pos_to_x_softline(buffer, line, 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…
- layout = get_pango_layout(buffer, hline);
- int num_sl = lline->softlines;
- 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(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(buffer, hline, x, sl_index, by…
- } else if (hline < buffer->lines_num - 1) {
- /* need to move to next hard line */
- *line_ret = hline + 1;
- ledit_x_softline_to_pos(buffer, hline + 1, x, 0, byte_…
- } 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(buffer, hline, x, num_sl - 1, …
- }
- } 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 …
- layout = get_pango_layout(buffer, hline);
- int num_sl = lline->softlines;
- 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(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(buffer, hline, x, sl_index, by…
- } 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 = lline->softlines;
- ledit_x_softline_to_pos(buffer, hline - 1, x, num_sl -…
- } 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(buffer, hline, 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 */
- /* FIXME: use y_offset in lines */
- long h = 0;
- double pos = buffer->display_offset + y;
- for (int i = 0; i < buffer->lines_num; i++) {
- ledit_line *line = ledit_buffer_get_line(buffer, i);
- if ((h <= pos && h + line->h > pos) || i == buffer->lines_num …
- int index, trailing;
- PangoLayout *layout = get_pango_layout(buffer, i);
- /* FIXME: what if i == buffer->lines_num - 1 but pos -…
- pango_layout_xy_to_index(
- layout,
- x * PANGO_SCALE, (int)(pos - h) * PANGO_SCALE,
- &index, &trailing
- );
- if (snap_to_nearest) {
- while (trailing > 0) {
- trailing--;
- index = ledit_line_next_utf8(line, ind…
- }
- }
- *line_ret = i;
- *byte_ret = index;
- break;
- }
- h += line->h;
- }
-}
-
-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);
- PangoLayout *layout = get_pango_layout(buffer, line);
- pango_layout_get_cursor_pos(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;
- int text_w, text_h;
- ledit_window_get_textview_size(buffer->window, &text_w, &text_h);
- ledit_line *line = ledit_buffer_get_line(buffer, buffer->cur_line);
- PangoLayout *layout = get_pango_layout(buffer, buffer->cur_line);
- pango_layout_get_cursor_pos(
- layout, buffer->cur_index, &strong, &weak
- );
- long cursor_y = strong.y / PANGO_SCALE + line->y_offset;
- if (cursor_y < buffer->display_offset) {
- ledit_buffer_scroll(buffer, cursor_y);
- } else if (cursor_y + strong.height / PANGO_SCALE >
- buffer->display_offset + text_h) {
- ledit_buffer_scroll(buffer, cursor_y - text_h + strong.height …
- }
-}
-
-static void
-swap(int *a, int *b) {
- int tmp = *a;
- *a = *b;
- *b = tmp;
-}
-
-void
-ledit_buffer_sort_selection(int *line1, int *byte1, int *line2, int *byte2) {
- if (*line1 > *line2) {
- swap(line1, line2);
- swap(byte1, byte2);
- } else if (*line1 == *line2 && *byte1 > *byte2) {
- swap(byte1, byte2);
- }
-}
-
-/* FIXME: don't reset selection when selection is clicked away */
-/* FIXME: when selecting with mouse, only call this when button is released */
-/* lines and bytes need to be sorted already! */
-static void
-copy_selection_to_x_primary(ledit_buffer *buffer, int line1, int byte1, int li…
- /* FIXME: let window handle this */
- txtbuf *primary = ledit_window_get_primary_clipboard_buffer();
- ledit_buffer_copy_text_to_txtbuf(buffer, primary, line1, byte1, line2,…
- XSetSelectionOwner(buffer->common->dpy, XA_PRIMARY, buffer->window->xw…
- /*
- FIXME
- if (XGetSelectionOwner(state.dpy, XA_PRIMARY) != state.win)
- selclear();
- */
-}
-
-void
-ledit_buffer_set_selection(ledit_buffer *buffer, int line1, int byte1, int lin…
- if (line1 == buffer->sel.line1 && line2 == buffer->sel.line2 &&
- byte1 == buffer->sel.byte1 && byte2 == buffer->sel.byte2) {
- return;
- }
- /* FIXME: maybe check both lines and bytes? */
- if (buffer->sel.line1 >= 0 || line1 >= 0) {
- int l1_new = line1, l2_new = line2;
- int b1_new = byte1, b2_new = byte2;
- ledit_buffer_sort_selection(&l1_new, &b1_new, &l2_new, &b2_new…
- ledit_buffer_sort_selection(&buffer->sel.line1, &buffer->sel.b…
- /* FIXME: make this a bit nicer and optimize it */
- if (buffer->sel.line1 > l2_new || buffer->sel.line2 < l1_new) {
- for (int i = buffer->sel.line1; i <= buffer->sel.line2…
- if (i >= 0)
- ledit_buffer_wipe_line_cursor_attrs(bu…
- }
- } else {
- for (int i = buffer->sel.line1; i < l1_new; i++) {
- if (i >= 0)
- ledit_buffer_wipe_line_cursor_attrs(bu…
- }
- for (int i = buffer->sel.line2; i > l2_new; i--) {
- ledit_buffer_wipe_line_cursor_attrs(buffer, i);
- }
- }
- if (l1_new >= 0 && l2_new >= 0) {
- for (int i = l1_new; i <= l2_new; i++) {
- /* only change the ones that were not already …
- if (i <= buffer->sel.line1 || i >= buffer->sel…
- ledit_line *ll = ledit_buffer_get_line…
- ll->highlight_dirty = 1;
- }
- }
- if (l1_new != l2_new || b1_new != b2_new)
- copy_selection_to_x_primary(buffer, l1_new, b1…
- }
- }
- buffer->sel.line1 = line1;
- buffer->sel.byte1 = byte1;
- buffer->sel.line2 = line2;
- buffer->sel.byte2 = byte2;
-}
-
-void
-ledit_buffer_scroll_handler(void *buffer, long pos) {
- ((ledit_buffer *)buffer)->display_offset = pos;
-}
-
-void
-ledit_buffer_button_handler(void *data, XEvent *event) {
- int l, b;
- ledit_buffer *buffer = (ledit_buffer *)data;
- int x = event->xbutton.x;
- int y = event->xbutton.y;
- int snap;
- switch (event->type) {
- case ButtonPress:
- snap = buffer->common->mode == NORMAL ? 0 : 1;
- ledit_xy_to_line_byte(buffer, x, y, snap, &l, &b);
- buffer->selecting = 1;
- if (buffer->common->mode == NORMAL)
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cu…
- buffer->cur_line = l;
- buffer->cur_index = b;
- /* don't set selection yet because the mouse may not be
- dragged, so we don't want to switch to visual (this
- allows setting just the cursor position in normal mode
- without always switching to visual) */
- ledit_buffer_set_selection(buffer, -1, -1, -1, -1);
- if (buffer->common->mode == NORMAL)
- ledit_buffer_set_line_cursor_attrs(buffer, l, b);
- break;
- case ButtonRelease:
- buffer->selecting = 0;
- break;
- case MotionNotify:
- if (buffer->selecting) {
- y = y >= 0 ? y : 0;
- ledit_xy_to_line_byte(buffer, x, y, 1, &l, &b);
- if (buffer->common->mode == NORMAL) {
- ledit_buffer_wipe_line_cursor_attrs(buffer, bu…
- /* FIXME: return to old mode afterwards? */
- /* should change_mode_group even be called her…
- ledit_buffer_set_mode(buffer, VISUAL);
- }
- if (buffer->sel.line1 < 0 || buffer->sel.byte1 < 0) {
- /* the selection has just started, so the curr…
- position is already set to the beginning of…
- selection (see case ButtonPress above) */
- ledit_buffer_set_selection(
- buffer,
- buffer->cur_line, buffer->cur_index, l, b
- );
- } else {
- ledit_buffer_set_selection(
- buffer,
- buffer->sel.line1, buffer->sel.byte1, l, b
- );
- }
- buffer->cur_line = l;
- buffer->cur_index = b;
- }
- break;
- }
-}
-
-void
-ledit_buffer_redraw(ledit_buffer *buffer) {
- int h = 0;
- int cur_line_y = 0;
- int cursor_displayed = 0;
- int text_w, text_h;
- ledit_window_get_textview_size(buffer->window, &text_w, &text_h);
- for (int i = 0; i < buffer->lines_num; i++) {
- ledit_line *line = ledit_buffer_get_line(buffer, i);
- if (h + line->h > buffer->display_offset) {
- /* FIXME: line->text_dirty should not happen here */
- if (line->text_dirty || line->highlight_dirty)
- set_pango_text_and_highlight(buffer, i);
- if (line->dirty || line->cache_pixmap_index == -1) {
- ledit_buffer_render_line(buffer, i);
- }
- int final_y = 0;
- int dest_y = h - buffer->display_offset;
- int final_h = line->h;
- if (h < buffer->display_offset) {
- dest_y = 0;
- final_y = buffer->display_offset - h;
- final_h -= buffer->display_offset - h;
- }
- if (dest_y + final_h > text_h) {
- final_h -= final_y + final_h -
- buffer->display_offset - text_h;
- }
- cache_pixmap *pix = cache_get_pixmap(
- buffer->cache, line->cache_pixmap_index
- );
- XCopyArea(
- buffer->common->dpy, pix->pixmap,
- buffer->window->drawable, buffer->window->gc,
- 0, final_y, line->w, final_h, 0, dest_y
- );
- if (i == buffer->cur_line) {
- cur_line_y = h - buffer->display_offset;
- cursor_displayed = 1;
- }
- if (h + line->h >= buffer->display_offset + text_h)
- break;
- }
- h += line->h;
- }
-
- XSetForeground(buffer->common->dpy, buffer->window->gc, buffer->theme-…
- PangoRectangle strong, weak;
- ledit_line *cur_line = ledit_buffer_get_line(buffer, buffer->cur_line);
- PangoLayout *layout = get_pango_layout(buffer, buffer->cur_line);
- pango_layout_get_cursor_pos(
- layout, buffer->cur_index, &strong, &weak
- );
- /* FIXME: long, int, etc. */
- int cursor_y = strong.y / PANGO_SCALE + cur_line_y;
- if (cursor_displayed && cursor_y >= 0) {
- if (buffer->common->mode == NORMAL) {
- /* FIXME: figure out if there's a better way to do thi…
- /* Seriously, which of the pango folks though it would…
- not highlight spaces at the end of soft lines? That…
- horrible idea. Or am I just too stupid to use it pr…
- /* FIXME: properly document what is happening here */
-
- int box_x = strong.x / PANGO_SCALE;
- int box_w = 10;
- /* determine where the box should be drawn */
- PangoDirection dir = PANGO_DIRECTION_LTR;
- int tmp_index = buffer->cur_index;
- if (buffer->cur_index >= cur_line->len)
- tmp_index = cur_line->len - 1;
- if (tmp_index >= 0)
- dir = pango_layout_get_direction(layout, tmp_i…
-
- int x, sli;
- pango_layout_index_to_line_x(layout, buffer->cur_index…
- PangoLayoutLine *sl = pango_layout_get_line_readonly(l…
- if (dir != sl->resolved_dir) {
- box_w = 3;
- }
- if (dir == PANGO_DIRECTION_RTL || dir == PANGO_DIRECTI…
- box_x = box_x - box_w;
- }
-
- if (buffer->cur_index == cur_line->len ||
- (cur_line->text[buffer->cur_index] == ' ' &&
- buffer->cur_index == sl->start_index + sl->length…
- XFillRectangle(
- buffer->common->dpy, buffer->window->drawa…
- box_x, cursor_y,
- box_w, strong.height / PANGO_SCALE
- );
- }
- } else if (buffer->common->mode == INSERT || buffer->common->m…
- XDrawLine(
- buffer->common->dpy, buffer->window->drawable, buf…
- strong.x / PANGO_SCALE, cursor_y,
- strong.x / PANGO_SCALE,
- (strong.y + strong.height) / PANGO_SCALE + cur_lin…
- );
- }
- }
- /* move input method position */
- if (!ledit_window_bottom_bar_text_shown(buffer->window)) {
- xximspot(
- buffer->window,
- strong.x / PANGO_SCALE,
- (strong.y + strong.height) / PANGO_SCALE + cur_line_y
- );
- }
-}
-
-static void
-undo_insert_helper(void *data, int line, int byte, char *text, int text_len) {
- ledit_buffer_insert_text_with_newlines_base((ledit_buffer *)data, line…
-}
-
-static void
-undo_delete_helper(void *data, int line1, int byte1, int line2, int byte2) {
- ledit_buffer_delete_range_base((ledit_buffer *)data, 0, line1, byte1, …
-}
-
-void
-ledit_buffer_undo(ledit_buffer *buffer) {
- int min_line;
- ledit_undo(
- buffer->undo, buffer->common->mode, buffer, &undo_insert_helper,
- &undo_delete_helper, &buffer->cur_line, &buffer->cur_index, &min_l…
- );
- if (buffer->common->mode == NORMAL) {
- buffer->cur_index = ledit_buffer_get_legal_normal_pos(
- buffer, buffer->cur_line, buffer->cur_index
- );
- }
- if (min_line < buffer->lines_num)
- ledit_buffer_recalc_from_line(buffer, min_line > 0 ? min_line …
- /* FIXME: show undo message */
-}
-
-void
-ledit_buffer_redo(ledit_buffer *buffer) {
- int min_line;
- ledit_redo(
- buffer->undo, buffer->common->mode, buffer, &undo_insert_helper,
- &undo_delete_helper, &buffer->cur_line, &buffer->cur_index, &min_l…
- );
- if (buffer->common->mode == NORMAL) {
- buffer->cur_index = ledit_buffer_get_legal_normal_pos(
- buffer, buffer->cur_line, buffer->cur_index
- );
- }
- if (min_line < buffer->lines_num)
- ledit_buffer_recalc_from_line(buffer, min_line > 0 ? min_line …
- /* FIXME: show undo message */
-}
-
-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…
-
-void
-ledit_buffer_paste_clipboard(ledit_buffer *buffer) {
- ledit_window_set_paste_callback(buffer->window, &paste_callback, buffe…
- clipboard_paste_clipboard(buffer->window);
-}
-
-void
-ledit_buffer_paste_primary(ledit_buffer *buffer) {
- ledit_window_set_paste_callback(buffer->window, &paste_callback, buffe…
- clipboard_paste_primary(buffer->window);
-}
diff --git a/buffer.h b/buffer.h
t@@ -1,31 +1,23 @@
+#ifndef _LEDIT_BUFFER_H_
+#define _LEDIT_BUFFER_H_
+
typedef struct ledit_buffer ledit_buffer;
+#include "view.h"
+
/* FIXME: size_t for len, etc. */
typedef struct {
ledit_buffer *parent_buffer;
- char *text; /* text, stored as gap buffer */
- int gap; /* position of gap for gap buffer */
- int cap; /* allocated space for text */
- int len; /* actual length of text */
- int w; /* width in pixels */
- int h; /* height in pixels */
- long y_offset; /* pixel offset starting at the top of the fil…
- int cache_pixmap_index; /* index of pixmap in cache, or -1 if not assi…
- int cache_layout_index; /* index of pango layout in cache, or -1 if no…
- int cursor_index; /* cursor index if it should be highlighted, -…
- int softlines; /* number of softlines - cached from PangoLayo…
- char dirty; /* whether line needs to be rendered before be…
- char text_dirty; /* whether the text in the PangoLayout needs t…
- * updated before the layout is rendered */
- char highlight_dirty; /* whether highlight (cursor or selection) nee…
- * updated still in the PangoLayout before ren…
- char h_dirty; /* whether height needs to be recalculated */
+ char *text; /* text, stored as gap buffer */
+ size_t gap; /* position of gap for gap buffer */
+ size_t cap; /* allocated space for text */
+ size_t len; /* actual length of text */
} ledit_line;
typedef struct {
char *text;
- int line;
- int byte;
+ size_t line;
+ size_t byte;
} ledit_buffer_mark;
typedef struct {
t@@ -35,155 +27,283 @@ typedef struct {
/* TODO: advisory lock on file? also check if modification date changed before…
struct ledit_buffer {
- ledit_common *common; /* common stuff, e.g. display, window, etc. */
- ledit_line *lines; /* array of lines */
- ledit_theme *theme;
- char *filename;
- int lines_cap; /* number of lines allocated in array */
- int lines_num; /* number of used lines */
- int cur_line; /* current line */
- int cur_index; /* current byte index in line */
- int trailing; /* used by pango for determining if index is at
- * beginning or end of character */
- int trailing_bytes; /* same thing, but with bytes instead of utf8 char…
- int end_of_soft_line; /* used to handle special behavior at end end of…
- long total_height; /* total pixel height of all lines */
- long display_offset; /* current pixel offset of viewport */
- int selecting;
- ledit_range sel; /* current selection; all entries -1 if no selection …
- ledit_cache *cache;
- ledit_undo_stack *undo;
- ledit_window *window;
- ledit_buffer_marklist *marklist;
+ ledit_common *common; /* common stuff, e.g. display, etc. */
+ char *filename; /* last opened filename */
+ ledit_undo_stack *undo; /* undo manager */
+ ledit_buffer_marklist *marklist; /* list of mark positions set */
+ ledit_line *lines; /* array of lines */
+ ledit_view **views; /* array of registered views */
+ size_t views_num; /* number of views in array */
+ size_t lines_cap; /* size of lines array */
+ size_t lines_gap; /* position of gap for line gap buffe…
+ size_t lines_num; /* number of lines */
+ int hard_line_based; /* whether operations should work on …
+ Note that this doesn't actually ch…
+ the buffer functions, it is just s…
+ views can be updated to display it…
};
-enum delete_mode {
- DELETE_CHAR,
- DELETE_SOFTLINE,
- DELETE_HARDLINE
-};
+/*
+ * Create a new buffer with one empty line
+ */
+ledit_buffer *ledit_buffer_create(ledit_common *common);
+
+/*
+ * Set the hard line mode of the buffer and update the
+ * displayed mode in all views.
+ */
+void ledit_buffer_set_hard_line_based(ledit_buffer *buffer, int hl);
+
+/*
+ * Add a new view to the buffer.
+ */
+void ledit_buffer_add_view(ledit_buffer *buffer, ledit_theme *theme, enum ledi…
+
+/*
+ * Remove the given view from the buffer.
+ * Nothing is done if the view does not belong to the buffer.
+ */
+void ledit_buffer_remove_view(ledit_buffer *buffer, ledit_view *view);
+
+/*
+ * Call 'view_recalc_from_line' for all views.
+ */
+void ledit_buffer_recalc_all_views_from_line(ledit_buffer *buffer, size_t line…
-ledit_buffer *ledit_buffer_create(ledit_common *common, ledit_theme *theme, le…
-int ledit_buffer_load_file(ledit_buffer *buffer, char *filename, int line, cha…
+/*
+ * Load a file into the buffer at line 'line'.
+ * If the line is empty, the text is inserted directly.
+ * Otherwise it is appended after the line.
+ * Returns 0 on success and 1 on error. In case of an error, *errstr is filled
+ * with an error message which must be copied as soon as possible because it m…
+ * be overwritten by subsequent function calls.
+ */
+int ledit_buffer_load_file(ledit_buffer *buffer, char *filename, size_t line, …
+
+/*
+ * Write the buffer to a file.
+ * Returns 0 on success and 1 on error. In case of an error, *errstr is filled
+ * with an error message which must be copied as soon as possible because it m…
+ * be overwritten by subsequent function calls.
+ */
int ledit_buffer_write_to_file(ledit_buffer *buffer, char *filename, char **er…
+
+/*
+ * Destroy a buffer.
+ */
void ledit_buffer_destroy(ledit_buffer *buffer);
+
+/*
+ * Normalize a line, i.e. move the gap to the end and add '\0'
+ * so the text can be used as a normal string
+ */
void ledit_buffer_normalize_line(ledit_line *line);
-void ledit_buffer_set_line_cursor_attrs(ledit_buffer *buffer, int line, int in…
-void ledit_buffer_wipe_line_cursor_attrs(ledit_buffer *buffer, int line);
-void ledit_buffer_render_line(ledit_buffer *buffer, int line_index);
-ledit_line *ledit_buffer_get_line(ledit_buffer *buffer, int index);
-int ledit_buffer_line_visible(ledit_buffer *buffer, int index);
-int ledit_buffer_get_legal_normal_pos(ledit_buffer *buffer, int line, int pos);
-void ledit_pos_to_x_softline(ledit_buffer *buffer, int line, int pos, int *x_r…
-void ledit_x_softline_to_pos(ledit_buffer *buffer, int line, int x, int softli…
-int ledit_line_next_utf8(ledit_line *line, int index);
-int ledit_line_prev_utf8(ledit_line *line, int index);
-int ledit_buffer_next_cursor_pos(ledit_buffer *buffer, int line, int byte, int…
-int ledit_buffer_prev_cursor_pos(ledit_buffer *buffer, int line, int byte, int…
-int ledit_buffer_move_cursor_visually(ledit_buffer *buffer, int line, int pos,…
-
-void ledit_buffer_next_word(ledit_buffer *buffer, int line, int byte, int num_…
-void ledit_buffer_next_word_end(ledit_buffer *buffer, int line, int byte, int …
-void ledit_buffer_next_bigword(ledit_buffer *buffer, int line, int byte, int n…
-void ledit_buffer_next_bigword_end(ledit_buffer *buffer, int line, int byte, i…
-void ledit_buffer_prev_word(ledit_buffer *buffer, int line, int byte, int num_…
-void ledit_buffer_prev_bigword(ledit_buffer *buffer, int line, int byte, int n…
-void ledit_buffer_get_pos_softline_bounds(ledit_buffer *buffer, int line, int …
-void ledit_buffer_get_softline_bounds(ledit_buffer *buffer, int line, int soft…
-int ledit_buffer_get_softline_count(ledit_buffer *buffer, int line);
-int ledit_buffer_pos_to_softline(ledit_buffer *buffer, int line, int pos);
-void ledit_buffer_get_cursor_pixel_pos(ledit_buffer *buffer, int line, int pos…
-
-size_t ledit_buffer_textlen(ledit_buffer *buffer, int line1, int byte1, int li…
-void ledit_buffer_copy_text(ledit_buffer *buffer, char *dst, int line1, int by…
-void ledit_buffer_copy_text_to_txtbuf(
+
+/*
+ * Insert 'src_len' bytes from 'src_line' starting at byte position 'src_index'
+ * into line 'dst_line' at byte position 'dst_index'.
+ * 'dst_line' must not be the same as 'src_line'.
+ * If 'text_ret' is not NULL, the copied text is additionally copied into 'tex…
+ * This function does not update the views or normalize the lines, so it should
+ * only be used for efficiency purposes when performing multiple operations.
+ */
+void ledit_buffer_insert_text_from_line_base(
ledit_buffer *buffer,
- txtbuf *buf, /* oh, isn't that a very non-confusing name? */
- int line1, int byte1,
- int line2, int byte2
+ size_t dst_line, size_t dst_index,
+ size_t src_line, size_t src_index, size_t src_len,
+ txtbuf *text_ret
);
-void ledit_buffer_recalc_line(ledit_buffer *buffer, int line);
-void ledit_buffer_recalc_from_line(ledit_buffer *buffer, int line);
-void ledit_buffer_recalc_all_lines(ledit_buffer *buffer);
-/* The following functions all have two versions:
- * - The _base version does not call any recalc functions - this can be used
- * when multiple operations are performed before the next render in order to
- * avoid recalculating everything every time.
- * - The non-base versions call the appropriate recalc function in order to
- * keep everything in a consistent state. */
+/*
+ * Same as ledit_buffer_insert_text_from_line_base, but the views are updated …
+ */
+void ledit_buffer_insert_text_from_line(
+ ledit_buffer *buffer,
+ size_t dst_line, size_t dst_index,
+ size_t src_line, size_t src_index, size_t src_len,
+ txtbuf *text_ret
+);
-void ledit_buffer_insert_text_base(ledit_buffer *buffer, int line_index, int i…
-void ledit_buffer_insert_text_with_newlines_base(
+/*
+ * Insert text 'text' with length 'len' at line 'line_index' and byte position…
+ * The text must not contain newlines.
+ * This function does not update the views or normalize the lines, so it should
+ * only be used for efficiency purposes when performing multiple operations.
+ */
+void ledit_buffer_insert_text_base(
ledit_buffer *buffer,
- int line_index, int index,
- char *text, long len,
- int *end_line_ret, int *end_char_ret
+ size_t line_index, size_t index,
+ char *text, size_t len
);
-void ledit_buffer_append_line_base(ledit_buffer *buffer, int line_index, int t…
-void ledit_buffer_delete_line_entries_base(ledit_buffer *buffer, int index1, i…
-void ledit_buffer_delete_line_entry_base(ledit_buffer *buffer, int index);
-int ledit_buffer_delete_unicode_char_base(ledit_buffer *buffer, int line_index…
-void ledit_buffer_delete_range_base(
- ledit_buffer *buffer, enum delete_mode delmode,
- int line_index1, int byte_index1,
- int line_index2, int byte_index2,
- int *new_line_ret, int *new_byte_ret,
- ledit_range *final_range_ret, txtbuf *text_ret
+
+/*
+ * Same as ledit_buffer_insert_text_base, but the views are updated afterwards.
+ */
+void ledit_buffer_insert_text(
+ ledit_buffer *buffer,
+ size_t line_index, size_t index,
+ char *text, size_t len
);
-void ledit_buffer_insert_text_from_line_base(
+
+/* Insert text 'text' with length 'len' at line 'line_index' and byte position…
+ * The text may contain newlines.
+ * If end_line_ret is not NULL, the line index at the end of the insertion is
+ * written into it.
+ * If end_byte_ret is not NULL, the byte position at the end of the insertion …
+ * written into it.
+ * This function does not update the views or normalize the lines, so it should
+ * only be used for efficiency purposes when performing multiple operations.
+ */
+void ledit_buffer_insert_text_with_newlines_base(
ledit_buffer *buffer,
- int dst_line, int dst_index,
- int src_line, int src_index, int src_len,
- txtbuf *text_ret
+ size_t line_index, size_t index,
+ char *text, size_t len,
+ size_t *end_line_ret, size_t *end_char_ret
);
-void ledit_buffer_insert_text(ledit_buffer *buffer, int line_index, int index,…
+/*
+ * Same as ledit_buffer_insert_text_with_newlines_base, but the views are upda…
+ */
void ledit_buffer_insert_text_with_newlines(
ledit_buffer *buffer,
- int line_index, int index,
- char *text, long len,
- int *end_line_ret, int *end_char_ret
+ size_t line_index, size_t index,
+ char *text, size_t len,
+ size_t *end_line_ret, size_t *end_char_ret
);
-void ledit_buffer_append_line(ledit_buffer *buffer, int line_index, int text_i…
-void ledit_buffer_delete_line_entries(ledit_buffer *buffer, int index1, int in…
-void ledit_buffer_delete_line_entry(ledit_buffer *buffer, int index);
-int ledit_buffer_delete_unicode_char(ledit_buffer *buffer, int line_index, int…
-void ledit_buffer_delete_range(
- ledit_buffer *buffer, enum delete_mode delmode,
- int line_index1, int byte_index1,
- int line_index2, int byte_index2,
- int *new_line_ret, int *new_byte_ret,
- ledit_range *final_range_ret, txtbuf *text_ret
-);
-void ledit_buffer_insert_text_from_line(
+
+/*
+ * Append line after line at 'line_index'.
+ * if 'break_text' is not 0, the text on line 'line_index' starting at
+ * byte index 'text_index' is moved to the newly appended line.
+ * The views are notified that a line has been appended, but not told to update
+ * their line heights and offsets.
+ */
+void ledit_buffer_append_line_base(ledit_buffer *buffer, size_t line_index, si…
+
+/*
+ * Same as ledit_buffer_append_line_base, but the views are told to update
+ * their line heights and offsets afterwards.
+ */
+void ledit_buffer_append_line(ledit_buffer *buffer, size_t line_index, size_t …
+
+/*
+ * Delete lines between 'index1' and 'index2' (inclusive).
+ * The views are notified of the deletion but not told to
+ * update their line heights and offsets.
+ */
+void ledit_buffer_delete_line_entries_base(ledit_buffer *buffer, size_t index1…
+
+/*
+ * Same as ledit_buffer_delete_line_entries_base, but the views are told to
+ * update their line heights and offsets.
+ */
+void ledit_buffer_delete_line_entries(ledit_buffer *buffer, size_t index1, siz…
+
+/*
+ * Convenience function to call ledit_buffer_delete_line_entries_base
+ * with two times the same line index.
+ */
+void ledit_buffer_delete_line_entry_base(ledit_buffer *buffer, size_t index);
+
+/*
+ * Convenience function to call ledit_buffer_delete_line_entries
+ * with two times the same line index.
+ */
+void ledit_buffer_delete_line_entry(ledit_buffer *buffer, size_t index);
+
+/*
+ * Get the line at logical index 'index'.
+ * The returned line is only valid until the next
+ * action that appends or deletes line entries.
+ */
+ledit_line *ledit_buffer_get_line(ledit_buffer *buffer, size_t index);
+
+/*
+ * Tell views to recalculate the height of line 'line' and
+ * update the pixel offsets of the following lines.
+ */
+void ledit_buffer_recalc_line(ledit_buffer *buffer, size_t line);
+
+/*
+ * Tell views to recalculate the height for all lines starting at 'line'
+ * where the text_dirty attribute is set and update the pixel offsets of
+ * all lines after 'line'.
+ * Also clear the text_dirty attribute for all lines starting at 'line'.
+ */
+void ledit_buffer_recalc_from_line(ledit_buffer *buffer, size_t line);
+
+/*
+ * Tell views to recalculate all lines.
+ * Also clear the text_dirty attribute for all lines.
+ */
+void ledit_buffer_recalc_all_lines(ledit_buffer *buffer);
+
+/*
+ * 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_buffer_textlen(ledit_buffer *buffer, size_t line1, size_t byte1, …
+
+/*
+ * Copy text range into given buffer.
+ * - dst is null-terminated
+ * - dst must be large enough to contain the text and NUL (only use this toget…
+ * - the range must be sorted already
+ */
+void ledit_buffer_copy_text(ledit_buffer *buffer, char *dst, int line1, int by…
+
+/*
+ * Copy text range into given buffer and resize it if necessary.
+ * - the range must be sorted already
+ */
+void ledit_buffer_copy_text_to_txtbuf(
ledit_buffer *buffer,
- int dst_line, int dst_index,
- int src_line, int src_index, int src_len,
- txtbuf *text_ret
+ txtbuf *buf, /* oh, isn't that a very non-confusing name? */
+ size_t line1, size_t byte1,
+ size_t line2, size_t byte2
);
-void ledit_buffer_resize_width(ledit_buffer *buffer, int width);
-/* x and y are in pixels, if snap_to_nearest is nonzero, the returned byte
- 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);
-void ledit_buffer_redraw(ledit_buffer *buffer);
-void ledit_buffer_undo(ledit_buffer *buffer);
-void ledit_buffer_redo(ledit_buffer *buffer);
-void ledit_buffer_set_selection(ledit_buffer *buffer, int line1, int byte1, in…
-void ledit_buffer_set_mode(ledit_buffer *buffer, enum ledit_mode mode);
-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…
-/* FIXME: just make generic sort range */
-void ledit_buffer_sort_selection(int *line1, int *byte1, int *line2, int *byte…
-int ledit_line_next_non_whitespace(ledit_buffer *buffer, int line, int byte);
-void ledit_buffer_insert_mark(ledit_buffer *buffer, char *mark, int len, int l…
+/*
+ * Get the byte index of the previous utf8 character starting at byte index 'i…
+ */
+size_t ledit_line_next_utf8(ledit_line *line, size_t index);
+
+/*
+ * Get the byte index of the previous utf8 character starting at byte index 'i…
+ */
+size_t ledit_line_prev_utf8(ledit_line *line, size_t index);
+
+/*
+ * Get the unicode character index of a byte position.
+ */
+size_t line_byte_to_char(ledit_line *line, size_t byte);
+
+/*
+ * Delete the section of line 'line' starting at byte 'start' with length 'len…
+ * and notify the views.
+ * Note that this does not tell the views to recalculate their line heights an…
+ */
+void ledit_buffer_delete_line_section_base(ledit_buffer *buffer, size_t line, …
+
+/*
+ * Delete the unicode char at 'line_index' and 'byte_index' if 'dir' is >= 0,
+ * or the previous char if 'dir' is < 0.
+ * Returns the byte index where the deleted text was located.
+ * This function only notifies the views of the deletion, but does not tell
+ * them to recalculate their line heights and offsets.
+ */
+size_t ledit_buffer_delete_unicode_char_base(ledit_buffer *buffer, size_t line…
+
+/*
+ * Same as ledit_buffer_delete_unicode_char_base, but the views are updated.
+ */
+size_t ledit_buffer_delete_unicode_char(ledit_buffer *buffer, size_t line_inde…
+
+/*
+ * Insert a mark with key 'mark' at line 'line' and byte 'byte'.
+ */
+void ledit_buffer_insert_mark(ledit_buffer *buffer, char *mark, size_t len, si…
+
+#endif
diff --git a/cache.c b/cache.c
t@@ -20,11 +20,13 @@ cache_create(Display *dpy) {
for (size_t i = 0; i < PIXMAP_CACHE_INITIAL_SIZE; i++) {
cache->pixmaps[i].pixmap = None;
cache->pixmaps[i].draw = NULL;
- cache->pixmaps[i].line = -1;
+ cache->pixmaps[i].line = 0;
+ cache->pixmaps[i].valid = 0;
}
for (size_t i = 0; i < LAYOUT_CACHE_SIZE; i++) {
cache->layouts[i].layout = NULL;
- cache->layouts[i].line = -1;
+ cache->layouts[i].line = 0;
+ cache->layouts[i].valid = 0;
}
cache->num_pixmaps = PIXMAP_CACHE_INITIAL_SIZE;
cache->num_layouts = LAYOUT_CACHE_SIZE;
t@@ -35,28 +37,30 @@ cache_create(Display *dpy) {
void
cache_flush(
ledit_cache *cache, void *callback_data,
- void (*set_pixmap_line)(void *, int, int),
- void (*set_layout_line)(void *, int, int)) {
+ void (*invalidate_pixmap_line)(void *, size_t),
+ void (*invalidate_layout_line)(void *, size_t)) {
cache_invalidate_from_line(
- cache, 0, callback_data, set_pixmap_line, set_layout_line
+ cache, 0, callback_data, invalidate_pixmap_line, invalidate_layout…
);
}
void
cache_invalidate_from_line(
- ledit_cache *cache, int start, void *callback_data,
- void (*set_pixmap_line)(void *, int, int),
- void (*set_layout_line)(void *, int, int)) {
+ ledit_cache *cache, size_t start, void *callback_data,
+ void (*invalidate_pixmap_line)(void *, size_t),
+ void (*invalidate_layout_line)(void *, size_t)) {
for (size_t i = 0; i < cache->num_pixmaps; i++) {
if (cache->pixmaps[i].line >= start) {
- set_pixmap_line(callback_data, cache->pixmaps[i].line,…
- cache->pixmaps[i].line = -1;
+ invalidate_pixmap_line(callback_data, cache->pixmaps[i…
+ cache->pixmaps[i].line = 0;
+ cache->pixmaps[i].valid = 0;
}
}
for (size_t i = 0; i < cache->num_layouts; i++) {
if (cache->layouts[i].line >= start) {
- set_layout_line(callback_data, cache->layouts[i].line,…
- cache->layouts[i].line = -1;
+ invalidate_layout_line(callback_data, cache->layouts[i…
+ cache->layouts[i].line = 0;
+ cache->layouts[i].valid = 0;
}
}
}
t@@ -79,49 +83,44 @@ cache_destroy(ledit_cache *cache) {
}
cache_pixmap *
-cache_get_pixmap(ledit_cache *cache, int index) {
- assert(index >= 0 && (size_t)index < cache->num_pixmaps);
+cache_get_pixmap(ledit_cache *cache, size_t index) {
+ assert(index < cache->num_pixmaps);
return &cache->pixmaps[index];
}
cache_layout *
-cache_get_layout(ledit_cache *cache, int index) {
- assert(index >= 0 && (size_t)index < cache->num_layouts);
+cache_get_layout(ledit_cache *cache, size_t index) {
+ assert(index < cache->num_layouts);
return &cache->layouts[index];
}
-/* FIXME: standardize overflow checking */
-static void
-err_overflow(void) {
- fprintf(stderr, "ERROR: Integer overflow in cache handling.\n");
- exit(1);
-}
-
/* FIXME: decide on int or size_t, but not both */
/* or maybe ssize_t */
+
+/* FIXME: max pixmap cache size */
void
cache_assign_pixmap_index(
- ledit_cache *cache, int line,
+ ledit_cache *cache, size_t line,
void *callback_data,
- int (*line_needed)(void *, int),
- void (*set_pixmap_line)(void *, int, int)) {
- int line_index;
+ int (*line_needed)(void *, size_t),
+ void (*set_pixmap_line)(void *, size_t, size_t),
+ void (*invalidate_pixmap_line)(void *, size_t)) {
+ size_t line_index;
size_t entry_index;
for (size_t i = 0; i <= cache->num_pixmaps; i++) {
entry_index = (i + cache->cur_pixmap_index) % cache->num_pixma…
line_index = cache->pixmaps[entry_index].line;
+ int valid = cache->pixmaps[entry_index].valid;
/* replace line when entry isn't assigned or currently assigne…
- if (line_index == -1 ||
- (line_index >= 0 &&
- !line_needed(callback_data, line_index))) {
+ if (!valid ||
+ (valid && !line_needed(callback_data, line_index))) {
cache->cur_pixmap_index = (entry_index + 1) % cache->n…
- if (entry_index > INT_MAX)
- err_overflow();
cache_pixmap *pix = &cache->pixmaps[entry_index];
- if (pix->line >= 0)
- set_pixmap_line(callback_data, pix->line, -1);
+ if (pix->valid)
+ invalidate_pixmap_line(callback_data, pix->lin…
pix->line = line;
- set_pixmap_line(callback_data, line, (int)entry_index);
+ pix->valid = 1;
+ set_pixmap_line(callback_data, line, entry_index);
return;
}
}
t@@ -133,32 +132,31 @@ cache_assign_pixmap_index(
cache->pixmaps = ledit_reallocarray(cache->pixmaps, cache->num_pixmaps…
entry_index = cache->num_pixmaps;
for (size_t i = cache->num_pixmaps; i < cache->num_pixmaps * 2; i++) {
- cache->pixmaps[i].line = -1;
+ cache->pixmaps[i].line = 0;
+ cache->pixmaps[i].valid = 0;
cache->pixmaps[i].pixmap = None;
cache->pixmaps[i].draw = NULL;
}
cache->num_pixmaps *= 2;
- if (entry_index > INT_MAX)
- err_overflow();
cache_pixmap *pix = &cache->pixmaps[entry_index];
pix->line = line;
- set_pixmap_line(callback_data, line, (int)entry_index);
+ pix->valid = 1;
+ set_pixmap_line(callback_data, line, entry_index);
}
/* FIXME: perhaps use "real" clock cache management, i.e. set a bit on a cache…
when it is used so it isn't invalidated yet. */
-void
-cache_assign_layout_index(
- ledit_cache *cache, int line,
+void cache_assign_layout_index(
+ ledit_cache *cache, size_t line,
void *callback_data,
- void (*set_layout_line)(void *, int, int)) {
+ void (*set_layout_line)(void *, size_t, size_t),
+ void (*invalidate_layout_line)(void *, size_t)) {
size_t old = cache->cur_layout_index;
cache->cur_layout_index = (cache->cur_layout_index + 1) % cache->num_l…
- if (old > INT_MAX)
- err_overflow();
cache_layout *layout = &cache->layouts[old];
- if (layout->line >= 0)
- set_layout_line(callback_data, layout->line, -1);
+ if (layout->valid)
+ invalidate_layout_line(callback_data, layout->line);
+ layout->valid = 1;
layout->line = line;
- set_layout_line(callback_data, line, (int)old);
+ set_layout_line(callback_data, line, old);
}
diff --git a/cache.h b/cache.h
t@@ -4,7 +4,7 @@
#define LAYOUT_CACHE_SIZE 40
/*
- * The initial number of pixmas in the cache.
+ * The initial number of pixmaps in the cache.
* The size is increased when more pixmaps are visible
* at the same time than there are entries in the cache.
*/
t@@ -13,13 +13,15 @@
typedef struct {
Pixmap pixmap;
XftDraw *draw;
- int w, h; /* width and height of the pixmap */
- int line;/* the line associated with this entry, or -1 if unassigned */
+ int w, h; /* width and height of the pixmap */
+ size_t line; /* the line associated with this entry */
+ int valid; /* whether the entry is assigned to a line */
} cache_pixmap;
typedef struct {
PangoLayout *layout;
- int line; /* the line associated with this entry, or -1 if unassigned …
+ size_t line; /* the line associated with this entry */
+ int valid; /* whether the entry is assigned to a line */
} cache_layout;
typedef struct {
t@@ -42,26 +44,26 @@ ledit_cache *cache_create(Display *dpy);
/*
* Reset line index of every cache entry (pixmaps and layouts).
- * set_pixmap_line is called with callback_data as its first argument,
- * a line index which has been removed from the pixmap cache as the
- * second argument, and '-1' as the third argument.
- * set_layout_line is the same, but for the layout cache.
+ * invalidate_pixmap_line is called with callback_data as its first
+ * argument and a line index which has been removed from the pixmap
+ * cache as the second argument.
+ * invalidate_layout_line is the same, but for the layout cache.
*/
void cache_flush(
ledit_cache *cache,
void *callback_data,
- void (*set_pixmap_line)(void *, int, int),
- void (*set_layout_line)(void *, int, int)
+ void (*invalidate_pixmap_line)(void *, size_t),
+ void (*invalidate_layout_line)(void *, size_t)
);
/*
* Like cache_flush, but only line numbers >= start are invalidated.
*/
void cache_invalidate_from_line(
- ledit_cache *cache, int start,
+ ledit_cache *cache, size_t start,
void *callback_data,
- void (*set_pixmap_line)(void *, int, int),
- void (*set_layout_line)(void *, int, int)
+ void (*invalidate_pixmap_line)(void *, size_t),
+ void (*invalidate_layout_line)(void *, size_t)
);
/*
t@@ -72,12 +74,12 @@ void cache_destroy(ledit_cache *cache);
/*
* Get the cache_pixmap at index.
*/
-cache_pixmap *cache_get_pixmap(ledit_cache *cache, int index);
+cache_pixmap *cache_get_pixmap(ledit_cache *cache, size_t index);
/*
* Get the cache_layout at index.
*/
-cache_layout *cache_get_layout(ledit_cache *cache, int index);
+cache_layout *cache_get_layout(ledit_cache *cache, size_t index);
/*
* The following two functions have a somewhat cumbersome interface
t@@ -94,17 +96,19 @@ cache_layout *cache_get_layout(ledit_cache *cache, int ind…
* It is called with callback_data as the first argument and the
* line to be checked as the second argument.
* The line of the cache entry is set to 'line' and if a line was
- * set before, it is reset by calling 'reset_pixmap_line' with
- * 'callback_data' as the first argument, the old line as the second
- * argument, and '-1' as the third argument.
- * Similarly, the cache index of the new line is changed by calling
- * 'set_pixmap_line' with the new cache index as the third argument.
+ * set before, it is reset by calling 'invalidate_pixmap_line' with
+ * 'callback_data' as the first argumentand the old line as the
+ * second argument.
+ * The cache index of the new line is changed by calling 'set_pixmap_line'
+ * with 'callback_data' as the first argument, 'line' as the second
+ * argument, and the new cache index as the third argument.
*/
void cache_assign_pixmap_index(
- ledit_cache *cache, int line,
+ ledit_cache *cache, size_t line,
void *callback_data,
- int (*line_needed)(void *, int),
- void (*set_pixmap_line)(void *, int, int)
+ int (*line_needed)(void *, size_t),
+ void (*set_pixmap_line)(void *, size_t, size_t),
+ void (*invalidate_pixmap_line)(void *, size_t)
);
/*
t@@ -112,14 +116,16 @@ void cache_assign_pixmap_index(
* Since it is not clear which layouts are needed more, this just
* uses the next index in a clock fashion.
* The line of the cache entry is set to 'line' and if a line was
- * set before, it is reset by calling 'set_layout_line' with
- * 'callback_data' as the first argument, the old line as the second
- * argument, and '-1' as the third argument.
- * Similarly, the cache index of the new line is changed by calling
- * 'set_layout_line' with the new cache index as the third argument.
+ * set before, it is reset by calling 'invalidate_layout_line' with
+ * 'callback_data' as the first argument and the old line as the
+ * second argument.
+ * The cache index of the new line is changed by calling 'set_layout_line'
+ * with 'callback_data' as the first argument, 'line' as the second
+ * argument, and the new cache index as the third argument.
*/
void cache_assign_layout_index(
- ledit_cache *cache, int line,
+ ledit_cache *cache, size_t line,
void *callback_data,
- void (*set_layout_line)(void *, int, int)
+ void (*set_layout_line)(void *, size_t, size_t),
+ void (*invalidate_layout_line)(void *, size_t)
);
diff --git a/cleanup.h b/cleanup.h
t@@ -0,0 +1,3 @@
+/* This is here so it can be called from other places
+ even though the function definition is in ledit.c */
+void ledit_cleanup(void);
diff --git a/common.h b/common.h
t@@ -1,8 +1,8 @@
typedef struct {
- int line1;
- int byte1;
- int line2;
- int byte2;
+ size_t line1;
+ size_t byte1;
+ size_t line2;
+ size_t byte2;
} ledit_range;
enum ledit_mode {
t@@ -18,5 +18,4 @@ typedef struct {
int screen;
int depth;
int redraw;
- enum ledit_mode mode;
} ledit_common;
diff --git a/keys_basic.c b/keys_basic.c
t@@ -1,5 +1,6 @@
-/* FIXME: I guess hard_line_based should be updated for all buffers/windows wh…
-/* FIXME: cursor isn't shown on spaces at end of softlines */
+/* FIXME: the stacks here are shared for all views which can cause weird
+ behavior, but I'm not sure what would be more logical */
+/* FIXME: cursor isn't shown properly on spaces at end of softlines */
/* FIXME: selection is sometimes not reset when it is "clicked away" */
/* FIXME: use weak cursor */
/* FIXME: spaces at end of soft line are weird in bidi text
t@@ -28,10 +29,10 @@
#include "theme.h"
#include "window.h"
#include "buffer.h"
+#include "view.h"
#include "search.h"
#include "keys.h"
-#include "action.h"
#include "keys_basic.h"
#include "keys_command.h"
#include "keys_basic_config.h"
t@@ -43,7 +44,7 @@ static int last_lines_scrolled = -1;
struct repetition_stack_elem {
char *key_text;
- int len;
+ size_t len;
KeySym sym;
unsigned int key_state;
int lang_index;
t@@ -57,7 +58,7 @@ static struct {
struct repetition_stack_elem *tmp_stack;
} repetition_stack = {0, 0, 0, 0, NULL, 0, 0, NULL};
-typedef void (*motion_callback)(ledit_buffer *buffer, int line, int char_pos, …
+typedef void (*motion_callback)(ledit_view *view, size_t line, size_t char_pos…
struct key_stack_elem {
enum key_type key;
t@@ -68,8 +69,6 @@ struct key_stack_elem {
* the command should operate on lines or chars) */
motion_callback motion_cb;
int count; /* number of repetitions */
- int data1; /* misc. data 1 */
- int data2; /* misc. data 2 */
};
static struct {
t@@ -77,7 +76,7 @@ static struct {
struct key_stack_elem *stack;
} key_stack = {0, 0, NULL};
-static struct action (*grab_char_cb)(ledit_buffer *buffer, char *text, int len…
+static struct action (*grab_char_cb)(ledit_view *view, char *text, size_t len)…
static int hard_line_based = 1;
void
t@@ -109,24 +108,24 @@ static struct key_stack_elem *peek_key_stack(void);
static struct key_stack_elem *pop_key_stack(void);
void clear_key_stack(void);
-static void move_cursor_left_right(ledit_buffer *buffer, int dir, int allow_il…
-static void move_cursor_up_down(ledit_buffer *buffer, int dir);
+static void move_cursor_left_right(ledit_view *view, int dir, int allow_illega…
+static void move_cursor_up_down(ledit_view *view, int dir);
static void push_num(int num);
-static void delete_cb(ledit_buffer *buffer, int line, int char_pos, enum key_t…
-static void yank_cb(ledit_buffer *buffer, int line, int char_pos, enum key_typ…
+static void delete_cb(ledit_view *view, size_t line, size_t char_pos, enum key…
+static void yank_cb(ledit_view *view, size_t line, size_t char_pos, enum key_t…
static void get_new_line_softline(
- ledit_buffer *buffer, int cur_line, int cur_index,
- int movement, int *new_line_ret, int *new_softline_ret
+ ledit_view *view, size_t cur_line, size_t cur_index,
+ int movement, size_t *new_line_ret, int *new_softline_ret
);
-static void move_cursor_logically(ledit_buffer *buffer, int movement_dir, int …
-static void change_cb(ledit_buffer *buffer, int line, int char_pos, enum key_t…
-static void push_undo_empty_insert(ledit_buffer *buffer, int line, int index, …
-static void move_half_screen(ledit_buffer *buffer, int movement);
+static void move_cursor_logically(ledit_view *view, int movement_dir, int allo…
+static void change_cb(ledit_view *view, size_t line, size_t char_pos, enum key…
+static void push_undo_empty_insert(ledit_view *view, size_t line, size_t index…
+static void move_half_screen(ledit_view *view, int movement);
/* FIXME: move to common */
static void
-swap(int *a, int *b) {
- int tmp = *a;
+swap_sz(size_t *a, size_t *b) {
+ size_t tmp = *a;
*a = *b;
*b = tmp;
}
t@@ -151,8 +150,6 @@ push_key_stack(void) {
e->followup = KEY_NONE;
e->motion_cb = NULL;
e->count = 0;
- e->data1 = 0;
- e->data2 = 0;
key_stack.len++;
return e;
}
t@@ -182,8 +179,8 @@ clear_key_stack(void) {
}
static struct action
-err_invalid_key(ledit_buffer *buffer) {
- ledit_window_show_message(buffer->window, "Invalid key", -1);
+err_invalid_key(ledit_view *view) {
+ ledit_window_show_message(view->window, "Invalid key", -1);
clear_key_stack();
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
t@@ -213,8 +210,14 @@ get_key_repeat_and_motion_cb(motion_callback *cb_ret) {
} else if (e->count == 0) {
num = 0;
}
- if (e != NULL)
- num *= (e->count > 0 ? e->count : 1);
+ if (e != NULL) {
+ int new_count = e->count > 0 ? e->count : 1;
+ if (INT_MAX / new_count < num) {
+ /* FIXME: show error */
+ num = INT_MAX;
+ }
+ num *= new_count;
+ }
} else {
num = 0;
}
t@@ -329,27 +332,28 @@ finalize_repetition_stack(void) {
down (negative means up, positive means down) */
static void
get_new_line_softline(
- ledit_buffer *buffer, int cur_line, int cur_index, int movement,
- int *new_line_ret, int *new_softline_ret) {
+ ledit_view *view, size_t cur_line, size_t cur_index, int movement,
+ size_t *new_line_ret, int *new_softline_ret) {
if (hard_line_based) {
- *new_line_ret = cur_line + movement;
- if (*new_line_ret < 0)
+ if (movement < 0 && (size_t)-movement > cur_line)
*new_line_ret = 0;
- else if (*new_line_ret >= buffer->lines_num)
- *new_line_ret = buffer->lines_num - 1;
+ else
+ *new_line_ret = cur_line + movement;
+ if (*new_line_ret >= view->lines_num)
+ *new_line_ret = view->lines_num - 1;
*new_softline_ret = 0;
} else {
- int softline = ledit_buffer_pos_to_softline(buffer, cur_line, …
+ int softline = view_pos_to_softline(view, cur_line, cur_index);
if (movement > 0) {
- int softlines = ledit_buffer_get_softline_count(buffer…
+ int softlines = view_get_softline_count(view, cur_line…
if (softlines - softline > movement) {
*new_line_ret = cur_line;
*new_softline_ret = softline + movement;
} else {
movement -= (softlines - softline - 1);
- int endline = cur_line + 1;
- while (movement > 0 && endline < buffer->lines…
- softlines = ledit_buffer_get_softline_…
+ size_t endline = cur_line + 1;
+ while (movement > 0 && endline < view->lines_n…
+ softlines = view_get_softline_count(vi…
movement -= softlines;
endline++;
}
t@@ -368,13 +372,12 @@ get_new_line_softline(
*new_softline_ret = softline + movement;
} else {
movement += softline;
- int endline = cur_line - 1;
- while (movement < 0 && endline >= 0) {
- softlines = ledit_buffer_get_softline_…
+ size_t endline = cur_line;
+ while (movement < 0 && endline > 0) {
+ softlines = view_get_softline_count(vi…
movement += softlines;
endline--;
}
- endline++;
if (movement >= 0) {
*new_softline_ret = movement;
} else {
t@@ -389,21 +392,21 @@ get_new_line_softline(
}
}
-/* FIXME: don't overwrite buffer->cur_line, etc. here? */
+/* FIXME: don't overwrite view->cur_line, etc. here? */
static void
delete_range(
- ledit_buffer *buffer,
+ ledit_view *view,
int line_based, int selected,
- int line_index1, int byte_index1,
- int line_index2, int byte_index2,
+ size_t line_index1, size_t byte_index1,
+ size_t line_index2, size_t byte_index2,
int copy_to_buffer) {
(void)selected; /* FIXME */
if (copy_to_buffer && !paste_buffer)
paste_buffer = txtbuf_new();
txtbuf *buf = copy_to_buffer ? paste_buffer : txtbuf_new();
ledit_range cur_range, del_range;
- cur_range.line1 = buffer->cur_line;
- cur_range.byte1 = buffer->cur_index;
+ cur_range.line1 = view->cur_line;
+ cur_range.byte1 = view->cur_index;
enum delete_mode delmode = DELETE_CHAR;
if (line_based) {
if (hard_line_based)
t@@ -411,17 +414,17 @@ delete_range(
else
delmode = DELETE_SOFTLINE;
}
- ledit_buffer_delete_range(
- buffer, delmode,
+ view_delete_range(
+ view, delmode,
line_index1, byte_index1,
line_index2, byte_index2,
- &buffer->cur_line, &buffer->cur_index,
+ &view->cur_line, &view->cur_index,
&del_range, buf
);
- cur_range.line2 = buffer->cur_line;
- cur_range.byte2 = buffer->cur_index;
+ cur_range.line2 = view->cur_line;
+ cur_range.byte2 = view->cur_index;
ledit_push_undo_delete(
- buffer->undo, buf, del_range, cur_range, 1, buffer->common->mode
+ view->buffer->undo, buf, del_range, cur_range, 1, view->mode
);
if (!copy_to_buffer)
txtbuf_destroy(buf);
t@@ -429,214 +432,214 @@ delete_range(
static void
insert_text(
- ledit_buffer *buffer,
- int line, int index,
- char *text, int len,
- int cur_line1, int cur_index1,
- int cur_line2, int cur_index2, int start_group) {
- if (len < 0)
- len = strlen(text);
+ ledit_view *view,
+ size_t line, size_t index,
+ char *text, size_t len,
+ size_t cur_line1, size_t cur_index1,
+ size_t cur_line2, size_t cur_index2,
+ int set_range_start, int set_range_end, int start_group) {
txtbuf ins_buf = {.text = text, .len = len, .cap = len};
ledit_range cur_range, del_range;
- if (cur_line1 >= 0 && cur_index1 >= 0) {
+ if (set_range_start) {
cur_range.line1 = cur_line1;
cur_range.byte1 = cur_index1;
} else {
- cur_range.line1 = buffer->cur_line;
- cur_range.byte1 = buffer->cur_index;
+ cur_range.line1 = view->cur_line;
+ cur_range.byte1 = view->cur_index;
}
del_range.line1 = line;
del_range.byte1 = index;
- int cur_line, cur_index;
+ size_t cur_line, cur_index;
ledit_buffer_insert_text_with_newlines(
- buffer, line, index, text, len,
+ view->buffer, line, index, text, len,
&cur_line, &cur_index
);
/* this is mainly for pasting, where the new line and index
should not be at the end of the pasted text */
- if (cur_line2 >= 0 && cur_index2 >= 0) {
- cur_range.line2 = buffer->cur_line = cur_line2;
- cur_range.byte2 = buffer->cur_index = cur_index2;
+ if (set_range_end) {
+ cur_range.line2 = view->cur_line = cur_line2;
+ cur_range.byte2 = view->cur_index = cur_index2;
} else {
- cur_range.line2 = buffer->cur_line = cur_line;
- cur_range.byte2 = buffer->cur_index = cur_index;
+ cur_range.line2 = view->cur_line = cur_line;
+ cur_range.byte2 = view->cur_index = cur_index;
}
del_range.line2 = cur_line;
del_range.byte2 = cur_index;
ledit_push_undo_insert(
- buffer->undo, &ins_buf, del_range, cur_range, start_group, buffer-…
+ view->buffer->undo, &ins_buf, del_range, cur_range, start_group, v…
);
}
static int
-delete_selection(ledit_buffer *buffer) {
- if (buffer->sel.line1 != buffer->sel.line2 || buffer->sel.byte1 != buf…
+delete_selection(ledit_view *view) {
+ if (view->sel_valid && (view->sel.line1 != view->sel.line2 || view->se…
delete_range(
- buffer, 0, 0,
- buffer->sel.line1, buffer->sel.byte1,
- buffer->sel.line2, buffer->sel.byte2, 1
+ view, 0, 0,
+ view->sel.line1, view->sel.byte1,
+ view->sel.line2, view->sel.byte2, 1
);
paste_buffer_line_based = 0;
- /* FIXME: maybe just set this to the current cursor pos? */
- buffer->sel.line1 = buffer->sel.line2 = -1;
- buffer->sel.byte1 = buffer->sel.byte2 = -1;
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ view->sel_valid = 0;
+ view->sel.line1 = view->sel.line2 = 0;
+ view->sel.byte1 = view->sel.byte2 = 0;
+ view_wipe_line_cursor_attrs(view, view->cur_line);
return 1;
}
return 0;
}
static struct action
-delete_chars_forwards(ledit_buffer *buffer, char *text, int len) {
+delete_chars_forwards(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
int num = get_key_repeat();
if (num == -1) {
- ledit_window_show_message(buffer->window, "Invalid key", -1);
+ ledit_window_show_message(view->window, "Invalid key", -1);
return (struct action){ACTION_NONE, NULL};
} else if (num == 0) {
num = 1;
}
- int end_index = ledit_buffer_next_cursor_pos(
- buffer, buffer->cur_line, buffer->cur_index, num
+ size_t end_index = view_next_cursor_pos(
+ view, view->cur_line, view->cur_index, num
);
delete_range(
- buffer, 0, 0,
- buffer->cur_line, buffer->cur_index,
- buffer->cur_line, end_index, 1
+ view, 0, 0,
+ view->cur_line, view->cur_index,
+ view->cur_line, end_index, 1
);
paste_buffer_line_based = 0;
- buffer->cur_index = ledit_buffer_get_legal_normal_pos(
- buffer, buffer->cur_line, buffer->cur_index
+ view->cur_index = view_get_legal_normal_pos(
+ view, view->cur_line, view->cur_index
);
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
return (struct action){ACTION_NONE, NULL};
}
static struct action
-delete_chars_backwards(ledit_buffer *buffer, char *text, int len) {
+delete_chars_backwards(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
int num = get_key_repeat();
if (num == -1) {
- ledit_window_show_message(buffer->window, "Invalid key", -1);
+ ledit_window_show_message(view->window, "Invalid key", -1);
return (struct action){ACTION_NONE, NULL};
} else if (num == 0) {
num = 1;
}
- int start_index = ledit_buffer_prev_cursor_pos(
- buffer, buffer->cur_line, buffer->cur_index, num
+ size_t start_index = view_prev_cursor_pos(
+ view, view->cur_line, view->cur_index, num
);
delete_range(
- buffer, 0, 0,
- buffer->cur_line, start_index,
- buffer->cur_line, buffer->cur_index, 1
+ view, 0, 0,
+ view->cur_line, start_index,
+ view->cur_line, view->cur_index, 1
);
paste_buffer_line_based = 0;
/* I guess this is technically unnecessary since only
text before the current position is deleted */
- buffer->cur_index = ledit_buffer_get_legal_normal_pos(
- buffer, buffer->cur_line, start_index
+ view->cur_index = view_get_legal_normal_pos(
+ view, view->cur_line, start_index
);
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
return (struct action){ACTION_NONE, NULL};
}
/* used to set cursor - I guess this is sort of a hack */
static void
-push_undo_empty_insert(ledit_buffer *buffer, int line, int index, int start_gr…
+push_undo_empty_insert(ledit_view *view, size_t line, size_t index, int start_…
txtbuf ins_buf = {.text = "", .len = 0, .cap = 0};
ledit_range ins_range = {.line1 = line, .byte1 = index, .line2 = line,…
ledit_range cur_range = {.line1 = line, .byte1 = index, .line2 = line,…
ledit_push_undo_insert(
- buffer->undo, &ins_buf, ins_range, cur_range, start_group, buffer-…
+ view->buffer->undo, &ins_buf, ins_range, cur_range, start_group, v…
);
}
static struct action
-append_line_above(ledit_buffer *buffer, char *text, int len) {
- int start, end;
+append_line_above(ledit_view *view, char *text, size_t len) {
+ size_t start, end;
/* do this here already so the mode group is the same for the newline …
- enter_insert(buffer, text, len);
- ledit_buffer_get_pos_softline_bounds(buffer, buffer->cur_line, buffer-…
+ enter_insert(view, text, len);
+ view_get_pos_softline_bounds(view, view->cur_line, view->cur_index, &s…
if (hard_line_based || start == 0) {
- insert_text(buffer, buffer->cur_line, 0, "\n", -1, -1, -1, buf…
+ insert_text(view, view->cur_line, 0, "\n", 1, 0, 0, view->cur_…
} else {
- insert_text(buffer, buffer->cur_line, start, "\n\n", -1, -1, -…
+ /* FIXME: this interface really is horrible */
+ insert_text(view, view->cur_line, start, "\n\n", 2, 0, 0, view…
}
return (struct action){ACTION_NONE, NULL};
}
static struct action
-append_line_below(ledit_buffer *buffer, char *text, int len) {
- int start, end;
- enter_insert(buffer, text, len);
- ledit_buffer_get_pos_softline_bounds(buffer, buffer->cur_line, buffer-…
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line);
+append_line_below(ledit_view *view, char *text, size_t len) {
+ size_t start, end;
+ enter_insert(view, text, len);
+ view_get_pos_softline_bounds(view, view->cur_line, view->cur_index, &s…
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, view->cur_line);
if (hard_line_based || end == ll->len) {
- insert_text(buffer, buffer->cur_line, ll->len, "\n", -1, -1, -…
+ insert_text(view, view->cur_line, ll->len, "\n", 1, 0, 0, view…
} else {
- insert_text(buffer, buffer->cur_line, end, "\n\n", -1, -1, -1,…
+ insert_text(view, view->cur_line, end, "\n\n", 2, 0, 0, view->…
}
return (struct action){ACTION_NONE, NULL};
}
static struct action
-append_after_cursor(ledit_buffer *buffer, char *text, int len) {
- enter_insert(buffer, text, len);
+append_after_cursor(ledit_view *view, char *text, size_t len) {
+ enter_insert(view, text, len);
/* make cursor jump back to original position on undo */
- push_undo_empty_insert(buffer, buffer->cur_line, buffer->cur_index, 1);
- buffer->cur_index = ledit_buffer_next_cursor_pos(
- buffer, buffer->cur_line, buffer->cur_index, 1
+ push_undo_empty_insert(view, view->cur_line, view->cur_index, 1);
+ view->cur_index = view_next_cursor_pos(
+ view, view->cur_line, view->cur_index, 1
);
return (struct action){ACTION_NONE, NULL};
}
static struct action
-append_after_eol(ledit_buffer *buffer, char *text, int len) {
- int start, end;
- enter_insert(buffer, text, len);
- ledit_buffer_get_pos_softline_bounds(buffer, buffer->cur_line, buffer-…
+append_after_eol(ledit_view *view, char *text, size_t len) {
+ size_t start, end;
+ enter_insert(view, text, len);
+ view_get_pos_softline_bounds(view, view->cur_line, view->cur_index, &s…
/* make cursor jump back to original position on undo */
- push_undo_empty_insert(buffer, buffer->cur_line, buffer->cur_index, 1);
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line);
+ push_undo_empty_insert(view, view->cur_line, view->cur_index, 1);
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, view->cur_line);
if (hard_line_based)
- buffer->cur_index = ll->len;
+ view->cur_index = ll->len;
else
- buffer->cur_index = end;
+ view->cur_index = end;
return (struct action){ACTION_NONE, NULL};
}
static struct action
-move_to_line(ledit_buffer *buffer, char *text, int len) {
+move_to_line(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
motion_callback cb = NULL;
int repeat = get_key_repeat_and_motion_cb(&cb);
- int line;
+ size_t line;
if (repeat > 0)
- line = repeat > buffer->lines_num ? buffer->lines_num : repeat;
+ line = (size_t)repeat > view->lines_num ? view->lines_num : (s…
else if (repeat == 0)
- line = buffer->lines_num;
+ line = view->lines_num;
else
- return err_invalid_key(buffer);
+ return err_invalid_key(view);
if (cb != NULL) {
- cb(buffer, line - 1, 0, KEY_MOTION_LINE);
+ cb(view, line - 1, 0, KEY_MOTION_LINE);
} else {
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- buffer->cur_line = line - 1;
- buffer->cur_index = 0;
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ view->cur_line = line - 1;
+ view->cur_index = 0;
int text_w, text_h;
- ledit_window_get_textview_size(buffer->window, &text_w, &text_…
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_lin…
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
+ ledit_view_line *vl = view_get_line(view, view->cur_line);
int x, y, h;
- ledit_buffer_get_cursor_pixel_pos(buffer, buffer->cur_line, 0,…
+ view_get_cursor_pixel_pos(view, view->cur_line, 0, &x, &y, &h);
/* if cursor is not on screen anymore, move to middle of scree…
- if (ll->y_offset < buffer->display_offset ||
- ll->y_offset + h > buffer->display_offset + text_h) {
- ledit_buffer_scroll(buffer, ll->y_offset - text_h / 2);
+ if (vl->y_offset < view->display_offset ||
+ vl->y_offset + h > view->display_offset + text_h) {
+ view_scroll(view, vl->y_offset - text_h / 2);
}
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, b…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
discard_repetition_stack();
}
return (struct action){ACTION_NONE, NULL};
t@@ -644,117 +647,117 @@ move_to_line(ledit_buffer *buffer, char *text, int len…
/* FIXME: should these scrolling functions change behavior when hard_line_base…
static void
-scroll_lines(ledit_buffer *buffer, int lines, int dir) {
+scroll_lines(ledit_view *view, int lines, int dir) {
if (last_lines_scrolled <= 0 && lines <= 0) {
/* no scroll command yet - scroll half of screen */
- move_half_screen(buffer, dir);
+ move_half_screen(view, dir);
} else {
int x, y, h, sli;
int final_lines, text_w, text_h;
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_lin…
- ledit_buffer_get_cursor_pixel_pos(buffer, buffer->cur_line, bu…
+ ledit_view_line *vl = view_get_line(view, view->cur_line);
+ view_get_cursor_pixel_pos(view, view->cur_line, view->cur_inde…
/* get the middle position of char */
- ledit_pos_to_x_softline(buffer, buffer->cur_line, buffer->cur_…
- long abs_pos = ll->y_offset + y;
- ledit_window_get_textview_size(buffer->window, &text_w, &text_…
+ ledit_pos_to_x_softline(view, view->cur_line, view->cur_index,…
+ long abs_pos = vl->y_offset + y;
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
if (lines > 0)
final_lines = last_lines_scrolled = lines;
else
final_lines = last_lines_scrolled;
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ view_wipe_line_cursor_attrs(view, view->cur_line);
get_new_line_softline(
- buffer, buffer->cur_line, buffer->cur_index,
+ view, view->cur_line, view->cur_index,
dir < 0 ? -final_lines : final_lines,
- &buffer->cur_line, &sli
+ &view->cur_line, &sli
);
- int start, end;
- ledit_buffer_get_softline_bounds(buffer, buffer->cur_line, sli…
- ll = ledit_buffer_get_line(buffer, buffer->cur_line);
- ledit_x_softline_to_pos(buffer, buffer->cur_line, x, sli, &buf…
- ledit_buffer_get_cursor_pixel_pos(buffer, buffer->cur_line, bu…
- long new_abs_pos = ll->y_offset + y;
- ledit_buffer_scroll(buffer, buffer->display_offset + (new_abs_…
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, b…
+ size_t start, end;
+ view_get_softline_bounds(view, view->cur_line, sli, &start, &e…
+ vl = view_get_line(view, view->cur_line);
+ ledit_x_softline_to_pos(view, view->cur_line, x, sli, &view->c…
+ view_get_cursor_pixel_pos(view, view->cur_line, view->cur_inde…
+ long new_abs_pos = vl->y_offset + y;
+ view_scroll(view, view->display_offset + (new_abs_pos - abs_po…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
}
}
static struct action
-scroll_lines_up(ledit_buffer *buffer, char *text, int len) {
+scroll_lines_up(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
int repeat = get_key_repeat();
if (repeat >= 0)
- scroll_lines(buffer, repeat, -1);
+ scroll_lines(view, repeat, -1);
else
- ledit_window_show_message(buffer->window, "Invalid key", -1);
+ ledit_window_show_message(view->window, "Invalid key", -1);
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
static struct action
-scroll_lines_down(ledit_buffer *buffer, char *text, int len) {
+scroll_lines_down(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
int repeat = get_key_repeat();
if (repeat >= 0)
- scroll_lines(buffer, repeat, 1);
+ scroll_lines(view, repeat, 1);
else
- ledit_window_show_message(buffer->window, "Invalid key", -1);
+ ledit_window_show_message(view->window, "Invalid key", -1);
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
static void
-scroll_with_cursor(ledit_buffer *buffer, int movement) {
+scroll_with_cursor(ledit_view *view, int movement) {
int x, y, h;
- ledit_buffer_get_cursor_pixel_pos(buffer, buffer->cur_line, buffer->cu…
- int pix_movement = movement * h;
- 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
+ view_get_cursor_pixel_pos(view, view->cur_line, view->cur_index, &x, &…
+ int pix_movement = movement * h; /* FIXME: overflow */
+ view_scroll(view, view->display_offset + pix_movement);
+ size_t old_line = view->cur_line;
+ size_t old_index = view->cur_index;
+ view_get_nearest_legal_pos(
+ view, old_line, old_index,
+ &view->cur_line, &view->cur_index
);
- if (old_line != buffer->cur_line || old_index != buffer->cur_index) {
- ledit_buffer_wipe_line_cursor_attrs(buffer, old_line);
+ if (old_line != view->cur_line || old_index != view->cur_index) {
+ view_wipe_line_cursor_attrs(view, 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
+ view_scroll_to_pos_top(
+ view, view->cur_line, view->cur_index
);
} else {
- ledit_buffer_scroll_to_pos_bottom(
- buffer, buffer->cur_line, buffer->cur_index
+ view_scroll_to_pos_bottom(
+ view, view->cur_line, view->cur_index
);
}
}
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
}
static struct action
-scroll_with_cursor_up(ledit_buffer *buffer, char *text, int len) {
+scroll_with_cursor_up(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
int repeat = get_key_repeat();
if (repeat >= 0)
- scroll_with_cursor(buffer, -(repeat == 0 ? 1 : repeat));
+ scroll_with_cursor(view, -(repeat == 0 ? 1 : repeat));
else
- ledit_window_show_message(buffer->window, "Invalid key", -1);
+ ledit_window_show_message(view->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) {
+scroll_with_cursor_down(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
int repeat = get_key_repeat();
if (repeat >= 0)
- scroll_with_cursor(buffer, repeat == 0 ? 1 : repeat);
+ scroll_with_cursor(view, repeat == 0 ? 1 : repeat);
else
- ledit_window_show_message(buffer->window, "Invalid key", -1);
+ ledit_window_show_message(view->window, "Invalid key", -1);
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
t@@ -765,160 +768,161 @@ scroll_with_cursor_down(ledit_buffer *buffer, char *te…
(unless the screen is already at the very top or bottom - then it is the ot…
/* FIXME: this is a bit weird at the moment */
static void
-move_half_screen(ledit_buffer *buffer, int movement) {
+move_half_screen(ledit_view *view, int movement) {
int w, h;
- ledit_window_get_textview_size(buffer->window, &w, &h);
+ ledit_window_get_textview_size(view->window, &w, &h);
/* FIXME: overflow */
int total = movement * h/2;
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line);
+ ledit_view_line *vl = view_get_line(view, view->cur_line);
int cur_x, cur_y, cur_h;
- ledit_buffer_get_cursor_pixel_pos(
- buffer, buffer->cur_line, buffer->cur_index, &cur_x, &cur_y, &cur_h
+ view_get_cursor_pixel_pos(
+ view, view->cur_line, view->cur_index, &cur_x, &cur_y, &cur_h
);
- long real_cur_y = ll->y_offset - buffer->display_offset + cur_y;
+ long real_cur_y = vl->y_offset - view->display_offset + cur_y;
/* new pixel position of cursor */
/* 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) */
+ view_get_nearest_legal_pos) */
int y = movement > 0 ? 0 : h;
int half_screen = abs(movement) % 2 == 1;
if (half_screen) {
/* if only half screens are moved and we are at the beginning …
end, just move the cursor the movement amount instead of
moving it to the very top or bottom */
- if (buffer->display_offset + total <= 0 ||
- buffer->display_offset + total + h >= buffer->total_height…
+ if (view->display_offset + total <= 0 ||
+ view->display_offset + total + h >= view->total_height) {
y = real_cur_y + total;
}
} else {
- if (buffer->display_offset + total <= 0)
+ if (view->display_offset + total <= 0)
y = 0;
- else if (buffer->display_offset + total + h > buffer->total_he…
+ else if (view->display_offset + total + h > view->total_height)
y = h;
}
if (y < 0)
y = 0;
if (y > h)
y = h;
- ledit_buffer_scroll(buffer, buffer->display_offset + total);
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ view_scroll(view, view->display_offset + total);
+ view_wipe_line_cursor_attrs(view, view->cur_line);
/* try to keep current x position of cursor */
int x, softline;
/* FIXME: properly document what uses PANGO_SCALE and what not */
- ledit_pos_to_x_softline(buffer, buffer->cur_line, buffer->cur_index, &…
+ ledit_pos_to_x_softline(view, view->cur_line, view->cur_index, &x, &so…
ledit_xy_to_line_byte(
- buffer, x / PANGO_SCALE, y, 0,
- &buffer->cur_line, &buffer->cur_index
+ view, x / PANGO_SCALE, y, 0,
+ &view->cur_line, &view->cur_index
);
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
}
static struct action
-screen_up(ledit_buffer *buffer, char *text, int len) {
+screen_up(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
int repeat = get_key_repeat();
if (repeat >= 0)
- move_half_screen(buffer, -(repeat == 0 ? 2 : repeat*2));
+ move_half_screen(view, -(repeat == 0 ? 2 : repeat*2));
else
- ledit_window_show_message(buffer->window, "Invalid key", -1);
+ ledit_window_show_message(view->window, "Invalid key", -1);
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
static struct action
-screen_down(ledit_buffer *buffer, char *text, int len) {
+screen_down(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
int repeat = get_key_repeat();
if (repeat >= 0)
- move_half_screen(buffer, repeat == 0 ? 2 : repeat*2);
+ move_half_screen(view, repeat == 0 ? 2 : repeat*2);
else
- ledit_window_show_message(buffer->window, "Invalid key", -1);
+ ledit_window_show_message(view->window, "Invalid key", -1);
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
static struct action
-delete_to_eol(ledit_buffer *buffer, char *text, int len) {
+delete_to_eol(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
if (!key_stack_empty())
- return err_invalid_key(buffer);
- int start, end;
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line);
+ return err_invalid_key(view);
+ size_t start, end;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, view->cur_line);
if (hard_line_based) {
end = ll->len;
} else {
- ledit_buffer_get_pos_softline_bounds(buffer, buffer->cur_line,…
+ view_get_pos_softline_bounds(view, view->cur_line, view->cur_i…
}
delete_range(
- buffer, 0, 0,
- buffer->cur_line, buffer->cur_index,
- buffer->cur_line, end, 1
+ view, 0, 0,
+ view->cur_line, view->cur_index,
+ view->cur_line, end, 1
);
paste_buffer_line_based = 0;
- buffer->cur_index = ledit_buffer_get_legal_normal_pos(
- buffer, buffer->cur_line, buffer->cur_index
+ view->cur_index = view_get_legal_normal_pos(
+ view, view->cur_line, view->cur_index
);
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
return (struct action){ACTION_NONE, NULL};
}
static struct action
-change_to_eol(ledit_buffer *buffer, char *text, int len) {
+change_to_eol(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
if (!key_stack_empty())
- return err_invalid_key(buffer);
- ledit_buffer_set_mode(buffer, INSERT);
- int start, end;
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line);
+ return err_invalid_key(view);
+ view_set_mode(view, INSERT);
+ size_t start, end;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, view->cur_line);
if (hard_line_based) {
end = ll->len;
} else {
- ledit_buffer_get_pos_softline_bounds(buffer, buffer->cur_line,…
+ view_get_pos_softline_bounds(view, view->cur_line, view->cur_i…
}
delete_range(
- buffer, 0, 0,
- buffer->cur_line, buffer->cur_index,
- buffer->cur_line, end, 1
+ view, 0, 0,
+ view->cur_line, view->cur_index,
+ view->cur_line, end, 1
);
paste_buffer_line_based = 0;
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ view_wipe_line_cursor_attrs(view, view->cur_line);
return (struct action){ACTION_NONE, NULL};
}
/* FIXME: clear selection on most commands */
/* FIXME: don't include escape when repeating change with '.'? */
static struct action
-change(ledit_buffer *buffer, char *text, int len) {
+change(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
motion_callback cb = NULL;
int num = get_key_repeat_and_motion_cb(&cb);
if (num == -1)
- return err_invalid_key(buffer);
- if (buffer->common->mode == VISUAL) {
- ledit_buffer_set_mode(buffer, INSERT);
- delete_selection(buffer);
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ return err_invalid_key(view);
+ if (view->mode == VISUAL) {
+ view_set_mode(view, INSERT);
+ delete_selection(view);
+ view_wipe_line_cursor_attrs(view, view->cur_line);
clear_key_stack();
} else {
if (cb == &change_cb) {
int lines = num > 0 ? num : 1;
- int new_line, new_softline;
+ size_t new_line;
+ int new_softline;
get_new_line_softline(
- buffer, buffer->cur_line, buffer->cur_index,
+ view, view->cur_line, view->cur_index,
lines - 1, &new_line, &new_softline
);
- int start, end;
- ledit_buffer_get_softline_bounds(buffer, new_line, new…
- cb(buffer, new_line, start, KEY_MOTION_LINE);
+ size_t start, end;
+ view_get_softline_bounds(view, new_line, new_softline,…
+ cb(view, new_line, start, KEY_MOTION_LINE);
clear_key_stack();
} else if (cb != NULL) {
- return err_invalid_key(buffer);
+ return err_invalid_key(view);
} else {
struct key_stack_elem *e = push_key_stack();
e->key = KEY_MOTION; /* ? */
t@@ -930,55 +934,55 @@ change(ledit_buffer *buffer, char *text, int len) {
}
static void
-change_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) {
+change_cb(ledit_view *view, size_t line, size_t char_pos, enum key_type type) {
/* set mode first so the deletion is included in the undo group */
- ledit_buffer_set_mode(buffer, INSERT);
+ view_set_mode(view, INSERT);
int line_based = type == KEY_MOTION_LINE ? 1 : 0;
/* this hackery is needed to avoid deleting the entire last line and
instead leave an empty line - this should be made nicer (FIXME) */
- int pos1 = buffer->cur_index, pos2 = char_pos;
+ size_t pos1 = view->cur_index, pos2 = char_pos;
if (line_based && !hard_line_based) {
- int pos1, pos2, tmp;
- ledit_buffer_get_pos_softline_bounds(buffer, buffer->cur_line,…
- ledit_buffer_get_pos_softline_bounds(buffer, line, char_pos, &…
+ size_t pos1, pos2, tmp;
+ view_get_pos_softline_bounds(view, view->cur_line, view->cur_i…
+ view_get_pos_softline_bounds(view, line, char_pos, &tmp, &pos2…
} else if (line_based && hard_line_based) {
pos1 = 0;
- ledit_line *ll = ledit_buffer_get_line(buffer, line);
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
pos2 = ll->len;
}
/* force line_based to 0 (see comment about hackery above) */
delete_range(
- buffer, 0, 0,
- buffer->cur_line, pos1,
+ view, 0, 0,
+ view->cur_line, pos1,
line, pos2, 1
);
paste_buffer_line_based = line_based;
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ view_wipe_line_cursor_attrs(view, view->cur_line);
}
static struct action
-yank(ledit_buffer *buffer, char *text, int len) {
+yank(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
if (!paste_buffer)
paste_buffer = txtbuf_new();
- if (buffer->common->mode == VISUAL) {
- ledit_buffer_sort_selection(
- &buffer->sel.line1, &buffer->sel.byte1, &buffer->sel.line2…
+ if (view->mode == VISUAL) {
+ view_sort_selection(
+ &view->sel.line1, &view->sel.byte1, &view->sel.line2, &vie…
);
ledit_buffer_copy_text_to_txtbuf(
- buffer, paste_buffer,
- buffer->sel.line1, buffer->sel.byte1, buffer->sel.line2, b…
+ view->buffer, paste_buffer,
+ view->sel.line1, view->sel.byte1, view->sel.line2, view->s…
);
paste_buffer_line_based = 0;
- buffer->cur_line = buffer->sel.line1;
- buffer->cur_index = buffer->sel.byte1;
- ledit_buffer_set_selection(buffer, -1, -1, -1, -1);
- ledit_buffer_set_mode(buffer, NORMAL);
- buffer->cur_index = ledit_buffer_get_legal_normal_pos(
- buffer, buffer->cur_line, buffer->cur_index
+ view->cur_line = view->sel.line1;
+ view->cur_index = view->sel.byte1;
+ view_wipe_selection(view);
+ view_set_mode(view, NORMAL);
+ view->cur_index = view_get_legal_normal_pos(
+ view, view->cur_line, view->cur_index
);
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, b…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
clear_key_stack();
} else {
motion_callback cb = NULL;
t@@ -986,14 +990,15 @@ yank(ledit_buffer *buffer, char *text, int len) {
if (num == 0)
num = 1;
if (cb == &yank_cb) {
- int new_line, new_softline;
+ size_t new_line;
+ int new_softline;
get_new_line_softline(
- buffer, buffer->cur_line, buffer->cur_index,
+ view, view->cur_line, view->cur_index,
num - 1, &new_line, &new_softline
);
- int start, end;
- ledit_buffer_get_softline_bounds(buffer, new_line, new…
- cb(buffer, new_line, start, KEY_MOTION_LINE);
+ size_t start, end;
+ view_get_softline_bounds(view, new_line, new_softline,…
+ cb(view, new_line, start, KEY_MOTION_LINE);
clear_key_stack();
} else if (cb == NULL) {
struct key_stack_elem *e = push_key_stack();
t@@ -1009,61 +1014,62 @@ yank(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-yank_lines(ledit_buffer *buffer, char *text, int len) {
+yank_lines(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
int num = get_key_repeat();
if (num == -1)
- return err_invalid_key(buffer);
+ return err_invalid_key(view);
else if (num == 0)
num = 1;
- int new_line, new_softline;
+ size_t new_line;
+ int new_softline;
get_new_line_softline(
- buffer, buffer->cur_line, buffer->cur_index,
+ view, view->cur_line, view->cur_index,
num - 1, &new_line, &new_softline
);
- int start, end;
- ledit_buffer_get_softline_bounds(buffer, new_line, new_softline, &star…
- yank_cb(buffer, new_line, start, KEY_MOTION_LINE);
+ size_t start, end;
+ view_get_softline_bounds(view, new_line, new_softline, &start, &end);
+ yank_cb(view, new_line, start, KEY_MOTION_LINE);
clear_key_stack();
return (struct action){ACTION_NONE, NULL};
}
static void
-yank_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) {
+yank_cb(ledit_view *view, size_t line, size_t char_pos, enum key_type type) {
int line_based = type == KEY_MOTION_LINE ? 1 : 0;
- int l1 = buffer->cur_line, l2 = line, b1 = buffer->cur_index, b2 = cha…
+ size_t l1 = view->cur_line, l2 = line, b1 = view->cur_index, b2 = char…
if (!paste_buffer)
paste_buffer = txtbuf_new();
if (l2 < l1 || (l1 == l2 && b2 < b1)) {
- swap(&l1, &l2);
- swap(&b1, &b2);
+ swap_sz(&l1, &l2);
+ swap_sz(&b1, &b2);
}
if (line_based && !hard_line_based) {
- int start1, end2, tmp;
- ledit_buffer_get_pos_softline_bounds(buffer, l1, b1, &start1, …
- ledit_buffer_get_pos_softline_bounds(buffer, l2, b2, &tmp, &en…
- ledit_line *ll = ledit_buffer_get_line(buffer, l2);
- if (end2 == ll->len && l2 < buffer->lines_num - 1) {
+ size_t start1, end2, tmp;
+ view_get_pos_softline_bounds(view, l1, b1, &start1, &tmp);
+ view_get_pos_softline_bounds(view, l2, b2, &tmp, &end2);
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, l2);
+ if (end2 == ll->len && l2 < view->lines_num - 1) {
l2++;
end2 = 0;
}
ledit_buffer_copy_text_to_txtbuf(
- buffer, paste_buffer, l1, start1, l2, end2
+ view->buffer, paste_buffer, l1, start1, l2, end2
);
} else if (line_based && hard_line_based) {
- ledit_line *ll = ledit_buffer_get_line(buffer, l2);
- int end = ll->len;
- if (l2 < buffer->lines_num - 1) {
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, l2);
+ size_t end = ll->len;
+ if (l2 < view->lines_num - 1) {
l2++;
end = 0;
}
ledit_buffer_copy_text_to_txtbuf(
- buffer, paste_buffer, l1, 0, l2, end
+ view->buffer, paste_buffer, l1, 0, l2, end
);
} else {
ledit_buffer_copy_text_to_txtbuf(
- buffer, paste_buffer, l1, b1, l2, b2
+ view->buffer, paste_buffer, l1, b1, l2, b2
);
}
paste_buffer_line_based = line_based;
t@@ -1071,33 +1077,34 @@ yank_cb(ledit_buffer *buffer, int line, int char_pos, …
}
static struct action
-delete(ledit_buffer *buffer, char *text, int len) {
+delete(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
motion_callback cb = NULL;
int num = get_key_repeat_and_motion_cb(&cb);
if (num == -1)
- return err_invalid_key(buffer);
- if (delete_selection(buffer)) {
- ledit_buffer_set_mode(buffer, NORMAL);
- buffer->cur_index = ledit_buffer_get_legal_normal_pos(buffer, …
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, b…
+ return err_invalid_key(view);
+ if (delete_selection(view)) {
+ view_set_mode(view, NORMAL);
+ view->cur_index = view_get_legal_normal_pos(view, view->cur_li…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
clear_key_stack();
} else {
/* FIXME: checking equality of the function pointer may be a b…
if (cb == &delete_cb) {
int lines = num > 0 ? num : 1;
- int new_line, new_softline;
+ size_t new_line;
+ int new_softline;
get_new_line_softline(
- buffer, buffer->cur_line, buffer->cur_index,
+ view, view->cur_line, view->cur_index,
lines - 1, &new_line, &new_softline
);
- int start, end;
- ledit_buffer_get_softline_bounds(buffer, new_line, new…
- cb(buffer, new_line, start, KEY_MOTION_LINE);
+ size_t start, end;
+ view_get_softline_bounds(view, new_line, new_softline,…
+ cb(view, new_line, start, KEY_MOTION_LINE);
clear_key_stack();
} else if (cb != NULL) {
- return err_invalid_key(buffer);
+ return err_invalid_key(view);
} else {
struct key_stack_elem *e = push_key_stack();
e->key = KEY_MOTION; /* ? */
t@@ -1110,15 +1117,15 @@ delete(ledit_buffer *buffer, char *text, int len) {
/* FIXME: should this get number of lines to remove or actual end line? */
static void
-delete_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) {
+delete_cb(ledit_view *view, size_t line, size_t char_pos, enum key_type type) {
int line_based = type == KEY_MOTION_LINE ? 1 : 0;
delete_range(
- buffer, line_based, 0,
- buffer->cur_line, buffer->cur_index,
+ view, line_based, 0,
+ view->cur_line, view->cur_index,
line, char_pos, 1
);
paste_buffer_line_based = line_based;
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
finalize_repetition_stack();
}
t@@ -1127,30 +1134,30 @@ delete_cb(ledit_buffer *buffer, int line, int char_pos…
hard lines, which may be unexpected, but the alternatives I could think of …
even weirder */
static struct action
-paste_normal(ledit_buffer *buffer, char *text, int len) {
+paste_normal(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
if (!paste_buffer) {
- ledit_window_show_message(buffer->window, "Nothing to paste", …
+ ledit_window_show_message(view->window, "Nothing to paste", -1…
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
if (paste_buffer_line_based) {
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_lin…
- int brk = 0;
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, view->cur…
+ size_t brk = 0;
if (hard_line_based) {
brk = ll->len;
} else {
- int tmp;
- ledit_buffer_get_pos_softline_bounds(buffer, buffer->c…
+ size_t tmp;
+ view_get_pos_softline_bounds(view, view->cur_line, vie…
}
insert_text(
- buffer, buffer->cur_line, brk,
- "\n", -1, -1, -1, buffer->cur_line, buffer->cur_index, 1
+ view, view->cur_line, brk,
+ "\n", 1, 0, 0, view->cur_line, view->cur_index, 0, 1, 1
);
- int text_len = paste_buffer->len;
- ll = ledit_buffer_get_line(buffer, buffer->cur_line + 1);
+ size_t text_len = paste_buffer->len;
+ ll = ledit_buffer_get_line(view->buffer, view->cur_line + 1);
if (ll->len == 0 && paste_buffer->text[text_len-1] == '\n') {
/* remove trailing newline if it exists and text is al…
text_len--;
t@@ -1158,79 +1165,80 @@ paste_normal(ledit_buffer *buffer, char *text, int len…
} else if (ll->len > 0 && paste_buffer->text[text_len-1] != '\…
/* ensure pasted text is on its own hard line */
insert_text(
- buffer, buffer->cur_line + 1, 0,
- "\n", -1, -1, -1, buffer->cur_line, buffer->cur_in…
+ view, view->cur_line + 1, 0,
+ "\n", 1, 0, 0, view->cur_line, view->cur_index, 0,…
);
}
insert_text(
- buffer, buffer->cur_line + 1, 0,
- paste_buffer->text, text_len, -1, -1, buffer->cur_line + 1…
+ view, view->cur_line + 1, 0,
+ paste_buffer->text, text_len, 0, 0, view->cur_line + 1, 0,…
);
} else {
- int old_line = buffer->cur_line;
- int old_index = buffer->cur_index;
+ size_t old_line = view->cur_line;
+ size_t old_index = view->cur_index;
/* must allow illegal index so text can be pasted at end of li…
- move_cursor_logically(buffer, 1, 1);
+ move_cursor_logically(view, 1, 1);
insert_text(
- buffer, buffer->cur_line, buffer->cur_index,
+ view, view->cur_line, view->cur_index,
paste_buffer->text, paste_buffer->len,
- old_line, old_index, buffer->cur_line, buffer->cur_index, 1
+ old_line, old_index, view->cur_line, view->cur_index, 1, 1…
);
}
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
finalize_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
static struct action
-paste_normal_backwards(ledit_buffer *buffer, char *text, int len) {
+paste_normal_backwards(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
if (!paste_buffer) {
- ledit_window_show_message(buffer->window, "Nothing to paste", …
+ ledit_window_show_message(view->window, "Nothing to paste", -1…
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
if (paste_buffer_line_based) {
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_lin…
- int brk = 0;
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, view->cur…
+ size_t brk = 0;
if (!hard_line_based) {
- int tmp;
- ledit_buffer_get_pos_softline_bounds(buffer, buffer->c…
+ size_t tmp;
+ view_get_pos_softline_bounds(view, view->cur_line, vie…
}
+ /* FIXME: better interface without these weird int args */
insert_text(
- buffer, buffer->cur_line, brk,
- "\n", -1, -1, -1, buffer->cur_line, buffer->cur_index, 1
+ view, view->cur_line, brk,
+ "\n", 1, 0, 0, view->cur_line, view->cur_index, 0, 1, 1
);
- int text_len = paste_buffer->len;
- ll = ledit_buffer_get_line(buffer, buffer->cur_line);
+ size_t text_len = paste_buffer->len;
+ ll = ledit_buffer_get_line(view->buffer, view->cur_line);
if (paste_buffer->text[text_len-1] == '\n') {
/* remove trailing newline if it exists */
text_len--;
paste_buffer->text[text_len] = '\0';
}
- int new_line = buffer->cur_line;
+ size_t new_line = view->cur_line;
if (ll->len > 0) {
/* ensure pasted text is on its own hard line */
insert_text(
- buffer, buffer->cur_line, ll->len,
- "\n", -1, -1, -1, buffer->cur_line, buffer->cur_in…
+ view, view->cur_line, ll->len,
+ "\n", 1, 0, 0, view->cur_line, view->cur_index, 0,…
);
- new_line = buffer->cur_line + 1;
+ new_line = view->cur_line + 1;
}
insert_text(
- buffer, new_line, 0,
- paste_buffer->text, text_len, -1, -1, new_line, 0, 0
+ view, new_line, 0,
+ paste_buffer->text, text_len, 0, 0, new_line, 0, 0, 1, 0
);
} else {
insert_text(
- buffer, buffer->cur_line, buffer->cur_index,
+ view, view->cur_line, view->cur_index,
paste_buffer->text, paste_buffer->len,
- -1, -1, buffer->cur_line, buffer->cur_index, 1
+ 0, 0, view->cur_line, view->cur_index, 0, 1, 1
);
}
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
finalize_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
t@@ -1243,14 +1251,22 @@ push_num(int num) {
e->key = KEY_NUMBER;
e->followup = KEY_NUMBER|KEY_NUMBERALLOWED;
}
- /* FIXME: error (overflow) checking */
+ /* FIXME: error messages */
+ if (INT_MAX / 10 < e->count) {
+ clear_key_stack();
+ return;
+ }
e->count *= 10;
+ if (INT_MAX - num < e->count) {
+ clear_key_stack();
+ return;
+ }
e->count += num;
}
static struct action
-push_0(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+push_0(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
push_num(0);
t@@ -1258,8 +1274,8 @@ push_0(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-push_1(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+push_1(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
push_num(1);
t@@ -1267,8 +1283,8 @@ push_1(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-push_2(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+push_2(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
push_num(2);
t@@ -1276,8 +1292,8 @@ push_2(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-push_3(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+push_3(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
push_num(3);
t@@ -1285,8 +1301,8 @@ push_3(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-push_4(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+push_4(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
push_num(4);
t@@ -1294,8 +1310,8 @@ push_4(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-push_5(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+push_5(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
push_num(5);
t@@ -1303,8 +1319,8 @@ push_5(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-push_6(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+push_6(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
push_num(6);
t@@ -1312,8 +1328,8 @@ push_6(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-push_7(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+push_7(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
push_num(7);
t@@ -1321,8 +1337,8 @@ push_7(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-push_8(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+push_8(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
push_num(8);
t@@ -1330,8 +1346,8 @@ push_8(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-push_9(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+push_9(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
push_num(9);
t@@ -1339,130 +1355,129 @@ push_9(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-backspace(ledit_buffer *buffer, char *text, int len) {
+backspace(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
/* FIXME: don't copy to paste buffer on del_sel here; delete entire gr…
- if (delete_selection(buffer)) {
+ if (delete_selection(view)) {
/* NOP */
- } else if (buffer->cur_index == 0) {
- if (buffer->cur_line != 0) {
- ledit_line *l1 = ledit_buffer_get_line(buffer, buffer-…
- delete_range(buffer, 0, 0, buffer->cur_line - 1, l1->l…
+ } else if (view->cur_index == 0) {
+ if (view->cur_line != 0) {
+ ledit_line *l1 = ledit_buffer_get_line(view->buffer, v…
+ delete_range(view, 0, 0, view->cur_line - 1, l1->len, …
}
} else {
- ledit_line *l = ledit_buffer_get_line(buffer, buffer->cur_line…
- int i = ledit_line_prev_utf8(l, buffer->cur_index);
- delete_range(buffer, 0, 0, buffer->cur_line, buffer->cur_index…
+ ledit_line *l = ledit_buffer_get_line(view->buffer, view->cur_…
+ int i = ledit_line_prev_utf8(l, view->cur_index);
+ delete_range(view, 0, 0, view->cur_line, view->cur_index, view…
}
- /* FIXME: This was probably a mistake earlier, right?
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
return (struct action){ACTION_NONE, NULL};
}
static struct action
-delete_key(ledit_buffer *buffer, char *text, int len) {
+delete_key(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- ledit_line *cur_line = ledit_buffer_get_line(buffer, buffer->cur_line);
- if (delete_selection(buffer)) {
+ ledit_line *cur_line = ledit_buffer_get_line(view->buffer, view->cur_l…
+ if (delete_selection(view)) {
/* NOP */
- } else if (buffer->cur_index == cur_line->len) {
- if (buffer->cur_line != buffer->lines_num - 1) {
- delete_range(buffer, 0, 0, buffer->cur_line, cur_line-…
+ } else if (view->cur_index == cur_line->len) {
+ if (view->cur_line != view->lines_num - 1) {
+ delete_range(view, 0, 0, view->cur_line, cur_line->len…
}
} else {
- int i = ledit_line_next_utf8(cur_line, buffer->cur_index);
- delete_range(buffer, 0, 0, buffer->cur_line, buffer->cur_index…
+ int i = ledit_line_next_utf8(cur_line, view->cur_index);
+ delete_range(view, 0, 0, view->cur_line, view->cur_index, view…
}
/* FIXME: This was probably a mistake earlier, right?
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);*/
return (struct action){ACTION_NONE, NULL};
}
static struct action
-move_to_eol(ledit_buffer *buffer, char *text, int len) {
+move_to_eol(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
motion_callback cb;
int num = get_key_repeat_and_motion_cb(&cb);
if (num == -1)
- return err_invalid_key(buffer);
+ return err_invalid_key(view);
if (num == 0)
num = 1;
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- int new_line, new_softline;
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ size_t new_line;
+ int new_softline;
get_new_line_softline(
- buffer, buffer->cur_line, buffer->cur_index, num - 1,
+ view, view->cur_line, view->cur_index, num - 1,
&new_line, &new_softline
);
- ledit_line *ll = ledit_buffer_get_line(buffer, new_line);
- int end_index = ll->len;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, new_line);
+ size_t end_index = ll->len;
if (!hard_line_based) {
- int tmp;
- ledit_buffer_get_softline_bounds(buffer, new_line, new_softlin…
+ size_t tmp;
+ view_get_softline_bounds(view, new_line, new_softline, &tmp, &…
}
if (cb != NULL) {
- cb(buffer, new_line, end_index, KEY_MOTION_CHAR);
+ cb(view, new_line, end_index, KEY_MOTION_CHAR);
} else {
- buffer->cur_line = new_line;
- buffer->cur_index = end_index;
- if (buffer->common->mode == VISUAL) {
- ledit_buffer_set_selection(
- buffer,
- buffer->sel.line1, buffer->sel.byte1,
+ view->cur_line = new_line;
+ view->cur_index = end_index;
+ if (view->mode == VISUAL) {
+ view_set_selection(
+ view,
+ view->sel.line1, view->sel.byte1,
new_line, end_index
);
} else {
/* FIXME: this is weird because the cursor is actually…
next soft line, but the alternative has too many we…
with bidi text */
- buffer->cur_index = ledit_buffer_get_legal_normal_pos(
- buffer, buffer->cur_line, buffer->cur_index
+ view->cur_index = view_get_legal_normal_pos(
+ view, view->cur_line, view->cur_index
);
}
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, b…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
}
return (struct action){ACTION_NONE, NULL};
}
#define GEN_WORD_MOVEMENT(name, func) …
static struct action …
-name(ledit_buffer *buffer, char *text, int len) { …
+name(ledit_view *view, char *text, size_t len) { …
(void)text; …
(void)len; …
motion_callback cb; …
int num = get_key_repeat_and_motion_cb(&cb); …
if (num == -1) …
- return err_invalid_key(buffer); …
+ return err_invalid_key(view); …
if (num == 0) …
num = 1; …
- int new_line, new_index, new_real_index; …
+ size_t new_line, new_index, new_real_index; …
func( …
- buffer, …
- buffer->cur_line, buffer->cur_index, num, …
+ view, …
+ view->cur_line, view->cur_index, num, …
&new_line, &new_index, &new_real_index …
); …
if (cb != NULL) { …
- cb(buffer, new_line, new_real_index, KEY_MOTION_CHAR); …
+ cb(view, new_line, new_real_index, KEY_MOTION_CHAR); …
} else { …
- if (buffer->common->mode == VISUAL) { …
- ledit_buffer_set_selection( …
- buffer, …
- buffer->sel.line1, buffer->sel.byte1, …
+ if (view->mode == VISUAL) { \
+ view_set_selection( …
+ view, …
+ view->sel.line1, view->sel.byte1, …
new_line, new_real_index …
); …
- buffer->cur_line = new_line; …
- buffer->cur_index = new_real_index; …
+ view->cur_line = new_line; …
+ view->cur_index = new_real_index; …
} else { …
- if (new_line != buffer->cur_line) …
- ledit_buffer_wipe_line_cursor_attrs( …
- buffer, buffer->cur_line …
+ if (new_line != view->cur_line) …
+ view_wipe_line_cursor_attrs( …
+ view, view->cur_line …
); …
- buffer->cur_line = new_line; …
- buffer->cur_index = new_index; …
- ledit_buffer_set_line_cursor_attrs( …
- buffer, buffer->cur_line, buffer->cur_index …
+ view->cur_line = new_line; …
+ view->cur_index = new_index; …
+ view_set_line_cursor_attrs( …
+ view, view->cur_line, view->cur_index …
); …
} …
discard_repetition_stack(); …
t@@ -1471,33 +1486,33 @@ name(ledit_buffer *buffer, char *text, int len) { …
return (struct action){ACTION_NONE, NULL}; …
}
-GEN_WORD_MOVEMENT(next_word, ledit_buffer_next_word)
-GEN_WORD_MOVEMENT(next_word_end, ledit_buffer_next_word_end)
-GEN_WORD_MOVEMENT(next_bigword, ledit_buffer_next_bigword)
-GEN_WORD_MOVEMENT(next_bigword_end, ledit_buffer_next_bigword_end)
-GEN_WORD_MOVEMENT(prev_word, ledit_buffer_prev_word)
-GEN_WORD_MOVEMENT(prev_bigword, ledit_buffer_prev_bigword)
+GEN_WORD_MOVEMENT(next_word, view_next_word)
+GEN_WORD_MOVEMENT(next_word_end, view_next_word_end)
+GEN_WORD_MOVEMENT(next_bigword, view_next_bigword)
+GEN_WORD_MOVEMENT(next_bigword_end, view_next_bigword_end)
+GEN_WORD_MOVEMENT(prev_word, view_prev_word)
+GEN_WORD_MOVEMENT(prev_bigword, view_prev_bigword)
static void
-move_cursor_left_right(ledit_buffer *buffer, int dir, int allow_illegal_index)…
+move_cursor_left_right(ledit_view *view, int dir, int allow_illegal_index) {
motion_callback cb;
int num = get_key_repeat_and_motion_cb(&cb);
if (num == -1)
- (void)err_invalid_key(buffer);
+ (void)err_invalid_key(view);
if (num == 0)
num = 1;
- ledit_line *cur_line = ledit_buffer_get_line(buffer, buffer->cur_line);
+ ledit_line *cur_line = ledit_buffer_get_line(view->buffer, view->cur_l…
/* FIXME: standardize interface - num * dir or separately? */
- int last_index;
- int new_index = ledit_buffer_move_cursor_visually(
- buffer, buffer->cur_line, buffer->cur_index, num * dir, &last_index
+ size_t last_index;
+ size_t new_index = view_move_cursor_visually(
+ view, view->cur_line, view->cur_index, num * dir, &last_index
);
/* when in normal mode, the cursor cannot be at the very end
of the line because it's always covering a character */
if (new_index >= cur_line->len) {
if (!allow_illegal_index &&
- buffer->common->mode == NORMAL && cb == NULL) {
+ view->mode == NORMAL && cb == NULL) {
new_index = last_index;
} else {
/* FIXME: I guess this is unnecessary */
t@@ -1505,17 +1520,15 @@ move_cursor_left_right(ledit_buffer *buffer, int dir, …
}
}
if (cb != NULL) {
- cb(buffer, buffer->cur_line, new_index, KEY_MOTION_CHAR);
+ cb(view, view->cur_line, new_index, KEY_MOTION_CHAR);
} else {
- buffer->cur_index = new_index;
- if (buffer->common->mode == VISUAL) {
- ledit_buffer_set_selection(buffer, buffer->sel.line1, …
- } else if (buffer->common->mode == INSERT &&
- (buffer->sel.line1 != buffer->sel.line2 ||
- buffer->sel.byte1 != buffer->sel.byte2)) {
- ledit_buffer_set_selection(buffer, buffer->cur_line, n…
- } else if (buffer->common->mode == NORMAL) {
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur…
+ view->cur_index = new_index;
+ if (view->mode == VISUAL) {
+ view_set_selection(view, view->sel.line1, view->sel.by…
+ } else if (view->mode == INSERT && view->sel_valid) {
+ view_wipe_selection(view);
+ } else if (view->mode == NORMAL) {
+ view_set_line_cursor_attrs(view, view->cur_line, view-…
}
discard_repetition_stack();
}
t@@ -1523,133 +1536,118 @@ move_cursor_left_right(ledit_buffer *buffer, int dir…
}
static struct action
-cursor_left(ledit_buffer *buffer, char *text, int len) {
+cursor_left(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- move_cursor_left_right(buffer, -1, 0);
+ move_cursor_left_right(view, -1, 0);
return (struct action){ACTION_NONE, NULL};
}
static struct action
-cursor_right(ledit_buffer *buffer, char *text, int len) {
+cursor_right(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- move_cursor_left_right(buffer, 1, 0);
+ move_cursor_left_right(view, 1, 0);
return (struct action){ACTION_NONE, NULL};
}
static struct action
-return_key(ledit_buffer *buffer, char *text, int len) {
+return_key(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
int start_group = 1;
- if (delete_selection(buffer))
+ if (delete_selection(view))
start_group = 0;
- insert_text(buffer, buffer->cur_line, buffer->cur_index, "\n", -1, -1,…
- /* FIXME: these aren't needed, right? This only works in insert mode
- * anyways, so there's nothing to wipe */
- /* ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- buffer->cur_line++;
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
- buffer->cur_index = 0; */
+ insert_text(view, view->cur_line, view->cur_index, "\n", 1, 0, 0, 0, 0…
return (struct action){ACTION_NONE, NULL};
}
static void
-move_cursor_logically(ledit_buffer *buffer, int movement_dir, int allow_illega…
+move_cursor_logically(ledit_view *view, int movement_dir, int allow_illegal_in…
if (movement_dir < 0) {
- buffer->cur_index = ledit_buffer_prev_cursor_pos(
- buffer, buffer->cur_line, buffer->cur_index, 1
+ view->cur_index = view_prev_cursor_pos(
+ view, view->cur_line, view->cur_index, 1
);
} else {
- buffer->cur_index = ledit_buffer_next_cursor_pos(
- buffer, buffer->cur_line, buffer->cur_index, 1
+ view->cur_index = view_next_cursor_pos(
+ view, view->cur_line, view->cur_index, 1
);
}
if (!allow_illegal_index) {
- buffer->cur_index = ledit_buffer_get_legal_normal_pos(
- buffer, buffer->cur_line, buffer->cur_index
+ view->cur_index = view_get_legal_normal_pos(
+ view, view->cur_line, view->cur_index
);
}
}
static struct action
-escape_key(ledit_buffer *buffer, char *text, int len) {
+escape_key(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
clear_key_stack();
- if (buffer->common->mode == INSERT)
+ if (view->mode == INSERT)
finalize_repetition_stack();
- if (buffer->common->mode == INSERT &&
- (buffer->sel.line1 != buffer->sel.line2 ||
- buffer->sel.byte1 != buffer->sel.byte2)) {
- ledit_buffer_set_mode(buffer, VISUAL);
- } else if (buffer->common->mode != NORMAL) {
- ledit_buffer_set_mode(buffer, NORMAL);
- move_cursor_logically(buffer, -1, 0);
- if (buffer->sel.line1 != buffer->sel.line2) {
- int min = buffer->sel.line1 < buffer->sel.line2 ? buff…
- int max = buffer->sel.line1 > buffer->sel.line2 ? buff…
- for (int i = min; i <= max; i++) {
- ledit_buffer_wipe_line_cursor_attrs(buffer, i);
- }
- }
- buffer->sel.line1 = buffer->sel.line2 = -1;
- buffer->sel.byte1 = buffer->sel.byte2 = -1;
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, b…
+ if (view->mode == INSERT && view->sel_valid) {
+ view_set_mode(view, VISUAL);
+ } else if (view->mode != NORMAL) {
+ view_set_mode(view, NORMAL);
+ move_cursor_logically(view, -1, 0);
+ view_wipe_selection(view);
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
}
return (struct action){ACTION_NONE, NULL};
}
static struct action
-enter_insert(ledit_buffer *buffer, char *text, int len) {
+enter_insert(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- if (buffer->common->mode == NORMAL)
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- ledit_buffer_set_mode(buffer, INSERT);
+ if (view->mode == NORMAL)
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ view_set_mode(view, INSERT);
clear_key_stack();
return (struct action){ACTION_NONE, NULL};
}
/* FIXME: Check if previous key allows motion command - or should this be chec…
static void
-move_cursor_up_down(ledit_buffer *buffer, int dir) {
- int new_line, new_softline;
+move_cursor_up_down(ledit_view *view, int dir) {
+ size_t new_line;
+ int new_softline;
motion_callback cb;
int num = get_key_repeat_and_motion_cb(&cb);
if (num == -1)
- (void)err_invalid_key(buffer);
+ (void)err_invalid_key(view);
if (num == 0)
num = 1;
num *= dir;
get_new_line_softline(
- buffer, buffer->cur_line, buffer->cur_index,
+ view, view->cur_line, view->cur_index,
num, &new_line, &new_softline
);
if (cb != NULL) {
- int start, end;
- ledit_buffer_get_softline_bounds(buffer, new_line, new_softlin…
- cb(buffer, new_line, start, KEY_MOTION_LINE);
+ size_t start, end;
+ view_get_softline_bounds(view, new_line, new_softline, &start,…
+ cb(view, new_line, start, KEY_MOTION_LINE);
} else {
+ /* FIXME: when selecting on last line, moving down moves the c…
+ one (when it stays on the same line because it's the last o…
int lineno, x;
- ledit_pos_to_x_softline(buffer, buffer->cur_line, buffer->cur_…
- ledit_x_softline_to_pos(buffer, new_line, x, new_softline, &bu…
- if (buffer->cur_line != new_line)
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cu…
- buffer->cur_line = new_line;
-
- if (buffer->common->mode == VISUAL) {
- ledit_buffer_set_selection(buffer, buffer->sel.line1, …
- } else if (buffer->common->mode == INSERT &&
- (buffer->sel.line1 != buffer->sel.line2 ||
- buffer->sel.byte1 != buffer->sel.byte2)) {
- ledit_buffer_set_selection(buffer, buffer->cur_line, b…
- } else if (buffer->common->mode == NORMAL) {
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur…
+ ledit_pos_to_x_softline(view, view->cur_line, view->cur_index,…
+ ledit_x_softline_to_pos(view, new_line, x, new_softline, &view…
+ if (view->cur_line != new_line)
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ view->cur_line = new_line;
+
+ if (view->mode == VISUAL) {
+ view_set_selection(view, view->sel.line1, view->sel.by…
+ } else if (view->mode == INSERT && view->sel_valid) {
+ view_wipe_selection(view);
+ } else if (view->mode == NORMAL) {
+ view_set_line_cursor_attrs(view, view->cur_line, view-…
}
discard_repetition_stack();
}
t@@ -1657,63 +1655,63 @@ move_cursor_up_down(ledit_buffer *buffer, int dir) {
}
static struct action
-cursor_down(ledit_buffer *buffer, char *text, int len) {
+cursor_down(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- move_cursor_up_down(buffer, 1);
+ move_cursor_up_down(view, 1);
return (struct action){ACTION_NONE, NULL};
}
static struct action
-cursor_up(ledit_buffer *buffer, char *text, int len) {
+cursor_up(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- move_cursor_up_down(buffer, -1);
+ move_cursor_up_down(view, -1);
return (struct action){ACTION_NONE, NULL};
}
static struct action
-join_lines(ledit_buffer *buffer, char *text, int len) {
+join_lines(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
int num = get_key_repeat();
if (num == -1)
- return err_invalid_key(buffer);
+ return err_invalid_key(view);
if (num == 0)
num = 1;
int start_group = 1;
ledit_line *ll1;
- int cur_line = buffer->cur_line;
+ size_t cur_line = view->cur_line;
/* FIXME: have a general tmp buf for everyone to use */
txtbuf *buf = txtbuf_new();
- int oldlen;
+ size_t oldlen;
ledit_range cur_range, del_range;
cur_range.line1 = cur_range.line2 = cur_line;
for (int i = 0; i < num; i++) {
- if (cur_line == buffer->lines_num - 1)
+ if (cur_line == view->lines_num - 1)
break;
/* getting cur line again should be unnecessary, but
I'll just leave it in case I change the way lines
are stored later */
- ll1 = ledit_buffer_get_line(buffer, cur_line);
+ ll1 = ledit_buffer_get_line(view->buffer, cur_line);
oldlen = ll1->len;
/* FIXME: truncate whitespace to one space */
- ledit_buffer_delete_range(
- buffer, DELETE_CHAR,
+ view_delete_range(
+ view, DELETE_CHAR,
cur_line, ll1->len, cur_line + 1, 0,
NULL, NULL, &del_range, buf
);
- cur_range.byte1 = buffer->cur_index;
- cur_range.byte2 = buffer->cur_index =
- ledit_buffer_get_legal_normal_pos(buffer, buffer->cur_line…
+ cur_range.byte1 = view->cur_index;
+ cur_range.byte2 = view->cur_index =
+ view_get_legal_normal_pos(view, view->cur_line, oldlen);
ledit_push_undo_delete(
- buffer->undo, buf, del_range, cur_range,
- start_group, buffer->common->mode
+ view->buffer->undo, buf, del_range, cur_range,
+ start_group, view->mode
);
start_group = 0;
}
- ledit_buffer_set_line_cursor_attrs(
- buffer, buffer->cur_line, buffer->cur_index
+ view_set_line_cursor_attrs(
+ view, view->cur_line, view->cur_index
);
txtbuf_destroy(buf);
finalize_repetition_stack();
t@@ -1721,49 +1719,49 @@ join_lines(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-insert_at_beginning(ledit_buffer *buffer, char *text, int len) {
+insert_at_beginning(ledit_view *view, char *text, size_t len) {
if (!key_stack_empty())
- return err_invalid_key(buffer);
- enter_insert(buffer, text, len);
- int new_index = 0;
+ return err_invalid_key(view);
+ enter_insert(view, text, len);
+ size_t new_index = 0;
if (!hard_line_based) {
- int tmp;
- ledit_buffer_get_pos_softline_bounds(buffer, buffer->cur_line,…
+ size_t tmp;
+ view_get_pos_softline_bounds(view, view->cur_line, view->cur_i…
}
- push_undo_empty_insert(buffer, buffer->cur_line, buffer->cur_index, 1);
- buffer->cur_index = new_index;
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ push_undo_empty_insert(view, view->cur_line, view->cur_index, 1);
+ view->cur_index = new_index;
+ view_wipe_line_cursor_attrs(view, view->cur_line);
return (struct action){ACTION_NONE, NULL};
}
static struct action
-cursor_to_first_non_ws(ledit_buffer *buffer, char *text, int len) {
+cursor_to_first_non_ws(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
motion_callback cb;
int num = get_key_repeat_and_motion_cb(&cb);
if (num != 0)
- return err_invalid_key(buffer);
- int new_index = 0;
+ return err_invalid_key(view);
+ size_t new_index = 0;
if (hard_line_based) {
- new_index = ledit_line_next_non_whitespace(buffer, buffer->cur…
+ new_index = view_line_next_non_whitespace(view, view->cur_line…
} else {
- int start, end;
- ledit_buffer_get_pos_softline_bounds(buffer, buffer->cur_line,…
- new_index = ledit_line_next_non_whitespace(buffer, buffer->cur…
+ size_t start, end;
+ view_get_pos_softline_bounds(view, view->cur_line, view->cur_i…
+ new_index = view_line_next_non_whitespace(view, view->cur_line…
/* next non-whitespace might be on next softline */
if (new_index >= end) {
- new_index = ledit_buffer_prev_cursor_pos(
- buffer, buffer->cur_line, end, 1
+ new_index = view_prev_cursor_pos(
+ view, view->cur_line, end, 1
);
}
}
if (cb != NULL) {
- cb(buffer, buffer->cur_line, new_index, KEY_MOTION_CHAR);
+ cb(view, view->cur_line, new_index, KEY_MOTION_CHAR);
} else {
- buffer->cur_index = new_index;
- ledit_buffer_set_line_cursor_attrs(
- buffer, buffer->cur_line, buffer->cur_index
+ view->cur_index = new_index;
+ view_set_line_cursor_attrs(
+ view, view->cur_line, view->cur_index
);
discard_repetition_stack();
}
t@@ -1771,32 +1769,32 @@ cursor_to_first_non_ws(ledit_buffer *buffer, char *tex…
}
static struct action
-cursor_to_beginning(ledit_buffer *buffer, char *text, int len) {
+cursor_to_beginning(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
motion_callback cb;
int num = get_key_repeat_and_motion_cb(&cb);
if (num != 0)
- return err_invalid_key(buffer);
+ return err_invalid_key(view);
/* FIXME: should anything be done with num? */
- int start_index = 0;
+ size_t start_index = 0;
if (!hard_line_based) {
- int tmp;
- ledit_buffer_get_pos_softline_bounds(buffer, buffer->cur_line,…
+ size_t tmp;
+ view_get_pos_softline_bounds(view, view->cur_line, view->cur_i…
}
if (cb != NULL) {
- cb(buffer, buffer->cur_line, start_index, KEY_MOTION_CHAR);
+ cb(view, view->cur_line, start_index, KEY_MOTION_CHAR);
} else {
- buffer->cur_index = start_index;
- if (buffer->common->mode == VISUAL) {
- ledit_buffer_set_selection(
- buffer,
- buffer->sel.line1, buffer->sel.byte1,
- buffer->cur_line, buffer->cur_index
+ view->cur_index = start_index;
+ if (view->mode == VISUAL) {
+ view_set_selection(
+ view,
+ view->sel.line1, view->sel.byte1,
+ view->cur_line, view->cur_index
);
} else {
- ledit_buffer_set_line_cursor_attrs(
- buffer, buffer->cur_line, buffer->cur_index
+ view_set_line_cursor_attrs(
+ view, view->cur_line, view->cur_index
);
}
discard_repetition_stack();
t@@ -1806,25 +1804,25 @@ cursor_to_beginning(ledit_buffer *buffer, char *text, …
}
static struct action
-enter_visual(ledit_buffer *buffer, char *text, int len) {
+enter_visual(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- ledit_buffer_set_mode(buffer, VISUAL);
- buffer->sel.line1 = buffer->sel.line2 = buffer->cur_line;
- buffer->sel.byte1 = buffer->sel.byte2 = buffer->cur_index;
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ view_set_mode(view, VISUAL);
+ view->sel.line1 = view->sel.line2 = view->cur_line;
+ view->sel.byte1 = view->sel.byte2 = view->cur_index;
+ view_wipe_line_cursor_attrs(view, view->cur_line);
clear_key_stack(); /* FIXME: error if not empty? */
return (struct action){ACTION_NONE, NULL};
}
static struct action
-switch_selection_end(ledit_buffer *buffer, char *text, int len) {
+switch_selection_end(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- 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;
+ swap_sz(&view->sel.line1, &view->sel.line2);
+ swap_sz(&view->sel.byte1, &view->sel.byte2);
+ view->cur_line = view->sel.line2;
+ view->cur_index = view->sel.byte2;
return (struct action){ACTION_NONE, NULL};
}
t@@ -1832,103 +1830,106 @@ switch_selection_end(ledit_buffer *buffer, char *tex…
#define XK_NO_MOD 0
static struct action
-enter_commandedit(ledit_buffer *buffer, char *text, int len) {
+enter_commandedit(ledit_view *view, char *text, size_t len) {
(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);
+ ledit_window_set_bottom_bar_text(view->window, ":", -1);
+ ledit_window_set_bottom_bar_min_pos(view->window, 1);
+ ledit_window_set_bottom_bar_cursor(view->window, 1);
+ view->cur_command_type = CMD_EDIT;
+ ledit_window_set_bottom_bar_text_shown(view->window, 1);
discard_repetition_stack();
return (struct action){ACTION_GRABKEY, &ledit_command_key_handler};
}
static struct action
-enter_searchedit_forward(ledit_buffer *buffer, char *text, int len) {
+enter_searchedit_forward(ledit_view *view, char *text, size_t len) {
(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);
+ ledit_window_set_bottom_bar_text(view->window, "/", -1);
+ ledit_window_set_bottom_bar_min_pos(view->window, 1);
+ ledit_window_set_bottom_bar_cursor(view->window, 1);
+ view->cur_command_type = CMD_EDITSEARCH;
+ ledit_window_set_bottom_bar_text_shown(view->window, 1);
discard_repetition_stack();
return (struct action){ACTION_GRABKEY, &ledit_command_key_handler};
}
static struct action
-enter_searchedit_backward(ledit_buffer *buffer, char *text, int len) {
+enter_searchedit_backward(ledit_view *view, char *text, size_t len) {
(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);
+ ledit_window_set_bottom_bar_text(view->window, "?", -1);
+ ledit_window_set_bottom_bar_min_pos(view->window, 1);
+ ledit_window_set_bottom_bar_cursor(view->window, 1);
+ view->cur_command_type = CMD_EDITSEARCHB;
+ ledit_window_set_bottom_bar_text_shown(view->window, 1);
discard_repetition_stack();
return (struct action){ACTION_GRABKEY, &ledit_command_key_handler};
}
/* FIXME: differentiate between jumping to line and index like nvi */
static struct action
-mark_line_cb(ledit_buffer *buffer, char *text, int len) {
+mark_line_cb(ledit_view *view, char *text, size_t len) {
grab_char_cb = NULL;
ledit_buffer_insert_mark(
- buffer, text, len, buffer->cur_line, buffer->cur_index
+ view->buffer, text, len, view->cur_line, view->cur_index
);
return (struct action){ACTION_NONE, NULL};
}
-/* FIXME: check that byte is actually in at grapheme boundary */
+/* FIXME: move part of this to buffer.c */
+/* FIXME: check that byte is actually at grapheme boundary */
static struct action
-jump_to_mark_cb(ledit_buffer *buffer, char *text, int len) {
+jump_to_mark_cb(ledit_view *view, char *text, size_t len) {
grab_char_cb = NULL;
- ledit_buffer_marklist *marklist = buffer->marklist;
+ ledit_buffer_marklist *marklist = view->buffer->marklist;
motion_callback cb;
int num = get_key_repeat_and_motion_cb(&cb);
if (num > 0)
- return err_invalid_key(buffer);
- int line = -1, index = -1;
+ return err_invalid_key(view);
+ size_t line = 0, index = 0;
+ int mark_found = 0;
for (size_t i = 0; i < marklist->len; i++) {
if (!strncmp(text, marklist->marks[i].text, len)) {
ledit_line *ll;
ledit_buffer_mark *m = &marklist->marks[i];
- if (m->line >= buffer->lines_num) {
- line = buffer->lines_num - 1;
- ll = ledit_buffer_get_line(buffer, line);
+ if (m->line >= view->lines_num) {
+ line = view->lines_num - 1;
+ ll = ledit_buffer_get_line(view->buffer, line);
index = ll->len;
} else {
line = m->line;
- ll = ledit_buffer_get_line(buffer, m->line);
+ ll = ledit_buffer_get_line(view->buffer, m->li…
if (m->byte >= ll->len)
index = ll->len;
else
index = m->byte;
}
+ mark_found = 1;
break;
}
}
- if (line == -1)
- return err_invalid_key(buffer);
- if (buffer->common->mode == VISUAL) {
- ledit_buffer_set_selection(
- buffer, buffer->sel.line1, buffer->sel.byte1, line, index
+ if (!mark_found)
+ return err_invalid_key(view);
+ if (view->mode == VISUAL) {
+ view_set_selection(
+ view, view->sel.line1, view->sel.byte1, line, index
);
- buffer->cur_line = line;
- buffer->cur_index = index;
+ view->cur_line = line;
+ view->cur_index = index;
} else {
if (cb) {
- cb(buffer, line, index, KEY_MOTION_LINE);
+ cb(view, line, index, KEY_MOTION_LINE);
} else {
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cu…
- buffer->cur_line = line;
- buffer->cur_index = index;
- buffer->cur_index = ledit_buffer_get_legal_normal_pos(
- buffer, buffer->cur_line, buffer->cur_index
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ view->cur_line = line;
+ view->cur_index = index;
+ view->cur_index = view_get_legal_normal_pos(
+ view, view->cur_line, view->cur_index
);
- ledit_buffer_set_line_cursor_attrs(
- buffer, buffer->cur_line, buffer->cur_index
+ view_set_line_cursor_attrs(
+ view, view->cur_line, view->cur_index
);
discard_repetition_stack();
}
t@@ -1937,8 +1938,8 @@ jump_to_mark_cb(ledit_buffer *buffer, char *text, int le…
}
static struct action
-mark_line(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+mark_line(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
grab_char_cb = &mark_line_cb;
t@@ -1947,8 +1948,8 @@ mark_line(ledit_buffer *buffer, char *text, int len) {
}
static struct action
-jump_to_mark(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+jump_to_mark(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
grab_char_cb = &jump_to_mark_cb;
t@@ -1958,125 +1959,129 @@ jump_to_mark(ledit_buffer *buffer, char *text, int l…
/* FIXME: support visual mode, i.e. change selection to new place? */
static struct action
-key_search_next(ledit_buffer *buffer, char *text, int len) {
+key_search_next(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- search_next(buffer);
+ search_next(view);
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
static struct action
-key_search_prev(ledit_buffer *buffer, char *text, int len) {
+key_search_prev(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- search_prev(buffer);
+ search_prev(view);
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
static struct action
-show_line(ledit_buffer *buffer, char *text, int len) {
+show_line(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- int textlen = snprintf(NULL, 0, "Line %d of %d", buffer->cur_line + 1,…
+ int textlen = snprintf(NULL, 0, "Line %zu of %zu", view->cur_line + 1,…
char *str = ledit_malloc(textlen + 1);
- snprintf(str, textlen + 1, "Line %d of %d", buffer->cur_line + 1, buff…
- ledit_window_show_message(buffer->window, str, textlen);
+ snprintf(str, textlen + 1, "Line %zu of %zu", view->cur_line + 1, view…
+ ledit_window_show_message(view->window, str, textlen);
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
/* FIXME: return status! */
static struct action
-undo(ledit_buffer *buffer, char *text, int len) {
+undo(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- ledit_buffer_set_selection(buffer, 0, 0, 0, 0);
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- ledit_buffer_undo(buffer);
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+ view_wipe_selection(view);
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ view_undo(view);
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
finalize_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
static struct action
-redo(ledit_buffer *buffer, char *text, int len) {
+redo(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- ledit_buffer_set_selection(buffer, 0, 0, 0, 0);
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- ledit_buffer_redo(buffer);
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+ view_wipe_selection(view);
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ view_redo(view);
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
finalize_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
static struct action
-insert_mode_insert_text(ledit_buffer *buffer, char *text, int len) {
- delete_selection(buffer);
- insert_text(buffer, buffer->cur_line, buffer->cur_index, text, len, -1…
+insert_mode_insert_text(ledit_view *view, char *text, size_t len) {
+ /* FIXME: set cur_index when deleting selection */
+ delete_selection(view);
+ insert_text(view, view->cur_line, view->cur_index, text, len, 0, 0, 0,…
return (struct action){ACTION_NONE, NULL};
}
static struct action
-clipcopy(ledit_buffer *buffer, char *text, int len) {
+clipcopy(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- /* FIXME: abstract this through buffer */
- clipboard_primary_to_clipboard(buffer->window);
+ /* FIXME: abstract this through view */
+ clipboard_primary_to_clipboard(view->window);
discard_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
static struct action
-clippaste(ledit_buffer *buffer, char *text, int len) {
+clippaste(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
- ledit_buffer_paste_clipboard(buffer);
+ view_paste_clipboard(view);
finalize_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
/* FIXME: make sure the found position is valid cursor position? */
static int
-search_str_backwards(char *haystack, int hlen, char *needle, int nlen, int sta…
- if (start_index < 0 || start_index > hlen)
+search_str_backwards(char *haystack, size_t hlen, char *needle, size_t nlen, s…
+ if (start_index > hlen)
return -1;
- int new_index = start_index;
- for (new_index--; new_index >= 0; new_index--) {
- if (!strncmp(haystack + new_index, needle, nlen))
- return new_index;
+ size_t new_index = start_index;
+ for (; new_index > 0; new_index--) {
+ if (!strncmp(haystack + new_index - 1, needle, nlen)) {
+ *ret = new_index;
+ return 0;
+ }
}
return -1;
}
static int
-search_str_forwards(char *haystack, int hlen, char *needle, int nlen, int star…
- if (start_index < 0 || start_index >= hlen)
+search_str_forwards(char *haystack, size_t hlen, char *needle, size_t nlen, si…
+ if (start_index >= hlen)
return -1;
/* duplicate so it is nul-terminated */
char *search_str = ledit_strndup(needle, nlen);
char *res = strstr(haystack + start_index + 1, search_str);
free(search_str);
/* FIXME: is this legal? */
- if (res)
- return (int)(res - haystack);
- else
+ if (res) {
+ *ret = (size_t)(res - haystack);
+ return 0;
+ } else {
return -1;
+ }
}
/* just to make the macro below works for all cases */
/* FIXME: is there a more elegant way to do this? */
-static int
-dummy_cursor_helper(ledit_buffer *buffer, int line, int index, int num) {
- (void)buffer;
+static size_t
+dummy_cursor_helper(ledit_view *view, size_t line, size_t index, int num) {
+ (void)view;
(void)line;
(void)num;
return index;
}
-/* FIXME: call normalize on line first? */
/* FIXME: add checks to functions that current mode is supported */
/* name is the name of the generated pair of functions
t@@ -2089,42 +2094,45 @@ dummy_cursor_helper(ledit_buffer *buffer, int line, in…
cur_funcv is called to position the cursor in visual mode */
#define GEN_MOVE_TO_CHAR(name, search_func, cur_funcm, cur_funcn, cur_funcv) …
static struct action …
-name##_cb(ledit_buffer *buffer, char *text, int len) { …
+name##_cb(ledit_view *view, char *text, size_t len) { …
motion_callback cb = NULL; …
int num = get_key_repeat_and_motion_cb(&cb); …
if (num == -1) …
- return err_invalid_key(buffer); …
+ return err_invalid_key(view); …
if (num == 0) …
num = 1; …
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line); …
- int new_index = buffer->cur_index; …
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, view->cur_line); …
+ size_t new_index = view->cur_index; …
+ int ret = -1; …
for (int i = 0; i < num; i++) { …
- new_index = search_func(ll->text, ll->len, text, len, new_inde…
- if (new_index == -1) …
+ if ((ret = search_func( …
+ ll->text, ll->len, text, len, …
+ new_index, &new_index)) == -1) { …
break; …
+ } …
} …
- if (new_index >= 0) { …
+ if (!ret) { …
if (cb != NULL) { …
new_index = cur_funcm( …
- buffer, buffer->cur_line, new_index, 1 …
+ view, view->cur_line, new_index, 1 …
); …
- cb(buffer, buffer->cur_line, new_index, KEY_MOTION_CHA…
+ cb(view, view->cur_line, new_index, KEY_MOTION_CHAR); …
} else { …
- if (buffer->common->mode == VISUAL) { …
- buffer->cur_index = cur_funcv( …
- buffer, buffer->cur_line, new_index, 1 …
+ if (view->mode == VISUAL) { \
+ view->cur_index = cur_funcv( …
+ view, view->cur_line, new_index, 1 …
); …
- ledit_buffer_set_selection( …
- buffer, …
- buffer->sel.line1, buffer->sel.byte1, …
- buffer->cur_line, buffer->cur_index …
+ view_set_selection( …
+ view, …
+ view->sel.line1, view->sel.byte1, …
+ view->cur_line, view->cur_index …
); …
} else { …
- buffer->cur_index = cur_funcn( …
- buffer, buffer->cur_line, new_index, 1 …
+ view->cur_index = cur_funcn( …
+ view, view->cur_line, new_index, 1 …
); …
- ledit_buffer_set_line_cursor_attrs( …
- buffer, buffer->cur_line, buffer->cur_inde…
+ view_set_line_cursor_attrs( …
+ view, view->cur_line, view->cur_index …
); …
} …
discard_repetition_stack(); …
t@@ -2136,8 +2144,8 @@ name##_cb(ledit_buffer *buffer, char *text, int len) { …
} …
…
static struct action …
-name(ledit_buffer *buffer, char *text, int len) { …
- (void)buffer; …
+name(ledit_view *view, char *text, size_t len) { …
+ (void)view; …
(void)text; …
(void)len; …
grab_char_cb = &name##_cb; …
t@@ -2148,15 +2156,15 @@ name(ledit_buffer *buffer, char *text, int len) { …
/* FIXME: dummy_cursor_helper is kind of ugly */
GEN_MOVE_TO_CHAR(
find_next_char_forwards, search_str_forwards,
- dummy_cursor_helper, ledit_buffer_prev_cursor_pos, dummy_cursor_helper
+ dummy_cursor_helper, view_prev_cursor_pos, dummy_cursor_helper
)
GEN_MOVE_TO_CHAR(
find_next_char_backwards, search_str_backwards,
- ledit_buffer_next_cursor_pos, ledit_buffer_next_cursor_pos, ledit_buffer_n…
+ view_next_cursor_pos, view_next_cursor_pos, view_next_cursor_pos
)
GEN_MOVE_TO_CHAR(
find_char_forwards, search_str_forwards,
- ledit_buffer_next_cursor_pos, dummy_cursor_helper, dummy_cursor_helper
+ view_next_cursor_pos, dummy_cursor_helper, dummy_cursor_helper
)
GEN_MOVE_TO_CHAR(
find_char_backwards, search_str_backwards,
t@@ -2164,68 +2172,55 @@ GEN_MOVE_TO_CHAR(
)
static struct action
-replace_cb(ledit_buffer *buffer, char *text, int len) {
- int start_index = buffer->cur_index;
+replace_cb(ledit_view *view, char *text, size_t len) {
+ size_t start_index = view->cur_index;
/* FIXME: replace with (key repeat) * text instead of just text */
- int end_index = ledit_buffer_next_cursor_pos(
- buffer, buffer->cur_line, buffer->cur_index, 1
+ size_t end_index = view_next_cursor_pos(
+ view, view->cur_line, view->cur_index, 1
);
delete_range(
- buffer, 0, 0,
- buffer->cur_line, start_index, buffer->cur_line, end_index, 0
+ view, 0, 0,
+ view->cur_line, start_index, view->cur_line, end_index, 0
);
insert_text(
- buffer, buffer->cur_line, start_index, text, len,
- buffer->cur_line, start_index, buffer->cur_line, start_index, 0
+ view, view->cur_line, start_index, text, len,
+ view->cur_line, start_index, view->cur_line, start_index, 1, 1, 0
);
/* this should not be necessary, but just in case */
- buffer->cur_index = ledit_buffer_get_legal_normal_pos(
- buffer, buffer->cur_line, buffer->cur_index
+ view->cur_index = view_get_legal_normal_pos(
+ view, view->cur_line, view->cur_index
);
- push_undo_empty_insert(buffer, buffer->cur_line, buffer->cur_index, 0);
+ push_undo_empty_insert(view, view->cur_line, view->cur_index, 0);
grab_char_cb = NULL;
return (struct action){ACTION_NONE, NULL};
}
static struct action
-replace(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+replace(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
int num = get_key_repeat();
if (num != 0)
- return err_invalid_key(buffer);
+ return err_invalid_key(view);
grab_char_cb = &replace_cb;
return (struct action){ACTION_NONE, NULL};
}
-static void
-set_hard_line_based(ledit_buffer *buffer, int hl) {
- hard_line_based = hl;
- char *text = hl ? "|HL" : "|SL";
- ledit_window_set_mode_extra_text(buffer->window, text);
-}
-
static struct action
-toggle_hard_line_based(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+toggle_hard_line_based(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
int num = get_key_repeat();
if (num != 0)
- return err_invalid_key(buffer);
- set_hard_line_based(buffer, !hard_line_based);
+ return err_invalid_key(view);
+ ledit_buffer_set_hard_line_based(view->buffer, !view->buffer->hard_lin…
return (struct action){ACTION_NONE, NULL};
}
-/* FIXME: this is sort of all over the place and ugly */
-void
-keys_basic_init(ledit_buffer *buffer) {
- set_hard_line_based(buffer, 1);
-}
-
static struct action
-handle_key(ledit_buffer *buffer, char *key_text, int len, KeySym sym, unsigned…
+handle_key(ledit_view *view, char *key_text, size_t len, KeySym sym, unsigned …
struct key *cur_keys = keys[lang_index].keys;
int num_keys = keys[lang_index].num_keys;
struct key_stack_elem *e = peek_key_stack();
t@@ -2236,13 +2231,13 @@ handle_key(ledit_buffer *buffer, char *key_text, int l…
return (struct action){ACTION_NONE, NULL};
} else if (len > 0 && grab_char_cb) {
*found = 1;
- return grab_char_cb(buffer, key_text, len);
+ return grab_char_cb(view, key_text, len);
}
*found = 0;
for (int i = 0; i < num_keys; i++) {
if (cur_keys[i].text) {
if (len > 0 &&
- (cur_keys[i].modes & buffer->common->mode) &&
+ (cur_keys[i].modes & view->mode) &&
(!e || (e->key & cur_keys[i].prev_keys)) &&
((!strncmp(cur_keys[i].text, key_text, len) &&
match_key(cur_keys[i].mods, key_state & ~ShiftM…
t@@ -2250,21 +2245,21 @@ handle_key(ledit_buffer *buffer, char *key_text, int l…
/* FIXME: seems a bit hacky to remove shift, b…
is needed to make keys that use shift match…
*found = 1;
- return cur_keys[i].func(buffer, key_text, len);
+ return cur_keys[i].func(view, key_text, len);
}
- } else if ((cur_keys[i].modes & buffer->common->mode) &&
+ } else if ((cur_keys[i].modes & view->mode) &&
cur_keys[i].keysym == sym &&
match_key(cur_keys[i].mods, key_state)) {
*found = 1;
- return cur_keys[i].func(buffer, key_text, len);
+ return cur_keys[i].func(view, key_text, len);
}
}
return (struct action){ACTION_NONE, NULL};
}
static struct action
-repeat_command(ledit_buffer *buffer, char *text, int len) {
- (void)buffer;
+repeat_command(ledit_view *view, char *text, size_t len) {
+ (void)view;
(void)text;
(void)len;
int found;
t@@ -2273,7 +2268,7 @@ repeat_command(ledit_buffer *buffer, char *text, int len…
unwind_repetition_stack();
struct repetition_stack_elem *e = get_cur_repetition_stack_elem();
while (e) {
- (void)handle_key(buffer, e->key_text, e->len, e->sym, e->key_s…
+ (void)handle_key(view, e->key_text, e->len, e->sym, e->key_sta…
advance_repetition_stack();
e = get_cur_repetition_stack_elem();
}
t@@ -2284,29 +2279,29 @@ repeat_command(ledit_buffer *buffer, char *text, int l…
}
struct action
-basic_key_handler(ledit_buffer *buffer, XEvent *event, int lang_index) {
+basic_key_handler(ledit_view *view, XEvent *event, int lang_index) {
char buf[64];
KeySym sym;
int n;
unsigned int key_state = event->xkey.state;
- preprocess_key(buffer->window, event, &sym, buf, sizeof(buf), &n);
+ preprocess_key(view->window, event, &sym, buf, sizeof(buf), &n);
struct repetition_stack_elem *re = push_repetition_stack();
re->key_text = ledit_strndup(buf, (size_t)n);
- re->len = n;
+ re->len = (size_t)n;
re->sym = sym;
re->key_state = key_state;
re->lang_index = lang_index;
/* FIXME: only hide when actually necessary */
- ledit_window_hide_message(buffer->window);
+ ledit_window_hide_message(view->window);
int found = 0;
- struct action act = handle_key(buffer, buf, n, sym, key_state, lang_in…
+ struct action act = handle_key(view, buf, (size_t)n, sym, key_state, l…
/* FIXME: only do this when necessary */
if (found)
- ledit_buffer_ensure_cursor_shown(buffer);
+ view_ensure_cursor_shown(view);
/* FIXME: maybe show error if not found */
return act;
}
diff --git a/keys_basic.h b/keys_basic.h
t@@ -1,3 +1,2 @@
-void keys_basic_init(ledit_buffer *buffer);
void basic_key_cleanup(void);
-struct action basic_key_handler(ledit_buffer *buffer, XEvent *event, int lang_…
+struct action basic_key_handler(ledit_view *view, XEvent *event, int lang_inde…
diff --git a/keys_basic_config.h b/keys_basic_config.h
t@@ -13,88 +13,88 @@ enum key_type {
};
struct key {
- char *text; /* for keys that c…
- unsigned int mods; /* modifier mask */
- KeySym keysym; /* for other keys,…
- enum ledit_mode modes; /* modes in which …
- enum key_type prev_keys; /* allowed previou…
- enum key_type key_types; /* key types - use…
- struct action (*func)(ledit_buffer *, char *, int); /* callback functi…
+ char *text; /* for keys that …
+ unsigned int mods; /* modifier mask …
+ KeySym keysym; /* for other keys…
+ enum ledit_mode modes; /* modes in which…
+ enum key_type prev_keys; /* allowed previo…
+ enum key_type key_types; /* key types - us…
+ struct action (*func)(ledit_view *, char *, size_t); /* callback funct…
};
-static struct action backspace(ledit_buffer *buffer, char *text, int len);
-static struct action cursor_left(ledit_buffer *buffer, char *text, int len);
-static struct action cursor_right(ledit_buffer *buffer, char *text, int len);
-static struct action cursor_up(ledit_buffer *buffer, char *text, int len);
-static struct action cursor_down(ledit_buffer *buffer, char *text, int len);
-static struct action return_key(ledit_buffer *buffer, char *text, int len);
-static struct action delete_key(ledit_buffer *buffer, char *text, int len);
-static struct action escape_key(ledit_buffer *buffer, char *text, int len);
-static struct action enter_insert(ledit_buffer *buffer, char *text, int len);
-static struct action cursor_to_beginning(ledit_buffer *buffer, char *text, int…
-static struct action push_0(ledit_buffer *buffer, char *text, int len);
-static struct action push_1(ledit_buffer *buffer, char *text, int len);
-static struct action push_2(ledit_buffer *buffer, char *text, int len);
-static struct action push_3(ledit_buffer *buffer, char *text, int len);
-static struct action push_4(ledit_buffer *buffer, char *text, int len);
-static struct action push_5(ledit_buffer *buffer, char *text, int len);
-static struct action push_6(ledit_buffer *buffer, char *text, int len);
-static struct action push_7(ledit_buffer *buffer, char *text, int len);
-static struct action push_8(ledit_buffer *buffer, char *text, int len);
-static struct action push_9(ledit_buffer *buffer, char *text, int len);
-static struct action delete(ledit_buffer *buffer, char *text, int len);
-static struct action enter_visual(ledit_buffer *buffer, char *text, int len);
-static struct action switch_selection_end(ledit_buffer *buffer, char *text, in…
-static struct action clipcopy(ledit_buffer *buffer, char *text, int len);
-static struct action clippaste(ledit_buffer *buffer, char *text, int len);
-static struct action show_line(ledit_buffer *buffer, char *text, int len);
-static struct action enter_commandedit(ledit_buffer *buffer, char *text, int l…
-static struct action enter_searchedit_backward(ledit_buffer *buffer, char *tex…
-static struct action enter_searchedit_forward(ledit_buffer *buffer, char *text…
-static struct action key_search_next(ledit_buffer *buffer, char *text, int len…
-static struct action key_search_prev(ledit_buffer *buffer, char *text, int len…
-static struct action undo(ledit_buffer *buffer, char *text, int len);
-static struct action redo(ledit_buffer *buffer, char *text, int len);
-static struct action insert_mode_insert_text(ledit_buffer *buffer, char *text,…
-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,…
-static struct action scroll_lines_up(ledit_buffer *buffer, char *text, int len…
-static struct action scroll_lines_down(ledit_buffer *buffer, char *text, int l…
-static struct action move_to_line(ledit_buffer *buffer, char *text, int len);
-static struct action paste_normal(ledit_buffer *buffer, char *text, int len);
-static struct action paste_normal_backwards(ledit_buffer *buffer, char *text, …
-static struct action change(ledit_buffer *buffer, char *text, int len);
-static struct action move_to_eol(ledit_buffer *buffer, char *text, int len);
-static struct action mark_line(ledit_buffer *buffer, char *text, int len);
-static struct action jump_to_mark(ledit_buffer *buffer, char *text, int len);
-static struct action next_word(ledit_buffer *buffer, char *text, int len);
-static struct action next_word_end(ledit_buffer *buffer, char *text, int len);
-static struct action next_bigword(ledit_buffer *buffer, char *text, int len);
-static struct action next_bigword_end(ledit_buffer *buffer, char *text, int le…
-static struct action prev_word(ledit_buffer *buffer, char *text, int len);
-static struct action prev_bigword(ledit_buffer *buffer, char *text, int len);
-static struct action append_after_eol(ledit_buffer *buffer, char *text, int le…
-static struct action append_after_cursor(ledit_buffer *buffer, char *text, int…
-static struct action append_line_above(ledit_buffer *buffer, char *text, int l…
-static struct action append_line_below(ledit_buffer *buffer, char *text, int l…
-static struct action find_next_char_forwards(ledit_buffer *buffer, char *text,…
-static struct action find_next_char_backwards(ledit_buffer *buffer, char *text…
-static struct action find_char_forwards(ledit_buffer *buffer, char *text, int …
-static struct action find_char_backwards(ledit_buffer *buffer, char *text, int…
-static struct action change_to_eol(ledit_buffer *buffer, char *text, int len);
-static struct action delete_to_eol(ledit_buffer *buffer, char *text, int len);
-static struct action delete_chars_forwards(ledit_buffer *buffer, char *text, i…
-static struct action delete_chars_backwards(ledit_buffer *buffer, char *text, …
-static struct action yank(ledit_buffer *buffer, char *text, int len);
-static struct action yank_lines(ledit_buffer *buffer, char *text, int len);
-static struct action replace(ledit_buffer *buffer, char *text, int len);
-static struct action cursor_to_first_non_ws(ledit_buffer *buffer, char *text, …
-static struct action join_lines(ledit_buffer *buffer, char *text, int len);
-static struct action insert_at_beginning(ledit_buffer *buffer, char *text, int…
-static struct action toggle_hard_line_based(ledit_buffer *buffer, char *text, …
+static struct action backspace(ledit_view *view, char *text, size_t len);
+static struct action cursor_left(ledit_view *view, char *text, size_t len);
+static struct action cursor_right(ledit_view *view, char *text, size_t len);
+static struct action cursor_up(ledit_view *view, char *text, size_t len);
+static struct action cursor_down(ledit_view *view, char *text, size_t len);
+static struct action return_key(ledit_view *view, char *text, size_t len);
+static struct action delete_key(ledit_view *view, char *text, size_t len);
+static struct action escape_key(ledit_view *view, char *text, size_t len);
+static struct action enter_insert(ledit_view *view, char *text, size_t len);
+static struct action cursor_to_beginning(ledit_view *view, char *text, size_t …
+static struct action push_0(ledit_view *view, char *text, size_t len);
+static struct action push_1(ledit_view *view, char *text, size_t len);
+static struct action push_2(ledit_view *view, char *text, size_t len);
+static struct action push_3(ledit_view *view, char *text, size_t len);
+static struct action push_4(ledit_view *view, char *text, size_t len);
+static struct action push_5(ledit_view *view, char *text, size_t len);
+static struct action push_6(ledit_view *view, char *text, size_t len);
+static struct action push_7(ledit_view *view, char *text, size_t len);
+static struct action push_8(ledit_view *view, char *text, size_t len);
+static struct action push_9(ledit_view *view, char *text, size_t len);
+static struct action delete(ledit_view *view, char *text, size_t len);
+static struct action enter_visual(ledit_view *view, char *text, size_t len);
+static struct action switch_selection_end(ledit_view *view, char *text, size_t…
+static struct action clipcopy(ledit_view *view, char *text, size_t len);
+static struct action clippaste(ledit_view *view, char *text, size_t len);
+static struct action show_line(ledit_view *view, char *text, size_t len);
+static struct action enter_commandedit(ledit_view *view, char *text, size_t le…
+static struct action enter_searchedit_backward(ledit_view *view, char *text, s…
+static struct action enter_searchedit_forward(ledit_view *view, char *text, si…
+static struct action key_search_next(ledit_view *view, char *text, size_t len);
+static struct action key_search_prev(ledit_view *view, char *text, size_t len);
+static struct action undo(ledit_view *view, char *text, size_t len);
+static struct action redo(ledit_view *view, char *text, size_t len);
+static struct action insert_mode_insert_text(ledit_view *view, char *text, siz…
+static struct action repeat_command(ledit_view *view, char *text, size_t len);
+static struct action screen_up(ledit_view *view, char *text, size_t len);
+static struct action screen_down(ledit_view *view, char *text, size_t len);
+static struct action scroll_with_cursor_up(ledit_view *view, char *text, size_…
+static struct action scroll_with_cursor_down(ledit_view *view, char *text, siz…
+static struct action scroll_lines_up(ledit_view *view, char *text, size_t len);
+static struct action scroll_lines_down(ledit_view *view, char *text, size_t le…
+static struct action move_to_line(ledit_view *view, char *text, size_t len);
+static struct action paste_normal(ledit_view *view, char *text, size_t len);
+static struct action paste_normal_backwards(ledit_view *view, char *text, size…
+static struct action change(ledit_view *view, char *text, size_t len);
+static struct action move_to_eol(ledit_view *view, char *text, size_t len);
+static struct action mark_line(ledit_view *view, char *text, size_t len);
+static struct action jump_to_mark(ledit_view *view, char *text, size_t len);
+static struct action next_word(ledit_view *view, char *text, size_t len);
+static struct action next_word_end(ledit_view *view, char *text, size_t len);
+static struct action next_bigword(ledit_view *view, char *text, size_t len);
+static struct action next_bigword_end(ledit_view *view, char *text, size_t len…
+static struct action prev_word(ledit_view *view, char *text, size_t len);
+static struct action prev_bigword(ledit_view *view, char *text, size_t len);
+static struct action append_after_eol(ledit_view *view, char *text, size_t len…
+static struct action append_after_cursor(ledit_view *view, char *text, size_t …
+static struct action append_line_above(ledit_view *view, char *text, size_t le…
+static struct action append_line_below(ledit_view *view, char *text, size_t le…
+static struct action find_next_char_forwards(ledit_view *view, char *text, siz…
+static struct action find_next_char_backwards(ledit_view *view, char *text, si…
+static struct action find_char_forwards(ledit_view *view, char *text, size_t l…
+static struct action find_char_backwards(ledit_view *view, char *text, size_t …
+static struct action change_to_eol(ledit_view *view, char *text, size_t len);
+static struct action delete_to_eol(ledit_view *view, char *text, size_t len);
+static struct action delete_chars_forwards(ledit_view *view, char *text, size_…
+static struct action delete_chars_backwards(ledit_view *view, char *text, size…
+static struct action yank(ledit_view *view, char *text, size_t len);
+static struct action yank_lines(ledit_view *view, char *text, size_t len);
+static struct action replace(ledit_view *view, char *text, size_t len);
+static struct action cursor_to_first_non_ws(ledit_view *view, char *text, size…
+static struct action join_lines(ledit_view *view, char *text, size_t len);
+static struct action insert_at_beginning(ledit_view *view, char *text, size_t …
+static struct action toggle_hard_line_based(ledit_view *view, char *text, size…
/* FIXME: maybe sort these and use binary search
-> but that would mess with the catch-all keys */
diff --git a/keys_command.c b/keys_command.c
t@@ -19,63 +19,77 @@
#include "theme.h"
#include "window.h"
#include "buffer.h"
+#include "view.h"
#include "search.h"
+#include "cleanup.h"
#include "keys.h"
-#include "action.h"
#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;
+static int create_view(ledit_view *view, char *cmd, size_t l1, size_t l2);
+static int close_view(ledit_view *view, char *cmd, size_t l1, size_t l2);
+static int handle_write(ledit_view *view, char *cmd, size_t l1, size_t l2);
+static int handle_quit(ledit_view *view, char *cmd, size_t l1, size_t l2);
+static int handle_write_quit(ledit_view *view, char *cmd, size_t l1, size_t l2…
+static int handle_substitute(ledit_view *view, char *cmd, size_t l1, size_t l2…
+static int parse_range(ledit_view *view, char *cmd, size_t len, char **cmd_ret…
+static int handle_cmd(ledit_view *view, char *cmd, size_t len);
-void
-command_key_cleanup(void) {
- /* nothing right now */
+static int
+handle_write(ledit_view *view, char *cmd, size_t l1, size_t l2) {
+ (void)view;
+ (void)cmd;
+ (void)l1;
+ (void)l2;
+ /* FIXME: Implement properly; handle error */
+ char *errstr;
+ if (view->buffer->filename)
+ ledit_buffer_write_to_file(view->buffer, view->buffer->filenam…
+ return 0;
}
-void
-ledit_command_set_type(enum ledit_command_type type) {
- cur_type = type;
+static int
+handle_quit(ledit_view *view, char *cmd, size_t l1, size_t l2) {
+ (void)view;
+ (void)cmd;
+ (void)l1;
+ (void)l2;
+ /* FIXME: ask to save changes */
+ ledit_cleanup();
+ exit(0);
+ return 0;
}
-static int handle_write(ledit_buffer *buffer, char *cmd, int l1, int l2);
-static int handle_quit(ledit_buffer *buffer, char *cmd, int l1, int l2);
-static int handle_write_quit(ledit_buffer *buffer, char *cmd, int l1, int l2);
-static int handle_substitute(ledit_buffer *buffer, char *cmd, int l1, int l2);
-static int parse_range(ledit_buffer *buffer, char *cmd, int len, char **cmd_re…
-static int handle_cmd(ledit_buffer *buffer, char *cmd, int len);
-
static int
-handle_write(ledit_buffer *buffer, char *cmd, int l1, int l2) {
- (void)buffer;
+create_view(ledit_view *view, char *cmd, size_t l1, size_t l2) {
(void)cmd;
(void)l1;
(void)l2;
- /* FIXME: Implement properly; handle error */
- char *errstr;
- if (buffer->filename)
- ledit_buffer_write_to_file(buffer, buffer->filename, &errstr);
+ ledit_buffer_add_view(view->buffer, view->theme, view->mode, view->cur…
return 0;
}
static int
-handle_quit(ledit_buffer *buffer, char *cmd, int l1, int l2) {
- (void)buffer;
+close_view(ledit_view *view, char *cmd, size_t l1, size_t l2) {
(void)cmd;
(void)l1;
(void)l2;
- /* FIXME: Implement */
- exit(1);
+ /* FIXME: This will lead to problems if I add something that
+ requires access to the view after the command is handled. */
+ ledit_buffer_remove_view(view->buffer, view);
+ if (view->buffer->views_num == 0) {
+ ledit_cleanup();
+ exit(0);
+ }
return 0;
}
static int
-handle_write_quit(ledit_buffer *buffer, char *cmd, int l1, int l2) {
- (void)buffer;
+handle_write_quit(ledit_view *view, char *cmd, size_t l1, size_t l2) {
+ (void)view;
(void)cmd;
(void)l1;
(void)l2;
t@@ -84,8 +98,8 @@ handle_write_quit(ledit_buffer *buffer, char *cmd, int l1, i…
}
static int
-handle_substitute(ledit_buffer *buffer, char *cmd, int l1, int l2) {
- (void)buffer;
+handle_substitute(ledit_view *view, char *cmd, size_t l1, size_t l2) {
+ (void)view;
(void)cmd;
(void)l1;
(void)l2;
t@@ -101,11 +115,13 @@ enum cmd_type {
static const struct {
char *cmd;
enum cmd_type type;
- int (*handler)(ledit_buffer *buffer, char *cmd, int l1, int l2);
+ int (*handler)(ledit_view *view, char *cmd, size_t l1, size_t l2);
} cmds[] = {
{"wq", CMD_OPTIONAL_RANGE, &handle_write_quit},
{"w", CMD_OPTIONAL_RANGE, &handle_write},
{"q", CMD_NORMAL, &handle_quit},
+ {"v", CMD_NORMAL, &create_view},
+ {"c", CMD_NORMAL, &close_view},
{"s", CMD_OPTIONAL_RANGE, &handle_substitute}
};
t@@ -117,7 +133,7 @@ $ last line
/* FIXME: ACTUALLY USE LEN!!! */
static int
-parse_range(ledit_buffer *buffer, char *cmd, int len, char **cmd_ret, int *lin…
+parse_range(ledit_view *view, char *cmd, size_t len, char **cmd_ret, size_t *l…
(void)len;
enum {
START_LINENO = 1,
t@@ -125,28 +141,34 @@ parse_range(ledit_buffer *buffer, char *cmd, int len, ch…
IN_RANGE = 4,
IN_LINENO = 8
} s = START_LINENO | START_RANGE;
- int l1 = -1, l2 = -1;
+ size_t l1 = 0, l2 = 0;
+ *l1_valid = 0;
+ *l2_valid = 0;
char *c = cmd;
for (; *c != '\0'; c++) {
if (isdigit(*c)) {
/* FIXME: integer overflow */
if (s & IN_LINENO) {
- if (l2 != -1)
+ if (*l2_valid) {
l2 = l2 * 10 + (*c - '0');
- else
+ } else {
l1 = l1 * 10 + (*c - '0');
+ *l1_valid = 1;
+ }
} else if ((s & START_LINENO) && (s & START_RANGE)) {
l1 = *c - '0';
+ *l1_valid = 1;
s &= ~START_RANGE;
s &= ~START_LINENO;
s |= IN_RANGE | IN_LINENO;
} else if ((s & START_LINENO)) {
l2 = *c - '0';
+ *l2_valid = 1;
s &= ~START_LINENO;
s |= IN_LINENO;
}
} else if (*c == ',' && !(s & START_RANGE)) {
- if (l1 != -1 && l2 != -1) {
+ if (*l1_valid && *l2_valid) {
return 1;
} else {
s |= START_LINENO;
t@@ -155,17 +177,21 @@ parse_range(ledit_buffer *buffer, char *cmd, int len, ch…
} else if (*c == '%') {
if (s & START_RANGE) {
l1 = 1;
- l2 = buffer->lines_num;
+ l2 = view->lines_num;
+ *l1_valid = *l2_valid = 1;
break;
} else {
return 1;
}
} else if (*c == '$') {
if (s & START_LINENO) {
- if (l1 == -1)
- l1 = buffer->lines_num;
- else
- l2 = buffer->lines_num;
+ if (!*l1_valid) {
+ l1 = view->lines_num;
+ *l1_valid = 1;
+ } else {
+ l2 = view->lines_num;
+ *l2_valid = 1;
+ }
s &= ~START_LINENO;
s &= ~IN_LINENO;
} else {
t@@ -175,7 +201,7 @@ parse_range(ledit_buffer *buffer, char *cmd, int len, char…
break;
}
}
- if ((l1 == -1 || l2 == -1) && !(s & START_RANGE))
+ if ((!*l1_valid || !*l2_valid) && !(s & START_RANGE))
return 1;
*cmd_ret = c;
*line1_ret = l1;
t@@ -184,196 +210,196 @@ parse_range(ledit_buffer *buffer, char *cmd, int len, …
}
static int
-handle_cmd(ledit_buffer *buffer, char *cmd, int len) {
- if (len < 0)
- len = strlen(cmd);
+handle_cmd(ledit_view *view, char *cmd, size_t len) {
if (len < 1)
return 0;
char *c;
- int l1, l2;
+ size_t l1, l2;
+ int l1_valid, l2_valid;
/* FIXME: show error msg here */
- if (parse_range(buffer, cmd, len, &c, &l1, &l2))
+ if (parse_range(view, cmd, len, &c, &l1, &l2, &l1_valid, &l2_valid))
return 0;
- int range_given = l1 != -1 && l2 != -1;
+ int range_given = l1_valid && l2_valid;
for (size_t i = 0; i < LENGTH(cmds); i++) {
if (!strncmp(cmds[i].cmd, c, strlen(cmds[i].cmd)) &&
(!range_given || cmds[i].type == CMD_OPTIONAL_RANGE)) {
- return cmds[i].handler(buffer, c, l1, l2);
+ return cmds[i].handler(view, c, l1, l2);
}
}
return 0;
}
static int
-substitute_yes(ledit_buffer *buffer, char *key_text, int len) {
- (void)buffer;
+substitute_yes(ledit_view *view, char *key_text, size_t len) {
+ (void)view;
(void)key_text;
(void)len;
return 1;
}
static int
-substitute_yes_all(ledit_buffer *buffer, char *key_text, int len) {
- (void)buffer;
+substitute_yes_all(ledit_view *view, char *key_text, size_t len) {
+ (void)view;
(void)key_text;
(void)len;
return 0;
}
static int
-substitute_no(ledit_buffer *buffer, char *key_text, int len) {
- (void)buffer;
+substitute_no(ledit_view *view, char *key_text, size_t len) {
+ (void)view;
(void)key_text;
(void)len;
return 1;
}
static int
-substitute_no_all(ledit_buffer *buffer, char *key_text, int len) {
- (void)buffer;
+substitute_no_all(ledit_view *view, char *key_text, size_t len) {
+ (void)view;
(void)key_text;
(void)len;
return 0;
}
static int
-edit_insert_text(ledit_buffer *buffer, char *key_text, int len) {
- ledit_window_insert_bottom_bar_text(buffer->window, key_text, len);
+edit_insert_text(ledit_view *view, char *key_text, size_t len) {
+ /* FIXME: overflow */
+ ledit_window_insert_bottom_bar_text(view->window, key_text, len);
ledit_window_set_bottom_bar_cursor(
- buffer->window, ledit_window_get_bottom_bar_cursor(buffer->window)…
+ view->window, ledit_window_get_bottom_bar_cursor(view->window) + l…
);
return 1;
}
static int
-edit_cursor_to_end(ledit_buffer *buffer, char *key_text, int len) {
+edit_cursor_to_end(ledit_view *view, char *key_text, size_t len) {
(void)key_text;
(void)len;
- ledit_window_bottom_bar_cursor_to_end(buffer->window);
+ ledit_window_bottom_bar_cursor_to_end(view->window);
return 1;
}
static int
-edit_cursor_to_beginning(ledit_buffer *buffer, char *key_text, int len) {
+edit_cursor_to_beginning(ledit_view *view, char *key_text, size_t len) {
(void)key_text;
(void)len;
- ledit_window_bottom_bar_cursor_to_beginning(buffer->window);
+ ledit_window_bottom_bar_cursor_to_beginning(view->window);
return 1;
}
static int
-edit_cursor_left(ledit_buffer *buffer, char *key_text, int len) {
+edit_cursor_left(ledit_view *view, char *key_text, size_t len) {
(void)key_text;
(void)len;
- ledit_window_move_bottom_bar_cursor(buffer->window, -1);
+ ledit_window_move_bottom_bar_cursor(view->window, -1);
return 1;
}
static int
-edit_cursor_right(ledit_buffer *buffer, char *key_text, int len) {
+edit_cursor_right(ledit_view *view, char *key_text, size_t len) {
(void)key_text;
(void)len;
- ledit_window_move_bottom_bar_cursor(buffer->window, 1);
+ ledit_window_move_bottom_bar_cursor(view->window, 1);
return 1;
}
static int
-edit_backspace(ledit_buffer *buffer, char *key_text, int len) {
+edit_backspace(ledit_view *view, char *key_text, size_t len) {
(void)key_text;
(void)len;
- ledit_window_delete_bottom_bar_char(buffer->window, -1);
+ ledit_window_delete_bottom_bar_char(view->window, -1);
return 1;
}
static int
-edit_delete(ledit_buffer *buffer, char *key_text, int len) {
+edit_delete(ledit_view *view, char *key_text, size_t len) {
(void)key_text;
(void)len;
- ledit_window_delete_bottom_bar_char(buffer->window, 1);
+ ledit_window_delete_bottom_bar_char(view->window, 1);
return 1;
}
static int
-edit_submit(ledit_buffer *buffer, char *key_text, int len) {
+edit_submit(ledit_view *view, char *key_text, size_t len) {
(void)key_text;
(void)len;
- ledit_window_set_bottom_bar_text_shown(buffer->window, 0);
+ ledit_window_set_bottom_bar_text_shown(view->window, 0);
/* FIXME: this is hacky */
- return handle_cmd(buffer, ledit_window_get_bottom_bar_text(buffer->win…
+ return handle_cmd(view, ledit_window_get_bottom_bar_text(view->window)…
}
/* FIXME: support visual mode, i.e. change selection to new place? */
void
-search_next(ledit_buffer *buffer) {
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- enum ledit_search_state ret = ledit_search_next(buffer, &buffer->cur_l…
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+search_next(ledit_view *view) {
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ enum ledit_search_state ret = ledit_search_next(view, &view->cur_line,…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
if (ret != SEARCH_NORMAL)
- ledit_window_show_message(buffer->window, ledit_search_state_t…
+ ledit_window_show_message(view->window, ledit_search_state_to_…
}
void
-search_prev(ledit_buffer *buffer) {
- ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
- enum ledit_search_state ret = ledit_search_prev(buffer, &buffer->cur_l…
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
+search_prev(ledit_view *view) {
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ enum ledit_search_state ret = ledit_search_prev(view, &view->cur_line,…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
if (ret != SEARCH_NORMAL)
- ledit_window_show_message(buffer->window, ledit_search_state_t…
+ ledit_window_show_message(view->window, ledit_search_state_to_…
}
static int
-editsearch_submit(ledit_buffer *buffer, char *key_text, int len) {
+editsearch_submit(ledit_view *view, char *key_text, size_t len) {
(void)key_text;
(void)len;
- 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);
+ ledit_window_set_bottom_bar_text_shown(view->window, 0);
+ ledit_set_search_forward(ledit_window_get_bottom_bar_text(view->window…
+ search_next(view);
return 0;
}
static int
-editsearchb_submit(ledit_buffer *buffer, char *key_text, int len) {
+editsearchb_submit(ledit_view *view, char *key_text, size_t len) {
(void)key_text;
(void)len;
- 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);
+ ledit_window_set_bottom_bar_text_shown(view->window, 0);
+ ledit_set_search_backward(ledit_window_get_bottom_bar_text(view->windo…
+ search_next(view);
return 0;
}
static int
-edit_discard(ledit_buffer *buffer, char *key_text, int len) {
- (void)buffer;
+edit_discard(ledit_view *view, char *key_text, size_t len) {
+ (void)view;
(void)key_text;
(void)len;
- ledit_window_set_bottom_bar_text_shown(buffer->window, 0);
+ ledit_window_set_bottom_bar_text_shown(view->window, 0);
return 0;
}
struct action
-ledit_command_key_handler(ledit_buffer *buffer, XEvent *event, int lang_index)…
+ledit_command_key_handler(ledit_view *view, XEvent *event, int lang_index) {
char buf[64];
KeySym sym;
int n;
struct key *cur_keys = keys[lang_index].keys;
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);
+ preprocess_key(view->window, event, &sym, buf, sizeof(buf), &n);
int grabkey = 1;
for (int i = 0; i < num_keys; i++) {
if (cur_keys[i].text) {
if (n > 0 &&
- (cur_keys[i].type == cur_type) &&
+ (cur_keys[i].type == view->cur_command_type) &&
((!strncmp(cur_keys[i].text, buf, n) &&
match_key(cur_keys[i].mods, key_state & ~ShiftMa…
cur_keys[i].text[0] == '\0')) {
- grabkey = cur_keys[i].func(buffer, buf, n);
+ grabkey = cur_keys[i].func(view, buf, (size_t)…
break;
}
- } else if ((cur_keys[i].type == cur_type) &&
+ } else if ((cur_keys[i].type == view->cur_command_type) &&
(cur_keys[i].keysym == sym) &&
(match_key(cur_keys[i].mods, key_state))) {
- grabkey = cur_keys[i].func(buffer, buf, n);
+ grabkey = cur_keys[i].func(view, buf, (size_t)n);
break;
}
}
diff --git a/keys_command.h b/keys_command.h
t@@ -1,16 +1,5 @@
-enum ledit_command_type {
- CMD_EDIT,
- CMD_EDITSEARCH,
- CMD_EDITSEARCHB,
- CMD_SEARCH,
- CMD_SEARCHB,
- CMD_SUBSTITUTE
-};
-
/* these are only here so they can also be used by keys_basic */
-void search_next(ledit_buffer *buffer);
-void search_prev(ledit_buffer *buffer);
+void search_next(ledit_view *view);
+void search_prev(ledit_view *view);
-void command_key_cleanup(void);
-void ledit_command_set_type(enum ledit_command_type type);
-struct action ledit_command_key_handler(ledit_buffer *buffer, XEvent *event, i…
+struct action ledit_command_key_handler(ledit_view *view, XEvent *event, int l…
diff --git a/keys_command_config.h b/keys_command_config.h
t@@ -1,25 +1,25 @@
-static int substitute_yes(ledit_buffer *buffer, char *key_text, int len);
-static int substitute_yes_all(ledit_buffer *buffer, char *key_text, int len);
-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);
+static int substitute_yes(ledit_view *view, char *key_text, size_t len);
+static int substitute_yes_all(ledit_view *view, char *key_text, size_t len);
+static int substitute_no(ledit_view *view, char *key_text, size_t len);
+static int substitute_no_all(ledit_view *view, char *key_text, size_t len);
+static int edit_insert_text(ledit_view *view, char *key_text, size_t len);
+static int edit_cursor_left(ledit_view *view, char *key_text, size_t len);
+static int edit_cursor_right(ledit_view *view, char *key_text, size_t len);
+static int edit_cursor_to_end(ledit_view *view, char *key_text, size_t len);
+static int edit_cursor_to_beginning(ledit_view *view, char *key_text, size_t l…
+static int edit_backspace(ledit_view *view, char *key_text, size_t len);
+static int edit_delete(ledit_view *view, char *key_text, size_t len);
+static int edit_submit(ledit_view *view, char *key_text, size_t len);
+static int editsearch_submit(ledit_view *view, char *key_text, size_t len);
+static int editsearchb_submit(ledit_view *view, char *key_text, size_t len);
+static int edit_discard(ledit_view *view, char *key_text, size_t len);
struct key {
char *text; /* for keys that correspond…
unsigned int mods; /* modifier mask */
KeySym keysym; /* for other keys, e.g. arr…
enum ledit_command_type type; /* substitute, etc. */
- int (*func)(ledit_buffer *, char *, int); /* callback function */
+ int (*func)(ledit_view *, char *, size_t); /* callback function */
};
/* "" means catch-all, i.e. all keys with text are given to that callback */
diff --git a/ledit.c b/ledit.c
t@@ -1,3 +1,4 @@
+/* FIXME: Just use int for everything? size_t just doesn't seem to be worth it…
/* FIXME: Make scrolling more smooth */
/* FIXME: Document that everything is assumed to be utf8 */
/* FIXME: Only redraw part of screen if needed */
t@@ -40,41 +41,25 @@
#include "cache.h"
#include "undo.h"
#include "buffer.h"
-#include "action.h"
+#include "view.h"
#include "search.h"
#include "keys.h"
#include "keys_basic.h"
#include "keys_command.h"
+#include "macros.h"
+#include "cleanup.h"
-static void resize_window(int w, int h);
static void mainloop(void);
static void setup(int argc, char *argv[]);
-static void cleanup(void);
static void redraw(void);
-static int button_press(XEvent *event, int scroll_num);
-static int button_release(XEvent *event);
-static int drag_motion(XEvent *event);
static void change_keyboard(char *lang);
-static void key_press(XEvent *event);
+static void key_press(ledit_view *view, XEvent *event);
ledit_theme *theme = NULL;
-ledit_window *window = NULL;
ledit_buffer *buffer = NULL;
ledit_common common;
int cur_lang = 0;
-struct action cur_action = {ACTION_NONE, NULL};
-
-/* stolen from OpenBSD */
-#define ledit_timespecsub(tsp, usp, vsp) …
- do { \
- (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
- (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
- if ((vsp)->tv_nsec < 0) { \
- (vsp)->tv_sec--; \
- (vsp)->tv_nsec += 1000000000L; \
- } \
- } while (0)
static void
mainloop(void) {
t@@ -83,6 +68,7 @@ mainloop(void) {
int major, minor;
if (!XkbQueryExtension(common.dpy, 0, &xkb_event_type, NULL, &major, &…
fprintf(stderr, "XKB not supported.");
+ ledit_cleanup();
exit(1);
}
/*printf("XKB (%d.%d) supported.\n", major, minor);*/
t@@ -103,19 +89,11 @@ mainloop(void) {
int running = 1;
int change_kbd = 0;
- int need_redraw = 0;
redraw();
- /* store last time that a mouse event was processed in order to
- avoid sending too many mouse events to be processed */
- /* also store last draw time so framerate can be limited */
- struct timespec now, elapsed, last, last_scroll, last_motion, last_res…
+ /* store last draw time so framerate can be limited */
+ struct timespec now, elapsed, last, sleep_time;
clock_gettime(CLOCK_MONOTONIC, &last);
- last_scroll = last_motion = last_resize = last;
sleep_time.tv_sec = 0;
- XEvent last_scroll_event, last_motion_event, last_resize_event;
- int last_scroll_valid = 0, last_motion_valid = 0, last_resize_valid = …
- int scroll_num = 0;
- int scroll_delta = 0;
while (running) {
while (XPending(common.dpy)) {
XNextEvent(common.dpy, &event);
t@@ -125,91 +103,55 @@ mainloop(void) {
}
if (XFilterEvent(&event, None))
continue;
+ ledit_view *view = NULL;
+ /* FIXME: abstract view handling a bit (don't access d…
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ if (buffer->views[i]->window->xwin == event.xa…
+ view = buffer->views[i];
+ break;
+ }
+ }
+ if (view == NULL)
+ continue; /* shouldn't happen */
+ ledit_window *window = view->window;
switch (event.type) {
case Expose:
- /* FIXME: why did I do this? */
- redraw();
- need_redraw = 1;
+ view->redraw = 1;
break;
case ConfigureNotify:
- last_resize_event = event;
- last_resize_valid = 1;
+ ledit_window_register_resize(view->window, &ev…
break;
case ButtonPress:
- /* FIXME: this is all a bit hacky */
- if (event.xbutton.button == Button4 ||
- event.xbutton.button == Button5) {
- scroll_delta = event.xbutton.button ==…
- if (last_scroll_valid) {
- scroll_num += scroll_delta;
- } else {
- last_scroll_event = event;
- last_scroll_valid = 1;
- scroll_num = scroll_delta;
- }
- } else {
- need_redraw |= button_press(&event, 0);
- }
+ ledit_window_register_button_press(view->windo…
break;
case ButtonRelease:
- need_redraw |= button_release(&event);
+ ledit_window_button_release(view->window, &eve…
break;
case MotionNotify:
- /* FIXME: is it legal to just copy event like …
- last_motion_event = event;
- last_motion_valid = 1;
+ ledit_window_register_motion(window, &event);
break;
case KeyPress:
- need_redraw = 1;
- key_press(&event);
+ key_press(view, &event);
break;
case ClientMessage:
- if ((Atom)event.xclient.data.l[0] == buffer->w…
- running = 0;
+ if ((Atom)event.xclient.data.l[0] == view->win…
+ ledit_buffer_remove_view(buffer, view);
+ if (buffer->views_num == 0)
+ running = 0;
+ }
break;
case SelectionNotify:
case PropertyNotify:
- /* redraw because text may be pasted, then fall
- through and let window handle the event */
- need_redraw = 1;
- /* fall through */
case SelectionRequest:
- ledit_window_clipboard_event(buffer->window, &…
+ ledit_window_clipboard_event(view->window, &ev…
break;
default:
break;
}
};
- if (last_motion_valid) {
- clock_gettime(CLOCK_MONOTONIC, &now);
- ledit_timespecsub(&now, &last_motion, &elapsed);
- if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= MOUSE_TIC…
- need_redraw |= drag_motion(&last_motion_event);
- last_motion = now;
- last_motion_valid = 0;
- }
- }
- if (last_scroll_valid) {
- clock_gettime(CLOCK_MONOTONIC, &now);
- ledit_timespecsub(&now, &last_scroll, &elapsed);
- if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= MOUSE_TIC…
- need_redraw |= button_press(&last_scroll_event…
- last_scroll = now;
- last_scroll_valid = 0;
- }
- }
- if (last_resize_valid) {
- clock_gettime(CLOCK_MONOTONIC, &now);
- ledit_timespecsub(&now, &last_resize, &elapsed);
- if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= RESIZE_TI…
- resize_window(
- last_resize_event.xconfigure.width,
- last_resize_event.xconfigure.height
- );
- last_resize = now;
- last_resize_valid = 0;
- need_redraw = 1;
- }
+
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ ledit_window_handle_filtered_events(buffer->views[i]->…
}
if (change_kbd) {
t@@ -226,10 +168,7 @@ mainloop(void) {
XFree(group);
XkbFreeKeyboard(desc, XkbAllComponentsMask, True);
}
- if (need_redraw) {
- redraw();
- need_redraw = 0;
- }
+ redraw();
clock_gettime(CLOCK_MONOTONIC, &now);
ledit_timespecsub(&now, &last, &elapsed);
t@@ -258,6 +197,7 @@ setup(int argc, char *argv[]) {
);
if (!info || num_screens < 1 || info->count < 1) {
fprintf(stderr, "No visuals support Xdbe.\n");
+ ledit_cleanup();
exit(1);
}
XVisualInfo xvisinfo_templ;
t@@ -276,11 +216,13 @@ setup(int argc, char *argv[]) {
stderr,
"Couldn't match a Visual with double buffering\n"
);
+ ledit_cleanup();
exit(1);
}
common.vis = xvisinfo_match->visual;
} else {
fprintf(stderr, "No Xdbe support.\n");
+ ledit_cleanup();
exit(1);
}
t@@ -288,63 +230,43 @@ setup(int argc, char *argv[]) {
common.cm = DefaultColormap(common.dpy, common.screen);
theme = ledit_theme_create(&common);
- window = ledit_window_create(&common, theme);
- buffer = ledit_buffer_create(&common, theme, window);
+ buffer = ledit_buffer_create(&common);
/* FIXME: Support multiple buffers/files */
if (argc > 1) {
char *load_err;
if (ledit_buffer_load_file(buffer, argv[1], 0, &load_err)) {
fprintf(stderr, "Error opening file '%s': %s\n", argv[…
+ ledit_cleanup();
exit(1);
}
/* FIXME: encapsulate */
buffer->filename = ledit_strdup(argv[1]);
}
- ledit_buffer_set_mode(buffer, NORMAL);
- ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c…
- keys_basic_init(buffer);
+ ledit_buffer_add_view(buffer, theme, NORMAL, 0, 0);
+ /* FIXME: don't access view directly here */
+ ledit_view *view = buffer->views[0];
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
redraw();
}
-static void
-cleanup(void) {
+void
+ledit_cleanup(void) {
/* FIXME: check for other things to clean up */
ledit_search_cleanup();
basic_key_cleanup();
- command_key_cleanup();
- ledit_buffer_destroy(buffer);
- ledit_window_destroy(window);
- ledit_theme_destroy(&common, theme);
+ if (buffer)
+ ledit_buffer_destroy(buffer);
+ if (theme)
+ ledit_theme_destroy(&common, theme);
XCloseDisplay(common.dpy);
}
static void
redraw(void) {
- ledit_window_clear(window);
- ledit_buffer_redraw(buffer);
- ledit_window_redraw(window);
-}
-
-static int
-button_press(XEvent *event, int scroll_num) {
- return ledit_window_button_press(window, event, scroll_num);
-}
-
-static int
-button_release(XEvent *event) {
- return ledit_window_button_release(window, event);
-}
-
-static int
-drag_motion(XEvent *event) {
- return ledit_window_drag_motion(window, event);
-}
-
-static void
-resize_window(int w, int h) {
- ledit_window_resize(window, w, h);
- ledit_buffer_resize_textview(buffer);
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_redraw(buffer->views[i]);
+ }
}
static void
t@@ -356,11 +278,13 @@ change_keyboard(char *lang) {
}
static void
-key_press(XEvent *event) {
- if (cur_action.type == ACTION_GRABKEY && cur_action.callback) {
- cur_action = cur_action.callback(buffer, event, cur_lang);
+key_press(ledit_view *view, XEvent *event) {
+ /* FIXME: just let view handle this since the action is part
+ of it anyways now */
+ if (view->cur_action.type == ACTION_GRABKEY && view->cur_action.callba…
+ view->cur_action = view->cur_action.callback(view, event, cur_…
} else {
- cur_action = basic_key_handler(buffer, event, cur_lang);
+ view->cur_action = basic_key_handler(view, event, cur_lang);
}
}
t@@ -368,7 +292,7 @@ int
main(int argc, char *argv[]) {
setup(argc, argv);
mainloop();
- cleanup();
+ ledit_cleanup();
return 0;
}
diff --git a/macros.h b/macros.h
t@@ -0,0 +1,10 @@
+/* stolen from OpenBSD */
+#define ledit_timespecsub(tsp, usp, vsp) …
+ do { \
+ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
+ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
+ if ((vsp)->tv_nsec < 0) { \
+ (vsp)->tv_sec--; \
+ (vsp)->tv_nsec += 1000000000L; \
+ } \
+ } while (0)
diff --git a/memory.c b/memory.c
t@@ -2,11 +2,21 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <assert.h>
+
+#include "cleanup.h"
-/* FIXME: clean up on exit */
static void
fatal_err(const char *msg) {
fprintf(stderr, "%s", msg);
+ ledit_cleanup();
+ exit(1);
+}
+
+void
+err_overflow(void) {
+ fprintf(stderr, "Integer overflow.\n");
+ ledit_cleanup();
exit(1);
}
t@@ -68,7 +78,7 @@ ledit_strcat(const char *str1, const char *str2) {
}
/*
- * This is from OpenBSD (adapted to exit on error):
+ * This (reallocarray) is from OpenBSD (adapted to exit on error):
* Copyright (c) 2008 Otto Moerbeek <[email protected]>
*/
t@@ -83,7 +93,105 @@ ledit_reallocarray(void *optr, size_t nmemb, size_t size)
{
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size) {
- fatal_err("Out of memory.\n");
+ fatal_err("Integer overflow in reallocarray.\n");
}
return realloc(optr, size * nmemb);
}
+
+void
+move_gap(
+ void *array, size_t elem_size, size_t index,
+ size_t gap, size_t cap, size_t len,
+ size_t *new_gap_ret) {
+ assert(array != NULL);
+ assert(index <= len);
+ assert(len <= cap);
+ char *carray = (char *)array; /* cast to char * for pointer arithmetic…
+ /* since the array has size cap * elem_size, it is assumed that no ove…
+ if (index > gap) {
+ /* move piece between end of original gap and
+ index to beginning of original gap */
+ memmove(
+ carray + gap * elem_size,
+ carray + (gap + cap - len) * elem_size,
+ (index - gap) * elem_size
+ );
+ } else if (index < gap) {
+ /* move piece between index and original gap to
+ end of original gap */
+ memmove(
+ carray + (index + cap - len) * elem_size,
+ carray + index * elem_size,
+ (gap - index) * elem_size
+ );
+ }
+ if (new_gap_ret)
+ *new_gap_ret = index;
+}
+
+/* FIXME: replace with macro version that takes type parameter in order
+ to avoid errors with elem_size */
+/* This is almost certainly premature optimization and maybe
+ not optimization at all. */
+void *
+resize_and_move_gap(
+ void *array, size_t elem_size,
+ size_t old_gap, size_t old_cap, size_t len,
+ size_t min_size, size_t index,
+ size_t *new_gap_ret, size_t *new_cap_ret) {
+ assert(index <= len);
+ assert(len <= old_cap);
+ size_t gap_size = old_cap - len;
+ size_t new_cap = old_cap;
+ /* FIXME: read up on what the best values are here */
+ if (new_cap < min_size)
+ new_cap = old_cap * 2 > min_size ? old_cap * 2 : min_size;
+ if (new_cap < min_size)
+ err_overflow();
+ if (new_cap != old_cap)
+ array = ledit_reallocarray(array, new_cap, elem_size);
+ char *carray = (char*)array; /* cast to char to do pointer arithmetic …
+ /* we already know new_cap * elem_size does not wrap around because ar…
+ is of that size, so all the other multiplications here should be sa…
+ (at least that's what I think, but I may be wrong) */
+ if (index > old_gap) {
+ /* move piece between end of original gap and index to
+ beginning of original gap */
+ memmove(
+ carray + old_gap * elem_size,
+ carray + (old_gap + gap_size) * elem_size,
+ (index - old_gap) * elem_size
+ );
+ /* move piece after index to end of buffer */
+ memmove(
+ carray + (new_cap - (len - index)) * elem_size,
+ carray + (index + gap_size) * elem_size,
+ (len - index) * elem_size
+ );
+ } else if (index < old_gap) {
+ /* move piece after original gap to end of buffer */
+ memmove(
+ carray + (new_cap - (len - old_gap)) * elem_size,
+ carray + (old_gap + gap_size) * elem_size,
+ (len - old_gap) * elem_size
+ );
+ /* move piece between index and original gap to end */
+ memmove(
+ carray + (new_cap - len + index) * elem_size,
+ carray + index * elem_size,
+ (old_gap - index) * elem_size
+ );
+ } else {
+ /* move piece after original gap to end of buffer */
+ memmove(
+ carray + (new_cap - (len - old_gap)) * elem_size,
+ carray + (old_gap + gap_size) * elem_size,
+ (len - old_gap) * elem_size
+ );
+ }
+ if (new_gap_ret)
+ *new_gap_ret = index;
+ if (new_cap_ret)
+ *new_cap_ret = new_cap;
+ return carray;
+}
diff --git a/memory.h b/memory.h
t@@ -5,3 +5,35 @@ void *ledit_calloc(size_t nmemb, size_t size);
void *ledit_realloc(void *ptr, size_t size);
char *ledit_strcat(const char *str1, const char *str2);
void *ledit_reallocarray(void *optr, size_t nmemb, size_t size);
+
+/*
+ * Move the gap of a gap buffer with elements of size 'elem_size' to 'index'.
+ * 'index' is also written to 'new_gap_ret' if it is not NULL. This is just
+ * for convenience because it usually has to be set anyways.
+ */
+void move_gap(
+ void *array, size_t elem_size, size_t index,
+ size_t gap, size_t cap, size_t len,
+ size_t *new_gap_ret
+);
+
+/*
+ * Resize a generic gap buffer with elements of size 'elem_size' to hold at le…
+ * 'min_size' elements and move the gap to element position 'index'.
+ * 'old_gap' is the old index of the gap buffer, 'old_cap' is the total length…
+ * array (number of elements, not bytes), and 'len' is the number of valid ele…
+ * 'index' is also written to 'new_gap_ret' if it is not NULL. This is just
+ * for convenience because it usually has to be set anyways.
+ * The new total length of the array is also written to 'new_cap_ret', if it i…
+ * NULL. If it is NULL, you're doing something wrong.
+ * Returns the final array (might be same as the old one).
+ */
+void *resize_and_move_gap(
+ void *array, size_t elem_size,
+ size_t old_gap, size_t old_cap, size_t len,
+ size_t min_size, size_t index,
+ size_t *new_gap_ret, size_t *new_cap_ret
+);
+
+/* FIXME: not sure if this really belongs here */
+void err_overflow(void);
diff --git a/pango-compat.c b/pango-compat.c
t@@ -6,7 +6,11 @@
/* FIXME: This is just copied from the newer version of pango. It *seems* like
the structs used are public (they're in the documentation), but it does seem
a bit dirty to do this here */
-#if !PANGO_VERSION_CHECK(1, 46, 0)
+/* This version check is disabled currently because an older version of pango …
+ bug where pango_layout_get_direction didn't work with lines of length 0.
+ I should actually check when that was changed so I can do a version check f…
+//#if !PANGO_VERSION_CHECK(1, 46, 0)
+#if 1
static PangoLayoutRun *
pango_layout_line_get_run(PangoLayoutLine *line, int index) {
GSList *run_list;
t@@ -44,7 +48,7 @@ pango_layout_line_get_char_direction(PangoLayoutLine *layout…
}
PangoDirection
-pango_layout_get_direction(PangoLayout *layout, int index) {
+ledit_pango_layout_get_direction(PangoLayout *layout, int index) {
int lineno, x;
PangoLayoutLine *line;
pango_layout_index_to_line_x(layout, index, 0, &lineno, &x);
diff --git a/pango-compat.h b/pango-compat.h
t@@ -1,3 +1,4 @@
-#if !PANGO_VERSION_CHECK(1, 46, 0)
-PangoDirection pango_layout_get_direction(PangoLayout *layout, int index);
+//#if !PANGO_VERSION_CHECK(1, 46, 0)
+#if 1
+PangoDirection ledit_pango_layout_get_direction(PangoLayout *layout, int index…
#endif
diff --git a/search.c b/search.c
t@@ -45,46 +45,46 @@ ledit_set_search_backward(char *pattern) {
}
static enum ledit_search_state
-search_forward(ledit_buffer *buffer, int *line_ret, int *byte_ret) {
- *line_ret = buffer->cur_line;
- *byte_ret = buffer->cur_index;
+search_forward(ledit_view *view, size_t *line_ret, size_t *byte_ret) {
+ *line_ret = view->cur_line;
+ *byte_ret = view->cur_index;
if (last_search == NULL)
return SEARCH_NO_PATTERN;
- int line = buffer->cur_line;
+ size_t line = view->cur_line;
/* start one byte later so it doesn't get stuck on a match
note: since the string ends with '\0', this is always valid */
- int byte = buffer->cur_index + 1;
+ size_t byte = view->cur_index + 1;
char *res;
- ledit_line *lline = ledit_buffer_get_line(buffer, line);
+ ledit_line *lline = ledit_buffer_get_line(view->buffer, line);
ledit_buffer_normalize_line(lline);
if ((res = strstr(lline->text + byte, last_search)) != NULL) {
*line_ret = line;
- *byte_ret = (int)(res - lline->text);
+ *byte_ret = (size_t)(res - lline->text);
return SEARCH_NORMAL;
}
- for (int i = line + 1; i < buffer->lines_num; i++) {
- lline = ledit_buffer_get_line(buffer, i);
+ for (size_t i = line + 1; i < view->lines_num; i++) {
+ lline = ledit_buffer_get_line(view->buffer, i);
ledit_buffer_normalize_line(lline);
if ((res = strstr(lline->text, last_search)) != NULL) {
*line_ret = i;
- *byte_ret = (int)(res - lline->text);
+ *byte_ret = (size_t)(res - lline->text);
return SEARCH_NORMAL;
}
}
- for (int i = 0; i < line; i++) {
- lline = ledit_buffer_get_line(buffer, i);
+ for (size_t i = 0; i < line; i++) {
+ lline = ledit_buffer_get_line(view->buffer, i);
ledit_buffer_normalize_line(lline);
if ((res = strstr(lline->text, last_search)) != NULL) {
*line_ret = i;
- *byte_ret = (int)(res - lline->text);
+ *byte_ret = (size_t)(res - lline->text);
return SEARCH_WRAPPED;
}
}
- lline = ledit_buffer_get_line(buffer, line);
+ lline = ledit_buffer_get_line(view->buffer, line);
ledit_buffer_normalize_line(lline);
if ((res = strstr(lline->text, last_search)) != NULL) {
*line_ret = line;
- *byte_ret = (int)(res - lline->text);
+ *byte_ret = (size_t)(res - lline->text);
return SEARCH_WRAPPED;
}
return SEARCH_NOT_FOUND;
t@@ -93,14 +93,14 @@ search_forward(ledit_buffer *buffer, int *line_ret, int *b…
/* FIXME: this is insanely inefficient */
/* FIXME: just go backwards char-by-char and compare */
static enum ledit_search_state
-search_backward(ledit_buffer *buffer, int *line_ret, int *byte_ret) {
- *line_ret = buffer->cur_line;
- *byte_ret = buffer->cur_index;
+search_backward(ledit_view *view, size_t *line_ret, size_t *byte_ret) {
+ *line_ret = view->cur_line;
+ *byte_ret = view->cur_index;
if (last_search == NULL)
return SEARCH_NO_PATTERN;
- int line = buffer->cur_line;
- int byte = buffer->cur_index;
- ledit_line *lline = ledit_buffer_get_line(buffer, line);
+ size_t line = view->cur_line;
+ size_t byte = view->cur_index;
+ ledit_line *lline = ledit_buffer_get_line(view->buffer, line);
ledit_buffer_normalize_line(lline);
char *last = NULL, *res = lline->text;
while ((res = strstr(res, last_search)) != NULL && res < lline->text +…
t@@ -110,11 +110,11 @@ search_backward(ledit_buffer *buffer, int *line_ret, int…
if (last != NULL) {
*line_ret = line;
/* FIXME: check if this is safe */
- *byte_ret = (int)(last - lline->text);
+ *byte_ret = (size_t)(last - lline->text);
return SEARCH_NORMAL;
}
- for (int i = line - 1; i >= 0; i--) {
- lline = ledit_buffer_get_line(buffer, i);
+ for (size_t i = line; i > 0; i--) {
+ lline = ledit_buffer_get_line(view->buffer, i-1);
ledit_buffer_normalize_line(lline);
res = lline->text;
while ((res = strstr(res, last_search)) != NULL) {
t@@ -122,13 +122,13 @@ search_backward(ledit_buffer *buffer, int *line_ret, int…
res++;
}
if (last != NULL) {
- *line_ret = i;
- *byte_ret = (int)(last - lline->text);
+ *line_ret = i-1;
+ *byte_ret = (size_t)(last - lline->text);
return SEARCH_NORMAL;
}
}
- for (int i = buffer->lines_num - 1; i > line; i--) {
- lline = ledit_buffer_get_line(buffer, i);
+ for (size_t i = view->lines_num - 1; i > line; i--) {
+ lline = ledit_buffer_get_line(view->buffer, i);
ledit_buffer_normalize_line(lline);
res = lline->text;
while ((res = strstr(res, last_search)) != NULL) {
t@@ -137,11 +137,11 @@ search_backward(ledit_buffer *buffer, int *line_ret, int…
}
if (last != NULL) {
*line_ret = i;
- *byte_ret = (int)(last - lline->text);
+ *byte_ret = (size_t)(last - lline->text);
return SEARCH_WRAPPED;
}
}
- lline = ledit_buffer_get_line(buffer, line);
+ lline = ledit_buffer_get_line(view->buffer, line);
ledit_buffer_normalize_line(lline);
res = lline->text + byte;
while ((res = strstr(res, last_search)) != NULL) {
t@@ -150,26 +150,26 @@ search_backward(ledit_buffer *buffer, int *line_ret, int…
}
if (last != NULL) {
*line_ret = line;
- *byte_ret = (int)(last - lline->text);
+ *byte_ret = (size_t)(last - lline->text);
return SEARCH_WRAPPED;
}
return SEARCH_NOT_FOUND;
}
enum ledit_search_state
-ledit_search_next(ledit_buffer *buffer, int *line_ret, int *byte_ret) {
+ledit_search_next(ledit_view *view, size_t *line_ret, size_t *byte_ret) {
if (last_dir == FORWARD)
- return search_forward(buffer, line_ret, byte_ret);
+ return search_forward(view, line_ret, byte_ret);
else
- return search_backward(buffer, line_ret, byte_ret);
+ return search_backward(view, line_ret, byte_ret);
}
enum ledit_search_state
-ledit_search_prev(ledit_buffer *buffer, int *line_ret, int *byte_ret) {
+ledit_search_prev(ledit_view *view, size_t *line_ret, size_t *byte_ret) {
if (last_dir == FORWARD)
- return search_backward(buffer, line_ret, byte_ret);
+ return search_backward(view, line_ret, byte_ret);
else
- return search_forward(buffer, line_ret, byte_ret);
+ return search_forward(view, line_ret, byte_ret);
}
char *
diff --git a/search.h b/search.h
t@@ -8,6 +8,6 @@ enum ledit_search_state {
void ledit_search_cleanup(void);
void ledit_set_search_forward(char *pattern);
void ledit_set_search_backward(char *pattern);
-enum ledit_search_state ledit_search_next(ledit_buffer *buffer, int *line_ret,…
-enum ledit_search_state ledit_search_prev(ledit_buffer *buffer, int *line_ret,…
+enum ledit_search_state ledit_search_next(ledit_view *view, size_t *line_ret, …
+enum ledit_search_state ledit_search_prev(ledit_view *view, size_t *line_ret, …
char *ledit_search_state_to_str(enum ledit_search_state state);
diff --git a/undo.c b/undo.c
t@@ -1,6 +1,7 @@
#include <string.h>
#include <assert.h>
#include <stdlib.h>
+#include <stdint.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
t@@ -69,6 +70,7 @@ push_undo_elem(ledit_undo_stack *undo) {
undo->cur++;
undo->len = undo->cur + 1;
if (undo->len > undo->cap) {
+ /* FIXME: wait, why is it size_t here already? */
size_t cap = undo->len * 2;
undo->stack = ledit_realloc(undo->stack, cap * sizeof(undo_ele…
for (size_t i = undo->cap; i < cap; i++) {
t@@ -140,7 +142,7 @@ ledit_push_undo_delete(
ledit_undo_status
ledit_undo(ledit_undo_stack *undo, enum ledit_mode mode, void *callback_data,
undo_insert_callback insert_cb, undo_delete_callback delete_cb,
- int *cur_line_ret, int *cur_index_ret, int *min_line_ret) {
+ size_t *cur_line_ret, size_t *cur_index_ret, size_t *min_line_ret) {
undo_elem *e;
/* skip empty elements */
while (undo->cur >= 0 && undo->stack[undo->cur].text->len == 0) {
t@@ -150,8 +152,10 @@ ledit_undo(ledit_undo_stack *undo, enum ledit_mode mode, …
return UNDO_OLDEST_CHANGE;
int group = undo->stack[undo->cur].group;
int mode_group = undo->stack[undo->cur].mode_group;
- int min_line = INT_MAX;
+ size_t min_line = SIZE_MAX;
int mode_group_same = 0;
+ size_t cur_line = 0;
+ size_t cur_index = 0;
while (undo->cur >= 0 &&
(undo->stack[undo->cur].group == group || (mode_group_same =
((mode == NORMAL ||
t@@ -190,9 +194,17 @@ ledit_undo(ledit_undo_stack *undo, enum ledit_mode mode, …
if (e->op_range.line1 < min_line)
min_line = e->op_range.line1;
undo->cur--;
- *cur_line_ret = e->cursor_range.line1;
- *cur_index_ret = e->cursor_range.byte1;
+ cur_line = e->cursor_range.line1;
+ cur_index = e->cursor_range.byte1;
}
+ /* these can't be written directly in the while loop because that caus…
+ conflicts - when text is inserted/deleted on the current line of the
+ view, the cursor is updated, but if the current line was already ch…
+ here before the end of the undo run, it's possible for multiple lin…
+ to have a cursor highlight set in the end (at least when working wi…
+ multiple views) */
+ *cur_line_ret = cur_line;
+ *cur_index_ret = cur_index;
*min_line_ret = min_line;
return UNDO_NORMAL;
}
t@@ -200,7 +212,7 @@ ledit_undo(ledit_undo_stack *undo, enum ledit_mode mode, v…
ledit_undo_status
ledit_redo(ledit_undo_stack *undo, enum ledit_mode mode, void *callback_data,
undo_insert_callback insert_cb, undo_delete_callback delete_cb,
- int *cur_line_ret, int *cur_index_ret, int *min_line_ret) {
+ size_t *cur_line_ret, size_t *cur_index_ret, size_t *min_line_ret) {
undo_elem *e;
/* skip elements where no text is changed */
while (undo->cur < undo->len - 1 && undo->stack[undo->cur + 1].text->l…
t@@ -211,8 +223,10 @@ ledit_redo(ledit_undo_stack *undo, enum ledit_mode mode, …
undo->cur++;
int group = undo->stack[undo->cur].group;
int mode_group = undo->stack[undo->cur].mode_group;
- int min_line = INT_MAX;
+ size_t min_line = SIZE_MAX;
int mode_group_same = 0;
+ size_t cur_line = 0;
+ size_t cur_index = 0;
while (undo->cur < undo->len &&
(undo->stack[undo->cur].group == group || (mode_group_same =
((mode == NORMAL ||
t@@ -244,9 +258,11 @@ ledit_redo(ledit_undo_stack *undo, enum ledit_mode mode, …
if (e->op_range.line1 < min_line)
min_line = e->op_range.line1;
undo->cur++;
- *cur_line_ret = e->cursor_range.line2;
- *cur_index_ret = e->cursor_range.byte2;
+ cur_line = e->cursor_range.line2;
+ cur_index = e->cursor_range.byte2;
}
+ *cur_line_ret = cur_line;
+ *cur_index_ret = cur_index;
undo->cur--;
*min_line_ret = min_line;
return UNDO_NORMAL;
diff --git a/undo.h b/undo.h
t@@ -5,8 +5,8 @@ typedef enum {
} ledit_undo_status;
typedef struct ledit_undo_stack ledit_undo_stack;
-typedef void (*undo_insert_callback)(void *, int, int, char *, int);
-typedef void (*undo_delete_callback)(void *, int, int, int, int);
+typedef void (*undo_insert_callback)(void *, size_t, size_t, char *, size_t);
+typedef void (*undo_delete_callback)(void *, size_t, size_t, size_t, size_t);
ledit_undo_stack *ledit_undo_stack_create(void);
void ledit_undo_stack_destroy(ledit_undo_stack *undo);
t@@ -24,10 +24,10 @@ void ledit_push_undo_delete(
ledit_undo_status ledit_undo(
ledit_undo_stack *undo, enum ledit_mode mode,
void *callback_data, undo_insert_callback insert_cb, undo_delete_callback …
- int *cur_line_ret, int *cur_index_ret, int *min_line_ret
+ size_t *cur_line_ret, size_t *cur_index_ret, size_t *min_line_ret
);
ledit_undo_status ledit_redo(
ledit_undo_stack *undo, enum ledit_mode mode,
void *callback_data, undo_insert_callback insert_cb, undo_delete_callback …
- int *cur_line_ret, int *cur_index_ret, int *min_line_ret
+ size_t *cur_line_ret, size_t *cur_index_ret, size_t *min_line_ret
);
diff --git a/util.h b/util.h
t@@ -1,3 +1,5 @@
+/* FIXME: rename this to draw_util.h and rename macros.h to util.h */
+
typedef struct {
XftDraw *xftdraw;
Pixmap pixmap;
diff --git a/view.c b/view.c
t@@ -0,0 +1,2096 @@
+/* FIXME: shrink buffers when text length less than a fourth of the size */
+/* FIXME: also cache PangoLayouts since keeping them around isn't really of mu…
+/* FIXME: handle all undo within buffer to keep it consistent */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <pango/pangoxft.h>
+#include <X11/extensions/Xdbe.h>
+
+#include "pango-compat.h"
+#include "memory.h"
+#include "common.h"
+#include "txtbuf.h"
+#include "undo.h"
+#include "cache.h"
+#include "theme.h"
+#include "window.h"
+#include "buffer.h"
+
+static PangoAttrList *basic_attrs = NULL;
+
+static void init_line(ledit_view *view, ledit_view_line *line);
+static void copy_selection_to_x_primary(ledit_view *view, size_t line1, size_t…
+static void set_pixmap_line_helper(void *data, size_t line, size_t index);
+static void invalidate_pixmap_line_helper(void *data, size_t line);
+static void set_layout_line_helper(void *data, size_t line, size_t index);
+static void invalidate_layout_line_helper(void *data, size_t line);
+
+/*
+ * Assign a cache index to line and set text and highlight of the pango layout.
+ */
+static void set_pango_text_and_highlight(ledit_view *view, size_t line);
+
+/*
+ * Get the pango layout for line.
+ * This first assigns a cache index (by calling set_pango_text_and_highlight).
+ */
+static PangoLayout *get_pango_layout(ledit_view *view, size_t line);
+
+/*
+ * Get an attribute list for a text highlight between the given range.
+ */
+static PangoAttrList *get_pango_attributes(ledit_view *view, size_t start_byte…
+
+/*
+ * Set the attributes for a PangoLayout belonging to the given line index.
+ * If the line is part of the view's selection, the selection is set.
+ * If that is not the case but cursor_index is set for the line, the character
+ * at that position is highlighted (this is used for the normal mode cursor).
+ * Otherwise, the default attributes (basic_attrs) are set.
+ */
+static void set_line_layout_attrs(ledit_view *view, size_t line, PangoLayout *…
+
+static void swap_sz(size_t *a, size_t *b);
+
+static int line_visible_callback(void *data, size_t line);
+static void set_pixmap_line_helper(void *data, size_t line, size_t index);
+static void invalidate_pixmap_line_helper(void *data, size_t line);
+static void invalidate_layout_line_helper(void *data, size_t line);
+
+/* FIXME: This is weird because mode is per-view but the undo mode group
+ is changed for the entire buffer. */
+void
+view_set_mode(ledit_view *view, enum ledit_mode mode) {
+ view->mode = mode;
+ ledit_change_mode_group(view->buffer->undo);
+ ledit_window_set_mode(view->window, mode);
+}
+
+ledit_view *
+view_create(ledit_buffer *buffer, ledit_theme *theme, enum ledit_mode mode, si…
+ if (basic_attrs == NULL) {
+ basic_attrs = pango_attr_list_new();
+ #if PANGO_VERSION_CHECK(1, 44, 0)
+ PangoAttribute *no_hyphens = pango_attr_insert_hyphens_new(FAL…
+ pango_attr_list_insert(basic_attrs, no_hyphens);
+ #endif
+ }
+
+ ledit_view *view = ledit_malloc(sizeof(ledit_view));
+ view->mode = mode;
+ view->buffer = buffer;
+ view->window = ledit_window_create(buffer->common, theme, mode);
+ view->theme = theme;
+ view->cache = cache_create(buffer->common->dpy);
+ view->cur_action = (struct action){ACTION_NONE, NULL};
+ ledit_window_set_scroll_callback(view->window, &view_scroll_handler, v…
+ ledit_window_set_button_callback(view->window, &view_button_handler, v…
+ ledit_window_set_resize_callback(view->window, &view_resize_textview, …
+
+ view->lines = ledit_reallocarray(NULL, buffer->lines_cap, sizeof(ledit…
+ view->lines_cap = buffer->lines_cap;
+ view->lines_gap = buffer->lines_num;
+ view->lines_num = buffer->lines_num;
+ for (size_t i = 0; i < view->lines_num; i++) {
+ init_line(view, &view->lines[i]);
+ }
+ view->cur_line = line;
+ view->cur_index = pos;
+ view->total_height = 0;
+ view->display_offset = 0;
+ view->sel.line1 = view->sel.byte1 = 0;
+ view->sel.line2 = view->sel.byte2 = 0;
+ view->selecting = 0;
+ view->sel_valid = 0;
+ view->redraw = 1;
+ ledit_view_line *vl = view_get_line(view, line);
+ vl->cursor_index = pos;
+ vl->cursor_index_valid = 1;
+
+ view_recalc_all_lines(view);
+
+ return view;
+}
+
+ledit_view_line *
+view_get_line(ledit_view *view, size_t index) {
+ assert(index < view->lines_num);
+ return index < view->lines_gap ?
+ &view->lines[index] :
+ &view->lines[index + view->lines_cap - view->lines_num];
+}
+
+static void
+move_line_gap(ledit_view *view, size_t index) {
+ move_gap(
+ view->lines, sizeof(ledit_view_line), index,
+ view->lines_gap, view->lines_cap, view->lines_num,
+ &view->lines_gap
+ );
+}
+
+static void
+resize_and_move_line_gap(ledit_view *view, size_t min_size, size_t index) {
+ /* FIXME: Add to common bug list: used sizeof(ledit_line) instead of s…
+ view->lines = resize_and_move_gap(
+ view->lines, sizeof(ledit_view_line),
+ view->lines_gap, view->lines_cap, view->lines_num,
+ min_size, index,
+ &view->lines_gap, &view->lines_cap
+ );
+}
+
+void
+view_notify_insert_text(ledit_view *view, size_t line, size_t index, size_t le…
+ ledit_view_line *vl = view_get_line(view, line);
+ vl->text_dirty = 1;
+ if (line == view->cur_line && index < view->cur_index) {
+ view->cur_index += len;
+ view_set_line_cursor_attrs(view, line, view->cur_index);
+ }
+ if (view->sel_valid)
+ view_set_selection(view, view->cur_line, view->cur_index, view…
+}
+
+void
+view_notify_delete_text(ledit_view *view, size_t line, size_t index, size_t le…
+ ledit_view_line *vl = view_get_line(view, line);
+ vl->text_dirty = 1;
+ if (line == view->cur_line) {
+ if (index + len <= view->cur_index) {
+ view->cur_index -= len;
+ } else if (index < view->cur_index && index + len > view->cur_…
+ view->cur_index = index;
+ }
+ /* just so it isn't stuck at end of line after deletion */
+ if (view->mode == NORMAL) {
+ view->cur_index = view_get_legal_normal_pos(
+ view, view->cur_line, view->cur_index
+ );
+ }
+ view_set_line_cursor_attrs(view, line, view->cur_index);
+ }
+ if (view->sel_valid)
+ view_set_selection(view, view->cur_line, view->cur_index, view…
+}
+
+void
+view_notify_append_line(ledit_view *view, size_t line) {
+ size_t new_len = view->lines_num + 1;
+ if (new_len <= view->lines_num)
+ err_overflow();
+ resize_and_move_line_gap(view, new_len, line + 1);
+ if (line < view->cur_line)
+ view->cur_line++;
+ if (view->sel_valid)
+ view_set_selection(view, view->cur_line, view->cur_index, view…
+ view->lines_num++;
+ view->lines_gap++;
+ ledit_view_line *vl = view_get_line(view, line + 1);
+ init_line(view, vl);
+}
+
+void
+view_notify_delete_lines(ledit_view *view, size_t index1, size_t index2) {
+ if (index2 < view->cur_line) {
+ view->cur_line -= index2 - index1 + 1;
+ } else if (index1 <= view->cur_line) {
+ /* FIXME: set cur_index properly */
+ if (index2 < view->lines_num - 1) {
+ view->cur_line = index2 + 1;
+ view->cur_index = 0;
+ } else if (index1 > 0) {
+ view->cur_line = index1 - 1;
+ view->cur_index = 0;
+ } else {
+ /* should never happen */
+ view->cur_line = 0;
+ view->cur_index = 0;
+ }
+ }
+ if (view->sel_valid)
+ view_set_selection(view, view->cur_line, view->cur_index, view…
+ cache_invalidate_from_line(
+ view->cache, index1, view,
+ &invalidate_pixmap_line_helper, &invalidate_layout_line_helper
+ );
+ move_line_gap(view, index1);
+ view->lines_num -= index2 - index1 + 1;
+ /* force first entry to offset 0 if first line was deleted */
+ if (index1 == 0) {
+ ledit_view_line *vl = view_get_line(view, 0);
+ vl->y_offset = 0;
+ }
+}
+
+void
+view_destroy(ledit_view *view) {
+ cache_destroy(view->cache);
+ ledit_window_destroy(view->window);
+ free(view->lines);
+ free(view);
+}
+
+void
+view_cleanup(void) {
+ if (basic_attrs)
+ pango_attr_list_unref(basic_attrs);
+}
+
+static PangoAttrList *
+get_pango_attributes(ledit_view *view, size_t start_byte, size_t end_byte) {
+ XRenderColor fg = view->theme->text_fg.color;
+ XRenderColor bg = view->theme->text_bg.color;
+ PangoAttribute *attr0 = pango_attr_background_new(fg.red, fg.green, fg…
+ PangoAttribute *attr1 = pango_attr_foreground_new(bg.red, bg.green, bg…
+ attr0->start_index = start_byte;
+ attr0->end_index = end_byte;
+ attr1->start_index = start_byte;
+ attr1->end_index = end_byte;
+ PangoAttrList *list = pango_attr_list_new();
+ pango_attr_list_insert(list, attr0);
+ pango_attr_list_insert(list, attr1);
+ #if PANGO_VERSION_CHECK(1, 44, 0)
+ PangoAttribute *attr2 = pango_attr_insert_hyphens_new(FALSE);
+ pango_attr_list_insert(list, attr2);
+ #endif
+ return list;
+}
+
+/* this takes layout directly to possibly avoid infinite recursion */
+static void
+set_line_layout_attrs(ledit_view *view, size_t line, PangoLayout *layout) {
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ ledit_view_line *vl = view_get_line(view, line);
+ PangoAttrList *list = NULL;
+ if (view->sel_valid) {
+ ledit_range sel = view->sel;
+ view_sort_selection(&sel.line1, &sel.byte1, &sel.line2, &sel.b…
+ if (sel.line1 < line && sel.line2 > line) {
+ list = get_pango_attributes(view, 0, ll->len);
+ } else if (sel.line1 == line && sel.line2 == line) {
+ size_t start = sel.byte1, end = sel.byte2;
+ if (start > end)
+ swap_sz(&start, &end);
+ list = get_pango_attributes(view, start, end);
+ } else if (sel.line1 == line && sel.line2 > line) {
+ list = get_pango_attributes(view, sel.byte1, ll->len);
+ } else if (sel.line1 < line && sel.line2 == line) {
+ list = get_pango_attributes(view, 0, sel.byte2);
+ }
+ } else if (vl->cursor_index_valid) {
+ /* FIXME: does just adding one really do the right thing? */
+ list = get_pango_attributes(view, vl->cursor_index, vl->cursor…
+ }
+ if (list != NULL) {
+ pango_layout_set_attributes(layout, list);
+ pango_attr_list_unref(list);
+ } else {
+ pango_layout_set_attributes(layout, basic_attrs);
+ }
+ vl->highlight_dirty = 0;
+ vl->dirty = 1;
+}
+
+void
+view_set_line_cursor_attrs(ledit_view *view, size_t line, size_t index) {
+ ledit_view_line *ll = view_get_line(view, line);
+ ll->cursor_index = index;
+ ll->cursor_index_valid = 1;
+ ll->highlight_dirty = 1;
+ ll->dirty = 1;
+ view->redraw = 1;
+}
+
+void
+view_wipe_line_cursor_attrs(ledit_view *view, size_t line) {
+ ledit_view_line *vl = view_get_line(view, line);
+ vl->cursor_index = 0;
+ vl->cursor_index_valid = 0;
+ vl->highlight_dirty = 1;
+ vl->dirty = 1;
+ view->redraw = 1;
+}
+
+static int
+line_visible_callback(void *data, size_t line) {
+ return view_line_visible((ledit_view*)data, line);
+}
+
+/* FIXME: standardize variable names (line/line_index, etc.) */
+void
+view_render_line(ledit_view *view, size_t line_index) {
+ /* FIXME: check for <= 0 on size */
+ ledit_view_line *ll = view_get_line(view, line_index);
+ assert(!ll->h_dirty); /* FIXME */
+ PangoLayout *layout = get_pango_layout(view, line_index);
+ if (!ll->cache_pixmap_valid) {
+ cache_assign_pixmap_index(
+ view->cache, line_index, view,
+ &line_visible_callback, &set_pixmap_line_helper,
+ &invalidate_pixmap_line_helper
+ );
+ }
+ cache_pixmap *pix = cache_get_pixmap(view->cache, ll->cache_pixmap_ind…
+ /* FIXME: fail on too large pixmap size (e.g. way too long line) */
+ /* FIXME: sensible default pixmap sizes here */
+ /* FIXME: handle this in cache */
+ if (pix->pixmap == None || pix->draw == NULL) {
+ pix->pixmap = XCreatePixmap(
+ view->buffer->common->dpy, view->window->drawable,
+ ll->w + 10, ll->h + 10, view->buffer->common->depth
+ );
+ pix->w = ll->w + 10;
+ pix->h = ll->h + 10;
+ pix->draw = XftDrawCreate(
+ view->buffer->common->dpy, pix->pixmap,
+ view->buffer->common->vis, view->buffer->common->cm
+ );
+ } else if (pix->w < ll->w || pix->h < ll->h) {
+ int new_w = ll->w > pix->w ? ll->w + 10 : pix->w + 10;
+ int new_h = ll->h > pix->h ? ll->h + 10 : pix->h + 10;
+ XFreePixmap(view->buffer->common->dpy, pix->pixmap);
+ pix->pixmap = XCreatePixmap(
+ view->buffer->common->dpy, view->window->drawable,
+ new_w, new_h, view->buffer->common->depth
+ );
+ pix->w = new_w;
+ pix->h = new_h;
+ XftDrawChange(pix->draw, pix->pixmap);
+ }
+ XftDrawRect(pix->draw, &view->theme->text_bg, 0, 0, ll->w, ll->h);
+ pango_xft_render_layout(pix->draw, &view->theme->text_fg, layout, 0, 0…
+ ll->dirty = 0;
+}
+
+static void
+init_line(ledit_view *view, ledit_view_line *line) {
+ int text_w, text_h;
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
+ line->view = view;
+ line->w = text_w;
+ line->h = 0;
+ line->y_offset = 0;
+ line->cache_pixmap_index = 0;
+ line->cache_layout_index = 0;
+ line->softlines = 0;
+ line->cursor_index = 0;
+ line->cursor_index_valid = 0;
+ line->cache_pixmap_valid = 0;
+ line->cache_layout_valid = 0;
+ line->dirty = 1;
+ line->text_dirty = 1;
+ line->highlight_dirty = 1;
+ line->h_dirty = 1;
+}
+
+static void
+set_pixmap_line_helper(void *data, size_t line, size_t index) {
+ ledit_view_line *vl = view_get_line((ledit_view *)data, line);
+ vl->cache_pixmap_index = index;
+ vl->cache_pixmap_valid = 1;
+}
+
+static void
+invalidate_pixmap_line_helper(void *data, size_t line) {
+ ledit_view_line *vl = view_get_line((ledit_view *)data, line);
+ vl->cache_pixmap_valid = 0;
+}
+
+static void
+set_layout_line_helper(void *data, size_t line, size_t index) {
+ ledit_view_line *vl = view_get_line((ledit_view *)data, line);
+ vl->cache_layout_index = index;
+ vl->cache_layout_valid = 1;
+}
+
+static void
+invalidate_layout_line_helper(void *data, size_t line) {
+ ledit_view_line *vl = view_get_line((ledit_view *)data, line);
+ vl->cache_layout_valid = 0;
+}
+
+/* set text of pango layout if dirty and recalculate height of line
+ * - if height hasn't changed, nothing further is done
+ * - if height has changed, offset of all following lines is changed */
+void
+view_recalc_line(ledit_view *view, size_t line) {
+ ledit_view_line *l = view_get_line(view, line);
+ if (l->text_dirty)
+ set_pango_text_and_highlight(view, line);
+
+ int text_w, text_h;
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
+ /* if height changed, set height of current line
+ * and adjust offsets of all lines following it */
+ if (l->h_dirty) {
+ l->h_dirty = 0;
+ long off = l->y_offset + l->h;
+ for (size_t i = line + 1; i < view->lines_num; i++) {
+ l = view_get_line(view, i);
+ l->y_offset = off;
+ off += l->h;
+ }
+ view->total_height = off;
+ if (l->y_offset < view->display_offset + text_h)
+ view->redraw = 1;
+ }
+ l = view_get_line(view, line);
+ if (l->y_offset < view->display_offset + text_h &&
+ l->y_offset + l->h >= view->display_offset) {
+ view->redraw = 1;
+ }
+ ledit_window_set_scroll_max(view->window, view->total_height);
+ view_scroll(view, view->display_offset);
+}
+
+/* set text of pango layout and recalculate height
+ * and offset for all lines starting at 'line' */
+void
+view_recalc_from_line(ledit_view *view, size_t line) {
+ ledit_view_line *l = view_get_line(view, line);
+ int text_w, text_h;
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
+ long off = l->y_offset;
+ if (off < view->display_offset + text_h)
+ view->redraw = 1;
+ for (size_t i = line; i < view->lines_num; i++) {
+ l = view_get_line(view, i);
+ if (l->text_dirty)
+ set_pango_text_and_highlight(view, i);
+ l->h_dirty = 0;
+ l->y_offset = off;
+ off += l->h;
+ }
+ view->total_height = off;
+ ledit_window_set_scroll_max(view->window, view->total_height);
+ view_scroll(view, view->display_offset);
+}
+
+void
+view_recalc_all_lines(ledit_view *view) {
+ /* force first line to offset 0 */
+ ledit_view_line *l = view_get_line(view, 0);
+ l->y_offset = 0;
+ view_recalc_from_line(view, 0);
+}
+
+int
+view_line_visible(ledit_view *view, size_t index) {
+ int text_w, text_h;
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
+ ledit_view_line *l = view_get_line(view, index);
+ return l->y_offset < view->display_offset + text_h &&
+ l->y_offset + l->h > view->display_offset;
+}
+
+/* FIXME: these functions are only here because they need the PangoLayouts to
+ determine grapheme boundaries. Maybe use a separate library for that? */
+size_t
+view_next_cursor_pos(ledit_view *view, size_t line, size_t byte, int num) {
+ int nattrs;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ size_t c = line_byte_to_char(ll, byte);
+ size_t cur_byte = byte;
+ PangoLayout *layout = get_pango_layout(view, line);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(layout, &nattrs);
+ if (num < 0)
+ return 0; /* FIXME: error */
+ for (size_t i = 0; i < (size_t)num; i++) {
+ cur_byte = ledit_line_next_utf8(ll, byte);
+ for (c++; c < (size_t)nattrs; c++) {
+ if (attrs[c].is_cursor_position)
+ break;
+ cur_byte = ledit_line_next_utf8(ll, cur_byte);
+ }
+ if (cur_byte >= ll->len)
+ break;
+ }
+ return cur_byte <= ll->len ? cur_byte : ll->len;
+}
+
+size_t
+view_prev_cursor_pos(ledit_view *view, size_t line, size_t byte, int num) {
+ int nattrs;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ size_t c = line_byte_to_char(ll, byte);
+ size_t cur_byte = byte;
+ PangoLayout *layout = get_pango_layout(view, line);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(layout, &nattrs);
+ if (num < 0)
+ return 0; /* FIXME: error */
+ for (int i = 0; i < num; i++) {
+ cur_byte = ledit_line_prev_utf8(ll, cur_byte);
+ for (; c > 0; c--) {
+ if (attrs[c-1].is_cursor_position)
+ break;
+ cur_byte = ledit_line_prev_utf8(ll, cur_byte);
+ }
+ if (cur_byte <= 0)
+ break;
+ }
+ return cur_byte > 0 ? cur_byte : 0;
+}
+
+static int
+line_next_word(
+ ledit_view *view,
+ size_t line, size_t byte, size_t char_index, int wrapped_line,
+ size_t *char_ret, size_t *byte_ret, size_t *real_byte_ret) {
+ int nattrs;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ int cur_byte = wrapped_line ? byte : ledit_line_next_utf8(ll, byte);
+ PangoLayout *layout = get_pango_layout(view, line);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(layout, &nattrs);
+ for (size_t i = wrapped_line ? char_index : char_index + 1; i < (size_…
+ if (attrs[i].is_word_start) {
+ *char_ret = i;
+ *real_byte_ret = cur_byte;
+ *byte_ret = cur_byte;
+ return 0;
+ }
+ cur_byte = ledit_line_next_utf8(ll, cur_byte);
+ }
+ return -1;
+}
+
+static int
+line_prev_word(
+ ledit_view *view,
+ size_t line, size_t byte, size_t char_index,
+ size_t *char_ret, size_t *byte_ret) {
+ int nattrs;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ size_t cur_byte = ledit_line_prev_utf8(ll, byte);
+ PangoLayout *layout = get_pango_layout(view, line);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(layout, &nattrs);
+ if (char_index > (size_t)nattrs)
+ return -1;
+ /* this is a bit weird because size_t can't be negative */
+ for (size_t i = char_index; i > 0; i--) {
+ if (attrs[i-1].is_word_start) {
+ *char_ret = i-1;
+ *byte_ret = cur_byte;
+ return 0;
+ }
+ cur_byte = ledit_line_prev_utf8(ll, cur_byte);
+ }
+ return -1;
+}
+
+static int
+line_prev_bigword(
+ ledit_view *view,
+ size_t line, size_t byte, size_t char_index,
+ size_t *char_ret, size_t *byte_ret) {
+ int nattrs;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ size_t cur_byte = ledit_line_prev_utf8(ll, byte);
+ PangoLayout *layout = get_pango_layout(view, line);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(layout, &nattrs);
+ size_t next_cursorb = byte;
+ size_t next_cursorc = char_index;
+ int found_word = 0;
+ /* this is a bit weird because size_t can't be negative */
+ for (size_t i = char_index; i > 0; i--) {
+ if (!found_word && !attrs[i-1].is_white) {
+ found_word = 1;
+ } else if (found_word && attrs[i-1].is_white) {
+ *char_ret = next_cursorc;
+ *byte_ret = next_cursorb;
+ return 0;
+ }
+ if (found_word && i-1 == 0) {
+ *char_ret = 0;
+ *byte_ret = 0;
+ return 0;
+ }
+ if (attrs[i-1].is_cursor_position) {
+ next_cursorc = i-1;
+ next_cursorb = cur_byte;
+ }
+ cur_byte = ledit_line_prev_utf8(ll, cur_byte);
+ }
+ return -1;
+}
+
+static int
+line_next_bigword_end(
+ ledit_view *view,
+ size_t line, size_t byte, size_t char_index, int wrapped_line,
+ size_t *char_ret, size_t *byte_ret, size_t *real_byte_ret) {
+ int nattrs;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ PangoLayout *layout = get_pango_layout(view, line);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(layout, &nattrs);
+ size_t last_cursorb = 0, last_cursorc = 0;
+ int last_cursor_valid;
+ if (wrapped_line) {
+ last_cursorb = byte;
+ last_cursorc = char_index;
+ last_cursor_valid = 1;
+ } else {
+ last_cursor_valid = 0;
+ }
+ int found_word = 0;
+ size_t cur_byte = byte;
+ for (size_t i = char_index; i < (size_t)nattrs; i++) {
+ if (last_cursor_valid && !found_word && !attrs[i].is_white) {
+ found_word = 1;
+ } else if (found_word && attrs[i].is_white) {
+ *char_ret = last_cursorc;
+ *real_byte_ret = cur_byte;
+ *byte_ret = last_cursorb;
+ return 0;
+ }
+ if (attrs[i].is_cursor_position) {
+ last_cursorc = i;
+ last_cursorb = cur_byte;
+ last_cursor_valid = 1;
+ }
+ cur_byte = ledit_line_next_utf8(ll, cur_byte);
+ }
+ return -1;
+}
+
+static int
+line_next_word_end(
+ ledit_view *view,
+ size_t line, size_t byte, size_t char_index, int wrapped_line,
+ size_t *char_ret, size_t *byte_ret, size_t *real_byte_ret) {
+ int nattrs;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ size_t cur_byte = ledit_line_next_utf8(ll, byte);
+ PangoLayout *layout = get_pango_layout(view, line);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(layout, &nattrs);
+ size_t last_cursorb = 0, last_cursorc = 0;
+ int last_cursor_valid;
+ if (wrapped_line) {
+ last_cursorb = byte;
+ last_cursorc = char_index;
+ last_cursor_valid = 1;
+ } else {
+ last_cursor_valid = 0;
+ }
+ for (size_t i = char_index + 1; i < (size_t)nattrs; i++) {
+ if (last_cursor_valid && attrs[i].is_word_end) {
+ *char_ret = last_cursorc;
+ *real_byte_ret = cur_byte;
+ *byte_ret = last_cursorb;
+ return 0;
+ }
+ if (attrs[i].is_cursor_position) {
+ last_cursorc = i;
+ last_cursorb = cur_byte;
+ last_cursor_valid = 1;
+ }
+ cur_byte = ledit_line_next_utf8(ll, cur_byte);
+ }
+ return -1;
+}
+
+static int
+line_next_bigword(
+ ledit_view *view,
+ size_t line, size_t byte, size_t char_index, int wrapped_line,
+ size_t *char_ret, size_t *byte_ret, size_t *real_byte_ret) {
+ int nattrs;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ size_t cur_byte = byte;
+ PangoLayout *layout = get_pango_layout(view, line);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(layout, &nattrs);
+ int found_ws = wrapped_line;
+ for (size_t i = char_index; i < (size_t)nattrs; i++) {
+ if (!found_ws && attrs[i].is_white) {
+ found_ws = 1;
+ } else if (found_ws && !attrs[i].is_white) {
+ *char_ret = i;
+ *real_byte_ret = cur_byte;
+ *byte_ret = cur_byte;
+ return 0;
+ }
+ cur_byte = ledit_line_next_utf8(ll, cur_byte);
+ }
+ return -1;
+}
+
+size_t
+view_line_next_non_whitespace(ledit_view *view, size_t line, size_t byte) {
+ int nattrs;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ size_t c = line_byte_to_char(ll, byte);
+ size_t cur_byte = byte;
+ PangoLayout *layout = get_pango_layout(view, line);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(layout, &nattrs);
+ for (; c < (size_t)nattrs; c++) {
+ if (!attrs[c].is_white)
+ return cur_byte;
+ cur_byte = ledit_line_next_utf8(ll, cur_byte);
+ }
+ return ll->len;
+}
+
+/* FIXME: document that word and bigword are a bit weird because word uses uni…
+
+#define GEN_NEXT_WORD(name, func) …
+void …
+view_next_##name( …
+ ledit_view *view, …
+ size_t line, size_t byte, int num_repeat, …
+ size_t *line_ret, size_t *byte_ret, size_t *real_byte_ret) { …
+ size_t cur_line = line; …
+ size_t cur_byte = byte; …
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line); …
+ size_t cur_char = line_byte_to_char(ll, byte); …
+ size_t real_byte = 0; …
+ int last_ret = -1; …
+ int wrapped_line; …
+ for (int i = 0; i < num_repeat; i++) { …
+ wrapped_line = 0; …
+ while ((last_ret = func(view, cur_line, cur_byte, cur_char, …
+ wrapped_line, &cur_char, &cur_byte, &real_byte)) == -1…
+ cur_line < view->lines_num - 1) { …
+ cur_line++; …
+ cur_byte = 0; …
+ wrapped_line = 1; …
+ } …
+ if (last_ret == -1 && cur_line == view->lines_num - 1) …
+ break; …
+ } …
+ if (last_ret == -1) { …
+ *line_ret = view->lines_num - 1; …
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, view->lin…
+ *byte_ret = view_get_legal_normal_pos(view, view->lines_num - …
+ *real_byte_ret = ll->len; …
+ } else { …
+ *line_ret = cur_line; …
+ *byte_ret = cur_byte; …
+ *real_byte_ret = real_byte; …
+ } …
+}
+
+#define GEN_PREV_WORD(name, func) …
+void …
+view_prev_##name( …
+ ledit_view *view, …
+ size_t line, size_t byte, int num_repeat, …
+ size_t *line_ret, size_t *byte_ret, size_t *real_byte_ret) { …
+ size_t cur_line = line; …
+ size_t cur_byte = byte; …
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line); …
+ size_t cur_char = line_byte_to_char(ll, byte); …
+ int last_ret = -1; …
+ for (int i = 0; i < num_repeat; i++) { …
+ while ((last_ret = func(view, cur_line, cur_byte, cur_char, …
+ &cur_char, &cur_byte)) == -1 && cur_line > 0) { …
+ cur_line--; …
+ ll = ledit_buffer_get_line(view->buffer, cur_line); …
+ cur_byte = ll->len; …
+ } …
+ if (last_ret == -1 && cur_line == 0) …
+ break; …
+ } …
+ if (last_ret == -1) { …
+ *line_ret = 0; …
+ *byte_ret = 0; …
+ *real_byte_ret = 0; …
+ } else { …
+ *line_ret = cur_line; …
+ *byte_ret = cur_byte; …
+ *real_byte_ret = cur_byte; …
+ } …
+}
+
+GEN_NEXT_WORD(word, line_next_word)
+GEN_NEXT_WORD(word_end, line_next_word_end)
+GEN_NEXT_WORD(bigword, line_next_bigword)
+GEN_NEXT_WORD(bigword_end, line_next_bigword_end)
+GEN_PREV_WORD(word, line_prev_word)
+GEN_PREV_WORD(bigword, line_prev_bigword)
+
+void
+view_get_pos_softline_bounds(
+ ledit_view *view, size_t line, size_t pos,
+ size_t *start_byte_ret, size_t *end_byte_ret) {
+ assert(line < view->lines_num);
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ assert(pos <= ll->len);
+ PangoLayout *layout = get_pango_layout(view, line);
+ int x, sli;
+ if (pos > INT_MAX)
+ err_overflow();
+ pango_layout_index_to_line_x(layout, (int)pos, 0, &sli, &x);
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(layout, sli);
+ *start_byte_ret = (size_t)pl->start_index;
+ *end_byte_ret = (size_t)(pl->start_index + pl->length);
+}
+
+void
+view_get_softline_bounds(
+ ledit_view *view, size_t line, int softline,
+ size_t *start_byte_ret, size_t *end_byte_ret) {
+ assert(line < view->lines_num);
+ ledit_view_line *vl = view_get_line(view, line);
+ PangoLayout *layout = get_pango_layout(view, line);
+ assert(softline < vl->softlines);
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(layout, softline);
+ *start_byte_ret = (size_t)pl->start_index;
+ *end_byte_ret = (size_t)(pl->start_index + pl->length);
+}
+
+int
+view_get_softline_count(ledit_view *view, size_t line) {
+ assert(line < view->lines_num);
+ ledit_view_line *vl = view_get_line(view, line);
+ if (vl->text_dirty)
+ set_pango_text_and_highlight(view, line);
+ return vl->softlines;
+}
+
+int
+view_pos_to_softline(ledit_view *view, size_t line, size_t pos) {
+ assert(line < view->lines_num);
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ assert(pos <= ll->len);
+ PangoLayout *layout = get_pango_layout(view, line);
+ int x, sli;
+ if (pos > INT_MAX)
+ err_overflow();
+ pango_layout_index_to_line_x(layout, (int)pos, 0, &sli, &x);
+ return sli;
+}
+
+void
+view_get_cursor_pixel_pos(ledit_view *view, size_t line, size_t pos, int *x_re…
+ assert(line < view->lines_num);
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ assert(pos <= ll->len);
+ PangoLayout *layout = get_pango_layout(view, line);
+ PangoRectangle strong, weak;
+ if (pos > INT_MAX)
+ err_overflow();
+ pango_layout_get_cursor_pos(layout, (int)pos, &strong, &weak);
+ *x_ret = strong.x / PANGO_SCALE;
+ *y_ret = strong.y / PANGO_SCALE;
+ *h_ret = strong.height / PANGO_SCALE;
+}
+
+/* prev_index_ret is used instead of just calling get_legal_normal_pos
+ because weird things happen otherwise
+ -> in certain cases, this is still weird because prev_index_ret sometimes
+ is not at the end of the line, but this is the best I could come up
+ with for now */
+size_t
+view_move_cursor_visually(ledit_view *view, size_t line, size_t pos, int movem…
+ if (pos > INT_MAX)
+ err_overflow();
+ /* FIXME: trailing */
+ int trailing = 0;
+ ledit_line *cur_line = ledit_buffer_get_line(view->buffer, line);
+ PangoLayout *layout = get_pango_layout(view, line);
+ int tmp_index;
+ int new_index = (int)pos, last_index = (int)pos;
+ int dir = 1;
+ int num = movement;
+ if (movement < 0) {
+ dir = -1;
+ num = -movement;
+ }
+ /* FIXME: This is stupid. Anything outside the range of int won't work
+ anyways because of pango (and because everything else would break
+ anyways with such long lines), so it's stupid to do all this weird
+ casting. */
+ if (cur_line->len > INT_MAX)
+ err_overflow();
+ while (num > 0) {
+ tmp_index = new_index;
+ pango_layout_move_cursor_visually(
+ layout, TRUE,
+ new_index, trailing, dir,
+ &new_index, &trailing
+ );
+ /* for some reason, this is necessary */
+ if (new_index < 0)
+ new_index = 0;
+ else if (new_index > (int)cur_line->len)
+ new_index = (int)cur_line->len;
+ num--;
+ if (tmp_index != new_index)
+ last_index = tmp_index;
+ }
+ /* 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 */
+ /* FIXME: spaces at end of softlines are weird in normal mode */
+ while (trailing > 0) {
+ trailing--;
+ new_index = ledit_line_next_utf8(cur_line, new_index);
+ }
+ if (new_index < 0)
+ new_index = 0;
+ if (prev_index_ret)
+ *prev_index_ret = (size_t)last_index;
+ return (size_t)new_index;
+}
+
+/* FIXME: implement */
+/*
+int
+ledit_line_nearest_cursor_pos(ledit_line *line, int byte) {
+}
+
+void
+ledit_line_word_boundaries(ledit_line *line, int byte, int *start_ret, int *en…
+}
+*/
+
+static void
+set_pango_text_and_highlight(ledit_view *view, size_t line) {
+ cache_layout *cl;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ ledit_view_line *vl = view_get_line(view, line);
+ char old_valid = vl->cache_layout_valid;
+ if (!vl->cache_layout_valid) {
+ cache_assign_layout_index(
+ view->cache, line,
+ view, &set_layout_line_helper, &invalidate_layout_line_hel…
+ );
+ cl = cache_get_layout(view->cache, vl->cache_layout_index);
+ } else {
+ cl = cache_get_layout(view->cache, vl->cache_layout_index);
+ }
+ if (cl->layout == NULL) {
+ cl->layout = pango_layout_new(view->window->context);
+ pango_layout_set_font_description(cl->layout, view->window->fo…
+ pango_layout_set_wrap(cl->layout, PANGO_WRAP_WORD_CHAR);
+ }
+ if (vl->text_dirty || !old_valid) {
+ ledit_buffer_normalize_line(ll);
+ if (ll->len > INT_MAX)
+ err_overflow();
+ pango_layout_set_text(cl->layout, ll->text, (int)ll->len);
+ set_line_layout_attrs(view, line, cl->layout);
+ /* FIXME: is this guard necessary? */
+ vl->softlines = ll->len > 0 ? pango_layout_get_line_count(cl->…
+ pango_layout_set_width(cl->layout, vl->w * PANGO_SCALE);
+ int w, h;
+ pango_layout_get_pixel_size(cl->layout, &w, &h);
+ if (h != vl->h) {
+ vl->h = h;
+ vl->h_dirty = 1;
+ }
+ vl->text_dirty = 0;
+ vl->dirty = 1;
+ } else if (vl->highlight_dirty) {
+ set_line_layout_attrs(view, line, cl->layout);
+ }
+ vl->highlight_dirty = 0;
+}
+
+static PangoLayout *
+get_pango_layout(ledit_view *view, size_t line) {
+ set_pango_text_and_highlight(view, line);
+ ledit_view_line *vl = view_get_line(view, line);
+ cache_layout *cl = cache_get_layout(
+ view->cache, vl->cache_layout_index
+ );
+ return cl->layout;
+}
+
+/* FIXME: document what works with pango units and what not */
+void
+ledit_pos_to_x_softline(ledit_view *view, size_t line, size_t pos, int *x_ret,…
+ ledit_view_line *vl = view_get_line(view, line);
+ PangoLayout *layout = get_pango_layout(view, line);
+ if (pos > INT_MAX)
+ err_overflow();
+ pango_layout_index_to_line_x(layout, (int)pos, 0, softline_ret, x_ret);
+ PangoLayoutLine *pango_line = pango_layout_get_line_readonly(layout, *…
+ /* 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 += (vl->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? */
+ /* FIXME: this is too much magic for my taste */
+ if (view->mode == NORMAL) {
+ PangoRectangle rect;
+ pango_layout_index_to_pos(layout, (int)pos, &rect);
+ *x_ret += rect.width / 2;
+ }
+}
+
+/* FIXME: change this to return pos_ret directly */
+void
+ledit_x_softline_to_pos(ledit_view *view, size_t line, int x, int softline, si…
+ int trailing = 0;
+ int x_relative = x;
+ ledit_view_line *vl = view_get_line(view, line);
+ PangoLayout *layout = get_pango_layout(view, line);
+ PangoLayoutLine *pango_line =
+ pango_layout_get_line_readonly(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 -= (vl->w * PANGO_SCALE - rect.width);
+ }
+ int tmp_pos;
+ pango_layout_line_x_to_index(
+ pango_line, x_relative, &tmp_pos, &trailing
+ );
+ *pos_ret = (size_t)tmp_pos;
+ /* if in insert mode, snap to the nearest border between graphemes */
+ /* FIXME: add parameter for this instead of checking mode */
+ if (view->mode == INSERT) {
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ while (trailing > 0) {
+ trailing--;
+ *pos_ret = ledit_line_next_utf8(ll, *pos_ret);
+ }
+ }
+}
+
+size_t
+view_get_legal_normal_pos(ledit_view *view, size_t line, size_t pos) {
+ /* move back one grapheme if at end of line */
+ size_t ret = pos;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line);
+ if (pos == ll->len && pos > 0) {
+ int nattrs;
+ PangoLayout *layout = get_pango_layout(view, line);
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(layout, &nattrs);
+ if (nattrs < 2)
+ return 0;
+ size_t cur = nattrs - 2;
+ ret = ledit_line_prev_utf8(ll, ret);
+ while (ret > 0 && cur > 0 && !attrs[cur].is_cursor_position) {
+ cur--;
+ ret = ledit_line_prev_utf8(ll, ret);
+ }
+ }
+ return ret;
+}
+
+void
+view_delete_range(
+ ledit_view *view, enum delete_mode delmode,
+ size_t line_index1, size_t byte_index1,
+ size_t line_index2, size_t byte_index2,
+ size_t *new_line_ret, size_t *new_byte_ret,
+ ledit_range *final_range_ret, txtbuf *text_ret) {
+ view_delete_range_base(
+ view, delmode,
+ line_index1, byte_index1,
+ line_index2, byte_index2,
+ new_line_ret, new_byte_ret,
+ final_range_ret, text_ret
+ );
+ /* need to start recalculating one line before in case first
+ line was deleted and offset is now wrong */
+ size_t min = line_index1 < line_index2 ? line_index1 : line_index2;
+ /* FIXME: a bit ugly to do this here */
+ for (size_t i = 0; i < view->buffer->views_num; i++) {
+ ledit_buffer_recalc_all_views_from_line(
+ view->buffer, min > 0 ? min - 1 : min
+ );
+ }
+}
+
+/* Note: line_index* and byte_index* don't need to be sorted */
+/* line_index1, byte_index1 are used as the cursor position in order
+ to determine the new cursor position */
+/* FIXME: use at least somewhat sensible variable names */
+/* FIXME: I once noticed a bug where using 'dG' to delete to the end of
+ the file caused a line index way larger than buffer->lines_num to be
+ given, but I couldn't reproduce this bug */
+void
+view_delete_range_base(
+ ledit_view *view, enum delete_mode delmode,
+ size_t line_index1, size_t byte_index1,
+ size_t line_index2, size_t byte_index2,
+ size_t *new_line_ret, size_t *new_byte_ret,
+ ledit_range *final_range_ret, txtbuf *text_ret) {
+ /* FIXME: Oh boy, this is nasty */
+ /* range line x, range byte x */
+ size_t rgl1 = 0, rgb1 = 0, rgl2 = 0, rgb2 = 0;
+ size_t new_line = 0, new_byte = 0;
+ assert(line_index1 < view->lines_num);
+ assert(line_index2 < view->lines_num);
+ /* FIXME: could this be simplified by just calculating the range and t…
+ the non-line-based version? */
+ if (delmode == DELETE_HARDLINE) {
+ int x, sl_useless;
+ size_t l1 = line_index1, l2 = line_index2;
+ if (line_index1 > line_index2) {
+ l1 = line_index2;
+ l2 = line_index1;
+ }
+ size_t dell1 = l1, dell2 = l2;
+ ledit_line *ll = ledit_buffer_get_line(view->buffer, line_inde…
+ ledit_pos_to_x_softline(view, line_index1, byte_index1, &x, &s…
+ if (l1 > 0 && l2 < view->lines_num - 1) {
+ rgl1 = l1;
+ rgb1 = 0;
+ rgl2 = l2 + 1;
+ rgb2 = 0;
+ } else if (l1 > 0) {
+ rgl1 = l1 - 1;
+ ll = ledit_buffer_get_line(view->buffer, rgl1);
+ rgb1 = ll->len;
+ rgl2 = l2;
+ ll = ledit_buffer_get_line(view->buffer, rgl2);
+ rgb2 = ll->len;
+ } else if (l2 < view->lines_num - 1) {
+ rgl1 = l1;
+ rgb1 = 0;
+ rgl2 = l2 + 1;
+ rgb2 = 0;
+ } else {
+ rgl1 = l1;
+ rgb1 = 0;
+ rgl2 = l2;
+ ll = ledit_buffer_get_line(view->buffer, rgl2);
+ rgb2 = ll->len;
+ }
+ if (text_ret) {
+ ledit_buffer_copy_text_to_txtbuf(
+ view->buffer, text_ret,
+ rgl1, rgb1, rgl2, rgb2
+ );
+ }
+ /* default is dell1 = l1, dell2 = l2 */
+ if (l2 < view->lines_num - 1) {
+ new_line = l1;
+ ledit_x_softline_to_pos(
+ view, l2 + 1,
+ x, 0, &new_byte
+ );
+ } else if (l1 > 0) {
+ new_line = l1 - 1;
+ ledit_x_softline_to_pos(
+ view, l1 - 1,
+ x, 0, &new_byte
+ );
+ } else {
+ dell1 = l1 + 1;
+ dell2 = l2;
+ new_line = l1;
+ new_byte = 0;
+ /* happens when all lines are deleted, so one line has…
+ ll = ledit_buffer_get_line(view->buffer, l1);
+ ledit_buffer_delete_line_section_base(
+ view->buffer, l1, 0, ll->len
+ );
+ }
+ if (dell1 <= dell2) {
+ ledit_buffer_delete_line_entries_base(view->buffer, de…
+ }
+ } else if (delmode == DELETE_SOFTLINE) {
+ int x, softline1, softline2;
+ ledit_line *line1 = ledit_buffer_get_line(view->buffer, line_i…
+ ledit_view_line *vline1 = view_get_line(view, line_index1);
+ ledit_pos_to_x_softline(view, line_index1, byte_index1, &x, &s…
+ if (line_index1 == line_index2) {
+ int x_useless;
+ PangoLayout *layout = get_pango_layout(view, line_inde…
+ pango_layout_index_to_line_x(layout, byte_index2, 0, &…
+ int l1 = softline1 < softline2 ? softline1 : softline2;
+ int l2 = softline1 < softline2 ? softline2 : softline1;
+ PangoLayoutLine *pl1 = pango_layout_get_line_readonly(…
+ PangoLayoutLine *pl2 = pango_layout_get_line_readonly(…
+ /* don't delete entire line if it is the last one rema…
+ if (l1 == 0 && l2 == vline1->softlines - 1 && view->li…
+ if (line_index1 < view->lines_num - 1) {
+ /* cursor can be moved to next hard li…
+ new_line = line_index1;
+ size_t tmp_byte;
+ ledit_x_softline_to_pos(
+ view, line_index1 + 1,
+ x, 0, &tmp_byte
+ );
+ new_byte = (size_t)tmp_byte;
+ rgl1 = line_index1;
+ rgb1 = 0;
+ rgl2 = line_index1 + 1;
+ rgb2 = 0;
+ } else {
+ /* cursor has to be be moved to previo…
+ because last line in buffer is dele…
+ /* note: logically, line_index1 - 1 mu…
+ view->lines_num > 1 && line_index1 …
+ new_line = line_index1 - 1;
+ ledit_line *prevline = ledit_buffer_ge…
+ ledit_view_line *vprevline = view_get_…
+ if (vprevline->text_dirty)
+ set_pango_text_and_highlight(v…
+ ledit_x_softline_to_pos(view, new_line…
+ rgl1 = line_index1 - 1;
+ rgb1 = prevline->len;
+ rgl2 = line_index1;
+ rgb2 = line1->len;
+ }
+ if (text_ret) {
+ ledit_buffer_copy_text_to_txtbuf(
+ view->buffer, text_ret,
+ rgl1, rgb1,
+ rgl2, rgb2
+ );
+ }
+ ledit_buffer_delete_line_entry_base(view->buff…
+ } else {
+ assert(pl2->start_index + pl2->length >= pl1->…
+ rgl1 = rgl2 = line_index1;
+ rgb1 = (size_t)pl1->start_index;
+ rgb2 = (size_t)(pl2->start_index + pl2->length…
+ if (text_ret) {
+ ledit_buffer_copy_text_to_txtbuf(
+ view->buffer, text_ret,
+ rgl1, rgb1,
+ rgl2, rgb2
+ );
+ }
+ ledit_buffer_delete_line_section_base(
+ view->buffer, line_index1, rgb1, rgb2 - rg…
+ );
+ if (l2 == vline1->softlines - 1 && line_index1…
+ new_line = line_index1 + 1;
+ size_t tmp_byte;
+ ledit_x_softline_to_pos(
+ view, line_index1 + 1,
+ x, 0, &tmp_byte
+ );
+ new_byte = (size_t)tmp_byte;
+ } else if (l2 < vline1->softlines - 1) {
+ new_line = line_index1;
+ size_t tmp_byte;
+ ledit_x_softline_to_pos(
+ view, line_index1,
+ x, l1, &tmp_byte
+ );
+ new_byte = (size_t)tmp_byte;
+ } else if (l1 > 0) {
+ new_line = line_index1;
+ size_t tmp_byte;
+ ledit_x_softline_to_pos(
+ view, line_index1,
+ x, l1 - 1, &tmp_byte
+ );
+ new_byte = (size_t)tmp_byte;
+ } else {
+ /* the line has been emptied and is th…
+ new_line = 0;
+ new_byte = 0;
+ }
+ }
+ } else {
+ int x_useless, sl1, sl2;
+ size_t 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_buffer_get_line(view->buffer, …
+ ledit_line *ll2 = ledit_buffer_get_line(view->buffer, …
+ ledit_view_line *vl1 = view_get_line(view, l1);
+ ledit_view_line *vl2 = view_get_line(view, l2);
+ PangoLayout *layout1 = get_pango_layout(view, l1);
+ PangoLayout *layout2 = get_pango_layout(view, l2);
+ pango_layout_index_to_line_x(layout1, b1, 0, &sl1, &x_…
+ pango_layout_index_to_line_x(layout2, b2, 0, &sl2, &x_…
+ PangoLayoutLine *pl1 = pango_layout_get_line_readonly(…
+ PangoLayoutLine *pl2 = pango_layout_get_line_readonly(…
+ if (sl1 == 0 && sl2 == vl2->softlines - 1) {
+ if (l1 == 0 && l2 == view->lines_num - 1) {
+ rgl1 = l1;
+ rgl2 = l2;
+ rgb1 = 0;
+ rgb2 = ll2->len;
+ if (text_ret) {
+ ledit_buffer_copy_text_to_txtb…
+ view->buffer, text_ret,
+ rgl1, rgb1,
+ rgl2, rgb2
+ );
+ }
+ ledit_buffer_delete_line_section_base(…
+ ledit_buffer_delete_line_entries_base(…
+ new_line = 0;
+ new_byte = 0;
+ } else {
+ if (l2 == view->lines_num - 1) {
+ new_line = l1 - 1;
+ ledit_line *new_lline = ledit_…
+ ledit_view_line *new_vline = v…
+ if (new_vline->text_dirty)
+ set_pango_text_and_hig…
+ ledit_x_softline_to_pos(view, …
+ rgl1 = l1 - 1;
+ rgb1 = new_lline->len;
+ rgl2 = l2;
+ rgb2 = ll2->len;
+ } else {
+ new_line = l1;
+ ledit_x_softline_to_pos(
+ view, l2 + 1, x, 0, &new_b…
+ );
+ rgl1 = l1;
+ rgb1 = 0;
+ rgl2 = l2 + 1;
+ rgb2 = 0;
+ }
+ if (text_ret) {
+ ledit_buffer_copy_text_to_txtb…
+ view->buffer, text_ret,
+ rgl1, rgb1,
+ rgl2, rgb2
+ );
+ }
+ ledit_buffer_delete_line_entries_base(…
+ }
+ } else if (sl1 == 0) {
+ rgl1 = l1;
+ rgb1 = 0;
+ rgl2 = l2;
+ rgb2 = (size_t)(pl2->start_index + pl2->length…
+ if (text_ret) {
+ ledit_buffer_copy_text_to_txtbuf(
+ view->buffer, text_ret,
+ rgl1, rgb1,
+ rgl2, rgb2
+ );
+ }
+ ledit_buffer_delete_line_section_base(view->bu…
+ new_line = l1;
+ ledit_x_softline_to_pos(view, l2, x, 0, &new_b…
+ ledit_buffer_delete_line_entries_base(view->bu…
+ } else if (sl2 == vl2->softlines - 1) {
+ rgl1 = l1;
+ rgb1 = (size_t)pl1->start_index;
+ rgl2 = l2;
+ rgb2 = ll2->len;
+ if (l2 + 1 == view->lines_num) {
+ new_line = l1;
+ ledit_x_softline_to_pos(view, l1, x, s…
+ } else {
+ new_line = l1 + 1;
+ ledit_x_softline_to_pos(
+ view, l2 + 1,
+ x, 0, &new_byte
+ );
+ }
+ if (text_ret) {
+ ledit_buffer_copy_text_to_txtbuf(
+ view->buffer, text_ret,
+ rgl1, rgb1,
+ rgl2, rgb2
+ );
+ }
+ ledit_buffer_delete_line_section_base(view->bu…
+ ledit_buffer_delete_line_entries_base(view->bu…
+ } else {
+ /* FIXME: this could be made nicer by just usi…
+ delete all in one go at the end */
+ rgl1 = l1;
+ rgb1 = (size_t)pl1->start_index;
+ rgl2 = l2;
+ rgb2 = (size_t)(pl2->start_index + pl2->length…
+ if (text_ret) {
+ ledit_buffer_copy_text_to_txtbuf(
+ view->buffer, text_ret,
+ rgl1, rgb1,
+ rgl2, rgb2
+ );
+ }
+ ledit_buffer_delete_line_section_base(view->bu…
+ ledit_buffer_insert_text_from_line_base(
+ view->buffer,
+ l1, rgb1, l2, rgb2,
+ ll2->len - rgb2, NULL
+ );
+ ledit_buffer_delete_line_entries_base(view->bu…
+ new_line = l1;
+ set_pango_text_and_highlight(view, l1);
+ /* it's technically possible that the remainin…
+ second line is so small that it doesn't gen…
+ softline, so there needs to be a special ca…
+ a bit weird because the cursor will seem to…
+ same line, but it now includes the rest of …
+ (FIXME: this is probably not the best thing…
+ ledit_x_softline_to_pos(
+ view, l1, x, sl1 + 1 < vl1->softlines ? sl…
+ );
+ }
+ }
+ } else {
+ if (line_index1 == line_index2) {
+ rgl1 = rgl2 = line_index1;
+ if (byte_index1 < byte_index2) {
+ rgb1 = byte_index1;
+ rgb2 = byte_index2;
+ } else {
+ rgb1 = byte_index2;
+ rgb2 = byte_index1;
+ }
+ if (text_ret) {
+ ledit_buffer_copy_text_to_txtbuf(
+ view->buffer, text_ret,
+ rgl1, rgb1,
+ rgl2, rgb2
+ );
+ }
+ ledit_buffer_delete_line_section_base(view->buffer, li…
+ new_line = line_index1;
+ new_byte = rgb1;
+ } else {
+ if (line_index1 < line_index2) {
+ rgl1 = line_index1;
+ rgb1 = byte_index1;
+ rgl2 = line_index2;
+ rgb2 = byte_index2;
+ } else {
+ rgl1 = line_index2;
+ rgb1 = byte_index2;
+ rgl2 = line_index1;
+ rgb2 = byte_index1;
+ }
+ if (text_ret) {
+ ledit_buffer_copy_text_to_txtbuf(
+ view->buffer, text_ret,
+ rgl1, rgb1,
+ rgl2, rgb2
+ );
+ }
+ ledit_line *line1 = ledit_buffer_get_line(view->buffer…
+ ledit_line *line2 = ledit_buffer_get_line(view->buffer…
+ ledit_buffer_delete_line_section_base(view->buffer, rg…
+ ledit_buffer_insert_text_from_line_base(
+ view->buffer, rgl1, rgb1, rgl2, rgb2, line2->len -…
+ );
+ new_line = rgl1;
+ new_byte = rgb1;
+ ledit_buffer_delete_line_entries_base(view->buffer, rg…
+ }
+ /* FIXME: too much magic - maybe don't include this here */
+ if (view->mode == NORMAL)
+ new_byte = view_get_legal_normal_pos(view, new_line, n…
+ }
+ if (final_range_ret) {
+ final_range_ret->line1 = rgl1;
+ final_range_ret->byte1 = rgb1;
+ final_range_ret->line2 = rgl2;
+ final_range_ret->byte2 = rgb2;
+ }
+ if (new_line_ret)
+ *new_line_ret = new_line;
+ if (new_byte_ret)
+ *new_byte_ret = new_byte;
+}
+
+/* FIXME: any way to make this more efficient? */
+void
+view_resize_textview(void *data) {
+ ledit_view *view = (ledit_view *)data;
+ view->total_height = 0;
+ int text_w, text_h;
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
+ for (size_t i = 0; i < view->lines_num; i++) {
+ ledit_view_line *line = view_get_line(view, i);
+ line->w = text_w;
+ line->text_dirty = 1; /* it's a bit weird to set this, it shou…
+ set_pango_text_and_highlight(view, i);
+ line->y_offset = view->total_height;
+ line->dirty = 1;
+ line->h_dirty = 0;
+ view->total_height += line->h;
+ }
+ ledit_window_set_scroll_max(view->window, view->total_height);
+ if (view->display_offset > 0 &&
+ view->display_offset + text_h > view->total_height) {
+ view_scroll(view, view->total_height - text_h);
+ }
+}
+
+void
+view_scroll(ledit_view *view, long new_offset) {
+ int text_w, text_h;
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
+ if (new_offset + text_h > view->total_height)
+ new_offset = view->total_height - text_h;
+ if (new_offset < 0)
+ new_offset = 0;
+ view->display_offset = new_offset;
+ ledit_window_set_scroll_pos(view->window, view->display_offset);
+}
+
+/* FIXME: there's gotta be a better/more efficient way to do this... */
+/* FIXME: make sure h_dirty is not set here */
+void
+view_get_nearest_legal_pos(
+ ledit_view *view,
+ size_t line, size_t byte,
+ /*int snap_to_nearest, int snap_middle, FIXME: take these parameters */
+ size_t *line_ret, size_t *byte_ret) {
+ PangoRectangle strong, weak;
+ int text_w, text_h;
+ int x, sl_useless;
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
+ ledit_view_line *vline = view_get_line(view, line);
+ PangoLayout *layout = get_pango_layout(view, line);
+ if (byte > INT_MAX)
+ err_overflow();
+ pango_layout_get_cursor_pos(layout, (int)byte, &strong, &weak);
+ ledit_pos_to_x_softline(view, line, byte, &x, &sl_useless);
+ long cursor_y = strong.y / PANGO_SCALE + vline->y_offset;
+ PangoRectangle ink, log;
+ if (cursor_y < view->display_offset) {
+ /* search for the hard line covering the top of the screen */
+ size_t hline = line;
+ while (vline->y_offset + vline->h <= view->display_offset && h…
+ vline = view_get_line(view, ++hline);
+ }
+ /* the current hard line is now the one at the very top of the…
+ layout = get_pango_layout(view, hline);
+ int num_sl = vline->softlines;
+ 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(layout, i);
+ if (cur_y_off + vline->y_offset >= view->display_offse…
+ 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(view, hline, x, sl_index, byte…
+ } else if (hline < view->lines_num - 1) {
+ /* need to move to next hard line */
+ *line_ret = hline + 1;
+ ledit_x_softline_to_pos(view, hline + 1, x, 0, byte_re…
+ } 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(view, hline, x, num_sl - 1, by…
+ }
+ } else if (cursor_y + strong.height / PANGO_SCALE >
+ view->display_offset + text_h) {
+ /* search for the hard line covering the bottom of the screen …
+ size_t hline = line;
+ while (vline->y_offset > view->display_offset + text_h && hlin…
+ vline = view_get_line(view, --hline);
+ }
+ /* the current hard line is now the one at the very bottom of …
+ layout = get_pango_layout(view, hline);
+ int num_sl = vline->softlines;
+ 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(layout, i);
+ if (vline->y_offset + vline->h - cur_y_off < view->dis…
+ 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(view, hline, x, sl_index, byte…
+ } else if (hline > 0) {
+ /* need to move to previous hard line */
+ *line_ret = hline - 1;
+ vline = view_get_line(view, hline - 1);
+ num_sl = vline->softlines;
+ ledit_x_softline_to_pos(view, hline - 1, x, num_sl - 1…
+ } 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(view, hline, x, 0, byte_ret);
+ }
+ }
+}
+
+void
+ledit_xy_to_line_byte(ledit_view *view, int x, int y, int snap_to_nearest, siz…
+ /* FIXME: store current line offset to speed this up */
+ /* FIXME: use y_offset in lines */
+ long h = 0;
+ long pos = view->display_offset + y;
+ for (size_t i = 0; i < view->lines_num; i++) {
+ ledit_view_line *vline = view_get_line(view, i);
+ if ((h <= pos && h + vline->h > pos) || i == view->lines_num -…
+ int index, trailing;
+ PangoLayout *layout = get_pango_layout(view, i);
+ /* FIXME: what if i == view->lines_num - 1 but pos - h…
+ pango_layout_xy_to_index(
+ layout,
+ x * PANGO_SCALE, (int)(pos - h) * PANGO_SCALE,
+ &index, &trailing
+ );
+ *byte_ret = (size_t)index;
+ if (snap_to_nearest) {
+ ledit_line *ll = ledit_buffer_get_line(view->b…
+ while (trailing > 0) {
+ trailing--;
+ *byte_ret = ledit_line_next_utf8(ll, *…
+ }
+ }
+ *line_ret = i;
+ break;
+ }
+ h += vline->h;
+ }
+}
+
+static void
+scroll_to_pos(ledit_view *view, size_t line, size_t byte, int top) {
+ PangoRectangle strong, weak;
+ int text_w, text_h;
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
+ ledit_view_line *vl = view_get_line(view, line);
+ PangoLayout *layout = get_pango_layout(view, line);
+ if (byte > INT_MAX)
+ err_overflow();
+ pango_layout_get_cursor_pos(layout, (int)byte, &strong, &weak);
+ long cursor_y = strong.y / PANGO_SCALE + vl->y_offset;
+ if (top) {
+ view_scroll(view, cursor_y);
+ } else {
+ view_scroll(view, cursor_y - text_h + strong.height / PANGO_SC…
+ }
+}
+
+void
+view_scroll_to_pos_top(ledit_view *view, size_t line, size_t byte) {
+ scroll_to_pos(view, line, byte, 1);
+}
+
+void
+view_scroll_to_pos_bottom(ledit_view *view, size_t line, size_t byte) {
+ scroll_to_pos(view, line, byte, 0);
+}
+
+void
+view_ensure_cursor_shown(ledit_view *view) {
+ PangoRectangle strong, weak;
+ int text_w, text_h;
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
+ ledit_view_line *vline = view_get_line(view, view->cur_line);
+ PangoLayout *layout = get_pango_layout(view, view->cur_line);
+ if (view->cur_index > INT_MAX)
+ err_overflow();
+ pango_layout_get_cursor_pos(
+ layout, (int)view->cur_index, &strong, &weak
+ );
+ long cursor_y = strong.y / PANGO_SCALE + vline->y_offset;
+ if (cursor_y < view->display_offset) {
+ view_scroll(view, cursor_y);
+ } else if (cursor_y + strong.height / PANGO_SCALE >
+ view->display_offset + text_h) {
+ view_scroll(view, cursor_y - text_h + strong.height / PANGO_SC…
+ }
+}
+
+static void
+swap_sz(size_t *a, size_t *b) {
+ size_t tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
+/* FIXME: this is generic, so it doesn't need to be in view.c */
+void
+view_sort_selection(size_t *line1, size_t *byte1, size_t *line2, size_t *byte2…
+ if (*line1 > *line2) {
+ swap_sz(line1, line2);
+ swap_sz(byte1, byte2);
+ } else if (*line1 == *line2 && *byte1 > *byte2) {
+ swap_sz(byte1, byte2);
+ }
+}
+
+/* FIXME: don't reset selection when selection is clicked away */
+/* FIXME: when selecting with mouse, only call this when button is released */
+/* lines and bytes need to be sorted already! */
+static void
+copy_selection_to_x_primary(ledit_view *view, size_t line1, size_t byte1, size…
+ /* FIXME: let window handle this */
+ txtbuf *primary = ledit_window_get_primary_clipboard_buffer();
+ ledit_buffer_copy_text_to_txtbuf(view->buffer, primary, line1, byte1, …
+ XSetSelectionOwner(view->buffer->common->dpy, XA_PRIMARY, view->window…
+ /*
+ FIXME
+ if (XGetSelectionOwner(state.dpy, XA_PRIMARY) != state.win)
+ selclear();
+ */
+}
+
+void
+view_wipe_selection(ledit_view *view) {
+ if (view->sel_valid) {
+ if (view->sel.line1 > view->sel.line2)
+ swap_sz(&view->sel.line1, &view->sel.line2);
+ for (size_t i = view->sel.line1; i <= view->sel.line2; i++) {
+ view_wipe_line_cursor_attrs(view, i);
+ }
+ }
+ view->sel_valid = 0;
+ view->sel.line1 = view->sel.line2 = 0;
+ view->sel.byte1 = view->sel.byte2 = 0;
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
+}
+
+void
+view_set_selection(ledit_view *view, size_t line1, size_t byte1, size_t line2,…
+ if (view->sel_valid &&
+ line1 == view->sel.line1 && line2 == view->sel.line2 &&
+ byte1 == view->sel.byte1 && byte2 == view->sel.byte2) {
+ return;
+ }
+ size_t l1_new = line1, l2_new = line2;
+ size_t b1_new = byte1, b2_new = byte2;
+ view_sort_selection(&l1_new, &b1_new, &l2_new, &b2_new);
+ view_sort_selection(&view->sel.line1, &view->sel.byte1, &view->sel.lin…
+ /* FIXME: make this a bit nicer and optimize it */
+ if (view->sel.line1 > l2_new || view->sel.line2 < l1_new) {
+ for (size_t i = view->sel.line1; i <= view->sel.line2; i++) {
+ view_wipe_line_cursor_attrs(view, i);
+ }
+ } else {
+ for (size_t i = view->sel.line1; i < l1_new; i++) {
+ view_wipe_line_cursor_attrs(view, i);
+ }
+ for (size_t i = view->sel.line2; i > l2_new; i--) {
+ view_wipe_line_cursor_attrs(view, i);
+ }
+ }
+ for (size_t i = l1_new; i <= l2_new; i++) {
+ /* only change the ones that were not already selected */
+ if (i <= view->sel.line1 || i >= view->sel.line2) {
+ ledit_view_line *vl = view_get_line(view, i);
+ vl->highlight_dirty = 1;
+ }
+ }
+ if (l1_new != l2_new || b1_new != b2_new)
+ copy_selection_to_x_primary(view, l1_new, b1_new, l2_new, b2_n…
+ view->sel.line1 = line1;
+ view->sel.byte1 = byte1;
+ view->sel.line2 = line2;
+ view->sel.byte2 = byte2;
+ view->sel_valid = 1;
+}
+
+void
+view_scroll_handler(void *view, long pos) {
+ ((ledit_view *)view)->display_offset = pos;
+}
+
+void
+view_button_handler(void *data, XEvent *event) {
+ size_t l, b;
+ ledit_view *view= (ledit_view *)data;
+ int x = event->xbutton.x;
+ int y = event->xbutton.y;
+ int snap;
+ switch (event->type) {
+ case ButtonPress:
+ snap = view->mode == NORMAL ? 0 : 1;
+ ledit_xy_to_line_byte(view, x, y, snap, &l, &b);
+ view->selecting = 1;
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ view->cur_line = l;
+ view->cur_index = b;
+ /* don't set selection yet because the mouse may not be
+ dragged, so we don't want to switch to visual (this
+ allows setting just the cursor position in normal mode
+ without always switching to visual) */
+ if (view->mode == NORMAL)
+ view_set_line_cursor_attrs(view, l, b);
+ else if (view->mode == VISUAL)
+ view_set_selection(view, l, b, l, b);
+ break;
+ case ButtonRelease:
+ view->selecting = 0;
+ break;
+ case MotionNotify:
+ if (view->selecting) {
+ y = y >= 0 ? y : 0;
+ ledit_xy_to_line_byte(view, x, y, 1, &l, &b);
+ if (view->mode == NORMAL) {
+ view_wipe_line_cursor_attrs(view, view->cur_li…
+ /* FIXME: return to old mode afterwards? */
+ /* should change_mode_group even be called her…
+ view_set_mode(view, VISUAL);
+ }
+ if (!view->sel_valid) {
+ /* the selection has just started, so the curr…
+ position is already set to the beginning of…
+ selection (see case ButtonPress above) */
+ view_set_selection(
+ view,
+ view->cur_line, view->cur_index, l, b
+ );
+ } else {
+ view_set_selection(
+ view,
+ view->sel.line1, view->sel.byte1, l, b
+ );
+ }
+ view->cur_line = l;
+ view->cur_index = b;
+ }
+ break;
+ }
+}
+
+static void
+view_redraw_text(ledit_view *view) {
+ int h = 0;
+ int cur_line_y = 0;
+ int cursor_displayed = 0;
+ int text_w, text_h;
+ ledit_window_get_textview_size(view->window, &text_w, &text_h);
+ for (size_t i = 0; i < view->lines_num; i++) {
+ ledit_view_line *vline = view_get_line(view, i);
+ if (h + vline->h > view->display_offset) {
+ /* FIXME: vline->text_dirty should not happen here */
+ if (vline->text_dirty || vline->highlight_dirty)
+ set_pango_text_and_highlight(view, i);
+ if (vline->dirty || !vline->cache_pixmap_valid) {
+ view_render_line(view, i);
+ }
+ int final_y = 0;
+ int dest_y = h - view->display_offset;
+ int final_h = vline->h;
+ if (h < view->display_offset) {
+ dest_y = 0;
+ final_y = view->display_offset - h;
+ final_h -= view->display_offset - h;
+ }
+ if (dest_y + final_h > text_h) {
+ final_h -= final_y + final_h -
+ view->display_offset - text_h;
+ }
+ cache_pixmap *pix = cache_get_pixmap(
+ view->cache, vline->cache_pixmap_index
+ );
+ XCopyArea(
+ view->buffer->common->dpy, pix->pixmap,
+ view->window->drawable, view->window->gc,
+ 0, final_y, vline->w, final_h, 0, dest_y
+ );
+ if (i == view->cur_line) {
+ cur_line_y = h - view->display_offset;
+ cursor_displayed = 1;
+ }
+ if (h + vline->h >= view->display_offset + text_h)
+ break;
+ }
+ h += vline->h;
+ }
+
+ XSetForeground(view->buffer->common->dpy, view->window->gc, view->them…
+ PangoRectangle strong, weak;
+ ledit_line *cur_line = ledit_buffer_get_line(view->buffer, view->cur_l…
+ PangoLayout *layout = get_pango_layout(view, view->cur_line);
+ pango_layout_get_cursor_pos(
+ layout, (int)view->cur_index, &strong, &weak
+ );
+ /* FIXME: long, int, etc. */
+ int cursor_y = strong.y / PANGO_SCALE + cur_line_y;
+ if (cursor_displayed && cursor_y >= 0) {
+ if (view->mode == NORMAL) {
+ /* FIXME: figure out if there's a better way to do thi…
+ /* Seriously, which of the pango folks though it would…
+ not highlight spaces at the end of soft lines? That…
+ horrible idea. Or am I just too stupid to use it pr…
+ /* FIXME: properly document what is happening here */
+
+ int box_x = strong.x / PANGO_SCALE;
+ int box_w = 10;
+ /* determine where the box should be drawn */
+ PangoDirection dir = PANGO_DIRECTION_LTR;
+ size_t tmp_index = view->cur_index;
+ if (view->cur_index >= cur_line->len && cur_line->len …
+ tmp_index = cur_line->len - 1;
+ else if (view->cur_index >= cur_line->len)
+ tmp_index = 0;
+ dir = ledit_pango_layout_get_direction(layout, (int)tm…
+
+ int x, sli;
+ pango_layout_index_to_line_x(layout, (int)view->cur_in…
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(l…
+ if (dir != sl->resolved_dir) {
+ box_w = 3;
+ }
+ if (dir == PANGO_DIRECTION_RTL || dir == PANGO_DIRECTI…
+ box_x = box_x - box_w;
+ }
+
+ if (view->cur_index == cur_line->len ||
+ (cur_line->text[view->cur_index] == ' ' &&
+ view->cur_index == (size_t)(sl->start_index + sl-…
+ XFillRectangle(
+ view->buffer->common->dpy, view->window->d…
+ box_x, cursor_y,
+ box_w, strong.height / PANGO_SCALE
+ );
+ }
+ } else if (view->mode == INSERT || view->mode == VISUAL) {
+ XDrawLine(
+ view->buffer->common->dpy, view->window->drawable,…
+ strong.x / PANGO_SCALE, cursor_y,
+ strong.x / PANGO_SCALE,
+ (strong.y + strong.height) / PANGO_SCALE + cur_lin…
+ );
+ }
+ }
+ /* move input method position */
+ if (!ledit_window_bottom_bar_text_shown(view->window)) {
+ xximspot(
+ view->window,
+ strong.x / PANGO_SCALE,
+ (strong.y + strong.height) / PANGO_SCALE + cur_line_y
+ );
+ }
+ view->redraw = 0;
+}
+
+void
+view_redraw(ledit_view *view) {
+ if (view->redraw || view->window->redraw) {
+ ledit_window_clear(view->window);
+ view_redraw_text(view);
+ ledit_window_redraw(view->window);
+ }
+}
+
+static void
+undo_insert_helper(void *data, size_t line, size_t byte, char *text, size_t te…
+ ledit_view *view = (ledit_view *)data;
+ ledit_buffer_insert_text_with_newlines_base(view->buffer, line, byte, …
+}
+
+static void
+undo_delete_helper(void *data, size_t line1, size_t byte1, size_t line2, size_…
+ ledit_view *view = (ledit_view *)data;
+ view_delete_range_base(view, DELETE_CHAR, line1, byte1, line2, byte2, …
+}
+
+void
+view_undo(ledit_view *view) {
+ size_t min_line;
+ size_t old_line = view->cur_line;
+ ledit_undo(
+ view->buffer->undo, view->mode, view, &undo_insert_helper,
+ &undo_delete_helper, &view->cur_line, &view->cur_index, &min_line
+ );
+ if (view->mode == NORMAL) {
+ view->cur_index = view_get_legal_normal_pos(
+ view, view->cur_line, view->cur_index
+ );
+ }
+ view_wipe_line_cursor_attrs(view, old_line);
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
+ if (min_line < view->lines_num) {
+ ledit_buffer_recalc_all_views_from_line(
+ view->buffer, min_line > 0 ? min_line - 1 : min_line
+ );
+ }
+ /* FIXME: show undo message */
+}
+
+void
+view_redo(ledit_view *view) {
+ size_t min_line;
+ size_t old_line = view->cur_line;
+ ledit_redo(
+ view->buffer->undo, view->mode, view, &undo_insert_helper,
+ &undo_delete_helper, &view->cur_line, &view->cur_index, &min_line
+ );
+ if (view->mode == NORMAL) {
+ view->cur_index = view_get_legal_normal_pos(
+ view, view->cur_line, view->cur_index
+ );
+ }
+ view_wipe_line_cursor_attrs(view, old_line);
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
+ if (min_line < view->lines_num) {
+ ledit_buffer_recalc_all_views_from_line(
+ view->buffer, min_line > 0 ? min_line - 1 : min_line
+ );
+ }
+ /* FIXME: show undo message */
+}
+
+static void
+paste_callback(void *data, char *text, size_t len) {
+ ledit_view *view = (ledit_view *)data;
+ txtbuf ins_buf = {.text = text, .len = len, .cap = len};
+ ledit_range cur_range, ins_range;
+ cur_range.line1 = ins_range.line1 = view->cur_line;
+ cur_range.byte1 = ins_range.byte1 = view->cur_index;
+ ledit_buffer_insert_text_with_newlines(
+ view->buffer, view->cur_line, view->cur_index,
+ text, len, &view->cur_line, &view->cur_index
+ );
+ cur_range.line2 = ins_range.line2 = view->cur_line;
+ cur_range.byte2 = ins_range.byte2 = view->cur_index;
+ ledit_push_undo_insert(
+ view->buffer->undo, &ins_buf, ins_range, cur_range, 1, view->mode
+ );
+}
+
+/* FIXME: guard against buffer being destroyed before paste callback is nulled…
+
+void
+view_paste_clipboard(ledit_view *view) {
+ ledit_window_set_paste_callback(view->window, &paste_callback, view);
+ clipboard_paste_clipboard(view->window);
+}
+
+void
+view_paste_primary(ledit_view *view) {
+ ledit_window_set_paste_callback(view->window, &paste_callback, view);
+ clipboard_paste_primary(view->window);
+}
diff --git a/view.h b/view.h
t@@ -0,0 +1,158 @@
+#ifndef _LEDIT_VIEW_H_
+#define _LEDIT_VIEW_H_
+
+typedef struct ledit_view ledit_view;
+
+#include "buffer.h"
+
+enum action_type {
+ ACTION_NONE, /* pass next key to basic key handler */
+ ACTION_GRABKEY /* pass next key to given callback */
+};
+
+struct action {
+ enum action_type type;
+ struct action (*callback)(ledit_view *view, XEvent *event, int lang_in…
+};
+
+typedef struct {
+ ledit_view *view; /* parent view */
+ int w; /* width in pixels */
+ int h; /* height in pixels */
+ long y_offset; /* pixel offset starting at the top of the …
+ size_t cache_pixmap_index; /* index of pixmap in cache, or -1 if not a…
+ size_t cache_layout_index; /* index of pango layout in cache, or -1 if…
+ int softlines; /* number of softlines - cached from PangoL…
+ size_t cursor_index; /* cursor index (for highlight in normal mo…
+ char cursor_index_valid; /* whether cursor index is valid */
+ char cache_pixmap_valid; /* whether cache_pixmap_index is valid */
+ char cache_layout_valid; /* whether cache_layout_index is valid */
+ char dirty; /* whether line needs to be rendered before…
+ char text_dirty; /* whether the text in the PangoLayout need…
+ * updated before the layout is rendered */
+ char highlight_dirty; /* whether highlight (cursor or selection) …
+ * updated still in the PangoLayout before …
+ char h_dirty; /* whether height needs to be recalculated …
+} ledit_view_line;
+
+/* FIXME: It's kind of ugly to put this here instead of keys_command.h,
+ but it has to be per-view, so I don't know any other option. */
+enum ledit_command_type {
+ CMD_EDIT,
+ CMD_EDITSEARCH,
+ CMD_EDITSEARCHB,
+ CMD_SEARCH,
+ CMD_SEARCHB,
+ CMD_SUBSTITUTE
+};
+
+struct ledit_view {
+ ledit_buffer *buffer; /* parent buffer */
+ ledit_window *window; /* window showing this view */
+ ledit_theme *theme; /* current theme in use */
+ ledit_cache *cache; /* cache for pixmaps and pango layouts */
+ ledit_view_line *lines; /* array of lines, stored as gap buffer */
+ /* current command type */
+ enum ledit_command_type cur_command_type;
+ struct action cur_action; /* current action to execute on key press */
+ size_t lines_cap; /* size of lines array */
+ size_t lines_gap; /* position of gap for line gap buffer */
+ size_t lines_num; /* number of lines */
+ size_t cur_line; /* current line */
+ size_t cur_index; /* current byte index in line */
+ long total_height; /* total pixel height of all lines */
+ long display_offset; /* current pixel offset of viewport */
+ ledit_range sel; /* current selection */
+ enum ledit_mode mode; /* current mode of this view */
+ char selecting; /* whether user is currently selecting text …
+ char sel_valid; /* whether there is currently a valid select…
+ char redraw; /* whether something has changed so the view…
+};
+
+enum delete_mode {
+ DELETE_CHAR,
+ DELETE_SOFTLINE,
+ DELETE_HARDLINE
+};
+
+void view_set_mode(ledit_view *view, enum ledit_mode mode);
+ledit_view *view_create(ledit_buffer *buffer, ledit_theme *theme, enum ledit_m…
+ledit_view_line *view_get_line(ledit_view *view, size_t index);
+void view_notify_insert_text(ledit_view *view, size_t line, size_t index, size…
+void view_notify_delete_text(ledit_view *view, size_t line, size_t index, size…
+void view_notify_append_line(ledit_view *view, size_t line);
+void view_notify_delete_lines(ledit_view *view, size_t index1, size_t index2);
+void view_destroy(ledit_view *view);
+void view_cleanup(void);
+void view_set_line_cursor_attrs(ledit_view *view, size_t line, size_t index);
+void view_wipe_line_cursor_attrs(ledit_view *view, size_t line);
+void view_render_line(ledit_view *view, size_t line_index);
+void view_recalc_line(ledit_view *view, size_t line);
+void view_recalc_from_line(ledit_view *view, size_t line);
+void view_recalc_all_lines(ledit_view *view);
+int view_line_visible(ledit_view *view, size_t index);
+size_t view_next_cursor_pos(ledit_view *view, size_t line, size_t byte, int nu…
+size_t view_prev_cursor_pos(ledit_view *view, size_t line, size_t byte, int nu…
+void view_next_word(ledit_view *view, size_t line, size_t byte, int num_repeat…
+void view_next_word_end(ledit_view *view, size_t line, size_t byte, int num_re…
+void view_next_bigword(ledit_view *view, size_t line, size_t byte, int num_rep…
+void view_next_bigword_end(ledit_view *view, size_t line, size_t byte, int num…
+void view_prev_word(ledit_view *view, size_t line, size_t byte, int num_repeat…
+void view_prev_bigword(ledit_view *view, size_t line, size_t byte, int num_rep…
+size_t view_line_next_non_whitespace(ledit_view *view, size_t line, size_t byt…
+void view_get_pos_softline_bounds(
+ ledit_view *view, size_t line, size_t pos,
+ size_t *start_byte_ret, size_t *end_byte_ret
+);
+void view_get_softline_bounds(
+ ledit_view *view, size_t line, int softline,
+ size_t *start_byte_ret, size_t *end_byte_ret
+);
+int view_get_softline_count(ledit_view *view, size_t line);
+int view_pos_to_softline(ledit_view *view, size_t line, size_t pos);
+void view_get_cursor_pixel_pos(ledit_view *view, size_t line, size_t pos, int …
+size_t view_move_cursor_visually(ledit_view *view, size_t line, size_t pos, in…
+void ledit_pos_to_x_softline(ledit_view *view, size_t line, size_t pos, int *x…
+void ledit_x_softline_to_pos(ledit_view *view, size_t line, int x, int softlin…
+size_t view_get_legal_normal_pos(ledit_view *view, size_t line, size_t pos);
+void view_delete_range(
+ ledit_view *view, enum delete_mode delmode,
+ size_t line_index1, size_t byte_index1,
+ size_t line_index2, size_t byte_index2,
+ size_t *new_line_ret, size_t *new_byte_ret,
+ ledit_range *final_range_ret, txtbuf *text_ret
+);
+void view_delete_range_base(
+ ledit_view *view, enum delete_mode delmode,
+ size_t line_index1, size_t byte_index1,
+ size_t line_index2, size_t byte_index2,
+ size_t *new_line_ret, size_t *new_byte_ret,
+ ledit_range *final_range_ret, txtbuf *text_ret
+);
+void view_resize_textview(void *data);
+void view_scroll(ledit_view *view, long new_offset);
+void view_get_nearest_legal_pos(
+ ledit_view *view,
+ size_t line, size_t byte,
+ /*int snap_to_nearest, int snap_middle, FIXME: take these parameters */
+ size_t *line_ret, size_t *byte_ret
+);
+/* x and y are in pixels, if snap_to_nearest is nonzero, the returned byte
+ 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_view *view, int x, int y, int snap_to_nearest…
+void view_scroll_to_pos_top(ledit_view *view, size_t line, size_t byte);
+void view_scroll_to_pos_bottom(ledit_view *view, size_t line, size_t byte);
+void view_ensure_cursor_shown(ledit_view *view);
+void view_sort_selection(size_t *line1, size_t *byte1, size_t *line2, size_t *…
+void view_wipe_selection(ledit_view *view);
+void view_set_selection(ledit_view *view, size_t line1, size_t byte1, size_t l…
+void view_scroll_handler(void *view, long pos);
+void view_button_handler(void *data, XEvent *event);
+void view_redraw(ledit_view *view);
+void view_undo(ledit_view *view);
+void view_redo(ledit_view *view);
+void view_paste_clipboard(ledit_view *view);
+void view_paste_primary(ledit_view *view);
+
+#endif
diff --git a/window.c b/window.c
t@@ -1,3 +1,5 @@
+/* FIXME: check if xim handling still works with multiple windows */
+#include <time.h>
#include <math.h>
#include <stdio.h>
#include <assert.h>
t@@ -17,6 +19,8 @@
#include "theme.h"
#include "window.h"
#include "util.h"
+#include "macros.h"
+#include "config.h"
/* FIXME: Everything to do with the bottom bar is extremely hacky */
struct bottom_bar {
t@@ -101,6 +105,7 @@ ledit_window_insert_bottom_bar_text(ledit_window *window, …
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);
+ window->redraw = 1;
}
void
t@@ -126,6 +131,7 @@ ledit_window_move_bottom_bar_cursor(ledit_window *window, …
if (new_index > window->bb->line_len)
new_index = window->bb->line_len;
window->bb->line_cur_pos = new_index;
+ window->redraw = 1;
}
void
t@@ -136,11 +142,13 @@ ledit_window_set_bottom_bar_min_pos(ledit_window *window…
void
ledit_window_bottom_bar_cursor_to_beginning(ledit_window *window) {
window->bb->line_cur_pos = window->bb->min_pos;
+ window->redraw = 1;
}
void
ledit_window_bottom_bar_cursor_to_end(ledit_window *window) {
window->bb->line_cur_pos = window->bb->line_len;
+ window->redraw = 1;
}
/* FIXME: respect PangoLogAttr.backspace_deletes_character */
t@@ -185,12 +193,14 @@ ledit_window_delete_bottom_bar_char(ledit_window *window…
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);
+ window->redraw = 1;
}
void
ledit_window_set_bottom_bar_cursor(ledit_window *window, int byte_pos) {
/* FIXME: check if valid? */
window->bb->line_cur_pos = byte_pos;
+ window->redraw = 1;
}
int
t@@ -201,11 +211,13 @@ ledit_window_get_bottom_bar_cursor(ledit_window *window)…
void
ledit_window_set_bottom_bar_text_shown(ledit_window *window, int shown) {
window->bottom_text_shown = shown;
+ window->redraw = 1;
}
int
ledit_window_bottom_bar_text_shown(ledit_window *window) {
return window->bottom_text_shown;
+ window->redraw = 1;
}
void
t@@ -213,6 +225,7 @@ ledit_window_set_bottom_bar_text(ledit_window *window, cha…
window->bb->line_len = 0;
window->bb->line_cur_pos = 0;
ledit_window_insert_bottom_bar_text(window, text, len);
+ window->redraw = 1;
}
char *
t@@ -226,6 +239,7 @@ ledit_window_show_message(ledit_window *window, char *text…
/* FIXME: rename these */
window->bottom_text_shown = 0;
window->message_shown = 1;
+ window->redraw = 1;
}
int
t@@ -236,10 +250,12 @@ ledit_window_message_shown(ledit_window *window) {
void
ledit_window_hide_message(ledit_window *window) {
window->message_shown = 0;
+ window->redraw = 1;
}
void
ledit_window_set_mode(ledit_window *window, enum ledit_mode mode) {
+ window->mode = mode;
char *text;
switch (mode) {
case NORMAL:
t@@ -263,12 +279,14 @@ ledit_window_set_mode(ledit_window *window, enum ledit_m…
XftDrawRect(window->bb->mode_draw->xftdraw, &window->theme->text_bg, 0…
pango_xft_render_layout(window->bb->mode_draw->xftdraw, &window->theme…
recalc_text_size(window);
+ window->redraw = 1;
}
void
ledit_window_set_mode_extra_text(ledit_window *window, char *text) {
window->mode_extra_text = ledit_strdup(text);
- ledit_window_set_mode(window, window->common->mode);
+ ledit_window_set_mode(window, window->mode);
+ window->redraw = 1;
}
/* FIXME: give these functions more sensible names */
t@@ -289,21 +307,19 @@ set_scroll_pos(ledit_window *window, double pos) {
/* FIXME: check for overflow */
if (window->scroll_callback)
window->scroll_callback(window->scroll_cb_data, (long)window->…
+ window->redraw = 1;
}
void
ledit_window_set_scroll_max(ledit_window *window, long max) {
window->scroll_max = max;
- /* FIXME: set offset if too large */
- /* actually not, because buffer does that already */
- /* FIXME: SHOULD THIS EVEN BE USED? */
- window->common->redraw = 1;
+ window->redraw = 1;
}
void
ledit_window_set_scroll_pos(ledit_window *window, long pos) {
window->scroll_offset = pos;
- window->common->redraw = 1;
+ window->redraw = 1;
}
void
t@@ -313,7 +329,7 @@ ledit_window_set_scroll_callback(ledit_window *window, voi…
}
void
-ledit_window_set_paste_callback(ledit_window *window, void (*cb)(void *, char …
+ledit_window_set_paste_callback(ledit_window *window, void (*cb)(void *, char …
window->paste_callback = cb;
window->paste_cb_data = data;
}
t@@ -324,6 +340,12 @@ ledit_window_set_button_callback(ledit_window *window, vo…
window->button_cb_data = data;
}
+void
+ledit_window_set_resize_callback(ledit_window *window, void (*cb)(void *), voi…
+ window->resize_callback = cb;
+ window->resize_cb_data = data;
+}
+
/* FIXME: Change naming convention to fit the rest of ledit */
/* FIXME: It's a bit weird when an input box pops up during normal mode.
Can/should this be disabled? */
t@@ -411,17 +433,26 @@ xximspot(ledit_window *window, int x, int y) {
}
ledit_window *
-ledit_window_create(ledit_common *common, ledit_theme *theme) {
+ledit_window_create(ledit_common *common, ledit_theme *theme, enum ledit_mode …
XSetWindowAttributes attrs;
XGCValues gcv;
ledit_window *window = ledit_malloc(sizeof(ledit_window));
+ window->mode = mode;
window->scroll_dragging = 0;
window->scroll_grab_handle = 0;
window->w = 500;
window->h = 500;
window->mode_extra_text = NULL;
+ window->paste_callback = NULL;
+ window->scroll_callback = NULL;
+ window->button_callback = NULL;
+ window->resize_callback = NULL;
+ window->paste_cb_data = NULL;
+ window->scroll_cb_data = NULL;
+ window->button_cb_data = NULL;
+ window->resize_cb_data = NULL;
memset(&window->wattrs, 0, sizeof(attrs));
window->wattrs.background_pixel = BlackPixel(common->dpy, common->scre…
t@@ -507,26 +538,41 @@ ledit_window_create(ledit_common *common, ledit_theme *t…
/* FIXME: maybe delay this (i.e. move to different function)? */
XMapWindow(common->dpy, window->xwin);
+ window->redraw = 1;
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ window->last_scroll = now;
+ window->last_motion = now;
+ window->last_resize = now;
+ window->last_scroll_valid = 0;
+ window->last_motion_valid = 0;
+ window->last_resize_valid = 0;
+ window->scroll_num = 0;
+ recalc_text_size(window);
+
return window;
}
void
ledit_window_destroy(ledit_window *window) {
- /* FIXME: cleanup everything else */
- /* FIXME: This doesn't seem to be correct - g_object_unref sometimes
- causes segfault */
+ /* FIXME: check what's still missing */
+ g_object_unref(window->bb->mode);
+ /*g_object_unref(window->bb->ruler);*/ /* FIXME: implement ruler */
+ g_object_unref(window->bb->line);
+ ledit_draw_destroy(window, window->bb->mode_draw);
+ ledit_draw_destroy(window, window->bb->line_draw);
+
pango_font_description_free(window->font);
+ /* FIXME: The pango documentation says that the context must be freed,
+ but the program segfaults when that is done. */
+ /*g_object_unref(window->context);*/
g_object_unref(window->fontmap);
- g_object_unref(window->context);
+
/* FIXME: is gc, etc. destroyed automatically when destroying window? …
if (window->spotlist)
XFree(window->spotlist);
XDestroyWindow(window->common->dpy, window->xwin);
- g_object_unref(window->bb->mode);
- /*g_object_unref(window->bb->ruler);*/ /* FIXME: implement ruler */
- g_object_unref(window->bb->line);
- ledit_draw_destroy(window, window->bb->mode_draw);
- ledit_draw_destroy(window, window->bb->line_draw);
+
if (window->mode_extra_text)
free(window->mode_extra_text);
free(window->bb->line_text);
t@@ -630,6 +676,7 @@ ledit_window_redraw(ledit_window *window) {
if (!XdbeSwapBuffers(window->common->dpy, &swap_info, 1))
exit(1);
XFlush(window->common->dpy);
+ window->redraw = 0;
}
void
t@@ -639,11 +686,50 @@ ledit_window_get_textview_size(ledit_window *window, int…
}
void
+ledit_window_handle_filtered_events(ledit_window *window) {
+ struct timespec now, elapsed;
+ if (window->last_motion_valid) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ledit_timespecsub(&now, &window->last_motion, &elapsed);
+ if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= MOUSE_TICK) {
+ ledit_window_drag_motion(window, &window->last_motion_…
+ window->last_motion = now;
+ window->last_motion_valid = 0;
+ }
+ }
+ if (window->last_scroll_valid) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ledit_timespecsub(&now, &window->last_scroll, &elapsed);
+ if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= MOUSE_TICK) {
+ ledit_window_button_press(window, &window->last_scroll…
+ window->last_scroll = now;
+ window->last_scroll_valid = 0;
+ }
+ }
+ if (window->last_resize_valid) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ledit_timespecsub(&now, &window->last_resize, &elapsed);
+ if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= RESIZE_TICK) {
+ ledit_window_resize(
+ window,
+ window->last_resize_event.xconfigure.width,
+ window->last_resize_event.xconfigure.height
+ );
+ window->last_resize = now;
+ window->last_resize_valid = 0;
+ window->redraw = 1;
+ }
+ }
+}
+
+void
ledit_window_resize(ledit_window *window, int w, int h) {
window->w = w;
window->h = h;
recalc_text_size(window);
- window->common->redraw = 1;
+ if (window->resize_callback)
+ window->resize_callback(window->resize_cb_data);
+ window->redraw = 1;
}
void
t@@ -748,8 +834,9 @@ clipboard_selnotify(ledit_window *window, XEvent *e) {
}
/* FIXME: XGetWindowProperty takes data as unsigned char, so i…
+ /* FIXME: buffer all pasted text and only send it in one go in…
if (window->paste_callback)
- window->paste_callback(window->paste_cb_data, (char *)…
+ window->paste_callback(window->paste_cb_data, (char *)…
XFree(data);
/* number of 32-bit chunks returned */
ofs += nitems * format / 32;
t@@ -820,8 +907,38 @@ clipboard_selrequest(ledit_window *window, XEvent *e)
fprintf(stderr, "Error sending SelectionNotify event\n");
}
+void
+ledit_window_register_button_press(ledit_window *window, XEvent *event) {
+ int scroll_delta;
+ if (event->xbutton.button == Button4 ||
+ event->xbutton.button == Button5) {
+ scroll_delta = event->xbutton.button == Button4 ? -1 : 1;
+ if (window->last_scroll_valid) {
+ window->scroll_num += scroll_delta;
+ } else {
+ window->last_scroll_event = *event;
+ window->last_scroll_valid = 1;
+ window->scroll_num = scroll_delta;
+ }
+ } else {
+ ledit_window_button_press(window, event, 0);
+ }
+}
+
+void
+ledit_window_register_resize(ledit_window *window, XEvent *event) {
+ window->last_resize_event = *event;
+ window->last_resize_valid = 1;
+}
+
+void
+ledit_window_register_motion(ledit_window *window, XEvent *event) {
+ window->last_motion_event = *event;
+ window->last_motion_valid = 1;
+}
+
/* FIXME: improve set_scroll_pos; make it a bit clearer */
-int
+void
ledit_window_button_press(ledit_window *window, XEvent *event, int scroll_num)…
int x, y;
double scroll_h, scroll_y;
t@@ -837,11 +954,11 @@ ledit_window_button_press(ledit_window *window, XEvent *…
double new_scroll_y = y - scroll_h / 2;
set_scroll_pos(window, new_scroll_y);
}
- return 1;
+ window->redraw = 1;
} else if (y < window->text_h) {
if (window->button_callback)
window->button_callback(window->button…
- return 1;
+ window->redraw = 1;
}
break;
case Button4:
t@@ -854,23 +971,21 @@ ledit_window_button_press(ledit_window *window, XEvent *…
}
if (window->scroll_callback)
window->scroll_callback(window->scroll_cb_data…
- return 1;
+ window->redraw = 1;
}
- return 0;
}
-int
+void
ledit_window_button_release(ledit_window *window, XEvent *event) {
if (event->xbutton.button == Button1) {
window->scroll_dragging = 0;
if (window->button_callback)
window->button_callback(window->button_cb_data, event);
- return 1;
+ window->redraw = 1;
}
- return 0;
}
-int
+void
ledit_window_drag_motion(ledit_window *window, XEvent *event) {
if (window->scroll_dragging) {
double scroll_h, scroll_y;
t@@ -878,16 +993,15 @@ ledit_window_drag_motion(ledit_window *window, XEvent *e…
scroll_y += event->xbutton.y - window->scroll_grab_handle;
window->scroll_grab_handle = event->xbutton.y;
set_scroll_pos(window, scroll_y);
- return 1;
+ window->redraw = 1;
} else {
if (window->button_callback)
window->button_callback(window->button_cb_data, event);
- return 1;
+ window->redraw = 1;
}
- return 0;
}
-int
+void
ledit_window_clipboard_event(ledit_window *window, XEvent *event) {
/* FIXME: paste in bottom bar */
switch (event->type) {
t@@ -903,5 +1017,4 @@ ledit_window_clipboard_event(ledit_window *window, XEvent…
default:
break;
}
- return 0;
}
diff --git a/window.h b/window.h
t@@ -1,6 +1,7 @@
typedef struct bottom_bar bottom_bar;
typedef struct {
+ /* FIXME: maybe move to common? */
PangoFontMap *fontmap;
PangoContext *context;
PangoFontDescription *font;
t@@ -23,6 +24,21 @@ typedef struct {
Atom xtarget;
bottom_bar *bb;
int bb_msg_shown;
+ int redraw;
+ enum ledit_mode mode; /* a bit ugly to duplicate this here... */
+
+ /* filtered events */
+ struct timespec last_scroll;
+ struct timespec last_motion;
+ struct timespec last_resize;
+ XEvent last_scroll_event;
+ XEvent last_motion_event;
+ XEvent last_resize_event;
+ int last_scroll_valid;
+ int last_motion_valid;
+ int last_resize_valid;
+ int scroll_num;
+ int scroll_delta;
/* IME stuff */
XIM xim;
t@@ -32,16 +48,18 @@ typedef struct {
ledit_common *common;
ledit_theme *theme;
- void (*paste_callback)(void *, char *, int);
+ void (*paste_callback)(void *, char *, size_t);
void (*scroll_callback)(void *, long);
void (*button_callback)(void *, XEvent *);
+ void (*resize_callback)(void *);
void *paste_cb_data;
void *scroll_cb_data;
void *button_cb_data;
+ void *resize_cb_data;
char *mode_extra_text;
} ledit_window;
-ledit_window *ledit_window_create(ledit_common *common, ledit_theme *theme);
+ledit_window *ledit_window_create(ledit_common *common, ledit_theme *theme, en…
void ledit_window_destroy(ledit_window *window);
void ledit_window_cleanup(void);
t@@ -68,8 +86,13 @@ void ledit_window_set_mode_extra_text(ledit_window *window,…
void ledit_window_set_scroll_max(ledit_window *window, long max);
void ledit_window_set_scroll_pos(ledit_window *window, long pos);
void ledit_window_set_scroll_callback(ledit_window *window, void (*cb)(void *,…
-void ledit_window_set_paste_callback(ledit_window *window, void (*cb)(void *, …
+void ledit_window_set_paste_callback(ledit_window *window, void (*cb)(void *, …
void ledit_window_set_button_callback(ledit_window *window, void (*cb)(void *,…
+void ledit_window_set_resize_callback(ledit_window *window, void (*cb)(void *)…
+void ledit_window_register_resize(ledit_window *window, XEvent *event);
+void ledit_window_register_button_press(ledit_window *window, XEvent *event);
+void ledit_window_register_motion(ledit_window *window, XEvent *event);
+void ledit_window_handle_filtered_events(ledit_window *window);
void ledit_window_clear(ledit_window *window);
void ledit_window_redraw(ledit_window *window);
t@@ -81,8 +104,8 @@ void clipboard_paste_clipboard(ledit_window *window);
void clipboard_paste_primary(ledit_window *window);
txtbuf *ledit_window_get_primary_clipboard_buffer(void);
-int ledit_window_button_press(ledit_window *window, XEvent *event, int scroll_…
-int ledit_window_button_release(ledit_window *window, XEvent *event);
-int ledit_window_drag_motion(ledit_window *window, XEvent *event);
-int ledit_window_clipboard_event(ledit_window *window, XEvent *event);
+void ledit_window_button_press(ledit_window *window, XEvent *event, int scroll…
+void ledit_window_button_release(ledit_window *window, XEvent *event);
+void ledit_window_drag_motion(ledit_window *window, XEvent *event);
+void ledit_window_clipboard_event(ledit_window *window, XEvent *event);
void xximspot(ledit_window *window, int x, int y);
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.