aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2014-08-02 14:16:18 +0200
committerMarc André Tanner <mat@brain-dump.org>2014-08-02 14:16:18 +0200
commit53ef4487f58f706f363f7db37e5a894dd98e23e6 (patch)
treefc8c6bd6d2140155fc717a5a38e64671f3c4ed21
parent62ec1d8570f14aae1640c009dfe2ecfcc75ead11 (diff)
downloadvis-53ef4487f58f706f363f7db37e5a894dd98e23e6.tar.gz
vis-53ef4487f58f706f363f7db37e5a894dd98e23e6.tar.xz
Further improve iterator API
- iterator_get now returns the correct piece - add utf8 aware methods to move by a character in either direction
-rw-r--r--editor.c78
-rw-r--r--editor.h19
2 files changed, 68 insertions, 29 deletions
diff --git a/editor.c b/editor.c
index 3f2966d..6516e5e 100644
--- a/editor.c
+++ b/editor.c
@@ -16,6 +16,9 @@
#define BUFFER_SIZE (1 << 20)
+/* is c the start of a utf8 sequence? */
+#define isutf8(c) (((c)&0xC0)!=0x80)
+
/* Buffer holding the file content, either readonly mmap(2)-ed from the original
* file or heap allocated to store the modifications.
*/
@@ -375,8 +378,14 @@ static void piece_init(Piece *p, Piece *prev, Piece *next, const char *data, siz
p->len = len;
}
-/* returns the piece holding the text at byte offset pos.
- * if pos is zero, then the begin sentinel piece is returned. */
+/* returns the piece holding the text at byte offset pos. if pos happens to
+ * be at a piece boundry, the piece to the left is returned with an offset
+ * of piece->len this is convenient for modifications to the piece chain
+ * where both pieces (the returned one and the one following it) are needed,
+ * but unsuitable as a public interface.
+ *
+ * in particular if pos is zero, the begin sentinel piece is returned.
+ */
static Location piece_get(Editor *ed, size_t pos) {
Location loc = {};
size_t cur = 0;
@@ -614,8 +623,8 @@ static void print_piece(Piece *p) {
p->prev ? p->prev->index : -1,
p->len, p->data);
fflush(stderr);
- write(1, p->data, p->len);
- write(1, "\n", 1);
+ write(2, p->data, p->len);
+ write(2, "\n", 1);
}
void editor_debug(Editor *ed) {
@@ -755,8 +764,9 @@ bool editor_modified(Editor *ed) {
return ed->saved_action != ed->undo;
}
-static bool editor_iterator_init(Iterator *it, Piece *p, size_t off) {
+static bool editor_iterator_init(Iterator *it, size_t pos, Piece *p, size_t off) {
*it = (Iterator){
+ .pos = pos,
.piece = p,
.start = p ? p->data : NULL,
.end = p ? p->data + p->len : NULL,
@@ -767,24 +777,34 @@ static bool editor_iterator_init(Iterator *it, Piece *p, size_t off) {
Iterator editor_iterator_get(Editor *ed, size_t pos) {
Iterator it;
- Location loc = piece_get(ed, pos);
- Piece *p = loc.piece;
- editor_iterator_init(&it, p == &ed->begin ? p->next : p, loc.off);
+ Piece *p;
+ size_t cur = 0, off = 0;
+ for (p = ed->begin.next; p->next; p = p->next) {
+ if (cur <= pos && pos < cur + p->len) {
+ off = pos - cur;
+ break;
+ }
+ cur += p->len;
+ }
+
+ editor_iterator_init(&it, pos, p, off);
return it;
}
-Iterator editor_iterator_byte_get(Editor *ed, size_t pos, char *b) {
- Iterator it = editor_iterator_get(ed, pos);
- editor_iterator_byte_peek(&it, b);
- return it;
+bool editor_iterator_byte_get(Iterator *it, char *b) {
+ if (editor_iterator_valid(it) && it->start <= it->text && it->text < it->end) {
+ *b = *it->text;
+ return true;
+ }
+ return false;
}
bool editor_iterator_next(Iterator *it) {
- return editor_iterator_init(it, it->piece ? it->piece->next : NULL, 0);
+ return editor_iterator_init(it, it->pos, it->piece ? it->piece->next : NULL, 0);
}
bool editor_iterator_prev(Iterator *it) {
- return editor_iterator_init(it, it->piece ? it->piece->prev : NULL, 0);
+ return editor_iterator_init(it, it->pos, it->piece ? it->piece->prev : NULL, 0);
}
bool editor_iterator_valid(const Iterator *it) {
@@ -792,14 +812,6 @@ bool editor_iterator_valid(const Iterator *it) {
return it->piece && it->piece->editor;
}
-bool editor_iterator_byte_peek(Iterator *it, char *b) {
- if (editor_iterator_valid(it) && it->start <= it->text && it->text < it->end) {
- *b = *it->text;
- return true;
- }
- return false;
-}
-
bool editor_iterator_byte_next(Iterator *it, char *b) {
if (!editor_iterator_valid(it))
return false;
@@ -809,6 +821,7 @@ bool editor_iterator_byte_next(Iterator *it, char *b) {
return false;
it->text = it->start;
}
+ it->pos++;
if (b)
*b = *it->text;
return true;
@@ -823,11 +836,32 @@ bool editor_iterator_byte_prev(Iterator *it, char *b) {
it->text = it->end;
}
--it->text;
+ --it->pos;
if (b)
*b = *it->text;
return true;
}
+bool editor_iterator_char_next(Iterator *it, char *c) {
+ while (editor_iterator_byte_next(it, NULL)) {
+ if (isutf8(*it->text)) {
+ *c = *it->text;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool editor_iterator_char_prev(Iterator *it, char *c) {
+ while (editor_iterator_byte_prev(it, NULL)) {
+ if (isutf8(*it->text)) {
+ *c = *it->text;
+ return true;
+ }
+ }
+ return false;
+}
+
size_t editor_bytes_get(Editor *ed, size_t pos, size_t len, char *buf) {
if (!buf)
return 0;
diff --git a/editor.h b/editor.h
index 9a109b2..e8d5a44 100644
--- a/editor.h
+++ b/editor.h
@@ -4,10 +4,11 @@ typedef struct Editor Editor;
typedef struct Piece Piece;
typedef struct {
- const char const *start;
- const char const *end;
- const char const *text;
- const Piece const *piece;
+ const char const *start; /* begin of piece's data */
+ const char const *end; /* pointer to the first byte after valid data i.e. [start, end) */
+ const char const *text; /* current position within piece: start <= text < end */
+ const Piece const *piece; /* internal state do not touch! */
+ size_t pos; /* global position in bytes from start of file */
} Iterator;
#define editor_iterate(ed, it, pos) \
@@ -26,14 +27,18 @@ bool editor_undo(Editor*);
bool editor_redo(Editor*);
size_t editor_bytes_get(Editor*, size_t pos, size_t len, char *buf);
-bool editor_iterator_valid(const Iterator*);
+
Iterator editor_iterator_get(Editor*, size_t pos);
+bool editor_iterator_valid(const Iterator*);
bool editor_iterator_next(Iterator*);
bool editor_iterator_prev(Iterator*);
-Iterator editor_iterator_byte_get(Editor*, size_t pos, char *byte);
+
+bool editor_iterator_byte_get(Iterator *it, char *b);
bool editor_iterator_byte_next(Iterator*, char *b);
bool editor_iterator_byte_prev(Iterator*, char *b);
-bool editor_iterator_byte_peek(Iterator *it, char *b);
+
+bool editor_iterator_char_next(Iterator *it, char *c);
+bool editor_iterator_char_prev(Iterator *it, char *c);
size_t editor_size(Editor*);
bool editor_modified(Editor*);