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); |