summaryrefslogtreecommitdiff
path: root/txt.c
diff options
context:
space:
mode:
Diffstat (limited to 'txt.c')
-rw-r--r--txt.c86
1 files changed, 51 insertions, 35 deletions
diff --git a/txt.c b/txt.c
index 36af521..3bd9eb4 100644
--- a/txt.c
+++ b/txt.c
@@ -94,48 +94,65 @@ static int txt_are_pieces_adjacent(Txt *t, u32 a, u32 b) {
return pa->buf == pb->buf && pa->ofs + pa->n == pb->ofs;
}
-static TxtLoc txt_join_or_kill(TxtLoc l) {
- Txt *b = l.t;
- while (l.t->ptbl.v[l.p].n == 0 && b->ptbl.n > 1) {
- txt_remove_piece(b, l.p);
- if (l.p >= b->ptbl.n) {
- l.p = b->ptbl.n - 1;
- l.i = b->ptbl.v[l.p].n;
- }
+static int txt_trim_empty(TxtLoc *lp) {
+ TxtLoc l = *lp;
+ int deleted = 0;
+ while (l.p > 0 && l.t->ptbl.v[l.p-1].n == 0) {
+ txt_remove_piece(l.t, l.p - 1);
+ l.p--;
+ deleted = 1;
}
- while (l.p + 1 < b->ptbl.n && l.t->ptbl.v[l.p + 1].n == 0) {
- txt_remove_piece(b, l.p + 1);
- if (l.p >= b->ptbl.n) {
- l.p = b->ptbl.n - 1;
- l.i = b->ptbl.v[l.p].n;
- }
+ while (l.p + 1 < l.t->ptbl.n && l.t->ptbl.v[l.p+1].n == 0) {
+ txt_remove_piece(l.t, l.p + 1);
+ deleted = 1;
}
- if (l.p + 1 < b->ptbl.n && txt_are_pieces_adjacent(b, l.p, l.p + 1)) {
- b->ptbl.v[l.p].n += b->ptbl.v[l.p+1].n;
- txt_remove_piece(b, l.p + 1);
- if (l.p >= b->ptbl.n) {
- l.p = b->ptbl.n - 1;
- l.i = b->ptbl.v[l.p].n;
+ while (l.t->ptbl.n > 1 && l.t->ptbl.v[l.p].n == 0) {
+ txt_remove_piece(l.t, l.p);
+ if (l.p >= l.t->ptbl.n) {
+ l.p = l.t->ptbl.n - 1;
+ l.i = l.t->ptbl.v[l.p].n;
}
+ deleted = 1;
}
- if (l.p > 0 && txt_are_pieces_adjacent(b, l.p - 1, l.p)) {
- l.i = b->ptbl.v[l.p - 1].n;
- b->ptbl.v[l.p - 1].n += b->ptbl.v[l.p].n;
- txt_remove_piece(b, l.p);
- l.p--;
- ASSERT(l.p < b->ptbl.n);
- }
- return l;
+ *lp = l;
+ return deleted;
}
static inline TxtLoc resolve_loc(TxtLoc l) {
- if (l.p + 1 < l.t->ptbl.n && l.i == l.t->ptbl.v[l.p].n) {
+ while (l.p + 1 < l.t->ptbl.n && l.i == l.t->ptbl.v[l.p].n) {
l.p++;
l.i = 0;
}
+ ASSERT(txt_valid_loc(l));
return l;
}
+static TxtLoc txt_post_edit(TxtLoc l) {
+ l = resolve_loc(l);
+ ASSERT(txt_valid_loc(l));
+loop:
+ if (txt_trim_empty(&l)) {
+ ASSERT(txt_valid_loc(l));
+ goto loop;
+ }
+ if (l.p > 0 && txt_are_pieces_adjacent(l.t, l.p - 1, l.p)) {
+ l.i = l.t->ptbl.v[l.p - 1].n;
+ l.t->ptbl.v[l.p - 1].n += l.t->ptbl.v[l.p].n;
+ txt_remove_piece(l.t, l.p);
+ l.p--;
+ ASSERT(txt_valid_loc(l));
+ goto loop;
+ }
+ if (l.p + 1 < l.t->ptbl.n && txt_are_pieces_adjacent(l.t, l.p, l.p + 1)) {
+ l.t->ptbl.v[l.p].n += l.t->ptbl.v[l.p + 1].n;
+ txt_remove_piece(l.t, l.p + 1);
+ ASSERT(txt_valid_loc(l));
+ goto loop;
+ }
+ ASSERT(txt_valid_loc(l));
+ return resolve_loc(l);
+}
+
TxtLoc txt_insert(TxtLoc l, const char *s, u32 n) {
l = txt_add_piece(l.t, l);
TxtPiece *p = &l.t->ptbl.v[l.p];
@@ -148,9 +165,7 @@ TxtLoc txt_insert(TxtLoc l, const char *s, u32 n) {
p->n += n;
l.t->len += n;
l.i = p->n;
- l = txt_join_or_kill(l);
- l.i = l.t->ptbl.v[l.p].n;
- return resolve_loc(l);
+ return txt_post_edit(l);
}
TxtLoc txt_insert_c(TxtLoc l, u32 ch) {
@@ -166,7 +181,7 @@ TxtLoc txt_delete(TxtLoc l, u32 n) {
l.p = pi;
l.i = l.t->ptbl.v[l.p].n;
for (;;) {
- ASSERT(l.i == l.t->ptbl.v[l.p].n);
+ if (l.i != l.t->ptbl.v[l.p].n) break;
if (l.i >= n) {
l.i -= n;
l.t->ptbl.v[l.p].n -= n;
@@ -179,9 +194,9 @@ TxtLoc txt_delete(TxtLoc l, u32 n) {
l.p = l.p - 1;
l.i = l.t->ptbl.v[l.p].n;
}
- l = txt_join_or_kill(l);
+ while (txt_trim_empty(&l));
}
- return resolve_loc(txt_join_or_kill(l));
+ return txt_post_edit(l);
}
u32 txt_range_len(TxtLoc lo, TxtLoc hi) {
@@ -270,6 +285,7 @@ void txt_write_range(int fd, TxtLoc lo, TxtLoc hi) {
lo.p++;
lo.i = 0;
}
+ ASSERT(lo.p == hi.p);
if (hi.i > lo.i) {
TxtPiece *p = &lo.t->ptbl.v[lo.p];
write(fd, lo.t->buf[p->buf].s + p->ofs + lo.i, hi.i - lo.i);