aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--editor.c205
-rw-r--r--editor.h10
-rw-r--r--text-motions.c228
-rw-r--r--text-motions.h58
-rw-r--r--text-objects.c38
-rw-r--r--text-objects.h13
-rw-r--r--text.c4
-rw-r--r--text.h11
9 files changed, 389 insertions, 185 deletions
diff --git a/Makefile b/Makefile
index 2bcc82e..cd0ca71 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,8 @@
include config.mk
-SRC += vis.c colors.c editor.c text.c
+SRC += vis.c colors.c editor.c text.c text-motions.c text-objects.c
+ALL = ${SRC} util.h editor.h text.h text-motions.h text-objects.h \
+ config.def.h config.mk Makefile LICENSE README vis.1
OBJ = ${SRC:.c=.o}
all: clean options vis
@@ -36,8 +38,7 @@ clean:
dist: clean
@echo creating dist tarball
@mkdir -p vis-${VERSION}
- @cp -R LICENSE Makefile README config.def.h config.mk \
- ${SRC} editor.h text.h util.h vis.1 vis-${VERSION}
+ @cp -R ${ALL} vis-${VERSION}
@tar -cf vis-${VERSION}.tar vis-${VERSION}
@gzip vis-${VERSION}.tar
@rm -rf vis-${VERSION}
diff --git a/editor.c b/editor.c
index 009511d..78f7916 100644
--- a/editor.c
+++ b/editor.c
@@ -21,6 +21,8 @@
#include <errno.h>
#include "editor.h"
#include "text.h"
+#include "text-motions.h"
+#include "text-objects.h"
#include "util.h"
typedef struct { /* used to calculate the display width of a character */
@@ -729,23 +731,7 @@ size_t editor_line_down(Editor *ed) {
}
static size_t window_line_begin(Win *win) {
- char c;
- size_t pos = win->cursor.pos;
- Iterator it = text_iterator_get(win->text, pos);
- if (!text_iterator_byte_get(&it, &c))
- return pos;
- if (c == '\r')
- text_iterator_byte_prev(&it, &c);
- if (c == '\n')
- text_iterator_byte_prev(&it, &c);
- while (text_iterator_byte_get(&it, &c)) {
- if (c == '\n' || c == '\r') {
- it.pos++;
- break;
- }
- text_iterator_byte_prev(&it, NULL);
- }
- return cursor_move_to(win, it.pos);
+ return cursor_move_to(win, text_line_begin(win->text, win->cursor.pos));
}
size_t editor_line_begin(Editor *ed) {
@@ -753,213 +739,76 @@ size_t editor_line_begin(Editor *ed) {
}
size_t editor_line_start(Editor *ed) {
- char c;
Win *win = ed->win;
- editor_line_begin(ed);
- Iterator it = text_iterator_get(win->text, win->cursor.pos);
- while (text_iterator_byte_get(&it, &c) && c != '\n' && isspace(c))
- text_iterator_byte_next(&it, NULL);
- while (win->end < it.pos && scroll_line_down(win, 1));
- return cursor_move_to(win, it.pos);
+ size_t pos = text_line_start(win->text, win->cursor.pos);
+ while (win->end < pos && scroll_line_down(win, 1));
+ return cursor_move_to(win, pos);
}
size_t editor_line_end(Editor *ed) {
- char c;
Win *win = ed->win;
- Iterator it = text_iterator_get(win->text, win->cursor.pos);
- while (text_iterator_byte_get(&it, &c) && c != '\n')
- text_iterator_byte_next(&it, NULL);
- while (win->end < it.pos && scroll_line_down(win, 1));
- return cursor_move_to(win, it.pos);
+ size_t pos = text_line_end(win->text, win->cursor.pos);
+ while (win->end < pos && scroll_line_down(win, 1));
+ return cursor_move_to(win, pos);
}
size_t editor_line_finish(Editor *ed) {
- char c;
Win *win = ed->win;
- Iterator it = text_iterator_get(win->text, editor_line_end(ed));
- do text_iterator_byte_prev(&it, NULL);
- while (text_iterator_byte_get(&it, &c) && c != '\n' && c != '\r' && isspace(c));
- return cursor_move_to(win, it.pos);
+ size_t pos = text_line_finish(win->text, win->cursor.pos);
+ return cursor_move_to(win, pos);
}
size_t editor_word_end_prev(Editor *ed) {
- char c;
Win *win = ed->win;
- Iterator it = text_iterator_get(win->text, win->cursor.pos);
- while (text_iterator_byte_prev(&it, &c) && !isspace(c));
- while (text_iterator_char_prev(&it, &c) && isspace(c));
- while (win->start > it.pos && scroll_line_up(win, 1));
- return cursor_move_to(win, it.pos);
+ size_t pos = text_word_end_prev(win->text, win->cursor.pos);
+ while (win->start > pos && scroll_line_up(win, 1));
+ return cursor_move_to(win, pos);
}
size_t editor_word_end_next(Editor *ed) {
- char c;
Win *win = ed->win;
- size_t pos = win->cursor.pos;
- Iterator it = text_iterator_get(win->text, pos);
- while (text_iterator_char_next(&it, &c) && isspace(c));
- do pos = it.pos; while (text_iterator_char_next(&it, &c) && !isspace(c));
+ size_t pos = text_word_end_next(win->text, win->cursor.pos);
while (win->end < pos && scroll_line_down(win, 1));
return cursor_move_to(win, pos);
}
size_t editor_word_start_next(Editor *ed) {
- char c;
Win *win = ed->win;
- Iterator it = text_iterator_get(win->text, win->cursor.pos);
- while (text_iterator_byte_get(&it, &c) && !isspace(c))
- text_iterator_byte_next(&it, NULL);
- while (text_iterator_byte_get(&it, &c) && isspace(c))
- text_iterator_byte_next(&it, NULL);
- while (win->end < it.pos && scroll_line_down(win, 1));
- return cursor_move_to(win, it.pos);
+ size_t pos = text_word_start_next(win->text, win->cursor.pos);
+ while (win->end < pos && scroll_line_down(win, 1));
+ return cursor_move_to(win, pos);
}
size_t editor_word_start_prev(Editor *ed) {
- char c;
Win *win = ed->win;
- size_t pos = win->cursor.pos;
- Iterator it = text_iterator_get(win->text, pos);
- while (text_iterator_byte_prev(&it, &c) && isspace(c));
- do pos = it.pos; while (text_iterator_char_prev(&it, &c) && !isspace(c));
+ size_t pos = text_word_start_prev(win->text, win->cursor.pos);
while (win->start > pos && scroll_line_up(win, 1));
return cursor_move_to(win, pos);
}
-static size_t editor_paragraph_sentence_next(Editor *ed, bool sentence) {
- char c;
- bool content = false, paragraph = false;
- Win *win = ed->win;
- size_t pos = win->cursor.pos;
- Iterator it = text_iterator_get(win->text, pos);
- while (text_iterator_byte_next(&it, &c)) {
- content |= !isspace(c);
- if (sentence && (c == '.' || c == '?' || c == '!') && text_iterator_byte_next(&it, &c) && isspace(c)) {
- if (c == '\n' && text_iterator_byte_next(&it, &c)) {
- if (c == '\r')
- text_iterator_byte_next(&it, &c);
- } else {
- while (text_iterator_byte_get(&it, &c) && c == ' ')
- text_iterator_byte_next(&it, NULL);
- }
- break;
- }
- if (c == '\n' && text_iterator_byte_next(&it, &c)) {
- if (c == '\r')
- text_iterator_byte_next(&it, &c);
- content |= !isspace(c);
- if (c == '\n')
- paragraph = true;
- }
- if (content && paragraph)
- break;
- }
- while (win->end < it.pos && scroll_line_down(win, 1));
- return cursor_move_to(win, it.pos);
-}
-
size_t editor_sentence_next(Editor *ed) {
- return editor_paragraph_sentence_next(ed, true);
+ Win *win = ed->win;
+ return cursor_move_to_line(win, text_sentence_next(win->text, win->cursor.pos));
}
size_t editor_paragraph_next(Editor *ed) {
- return editor_paragraph_sentence_next(ed, false);
-}
-
-static size_t editor_paragraph_sentence_prev(Editor *ed, bool sentence) {
- char prev, c;
- bool content = false, paragraph = false;
Win *win = ed->win;
- size_t pos = win->cursor.pos;
-
- Iterator it = text_iterator_get(win->text, pos);
- if (!text_iterator_byte_get(&it, &prev))
- return pos;
-
- while (text_iterator_byte_prev(&it, &c)) {
- content |= !isspace(c) && c != '.' && c != '?' && c != '!';
- if (sentence && content && (c == '.' || c == '?' || c == '!') && isspace(prev)) {
- do text_iterator_byte_next(&it, NULL);
- while (text_iterator_byte_get(&it, &c) && isspace(c));
- break;
- }
- if (c == '\r')
- text_iterator_byte_prev(&it, &c);
- if (c == '\n' && text_iterator_byte_prev(&it, &c)) {
- content |= !isspace(c);
- if (c == '\r')
- text_iterator_byte_prev(&it, &c);
- if (c == '\n') {
- paragraph = true;
- if (content) {
- do text_iterator_byte_next(&it, NULL);
- while (text_iterator_byte_get(&it, &c) && isspace(c));
- break;
- }
- }
- }
- if (content && paragraph) {
- do text_iterator_byte_next(&it, NULL);
- while (text_iterator_byte_get(&it, &c) && !isspace(c));
- break;
- }
- prev = c;
- }
- while (win->end < it.pos && scroll_line_down(win, 1));
- return cursor_move_to(win, it.pos);
+ return cursor_move_to_line(win, text_paragraph_next(win->text, win->cursor.pos));
}
size_t editor_sentence_prev(Editor *ed) {
- return editor_paragraph_sentence_prev(ed, true);
+ Win *win = ed->win;
+ return cursor_move_to_line(win, text_sentence_prev(win->text, win->cursor.pos));
}
size_t editor_paragraph_prev(Editor *ed) {
- return editor_paragraph_sentence_prev(ed, false);
+ Win *win = ed->win;
+ return cursor_move_to_line(win, text_paragraph_prev(win->text, win->cursor.pos));
}
size_t editor_bracket_match(Editor *ed) {
Win *win = ed->win;
- int direction, count = 1;
- char search, current, c;
- size_t pos = win->cursor.pos;
- Iterator it = text_iterator_get(win->text, pos);
- if (!text_iterator_byte_get(&it, &current))
- return pos;
-
- switch (current) {
- case '(': search = ')'; direction = 1; break;
- case ')': search = '('; direction = -1; break;
- case '{': search = '}'; direction = 1; break;
- case '}': search = '{'; direction = -1; break;
- case '[': search = ']'; direction = 1; break;
- case ']': search = '['; direction = -1; break;
- case '<': search = '>'; direction = 1; break;
- case '>': search = '<'; direction = -1; break;
- case '"': search = '"'; direction = 1; break;
- default: return pos;
- }
-
- if (direction >= 0) { /* forward search */
- while (text_iterator_byte_next(&it, &c)) {
- if (c == search && --count == 0) {
- pos = it.pos;
- break;
- } else if (c == current) {
- count++;
- }
- }
- } else { /* backwards */
- while (text_iterator_byte_prev(&it, &c)) {
- if (c == search && --count == 0) {
- pos = it.pos;
- break;
- } else if (c == current) {
- count++;
- }
- }
- }
-
- return cursor_move_to_line(win, pos);
+ return cursor_move_to_line(win, text_bracket_match(win->text, win->cursor.pos));
}
void editor_draw(Editor *ed) {
diff --git a/editor.h b/editor.h
index d36e503..f141963 100644
--- a/editor.h
+++ b/editor.h
@@ -1,5 +1,9 @@
+#ifndef EDITOR_H
+#define EDITOR_H
+
#include <curses.h>
#include <regex.h>
+#include "text.h"
typedef struct {
short fg, bg; /* fore and background color */
@@ -25,10 +29,6 @@ typedef struct { /* a syntax definition */
typedef struct Editor Editor;
typedef size_t Filepos;
-typedef struct {
- Filepos start, end; /* range in bytes from start of file */
-} Filerange;
-
typedef void (*editor_statusbar_t)(WINDOW *win, bool active, const char *filename, int line, int col);
/* initialize a new editor with the available screen size */
@@ -102,3 +102,5 @@ void editor_init(void);
// TODO: comment
short editor_color_reserve(short fg, short bg);
short editor_color_get(short fg, short bg);
+
+#endif
diff --git a/text-motions.c b/text-motions.c
new file mode 100644
index 0000000..1313c94
--- /dev/null
+++ b/text-motions.c
@@ -0,0 +1,228 @@
+#include <ctype.h>
+#include "text-motions.h"
+
+// TODO: consistent usage of iterators either char or byte based where appropriate.
+
+size_t text_line_begin(Text *txt, size_t pos) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ if (!text_iterator_byte_get(&it, &c))
+ return pos;
+ if (c == '\r')
+ text_iterator_byte_prev(&it, &c);
+ if (c == '\n')
+ text_iterator_byte_prev(&it, &c);
+ while (text_iterator_byte_get(&it, &c)) {
+ if (c == '\n' || c == '\r') {
+ it.pos++;
+ break;
+ }
+ text_iterator_byte_prev(&it, NULL);
+ }
+ return pos;
+}
+
+size_t text_line_start(Text *txt, size_t pos) {
+ char c;
+ Iterator it = text_iterator_get(txt, text_line_begin(txt, pos));
+ while (text_iterator_byte_get(&it, &c) && c != '\n' && isspace(c))
+ text_iterator_byte_next(&it, NULL);
+ return it.pos;
+}
+
+size_t text_line_finish(Text *txt, size_t pos) {
+ char c;
+ Iterator it = text_iterator_get(txt, text_line_end(txt, pos));
+ do text_iterator_byte_prev(&it, NULL);
+ while (text_iterator_byte_get(&it, &c) && c != '\n' && c != '\r' && isspace(c));
+ return it.pos;
+}
+
+size_t text_line_end(Text *txt, size_t pos) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_byte_get(&it, &c) && c != '\n')
+ text_iterator_byte_next(&it, NULL);
+ return it.pos;
+}
+
+
+size_t text_word_boundry_start_next(Text *txt, size_t pos, int (*isboundry)(int)) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_byte_get(&it, &c) && !isboundry(c))
+ text_iterator_byte_next(&it, NULL);
+ while (text_iterator_byte_get(&it, &c) && isboundry(c))
+ text_iterator_byte_next(&it, NULL);
+ return it.pos;
+}
+
+size_t text_word_boundry_start_prev(Text *txt, size_t pos, int (*isboundry)(int)) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_byte_prev(&it, &c) && isboundry(c));
+ do pos = it.pos; while (text_iterator_char_prev(&it, &c) && !isboundry(c));
+ return pos;
+}
+
+size_t text_word_boundry_end_next(Text *txt, size_t pos, int (*isboundry)(int)) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_char_next(&it, &c) && isboundry(c));
+ do pos = it.pos; while (text_iterator_char_next(&it, &c) && !isboundry(c));
+ return pos;
+}
+
+size_t text_word_boundry_end_prev(Text *txt, size_t pos, int (*isboundry)(int)) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_byte_prev(&it, &c) && !isboundry(c));
+ while (text_iterator_char_prev(&it, &c) && isboundry(c));
+ return it.pos;
+}
+
+size_t text_word_end_next(Text *txt, size_t pos) {
+ return text_word_boundry_end_next(txt, pos, isspace);
+}
+
+size_t text_word_end_prev(Text *txt, size_t pos) {
+ return text_word_boundry_end_prev(txt, pos, isspace);
+}
+
+size_t text_word_start_next(Text *txt, size_t pos) {
+ return text_word_boundry_start_next(txt, pos, isspace);
+}
+
+size_t text_word_start_prev(Text *txt, size_t pos) {
+ return text_word_boundry_start_prev(txt, pos, isspace);
+}
+
+static size_t text_paragraph_sentence_next(Text *txt, size_t pos, bool sentence) {
+ char c;
+ bool content = false, paragraph = false;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_byte_next(&it, &c)) {
+ content |= !isspace(c);
+ if (sentence && (c == '.' || c == '?' || c == '!') && text_iterator_byte_next(&it, &c) && isspace(c)) {
+ if (c == '\n' && text_iterator_byte_next(&it, &c)) {
+ if (c == '\r')
+ text_iterator_byte_next(&it, &c);
+ } else {
+ while (text_iterator_byte_get(&it, &c) && c == ' ')
+ text_iterator_byte_next(&it, NULL);
+ }
+ break;
+ }
+ if (c == '\n' && text_iterator_byte_next(&it, &c)) {
+ if (c == '\r')
+ text_iterator_byte_next(&it, &c);
+ content |= !isspace(c);
+ if (c == '\n')
+ paragraph = true;
+ }
+ if (content && paragraph)
+ break;
+ }
+ return it.pos;
+}
+
+static size_t text_paragraph_sentence_prev(Text *txt, size_t pos, bool sentence) {
+ char prev, c;
+ bool content = false, paragraph = false;
+
+ Iterator it = text_iterator_get(txt, pos);
+ if (!text_iterator_byte_get(&it, &prev))
+ return pos;
+
+ while (text_iterator_byte_prev(&it, &c)) {
+ content |= !isspace(c) && c != '.' && c != '?' && c != '!';
+ if (sentence && content && (c == '.' || c == '?' || c == '!') && isspace(prev)) {
+ do text_iterator_byte_next(&it, NULL);
+ while (text_iterator_byte_get(&it, &c) && isspace(c));
+ break;
+ }
+ if (c == '\r')
+ text_iterator_byte_prev(&it, &c);
+ if (c == '\n' && text_iterator_byte_prev(&it, &c)) {
+ content |= !isspace(c);
+ if (c == '\r')
+ text_iterator_byte_prev(&it, &c);
+ if (c == '\n') {
+ paragraph = true;
+ if (content) {
+ do text_iterator_byte_next(&it, NULL);
+ while (text_iterator_byte_get(&it, &c) && isspace(c));
+ break;
+ }
+ }
+ }
+ if (content && paragraph) {
+ do text_iterator_byte_next(&it, NULL);
+ while (text_iterator_byte_get(&it, &c) && !isspace(c));
+ break;
+ }
+ prev = c;
+ }
+ return it.pos;
+}
+
+size_t text_sentence_next(Text *txt, size_t pos) {
+ return text_paragraph_sentence_next(txt, pos, true);
+}
+
+size_t text_sentence_prev(Text *txt, size_t pos) {
+ return text_paragraph_sentence_prev(txt, pos, true);
+}
+
+size_t text_paragraph_next(Text *txt, size_t pos) {
+ return text_paragraph_sentence_next(txt, pos, false);
+}
+
+size_t text_paragraph_prev(Text *txt, size_t pos) {
+ return text_paragraph_sentence_prev(txt, pos, false);
+}
+
+size_t text_bracket_match(Text *txt, size_t pos) {
+ int direction, count = 1;
+ char search, current, c;
+ Iterator it = text_iterator_get(txt, pos);
+ if (!text_iterator_byte_get(&it, &current))
+ return pos;
+
+ switch (current) {
+ case '(': search = ')'; direction = 1; break;
+ case ')': search = '('; direction = -1; break;
+ case '{': search = '}'; direction = 1; break;
+ case '}': search = '{'; direction = -1; break;
+ case '[': search = ']'; direction = 1; break;
+ case ']': search = '['; direction = -1; break;
+ case '<': search = '>'; direction = 1; break;
+ case '>': search = '<'; direction = -1; break;
+ // TODO: heuristic basic on neighbouring chars shared with text-object
+ case '"': search = '"'; direction = 1; break;
+ case '\'': search = '\''; direction = 1; break;
+ default: return pos;
+ }
+
+ if (direction >= 0) { /* forward search */
+ while (text_iterator_byte_next(&it, &c)) {
+ if (c == search && --count == 0) {
+ pos = it.pos;
+ break;
+ } else if (c == current) {
+ count++;
+ }
+ }
+ } else { /* backwards */
+ while (text_iterator_byte_prev(&it, &c)) {
+ if (c == search && --count == 0) {
+ pos = it.pos;
+ break;
+ } else if (c == current) {
+ count++;
+ }
+ }
+ }
+
+ return pos;
+}
diff --git a/text-motions.h b/text-motions.h
new file mode 100644
index 0000000..bbeca49
--- /dev/null
+++ b/text-motions.h
@@ -0,0 +1,58 @@
+#ifndef TEXT_MOTIONS_H
+#define TEXT_MOTIONS_H
+
+#include <stddef.h>
+#include "text.h"
+
+/* begin finish
+ * v v
+ * | I am a line! |
+ * ^ ^
+ * start end
+ */
+size_t text_line_begin(Text*, size_t pos);
+size_t text_line_start(Text*, size_t pos);
+size_t text_line_finish(Text*, size_t pos);
+size_t text_line_end(Text*, size_t pos);
+/*
+ * A word consists of a sequence of non-blank characters, separated with white space.
+ * TODO?: An empty line is also considered to be a word. This is equivalant to a WORD
+ * in vim terminology.
+ */
+size_t text_word_end_next(Text*, size_t pos);
+size_t text_word_end_prev(Text*, size_t pos);
+size_t text_word_start_next(Text*, size_t pos);
+size_t text_word_start_prev(Text*, size_t pos);
+/*
+ * These are variants of the above with the additional possibility to implement
+ * a custom word detection logic. Can be used to implment the equivalent of a what
+ * vim reconizes as a word (lowercase).
+ */
+size_t text_word_boundry_end_next(Text*, size_t pos, int (*isboundry)(int));
+size_t text_word_boundry_end_prev(Text*, size_t pos, int (*isboundry)(int));
+size_t text_word_boundry_start_next(Text*, size_t pos, int (*isboundry)(int));
+size_t text_word_boundry_start_prev(Text*, size_t pos, int (*isboundry)(int));
+/* TODO: implement the following semantics
+ * A sentence is defined as ending at a '.', '!' or '?' followed by either the
+ * end of a line, or by a space or tab. Any number of closing ')', ']', '"'
+ * and ''' characters may appear after the '.', '!' or '?' before the spaces,
+ * tabs or end of line. A paragraph and section boundary is also a sentence
+ * boundary.
+ */
+size_t text_sentence_next(Text*, size_t pos);
+size_t text_sentence_prev(Text*, size_t pos);
+/* TODO: implement the following semantics
+ * A paragraph begins after each empty line. A section boundary is also a
+ * paragraph boundary. Note that a blank line (only containing white space)
+ * is NOT a paragraph boundary.
+ */
+size_t text_paragraph_next(Text*, size_t pos);
+size_t text_paragraph_prev(Text*, size_t pos);
+/* A section begins after a form-feed in the first column.
+size_t text_section_next(Text*, size_t pos);
+size_t text_section_prev(Text*, size_t pos);
+*/
+/* search coresponding '(', ')', '{', '}', '[', ']', '>', '<', '"', ''' */
+size_t text_bracket_match(Text*, size_t pos);
+
+#endif
diff --git a/text-objects.c b/text-objects.c
new file mode 100644
index 0000000..d6ac4a3
--- /dev/null
+++ b/text-objects.c
@@ -0,0 +1,38 @@
+#include <ctype.h>
+#include "text-motions.h"
+#include "text-objects.h"
+
+static Filerange empty = {
+ .start = -1,
+ .end = -1,
+};
+
+// TODO: fix problems with inclusive / exclusive
+Filerange text_object_word(Text *txt, size_t pos) {
+ char c;
+ Filerange r;
+ if (!text_byte_get(txt, pos, &c))
+ return empty;
+ if (!isspace(c)) {
+ r.start = text_word_start_prev(txt, pos);
+ r.end = text_word_end_next(txt, pos);
+ } else {
+ r.start = text_word_end_prev(txt, pos);
+ r.end = text_word_start_next(txt, pos);
+ }
+ return r;
+}
+
+Filerange text_object_sentence(Text *txt, size_t pos) {
+ Filerange r;
+ r.start = text_sentence_prev(txt, pos);
+ r.end = text_sentence_next(txt, pos);
+ return r;
+}
+
+Filerange text_object_paragraph(Text *txt, size_t pos) {
+ Filerange r;
+ r.start = text_paragraph_prev(txt, pos);
+ r.end = text_paragraph_next(txt, pos);
+ return r;
+}
diff --git a/text-objects.h b/text-objects.h
new file mode 100644
index 0000000..62d30e5
--- /dev/null
+++ b/text-objects.h
@@ -0,0 +1,13 @@
+#ifndef TEXT_OBJECTS_H
+#define TEXT_OBJECTS_H
+
+#include <stddef.h>
+#include "text.h"
+
+Filerange text_object_word(Text*, size_t pos);
+Filerange text_object_word_boundry(Text*, size_t pos, int (*isboundry)(int));
+Filerange text_object_char(Text*, size_t pos, char c);
+Filerange text_object_sentence(Text*, size_t pos);
+Filerange text_object_paragraph(Text*, size_t pos);
+
+#endif
diff --git a/text.c b/text.c
index 25ce1ed..c41fe3e 100644
--- a/text.c
+++ b/text.c
@@ -897,6 +897,10 @@ bool text_iterator_char_prev(Iterator *it, char *c) {
return false;
}
+bool text_byte_get(Text *ed, size_t pos, char *buf) {
+ return text_bytes_get(ed, pos, 1, buf);
+}
+
size_t text_bytes_get(Text *ed, size_t pos, size_t len, char *buf) {
if (!buf)
return 0;
diff --git a/text.h b/text.h
index 62800b8..9d4fa34 100644
--- a/text.h
+++ b/text.h
@@ -1,4 +1,12 @@
+#ifndef TEXT_H
+#define TEXT_H
+
#include <stdbool.h>
+#include <stddef.h>
+
+typedef struct {
+ size_t start, end; /* range in bytes from start of file */
+} Filerange;
typedef struct Text Text;
typedef struct Piece Piece;
@@ -28,6 +36,7 @@ bool text_redo(Text*);
size_t text_pos_by_lineno(Text*, size_t lineno);
size_t text_lineno_by_pos(Text*, size_t pos);
+bool text_byte_get(Text *ed, size_t pos, char *buf);
size_t text_bytes_get(Text*, size_t pos, size_t len, char *buf);
Iterator text_iterator_get(Text*, size_t pos);
@@ -68,3 +77,5 @@ int text_search_backward(Text*, size_t pos, size_t len, Regex *r, size_t nmatch,
// TMP
void text_debug(Text *ed);
+
+#endif