/* text files should always end in a new line. If we detected a
binary file or at least a non-utf8 file, skip this part. */
if (!buf_iseol(buf, buf_end(buf)-1))
- buf_insert(buf, false, buf_end(buf), '\n');
+ buf_putc(buf, '\n', &(Sel){ .end = buf_end(buf)-1 });
char* wptr;
long fd, nwrite, towrite;
}
}
-Rune buf_get(Buf* buf, size_t off) {
- if (off >= buf_end(buf)) return (Rune)'\n';
+size_t buf_end(Buf* buf) {
+ size_t bufsz = buf->bufend - buf->bufstart;
+ size_t gapsz = buf->gapend - buf->gapstart;
+ return (bufsz - gapsz);
+}
+
+/******************************************************************************/
+
+static Sel getsel(Buf* buf, Sel* p_sel) {
+ size_t temp;
+ Sel sel = (p_sel ? *p_sel : buf->selection);
+ if (sel.end < sel.beg)
+ temp = sel.beg, sel.beg = sel.end, sel.end = temp;
+ return sel;
+}
+
+static void setsel(Buf* buf, Sel* p_sel, Sel* p_newsel) {
+ if (p_sel)
+ *p_sel = *p_newsel;
+ else
+ buf->selection = *p_newsel;
+}
+
+static void putb(Buf* buf, char b, Sel* p_sel) {
+ syncgap(buf, p_sel->end);
+ *(buf->gapstart++) = b;
+ p_sel->end = p_sel->end + 1u;
+ p_sel->beg = p_sel->end;
+}
+
+static char getb(Buf* buf, size_t off) {
size_t bsz = (buf->gapstart - buf->bufstart);
if (off < bsz)
return *(buf->bufstart + off);
return *(buf->gapend + (off - bsz));
}
-size_t buf_end(Buf* buf) {
- size_t bufsz = buf->bufend - buf->bufstart;
- size_t gapsz = buf->gapend - buf->gapstart;
- return (bufsz - gapsz);
+int buf_getrat(Buf* buf, size_t off) {
+ size_t rlen = 0;
+ Rune rune = 0;
+ while (!utf8decode(&rune, &rlen, getb(buf, off++)));
+ return rune;
}
-size_t buf_insert(Buf* buf, bool fmt, size_t off, Rune rune) {
- bool is_eol = (rune == '\n');
- buf->modified = true;
- if (fmt && ExpandTabs && rune == '\t') {
- size_t tabwidth = TabWidth;
- size_t n = (tabwidth - ((off - buf_bol(buf, off)) % tabwidth));
- log_insert(buf, &(buf->undo), off, off+n);
- for(; n > 0; n--) off += insert(buf, off, ' ');
- } else {
- size_t n = insert(buf, off, rune);
- if (n > 0) {
- log_insert(buf, &(buf->undo), off, off+n);
- off += n;
- }
- }
- if (fmt && CopyIndent && is_eol) {
- size_t beg = buf_bol(buf, off-1), end = beg;
- for (; end < buf_end(buf) && (' ' == buf_get(buf, end) || '\t' == buf_get(buf, end)); end++);
- for (; beg < end; beg++)
- off = buf_insert(buf, true, off, buf_get(buf, beg));
- }
- log_clear(&(buf->redo));
- return off;
+void buf_putc(Buf* buf, int c, Sel* p_sel) {
+ char utf8buf[UTF_MAX+1] = {0};
+ (void)utf8encode(utf8buf, c);
+ buf_puts(buf, utf8buf, p_sel);
}
-size_t buf_delete(Buf* buf, size_t beg, size_t end) {
- buf->modified = true;
- log_clear(&(buf->redo));
- for (size_t i = end-beg; i > 0; i--) {
- char c = buf_get(buf, beg);
- log_delete(buf, &(buf->undo), beg, &c, 1);
- delete(buf, beg);
+void buf_puts(Buf* buf, char* s, Sel* p_sel) {
+ buf_del(buf, p_sel);
+ Sel sel = getsel(buf, p_sel);
+ while (s && *s) putb(buf, *(s++), &sel);
+ setsel(buf, p_sel, &sel);
+}
+
+int buf_getc(Buf* buf, Sel* p_sel) {
+ Sel sel = getsel(buf, p_sel);
+ return buf_getrat(buf, sel.end);
+}
+
+char* buf_gets(Buf* buf, Sel* p_sel) {
+ Sel sel = getsel(buf, p_sel);
+ size_t nbytes = sel.end - sel.beg;
+ char* str = malloc(nbytes+1);
+ for (size_t i = 0; i < nbytes; i++)
+ str[i] = getb(buf, sel.beg + i);
+ str[nbytes] = '\0';
+ return str;
+}
+
+void buf_del(Buf* buf, Sel* p_sel) {
+ Sel sel = getsel(buf, p_sel);
+ size_t nbytes = sel.end - sel.beg;
+ if (nbytes > 0) {
+ //char* str = buf_gets(buf, &sel);
+ syncgap(buf, sel.beg);
+ buf->gapend += nbytes;
+ // update log here
+ // free(str);
}
- return beg;
-}
-
-size_t buf_change(Buf* buf, size_t beg, size_t end) {
- /* delete the range first */
- size_t off = buf_delete(buf, beg, end);
- /* now create a new insert item of length 0 with the same transaction id as
- the delete. This will cause subsequent inserts to be coalesced into the
- same transaction */
- Log* dellog = buf->undo;
- Log* inslog = (Log*)calloc(sizeof(Log), 1);
- inslog->transid = (dellog ? dellog->transid : buf->transid);
- inslog->insert = true;
- inslog->data.ins.beg = beg;
- inslog->data.ins.end = beg;
- inslog->next = dellog;
- buf->undo = inslog;
- return off;
}
+/******************************************************************************/
+
void buf_chomp(Buf* buf) {
size_t end = buf_end(buf);
if (!end) return;
- Rune r = buf_get(buf, end-1);
+ Rune r = buf_getrat(buf, end-1);
if (r == '\n') {
delete(buf, end-1);
if (buf->undo->insert && buf->undo->data.ins.end == end)
}
bool buf_iseol(Buf* buf, size_t off) {
- Rune r = buf_get(buf, off);
+ Rune r = buf_getrat(buf, off);
return (r == '\n');
}
}
size_t buf_bow(Buf* buf, size_t off) {
- for (; risword(buf_get(buf, off-1)); off--);
+ for (; risword(buf_getrat(buf, off-1)); off--);
return off;
}
size_t buf_eow(Buf* buf, size_t off) {
- for (; risword(buf_get(buf, off)); off++);
+ for (; risword(buf_getrat(buf, off)); off++);
return off-1;
}
size_t buf_lscan(Buf* buf, size_t pos, Rune r) {
size_t off = pos;
- for (; (off > 0) && (r != buf_get(buf, off)); off--);
- return (buf_get(buf, off) == r ? off : pos);
+ for (; (off > 0) && (r != buf_getrat(buf, off)); off--);
+ return (buf_getrat(buf, off) == r ? off : pos);
}
size_t buf_rscan(Buf* buf, size_t pos, Rune r) {
size_t off = pos;
size_t end = buf_end(buf);
- for (; (off < end) && (r != buf_get(buf, off)); off++);
- return (buf_get(buf, off) == r ? off : pos);
+ for (; (off < end) && (r != buf_getrat(buf, off)); off++);
+ return (buf_getrat(buf, off) == r ? off : pos);
}
void buf_getword(Buf* buf, bool (*isword)(Rune), Sel* sel) {
- for (; isword(buf_get(buf, sel->beg-1)); sel->beg--);
- for (; isword(buf_get(buf, sel->end)); sel->end++);
+ for (; isword(buf_getrat(buf, sel->beg-1)); sel->beg--);
+ for (; isword(buf_getrat(buf, sel->end)); sel->end++);
sel->end--;
}
size_t beg, end = sel->end;
/* figure out which end of the block we're starting at */
- if (buf_get(buf, end) == first)
+ if (buf_getrat(buf, end) == first)
dir = +1, balance++, beg = end++;
- else if (buf_get(buf, end) == last)
+ else if (buf_getrat(buf, end) == last)
dir = -1, balance--, beg = end--;
else
return;
/* scan for a blanced set of braces */
while (true) {
- if (buf_get(buf, end) == first)
+ if (buf_getrat(buf, end) == first)
balance++;
- else if (buf_get(buf, end) == last)
+ else if (buf_getrat(buf, end) == last)
balance--;
if (balance == 0 || end >= buf_end(buf) || end == 0)
size_t rlen = rstrlen(runes);
size_t start = *beg, mbeg = start+dir, mend = mbeg + rlen;
while (mbeg != start) {
- if ((buf_get(buf, mbeg) == runes[0]) &&
- (buf_get(buf, mend-1) == runes[rlen-1]) &&
+ if ((buf_getrat(buf, mbeg) == runes[0]) &&
+ (buf_getrat(buf, mend-1) == runes[rlen-1]) &&
(0 == rune_match(buf, mbeg, mend, runes)))
{
*beg = mbeg;
size_t curr = buf_bol(buf, pos);
size_t col = 0;
for (; curr < pos; curr = buf_byrune(buf, curr, 1))
- col += runewidth(col, buf_get(buf, curr));
+ col += runewidth(col, buf_getrat(buf, curr));
return col;
}
size_t i = 0;
/* determine the length of the line in columns */
for (; !buf_iseol(buf, curr); curr++)
- len += runewidth(len, buf_get(buf, curr));
+ len += runewidth(len, buf_getrat(buf, curr));
/* iterate over the runes until we reach the target column */
curr = bol, i = 0;
while (i < col && i < len) {
- int width = runewidth(i, buf_get(buf, curr));
+ int width = runewidth(i, buf_getrat(buf, curr));
curr = buf_byrune(buf, curr, 1);
if (col >= i && col < (i+width))
break;
static int rune_match(Buf* buf, size_t mbeg, size_t mend, Rune* runes) {
for (; *runes; runes++, mbeg++) {
- int cmp = *runes - buf_get(buf, mbeg);
+ int cmp = *runes - buf_getrat(buf, mbeg);
if (cmp != 0) return cmp;
}
return 0;
newlog->data.del.len = n;
newlog->data.del.runes = (char*)malloc(n);
for (size_t i = 0; i < n; i++) {
- newlog->data.del.runes[i] = buf_get(buf, log->data.ins.beg);
+ newlog->data.del.runes[i] = buf_getrat(buf, log->data.ins.beg);
delete(buf, log->data.ins.beg);
}
} else {
bool ret = false;
size_t end = buf_end(buf);
if (move < 0 && off > 0)
- ret = testfn(buf_get(buf, off-1));
+ ret = testfn(buf_getrat(buf, off-1));
else if (move > 0 && off < end)
- ret = testfn(buf_get(buf, off+1));
+ ret = testfn(buf_getrat(buf, off+1));
return ret;
}
-/******************************************************************************/
-
-static Sel getsel(Buf* buf, Sel* p_sel) {
- size_t temp;
- Sel sel = (p_sel ? *p_sel : buf->selection);
- if (sel.end < sel.beg)
- temp = sel.beg, sel.beg = sel.end, sel.end = temp;
- return sel;
-}
-
-static void setsel(Buf* buf, Sel* p_sel, Sel* p_newsel) {
- if (p_sel)
- *p_sel = *p_newsel;
- else
- buf->selection = *p_newsel;
-}
-
-static void putb(Buf* buf, char b, Sel* p_sel) {
- syncgap(buf, p_sel->end);
- *(buf->gapstart++) = b;
- p_sel->end = p_sel->end + 1u;
- p_sel->beg = p_sel->end;
-}
-
-static char getb(Buf* buf, size_t off) {
- size_t bsz = (buf->gapstart - buf->bufstart);
- if (off < bsz)
- return *(buf->bufstart + off);
- else
- return *(buf->gapend + (off - bsz));
-}
-
-void buf_putc(Buf* buf, int c, Sel* p_sel) {
- char utf8buf[UTF_MAX+1] = {0};
- (void)utf8encode(utf8buf, c);
- buf_puts(buf, utf8buf, p_sel);
-}
-
-void buf_puts(Buf* buf, char* s, Sel* p_sel) {
- buf_del(buf, p_sel);
- Sel sel = getsel(buf, p_sel);
- while (s && *s) putb(buf, *(s++), &sel);
- setsel(buf, p_sel, &sel);
-}
-
-int buf_getc(Buf* buf, Sel* p_sel) {
- Sel sel = getsel(buf, p_sel);
- size_t rlen = 0;
- Rune rune = 0;
- while (!utf8decode(&rune, &rlen, getb(buf, sel.end++)));
- return rune;
-}
-
-char* buf_gets(Buf* buf, Sel* p_sel) {
- Sel sel = getsel(buf, p_sel);
- size_t nbytes = sel.end - sel.beg;
- char* str = malloc(nbytes+1);
- for (size_t i = 0; i < nbytes; i++)
- str[i] = getb(buf, sel.beg + i);
- str[nbytes] = '\0';
- return str;
-}
-
-void buf_del(Buf* buf, Sel* p_sel) {
- Sel sel = getsel(buf, p_sel);
- size_t nbytes = sel.end - sel.beg;
- if (nbytes > 0) {
- //char* str = buf_gets(buf, &sel);
- syncgap(buf, sel.beg);
- buf->gapend += nbytes;
- // update log here
- // free(str);
- }
-}
size_t view_limitrows(View* view, size_t maxrows, size_t ncols) {
size_t nrows = 1, pos = 0, col = 0;
while (nrows < maxrows && pos < buf_end(&(view->buffer))) {
- Rune r = buf_get(&(view->buffer), pos++);
+ Rune r = buf_getrat(&(view->buffer), pos++);
col += runewidth(col, r);
if (col >= ncols || r == '\n')
col = 0, nrows++;
/* ignore non-printable control characters */
if (!isspace(rune) && (rune >= 0 && rune < 0x20))
return;
- if (num_selected(view->selection)) {
- Sel sel = view->selection;
- selswap(&sel);
- sel.beg = sel.end = buf_change(&(view->buffer), sel.beg, sel.end);
- view->selection = sel;
- }
- unsigned newpos = buf_insert(&(view->buffer), indent, view->selection.end, rune);
- move_to(view, false, newpos);
+ buf_putc(&(view->buffer), rune, &(view->selection));
+ move_to(view, false, view->selection.end);
}
void view_delete(View* view, int dir, bool byword) {
if (sel->beg == sel->end)
(byword ? view_byword : view_byrune)(view, dir, true);
selswap(sel);
- unsigned newpos = buf_delete(&(view->buffer), sel->beg, sel->end);
- move_to(view, false, newpos);
+ buf_del(&(view->buffer), sel);
+ move_to(view, false, sel->beg);
}
void view_jumpto(View* view, bool extsel, size_t off) {
Buf* buf = &(view->buffer);
unsigned bol = buf_bol(buf, view->selection.end);
unsigned boi = bol;
- for (; ' ' == buf_get(buf, boi) || '\t' == buf_get(buf, boi); boi++);
+ for (; ' ' == buf_getrat(buf, boi) || '\t' == buf_getrat(buf, boi); boi++);
unsigned pos = view->selection.end;
pos = (pos == bol || pos > boi ? boi : bol);
move_to(view, extsel, pos);
if (view->selection.end != end)
view->selection = (Sel){ .beg = end, .end = end };
if (!num_selected(view->selection) && !buf_iseol(&(view->buffer), view->selection.end-1)) {
- buf_insert(&(view->buffer), false, view->selection.end++, '\n');
+ buf_putc(&(view->buffer), '\n', &(view->selection));
view->selection.beg++;
}
unsigned beg = view->selection.beg;
}
char* view_getstr(View* view, Sel* range) {
- Buf* buf = &(view->buffer);
- Sel sel = (range ? *range : view->selection);
- selswap(&sel);
- char utf[UTF_MAX] = {0};
- size_t len = 0;
- char* str = NULL;
- for (; sel.beg < sel.end; sel.beg++) {
- Rune rune = buf_get(buf, sel.beg);
- size_t n = utf8encode(utf, rune);
- str = realloc(str, len + n);
- memcpy(str+len, utf, n);
- len += n;
- }
- if (str) {
- str = realloc(str, len+1);
- str[len] = '\0';
- }
- return str;
+ return buf_gets(&(view->buffer), &(view->selection));
}
char* view_getcmd(View* view) {
view_scroll(view, move);
}
-void view_indent(View* view, int dir) {
- Buf* buf = &(view->buffer);
- unsigned indoff = (ExpandTabs ? TabWidth : 1);
- selswap(&(view->selection));
- view->selection.beg = buf_bol(buf, view->selection.beg);
- view->selection.end = buf_eol(buf, view->selection.end);
- unsigned off = buf_bol(buf, view->selection.end);
- if (num_selected(view->selection) == 0) return;
-
- do {
- if (dir == RIGHT) {
- buf_insert(buf, true, off, '\t');
- view->selection.end += indoff;
- } else if (dir == LEFT) {
- unsigned i = 4;
- for (; i > 0; i--) {
- if (' ' == buf_get(buf, off)) {
- buf_delete(buf, off, off+1);
- view->selection.end--;
- } else {
- break;
- }
- }
- if (i && '\t' == buf_get(buf, off)) {
- buf_delete(buf, off, off+1);
- view->selection.end--;
- }
- }
- off = buf_byline(buf, off, UP);
-
- } while (off && off >= view->selection.beg);
-}
-
Rune view_getrune(View* view) {
- return buf_get(&(view->buffer), view->selection.end);
+ return buf_getc(&(view->buffer), &(view->selection));
}
void view_scrollto(View* view, size_t csr) {
static void select_context(View* view, bool (*isword)(Rune), Sel* sel) {
Buf* buf = &(view->buffer);
size_t bol = buf_bol(buf, sel->end);
- Rune r = buf_get(buf, sel->end);
+ Rune r = buf_getc(buf, sel);
if (r == '(' || r == ')') {
buf_getblock(buf, '(', ')', sel);
} else if (r == '[' || r == ']') {
*csry = y, *csrx = x;
break;
}
- x += runewidth(x, buf_get(&(view->buffer),pos++));
+ x += runewidth(x, buf_getrat(&(view->buffer), pos++));
}
break;
}
clearrow(view, row);
for (size_t x = 0; x < view->ncols;) {
uint32_t attr = (in_selection(view->selection, pos) ? view->clrsel : view->clrnor);
- Rune r = buf_get(&(view->buffer), pos++);
+ Rune r = buf_getrat(&(view->buffer), pos++);
x += setcell(view, row, x, attr, r);
if (buf_iseol(&(view->buffer), pos-1)) {
break;
while (true) {
unsigned x;
for (x = 0; x < view->ncols && (pos + x) < off; x++)
- x += runewidth(x, buf_get(&(view->buffer), pos+x));
+ x += runewidth(x, buf_getrat(&(view->buffer), pos+x));
if ((pos + x) >= off) break;
pos += x;
}