Introduction
Introduction Statistics Contact Development Disclaimer Help
tAdd very basic search functionality and start working on commands - ledit - Te…
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 e181351df92df2596bd48578667ce195f4cf34d0
parent b8f2762e5d7b778ba858d790f40c85aeab2f57ab
Author: lumidify <[email protected]>
Date: Wed, 26 May 2021 21:39:22 +0200
Add very basic search functionality and start working on commands
Diffstat:
M Makefile | 4 ++--
M buffer.c | 31 ++++++++++++++++++++++++++---…
A commands.c | 68 +++++++++++++++++++++++++++++…
M common.h | 6 +++++-
M ledit.c | 188 ++++++++++++++++++++++++++++-…
A search.c | 171 +++++++++++++++++++++++++++++…
A search.h | 13 +++++++++++++
7 files changed, 459 insertions(+), 22 deletions(-)
---
diff --git a/Makefile b/Makefile
t@@ -9,8 +9,8 @@ MANPREFIX = ${PREFIX}/man
BIN = ${NAME}
MAN1 = ${BIN:=.1}
-OBJ = ${BIN:=.o} cache.o buffer.o memory.o util.o
-HDR = cache.h buffer.h memory.h common.h util.h
+OBJ = ${BIN:=.o} cache.o buffer.o memory.o util.o search.o
+HDR = cache.h buffer.h memory.h common.h util.h search.h
CFLAGS_LEDIT = -g -Wall -Wextra -D_POSIX_C_SOURCE=200809L `pkg-config --cflags…
LDFLAGS_LEDIT = ${LDFLAGS} `pkg-config --libs x11 xkbfile pangoxft xext` -lm
diff --git a/buffer.c b/buffer.c
t@@ -105,14 +105,16 @@ ledit_insert_text(ledit_buffer *buffer, int line_index, …
ledit_line *line = &buffer->lines[line_index];
if (len == -1)
len = strlen(text);
- if (line->len + len > line->cap || line->text == NULL) {
+ /* \0 is not included in line->len */
+ if (line->len + len + 1 > line->cap || line->text == NULL) {
/* FIXME: read up on what the best values are here */
- line->cap = line->cap * 2 > line->len + len ? line->cap * 2 : …
+ line->cap = line->cap * 2 > line->len + len + 1 ? line->cap * …
line->text = ledit_realloc(line->text, line->cap);
}
memmove(line->text + index + len, line->text + index, line->len - inde…
memcpy(line->text + index, text, len);
line->len += len;
+ line->text[line->len] = '\0';
pango_layout_set_text(line->layout, line->text, line->len);
/*recalc_single_line_size(buffer, line_index);*/
line->dirty = 1;
t@@ -120,6 +122,16 @@ ledit_insert_text(ledit_buffer *buffer, int line_index, i…
static void append_line_impl(ledit_buffer *buffer, int line_index, int text_in…
+/* FIXME: this isn't optimized like the standard version, but whatever */
+static char *
+strchr_len(char *text, char c, int len) {
+ for (int i = 0; i < len; i++) {
+ if (text[i] == c)
+ return text + i;
+ }
+ return NULL;
+}
+
void
ledit_insert_text_with_newlines(
ledit_buffer *buffer,
t@@ -128,16 +140,18 @@ ledit_insert_text_with_newlines(
int *end_line_ret, int *end_char_ret) {
if (len == -1)
len = strlen(text);
+ int rem_len = len;
char *cur, *last = text;
int cur_line = line_index;
int cur_index = index;
- while ((cur = strchr(last, '\n'))) {
+ while ((cur = strchr_len(last, '\n', rem_len)) != NULL) {
ledit_insert_text(buffer, cur_line, cur_index, last, cur - las…
/* FIXME: inefficient because there's no gap buffer yet */
append_line_impl(buffer, cur_line, -1);
cur_index = 0;
cur_line++;
last = cur + 1;
+ rem_len -= cur - last + 1;
}
/* FIXME: check how legal this casting between pointers and ints is */
ledit_insert_text(buffer, cur_line, cur_index, last, text + len - last…
t@@ -193,8 +207,10 @@ init_line(ledit_buffer *buffer, ledit_line *line) {
pango_layout_set_font_description(line->layout, buffer->state->font);
pango_layout_set_wrap(line->layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_attributes(line->layout, basic_attrs);
- line->text = NULL;
- line->cap = line->len = 0;
+ line->cap = 2; /* arbitrary */
+ line->text = ledit_malloc(line->cap);
+ line->text[0] = '\0';
+ line->len = 0;
line->cache_index = -1;
line->dirty = 1;
/* FIXME: does this set line height reasonably when no text yet? */
t@@ -223,13 +239,16 @@ append_line_impl(ledit_buffer *buffer, int line_index, i…
init_line(buffer, new_l);
buffer->lines_num++;
if (text_index != -1) {
+ /* FIXME: use ledit_insert... here */
ledit_line *l = &buffer->lines[line_index];
int len = l->len - text_index;
new_l->len = len;
new_l->cap = len + 10;
new_l->text = ledit_malloc(new_l->cap);
memcpy(new_l->text, l->text + text_index, len);
+ new_l->text[new_l->len] = '\0';
l->len = text_index;
+ l->text[l->len] = '\0';
pango_layout_set_text(new_l->layout, new_l->text, new_l->len);
pango_layout_set_text(l->layout, l->text, l->len);
/* FIXME: set height here */
t@@ -333,6 +352,7 @@ ledit_delete_unicode_char(ledit_buffer *buffer, int line_i…
memmove(l->text + byte_index, l->text + i, l->len - i);
l->len -= i - byte_index;
}
+ l->text[l->len] = '\0';
pango_layout_set_text(l->layout, l->text, l->len);
recalc_single_line_size(buffer, line_index);
return new_index;
t@@ -343,6 +363,7 @@ delete_line_section(ledit_buffer *buffer, int line, int st…
ledit_line *l = &buffer->lines[line];
memmove(l->text + start, l->text + start + length, l->len - start - le…
l->len -= length;
+ l->text[l->len] = '\0';
pango_layout_set_text(l->layout, l->text, l->len);
recalc_single_line_size(buffer, line);
l->dirty = 1;
diff --git a/commands.c b/commands.c
t@@ -0,0 +1,68 @@
+/* FIXME: Parse commands properly and allow combinations of commands */
+
+static int
+handle_write_quit(ledit_buffer *buffer, char *cmd, int l1, int l2) {
+ return 0;
+}
+
+static int
+handle_substitute(ledit_buffer *buffer, char *cmd, int l1, int l2) {
+ return 0;
+}
+
+enum cmd_type {
+ CMD_NORMAL,
+ CMD_OPTIONAL_RANGE
+};
+
+static const struct {
+ char *cmd;
+ enum cmd_type type;
+ int (*handler)(ledit_buffer *buffer, char *cmd, int l1, int l2);
+} cmds[] = {
+ {"w", CMD_NORMAL, &handle_write_quit},
+ {"q", CMD_NORMAL, &handle_write_quit},
+ {"s", CMD_OPTIONAL_RANGE, &handle_substitute}
+};
+
+#define LENGTH(X) (sizeof(X) / sizeof(X[0]))
+
+int
+ledit_handle_cmd(ledit_buffer *buffer, char *cmd, int len) {
+ if (len < 0)
+ len = strlen(cmd);
+ if (len < 1)
+ return;
+ char *cur_pos = cmd;
+ int l1 = buffer->cur_line;
+ int l2 = buffer->cur_line;
+ int range_given = 0;
+ switch (cur_pos[0]) {
+ case '%':
+ l1 = 0;
+ l2 = buffer->lines_num - 1;
+ range_given = 1;
+ cur_pos++;
+ break;
+ case '&'
+ l1 = buffer->sel.line1;
+ l2 = buffer->sel.line2;
+ if (l1 < 0 || l2 < 0)
+ return 1;
+ if (l1 < l2) {
+ int tmp = l1;
+ l1 = l2;
+ l2 = tmp;
+ }
+ range_given = 1;
+ cur_pos++;
+ break
+ }
+ for (int i = 0; i < LENGTH(cmds); i++) {
+ if (!strncmp(cmds[i].cmd, cur_pos, strlen(cmds[i].cmd)) &&
+ (!range_given || cmds[i].type == CMD_NORMAL)) {
+ return cmds[i].handler(buffer, cur_pos, l1, l2);
+ }
+ }
+ return 1;
+}
diff --git a/common.h b/common.h
t@@ -1,7 +1,9 @@
enum ledit_mode {
NORMAL = 1,
INSERT = 2,
- VISUAL = 4
+ VISUAL = 4,
+ COMMANDEDIT = 8,
+ SEARCHEDIT = 16
};
typedef struct {
t@@ -24,6 +26,8 @@ typedef struct {
int scroll_dragging;
int scroll_grab_handle;
int selecting;
+ int bottom_text_shown;
+ int message_shown;
enum ledit_mode mode;
XIM xim;
XIC xic;
diff --git a/ledit.c b/ledit.c
t@@ -1,3 +1,4 @@
+/* FIXME: overflow in repeated commands */
/* FIXME: Fix lag when scrolling */
/* FIXME: Fix lag when selecting with mouse */
/* FIXME: Use PANGO_PIXELS() */
t@@ -8,6 +9,7 @@
#include <math.h>
#include <stdio.h>
#include <errno.h>
+#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
t@@ -29,6 +31,7 @@
#include "memory.h"
#include "common.h"
#include "buffer.h"
+#include "search.h"
#include "cache.h"
#include "util.h"
t@@ -52,6 +55,12 @@ struct {
PangoLayout *ruler;
ledit_draw *ruler_draw;
int ruler_w, ruler_h;
+ PangoLayout *line;
+ ledit_draw *line_draw;
+ int line_w, line_h;
+ char *line_text;
+ int line_alloc, line_len;
+ int line_cur_pos;
} bottom_bar;
struct key {
t@@ -142,13 +151,64 @@ static void get_new_line_softline(
#define SCROLLBAR_WIDTH 10
#define SCROLL_STEP 10
+/* FIXME: shouldn't state.bottom_text_shown also be true when message_shown? */
static void
recalc_text_size(void) {
int bar_h = bottom_bar.mode_h;
+ if ((state.bottom_text_shown || state.message_shown) && bottom_bar.lin…
+ bar_h = bottom_bar.line_h;
state.text_w = state.w - SCROLLBAR_WIDTH;
state.text_h = state.h - bar_h;
}
+/* FIXME: allow lines longer than window width to be displayed properly */
+static void
+insert_bottom_bar_text(char *text, int len) {
+ assert(len >= -1);
+ assert(bottom_bar.line_cur_pos <= bottom_bar.line_alloc);
+
+ if (len == -1)
+ len = strlen(text);
+ /* \0 not included in len */
+ if (bottom_bar.line_len + len + 1 > bottom_bar.line_alloc || bottom_ba…
+ /* FIXME: read up on what the best values are here */
+ bottom_bar.line_alloc =
+ bottom_bar.line_alloc * 2 > bottom_bar.line_len + len + 1 ?
+ bottom_bar.line_alloc * 2 :
+ bottom_bar.line_len + len + 1;
+ bottom_bar.line_text = ledit_realloc(bottom_bar.line_text, bot…
+ }
+ memmove(
+ bottom_bar.line_text + bottom_bar.line_cur_pos + len,
+ bottom_bar.line_text + bottom_bar.line_cur_pos,
+ bottom_bar.line_len - bottom_bar.line_cur_pos
+ );
+ memcpy(bottom_bar.line_text + bottom_bar.line_cur_pos, text, len);
+ bottom_bar.line_len += len;
+ bottom_bar.line_text[bottom_bar.line_len] = '\0';
+ pango_layout_set_text(bottom_bar.line, bottom_bar.line_text, bottom_ba…
+ pango_layout_get_pixel_size(bottom_bar.line, &bottom_bar.line_w, &bott…
+ ledit_grow_draw(&state, bottom_bar.line_draw, bottom_bar.line_w, botto…
+ XftDrawRect(bottom_bar.line_draw->xftdraw, &state.bg, 0, 0, bottom_bar…
+ pango_xft_render_layout(bottom_bar.line_draw->xftdraw, &state.fg, bott…
+ recalc_text_size();
+}
+
+static void
+set_bottom_bar_text(char *text, int len) {
+ bottom_bar.line_len = 0;
+ bottom_bar.line_cur_pos = 0;
+ insert_bottom_bar_text(text, len);
+}
+
+static void
+show_message(char *text, int len) {
+ set_bottom_bar_text(text, len);
+ /* FIXME: rename these */
+ state.bottom_text_shown = 0;
+ state.message_shown = 2;
+}
+
/* clipboard handling largely stolen from st (simple terminal) */
#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
t@@ -181,7 +241,7 @@ set_mode(enum ledit_mode mode) {
ledit_grow_draw(&state, bottom_bar.mode_draw, bottom_bar.mode_w, botto…
XftDrawRect(bottom_bar.mode_draw->xftdraw, &state.bg, 0, 0, bottom_bar…
pango_xft_render_layout(bottom_bar.mode_draw->xftdraw, &state.fg, bott…
- recalc_text_size(); /* probably not necessary, but whatever */
+ recalc_text_size();
}
void
t@@ -885,6 +945,15 @@ setup(int argc, char *argv[]) {
/* FIXME: only create "dummy draw" at first and create with proper siz…
bottom_bar.mode_draw = ledit_create_draw(&state, 10, 10);
set_mode(INSERT);
+ bottom_bar.line = pango_layout_new(state.context);
+ pango_layout_set_font_description(bottom_bar.line, state.font);
+ bottom_bar.line_draw = ledit_create_draw(&state, 10, 10);
+ bottom_bar.line_w = bottom_bar.line_h = 10;
+ bottom_bar.line_text = NULL;
+ bottom_bar.line_alloc = bottom_bar.line_len = 0;
+ bottom_bar.line_cur_pos = 0;
+ state.bottom_text_shown = 0;
+ state.message_shown = 0;
XMapWindow(state.dpy, state.win);
t@@ -908,6 +977,7 @@ setup(int argc, char *argv[]) {
static void
cleanup(void) {
/* FIXME: cleanup everything else */
+ ledit_cleanup_search();
ledit_destroy_cache();
ledit_destroy_buffer(buffer);
XDestroyWindow(state.dpy, state.win);
t@@ -1006,12 +1076,21 @@ redraw(void) {
0, state.text_h,
state.w, state.h - state.text_h
);
- XCopyArea(
- state.dpy, bottom_bar.mode_draw->pixmap,
- state.drawable, state.gc,
- 0, 0, bottom_bar.mode_w, bottom_bar.mode_h,
- state.w - bottom_bar.mode_w, state.text_h
- );
+ if (state.bottom_text_shown || state.message_shown) {
+ XCopyArea(
+ state.dpy, bottom_bar.line_draw->pixmap,
+ state.drawable, state.gc,
+ 0, 0, bottom_bar.line_w, bottom_bar.line_h,
+ 0, state.text_h
+ );
+ } else {
+ XCopyArea(
+ state.dpy, bottom_bar.mode_draw->pixmap,
+ state.drawable, state.gc,
+ 0, 0, bottom_bar.mode_w, bottom_bar.mode_h,
+ state.w - bottom_bar.mode_w, state.text_h
+ );
+ }
XdbeSwapInfo swap_info;
swap_info.swap_window = state.win;
t@@ -1582,6 +1661,71 @@ switch_selection_end(void) {
#define XK_ANY_MOD UINT_MAX
#define XK_NO_MOD 0
+static void
+enter_commandedit(void) {
+ set_bottom_bar_text(":", -1);
+ bottom_bar.line_cur_pos = 1;
+ state.mode = COMMANDEDIT;
+ state.bottom_text_shown = 1;
+}
+
+static void
+enter_searchedit_forward(void) {
+ set_bottom_bar_text("/", -1);
+ bottom_bar.line_cur_pos = 1;
+ state.mode = SEARCHEDIT;
+ state.bottom_text_shown = 1;
+}
+
+static void
+enter_searchedit_backward(void) {
+ set_bottom_bar_text("?", -1);
+ bottom_bar.line_cur_pos = 1;
+ state.mode = SEARCHEDIT;
+ state.bottom_text_shown = 1;
+}
+
+/* FIXME: support visual mode, i.e. change selection to new place? */
+static void
+search_next(void) {
+ /* FIXME: avoid this when line doesn't change */
+ ledit_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ enum ledit_search_state ret = ledit_search_next(buffer, &buffer->cur_l…
+ ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_inde…
+ if (ret != SEARCH_NORMAL)
+ show_message(ledit_search_state_to_str(ret), -1);
+}
+
+static void
+search_prev(void) {
+ /* FIXME: avoid this when line doesn't change */
+ ledit_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ enum ledit_search_state ret = ledit_search_prev(buffer, &buffer->cur_l…
+ ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_inde…
+ if (ret != SEARCH_NORMAL)
+ show_message(ledit_search_state_to_str(ret), -1);
+}
+
+static void
+end_lineedit(void) {
+ enum ledit_mode old_mode = state.mode;
+ /* FIXME: go to last mode (visual or normal) */
+ set_mode(NORMAL);
+ state.bottom_text_shown = 0;
+
+ /* FIXME: forward/backward; check for empty string;
+ end edit mode when / or ? is deleted with backspace */
+ if (old_mode == SEARCHEDIT) {
+ /* FIXME: this is all so horrible */
+ if (bottom_bar.line_text[0] == '/')
+ ledit_set_search_forward(bottom_bar.line_text + 1);
+ else
+ ledit_set_search_backward(bottom_bar.line_text + 1);
+ search_next();
+ }
+}
+
+/* FIXME: maybe sort these and use binary search */
static struct key keys_en[] = {
{NULL, 0, XK_BackSpace, INSERT, KEY_ANY, KEY_ANY, &backspace},
{NULL, 0, XK_Left, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_lef…
t@@ -1612,7 +1756,13 @@ static struct key keys_en[] = {
{"v", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &enter_visual},
{"o", 0, 0, VISUAL, KEY_ANY, KEY_ANY, &switch_selection_end},
{"c", ControlMask, 0, INSERT|VISUAL, KEY_ANY, KEY_ANY, &clipcopy},
- {"v", ControlMask, 0, INSERT, KEY_ANY, KEY_ANY, &clippaste}
+ {"v", ControlMask, 0, INSERT, KEY_ANY, KEY_ANY, &clippaste},
+ {":", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &enter_commandedit},
+ {"?", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &enter_searchedit_backwa…
+ {"/", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &enter_searchedit_forwar…
+ {NULL, 0, XK_Return, COMMANDEDIT|SEARCHEDIT, KEY_ANY, KEY_ANY, &end_li…
+ {"n", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &search_next},
+ {"N", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &search_prev}
};
static struct key keys_ur[] = {
t@@ -1720,7 +1870,9 @@ key_press(XEvent event) {
(cur_keys->keys[i].modes & state.mode) &&
(!e || (e->key & cur_keys->keys[i].prev_keys)) &&
!strncmp(cur_keys->keys[i].text, buf, n) &&
- match(cur_keys->keys[i].mods, key_state)) {
+ match(cur_keys->keys[i].mods, key_state & ~ShiftM…
+ /* FIXME: seems a bit hacky to remove shift, b…
+ is needed to make keys that use shift match…
cur_keys->keys[i].func();
found = 1;
}
t@@ -1730,10 +1882,14 @@ key_press(XEvent event) {
cur_keys->keys[i].func();
found = 1;
}
- if (found)
- break;
}
- if (state.mode == INSERT && !found && n > 0) {
+ if (found) {
+ /* FIXME: only do this when necessary */
+ ensure_cursor_shown();
+ /* FIXME: this is a bit hacky */
+ if (state.message_shown > 0)
+ state.message_shown--;
+ } else if (state.mode == INSERT && !found && n > 0) {
delete_selection();
ledit_insert_text_with_newlines(
buffer,
t@@ -1741,7 +1897,11 @@ key_press(XEvent event) {
buf, n,
&buffer->cur_line, &buffer->cur_index
);
+ ensure_cursor_shown();
+ if (state.message_shown > 0)
+ state.message_shown--;
+ } else if (!found && (state.mode == COMMANDEDIT || state.mode == SEARC…
+ insert_bottom_bar_text(buf, n);
+ bottom_bar.line_cur_pos += n;
}
- /* FIXME: only do this when necessary */
- ensure_cursor_shown();
}
diff --git a/search.c b/search.c
t@@ -0,0 +1,171 @@
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <pango/pangoxft.h>
+#include <X11/extensions/Xdbe.h>
+
+#include "memory.h"
+#include "common.h"
+#include "buffer.h"
+#include "search.h"
+
+/* FIXME: make sure only whole utf8 chars are matched */
+/* FIXME: clean this up */
+char *last_search = NULL;
+enum {
+ FORWARD,
+ BACKWARD
+} last_dir = FORWARD;
+
+void
+ledit_set_search_forward(char *pattern) {
+ last_dir = FORWARD;
+ free(last_search);
+ last_search = ledit_strdup(pattern);
+}
+
+void
+ledit_cleanup_search(void) {
+ free(last_search);
+}
+
+void
+ledit_set_search_backward(char *pattern) {
+ last_dir = BACKWARD;
+ free(last_search);
+ last_search = ledit_strdup(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;
+ if (last_search == NULL)
+ return SEARCH_NO_PATTERN;
+ int line = buffer->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;
+ char *res;
+ ledit_line *lline = ledit_get_line(buffer, line);
+ if ((res = strstr(lline->text + byte, last_search)) != NULL) {
+ *line_ret = line;
+ *byte_ret = (int)(res - lline->text);
+ return SEARCH_NORMAL;
+ }
+ for (int i = line + 1; i < buffer->lines_num; i++) {
+ lline = ledit_get_line(buffer, i);
+ if ((res = strstr(lline->text, last_search)) != NULL) {
+ *line_ret = i;
+ *byte_ret = (int)(res - lline->text);
+ return SEARCH_NORMAL;
+ }
+ }
+ for (int i = 0; i < line; i++) {
+ lline = ledit_get_line(buffer, i);
+ if ((res = strstr(lline->text, last_search)) != NULL) {
+ *line_ret = i;
+ *byte_ret = (int)(res - lline->text);
+ return SEARCH_WRAPPED;
+ }
+ }
+ lline = ledit_get_line(buffer, line);
+ if ((res = strstr(lline->text, last_search)) != NULL) {
+ *line_ret = line;
+ *byte_ret = (int)(res - lline->text);
+ return SEARCH_WRAPPED;
+ }
+ return SEARCH_NOT_FOUND;
+}
+
+/* FIXME: this is insanely inefficient */
+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;
+ if (last_search == NULL)
+ return SEARCH_NO_PATTERN;
+ int line = buffer->cur_line;
+ int byte = buffer->cur_index;
+ ledit_line *lline = ledit_get_line(buffer, line);
+ char *last = NULL, *res = lline->text;
+ while ((res = strstr(res, last_search)) != NULL && res < lline->text +…
+ last = res;
+ res++;
+ }
+ if (last != NULL) {
+ *line_ret = line;
+ /* FIXME: check if this is safe */
+ *byte_ret = (int)(last - lline->text);
+ return SEARCH_NORMAL;
+ }
+ for (int i = line - 1; i >= 0; i--) {
+ lline = ledit_get_line(buffer, i);
+ res = lline->text;
+ while ((res = strstr(res, last_search)) != NULL) {
+ last = res;
+ res++;
+ }
+ if (last != NULL) {
+ *line_ret = i;
+ *byte_ret = (int)(last - lline->text);
+ return SEARCH_NORMAL;
+ }
+ }
+ for (int i = buffer->lines_num - 1; i > line; i--) {
+ lline = ledit_get_line(buffer, i);
+ res = lline->text;
+ while ((res = strstr(res, last_search)) != NULL) {
+ last = res;
+ res++;
+ }
+ if (last != NULL) {
+ *line_ret = i;
+ *byte_ret = (int)(last - lline->text);
+ return SEARCH_WRAPPED;
+ }
+ }
+ lline = ledit_get_line(buffer, line);
+ res = lline->text + byte;
+ while ((res = strstr(res, last_search)) != NULL) {
+ last = res;
+ res++;
+ }
+ if (last != NULL) {
+ *line_ret = line;
+ *byte_ret = (int)(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) {
+ if (last_dir == FORWARD)
+ return search_forward(buffer, line_ret, byte_ret);
+ else
+ return search_backward(buffer, line_ret, byte_ret);
+}
+
+enum ledit_search_state
+ledit_search_prev(ledit_buffer *buffer, int *line_ret, int *byte_ret) {
+ if (last_dir == FORWARD)
+ return search_backward(buffer, line_ret, byte_ret);
+ else
+ return search_forward(buffer, line_ret, byte_ret);
+}
+
+char *
+ledit_search_state_to_str(enum ledit_search_state state) {
+ switch (state) {
+ case SEARCH_WRAPPED:
+ return "Search wrapped";
+ case SEARCH_NOT_FOUND:
+ return "Pattern not found";
+ case SEARCH_NO_PATTERN:
+ return "No previous search pattern";
+ default:
+ return "This message should not be shown. "
+ "Please bug lumidify about it.";
+ }
+}
diff --git a/search.h b/search.h
t@@ -0,0 +1,13 @@
+enum ledit_search_state {
+ SEARCH_NORMAL,
+ SEARCH_WRAPPED,
+ SEARCH_NOT_FOUND,
+ SEARCH_NO_PATTERN
+};
+
+void ledit_cleanup_search(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,…
+char *ledit_search_state_to_str(enum ledit_search_state state);
You are viewing proxied material from lumidify.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.