#include "config.h"
#ifndef NDEBUG
-static bool view_valid(View* view) {
+static bool view_valid(View* view)
+{
return (
(view->sync_flags <= 3u)
&& (!view->nrows || view->index < view->nrows)
typedef size_t (*movefn_t)(Buf* buf, size_t pos, int count);
-static void move_selection(View* view, bool extsel, int move, movefn_t bything) {
+static void move_selection(View* view, bool extsel, int move, movefn_t bything)
+{
view->sync_flags |= CURSOR;
- if (buf_selsz(BUF) && !extsel) {
+ if (buf_selsz(BUF) && !extsel)
+ {
buf_selclr(BUF, move);
buf_getcol(BUF);
- if (bything == buf_byline) {
+ if (bything == buf_byline)
+ {
CSRPOS = bything(BUF, CSRPOS, move);
buf_setcol(BUF);
if (!extsel)
+ {
buf_selclr(BUF, (move < 0 ? LEFT : RIGHT));
+ }
}
- } else {
+ }
+ else
+ {
CSRPOS = bything(BUF, CSRPOS, move);
if (bything == buf_byline)
+ {
buf_setcol(BUF);
+ }
+
if (!extsel)
+ {
buf_selclr(BUF, (move < 0 ? LEFT : RIGHT));
+ }
+
/* only update column if not moving vertically */
if (bything != buf_byline)
+ {
buf_getcol(BUF);
+ }
}
}
-static void move_to(View* view, bool extsel, size_t off) {
+static void move_to(View* view, bool extsel, size_t off)
+{
Buf* buf = BUF;
off = (off > buf_end(buf) ? buf_end(buf) : off);
int dir = (off < CSRPOS ? LEFT : RIGHT);
CSRPOS = off;
if (!extsel)
+ {
buf_selclr(BUF, dir);
+ }
buf_getcol(buf);
view->sync_flags |= CURSOR;
}
-static bool selection_visible(View* view) {
- if (!view->rows || !view->nrows) return true;
+static bool selection_visible(View* view)
+{
+ if (!view->rows || !view->nrows)
+ {
+ return true;
+ }
size_t csr = CSRPOS;
size_t beg = view->rows[0]->off;
- size_t end = view->rows[view->nrows-1]->off +
- view->rows[view->nrows-1]->len;
+ size_t end = view->rows[view->nrows-1]->off
+ + view->rows[view->nrows-1]->len;
return (beg <= csr && csr <= end);
}
-static Sel* getsel(View* view) {
+static Sel* getsel(View* view)
+{
return &(view->buffer.selection);
}
-static void clear_rows(View* view, size_t startidx) {
- if (view->rows) {
+static void clear_rows(View* view, size_t startidx)
+{
+ if (view->rows)
+ {
/* Free and clear invalid rows now */
- for (size_t i = startidx; i < view->nrows; i++) {
+ for (size_t i = startidx; i < view->nrows; i++)
+ {
free(view->rows[i]);
view->rows[i] = NULL;
}
/* grow row array if needed */
if (startidx > view->nrows)
+ {
view->rows = realloc(view->rows, startidx);
+ }
/* zero out newly created slots */
for (size_t i = view->nrows; i < startidx; i++)
+ {
view->rows[i] = NULL;
+ }
view->nrows = startidx;
}
}
-void view_init(View* view, char* file) {
+void view_init(View* view, char* file)
+{
require(view != NULL);
clear_rows(view, 0);
view->sync_flags |= (CURSOR|CENTER);
view->nvisible = 0;
/* load the file and jump to the address returned from the load function */
buf_init(BUF);
- if (file) buf_load(BUF, file);
+ if (file)
+ {
+ buf_load(BUF, file);
+ }
ensure(view_valid(view));
}
-void view_reload(View* view) {
+void view_reload(View* view)
+{
require(view != NULL);
- if (view->buffer.path) {
+ if (view->buffer.path)
+ {
buf_reload(BUF);
view->sync_flags |= (CURSOR|CENTER);
}
ensure(view_valid(view));
}
-void view_sync(View* view) {
+void view_sync(View* view)
+{
require(view != NULL);
view->sync_flags |= (CURSOR|CENTER);
ensure(view_valid(view));
}
-static size_t rune_width(View* view, int c, size_t xpos, size_t width) {
+static size_t rune_width(View* view, int c, size_t xpos, size_t width)
+{
if (c == '\r')
+ {
return 0;
+ }
else if (c == '\n')
+ {
return (width-xpos);
+ }
else if (c == '\t')
+ {
return (glyph_width(view, c) - (xpos % glyph_width(view, c)));
+ }
else
+ {
return glyph_width(view, c);
+ }
}
-size_t view_limitrows(View* view, size_t maxrows) {
+size_t view_limitrows(View* view, size_t maxrows)
+{
require(view != NULL);
size_t nrows = 1, off = 0, xpos = 0;
- while (nrows < maxrows && off < buf_end(&(view->buffer))) {
+ while (nrows < maxrows && off < buf_end(&(view->buffer)))
+ {
Rune rune = buf_getrat(&(view->buffer), off);
xpos += rune_width(view, rune, xpos, view->width);
/* if the line is full, reset the line and increase row count */
- if (xpos > view->width) {
+ if (xpos > view->width)
+ {
xpos = 0, nrows++;
- } else {
+ }
+ else
+ {
if (rune == '\n')
- xpos = 0, nrows++;
+ {
+ xpos = 0;
+ nrows++;
+ }
off = buf_byrune(&(view->buffer), off, RIGHT);
}
}
return nrows;
}
-static size_t add_row(View* view, size_t off) {
+static size_t add_row(View* view, size_t off)
+{
/* allocate a new row */
view->nrows++;
view->rows = realloc(view->rows, sizeof(Row*) * view->nrows);
view->rows[view->nrows-1] = calloc(1, sizeof(Row));
view->rows[view->nrows-1]->off = off;
+
/* populate the row with characters */
- for (size_t xpos = 0; xpos < view->width;) {
+ for (size_t xpos = 0; xpos < view->width;)
+ {
int rune = buf_getrat(&(view->buffer), off);
size_t rwidth = rune_width(view, rune, xpos, view->width);
xpos += rwidth;
- if (xpos <= view->width) {
+ if (xpos <= view->width)
+ {
size_t len = view->rows[view->nrows-1]->len + 1;
view->rows[view->nrows-1] = realloc(
view->rows[view->nrows-1], sizeof(Row) + (len * sizeof(UGlyph)));
return off;
}
-static void resize(View* view, size_t width, size_t nrows, size_t off) {
+static void resize(View* view, size_t width, size_t nrows, size_t off)
+{
bool first_line_done = false;
clear_rows(view, 0);
view->width = width;
view->index = 0;
size_t beg = off, bend = buf_end(&(view->buffer));
off = buf_bol(&(view->buffer), off);
- if (off > bend) off = bend;
- for (size_t i = 0; nrows > 0; i++) {
+ if (off > bend)
+ {
+ off = bend;
+ }
+
+ for (size_t i = 0; nrows > 0; i++)
+ {
off = add_row(view, off);
Row* row = view->rows[view->nrows-1];
first_line_done = (first_line_done || (row->cols[row->len-1].rune == '\n'));
if (first_line_done)
+ {
nrows--;
+ }
if (beg < bend && beg >= row->off && beg <= row->cols[row->len-1].off)
+ {
view->index = i;
+ }
}
}
-void view_resize(View* view, size_t width, size_t nrows) {
+void view_resize(View* view, size_t width, size_t nrows)
+{
require(view != NULL);
require(width > 0);
require(nrows > 0);
if (view->width == width && view->nvisible == nrows)
+ {
return;
+ }
size_t off = (view->nrows && view->index < view->nrows ? view->rows[view->index]->off : 0);
resize(view, width, nrows, off);
ensure(view_valid(view));
}
-void view_update(View* view) {
+void view_update(View* view)
+{
require(view != NULL);
/* refill the view contents to make sure updates are visible */
size_t off = view->rows[view->index]->off;
clear_rows(view, view->index);
for (size_t i = 0; i < view->nvisible; i++)
+ {
off = add_row(view, off);
+ }
/* sync up the view with the cursor */
- if (view->sync_flags) {
- if (view->sync_flags & CENTER) {
+ if (view->sync_flags)
+ {
+ if (view->sync_flags & CENTER)
+ {
resize(view, view->width, view->nrows, CSRPOS);
view_scroll(view, UP * (view->nvisible/2));
- } else {
+ }
+ else
+ {
Row* lastrow = view->rows[view->nrows-1];
size_t last_off = lastrow->cols[lastrow->len-1].off;
view_scrollto(view, CSRPOS);
if (last_off < CSRPOS)
+ {
view_scroll(view, UP * (view->nvisible-1));
+ }
}
view->sync_flags = 0;
}
ensure(view_valid(view));
}
-Row* view_getrow(View* view, size_t row) {
+Row* view_getrow(View* view, size_t row)
+{
return (row < view->nrows ? view->rows[row] : NULL);
}
-void view_byrune(View* view, int move, bool extsel) {
+void view_byrune(View* view, int move, bool extsel)
+{
require(view != NULL);
move_selection(view, extsel, move, buf_byrune);
ensure(view_valid(view));
}
-void view_byword(View* view, int move, bool extsel) {
+void view_byword(View* view, int move, bool extsel)
+{
require(view != NULL);
move_selection(view, extsel, move, buf_byword);
ensure(view_valid(view));
}
-void view_byline(View* view, int move, bool extsel) {
+void view_byline(View* view, int move, bool extsel)
+{
require(view != NULL);
move_selection(view, extsel, move, buf_byline);
ensure(view_valid(view));
}
-static size_t getoffset(View* view, size_t row, size_t col) {
+static size_t getoffset(View* view, size_t row, size_t col)
+{
size_t i = 0, y = 0, idx = view->index + row;
if (idx >= view->nrows) return 0;
Row* selrow = view->rows[idx];
- for (; i < selrow->len; i++) {
+ for (; i < selrow->len; i++)
+ {
y += selrow->cols[i].width;
- if (col < y) break;
+ if (col < y)
+ {
+ break;
+ }
}
return selrow->cols[i].off;
}
-void view_setcursor(View* view, size_t row, size_t col, bool extsel) {
+void view_setcursor(View* view, size_t row, size_t col, bool extsel)
+{
getsel(view)->end = getoffset(view, row, col);
if (!extsel)
+ {
getsel(view)->beg = getsel(view)->end;
+ }
buf_getcol(BUF);
ensure(view_valid(view));
}
-void view_selword(View* view, size_t row, size_t col) {
+void view_selword(View* view, size_t row, size_t col)
+{
if (row != SIZE_MAX && col != SIZE_MAX)
+ {
view_setcursor(view, row, col, false);
+ }
buf_selword(BUF, risbigword);
ensure(view_valid(view));
}
-void view_selprev(View* view) {
+void view_selprev(View* view)
+{
if (!view_selsize(view))
+ {
buf_lastins(BUF);
+ }
else
+ {
buf_selclr(BUF, RIGHT);
+ }
ensure(view_valid(view));
}
-void view_select(View* view, size_t row, size_t col) {
+void view_select(View* view, size_t row, size_t col)
+{
view_setcursor(view, row, col, false);
buf_selctx(BUF, risword);
ensure(view_valid(view));
}
-size_t view_selsize(View* view) {
+size_t view_selsize(View* view)
+{
return buf_selsz(BUF);
}
-char* view_fetch(View* view, size_t row, size_t col, bool (*isword)(Rune)) {
+char* view_fetch(View* view, size_t row, size_t col, bool (*isword)(Rune))
+{
char* str = NULL;
size_t off = getoffset(view, row, col);
if (off != SIZE_MAX)
+ {
str = buf_fetch(BUF, isword, off);
+ }
ensure(view_valid(view));
return str;
}
-bool view_findstr(View* view, int dir, char* str) {
+bool view_findstr(View* view, int dir, char* str)
+{
bool found = buf_findstr(BUF, dir, str);
view->sync_flags |= (CURSOR|CENTER);
ensure(view_valid(view));
return found;
}
-void view_insert(View* view, Rune rune) {
+void view_insert(View* view, Rune rune)
+{
/* ignore non-printable control characters */
if (!isspace(rune) && (rune >= 0 && rune < 0x20))
+ {
return;
- if (ExpandTabs && rune == '\t') {
+ }
+ if (ExpandTabs && rune == '\t')
+ {
size_t off = buf_selbeg(BUF);
size_t n = (TabWidth - ((off - buf_bol(BUF, off)) % TabWidth));
for (; n > 0; n--) buf_putc(BUF, ' ');
- } else if (CopyIndent && rune == '\n') {
+ }
+ else if (CopyIndent && rune == '\n')
+ {
size_t off = buf_selbeg(BUF);
size_t beg = buf_bol(BUF, off), end = beg;
- for (; end < buf_end(BUF) && end < off && (' ' == buf_getrat(BUF, end) || '\t' == buf_getrat(BUF, end)); end++);
+ for (; end < buf_end(BUF) && end < off && (' ' == buf_getrat(BUF, end) || '\t' == buf_getrat(BUF, end)); end++)
+ {
+ }
char* str = buf_getsat(BUF, beg, end);
buf_putc(BUF, '\n');
buf_puts(BUF, str);
free(str);
- } else {
+ }
+ else
+ {
buf_putc(BUF, rune);
}
move_to(view, false, CSRPOS);
ensure(view_valid(view));
}
-void view_delete(View* view, int dir, bool byword) {
+void view_delete(View* view, int dir, bool byword)
+{
if (!view_selsize(view))
+ {
(byword ? view_byword : view_byrune)(view, dir, true);
+ }
buf_del(BUF);
move_to(view, false, CSRPOS);
ensure(view_valid(view));
}
-void view_jumpto(View* view, bool extsel, size_t off) {
+void view_jumpto(View* view, bool extsel, size_t off)
+{
move_to(view, extsel, off);
ensure(view_valid(view));
}
-void view_bol(View* view, bool extsel) {
+void view_bol(View* view, bool extsel)
+{
/* determine whether we are jumping to start of content or line */
Buf* buf = BUF;
unsigned bol = buf_bol(buf, CSRPOS);
ensure(view_valid(view));
}
-void view_eol(View* view, bool extsel) {
+void view_eol(View* view, bool extsel)
+{
move_to(view, extsel, buf_eol(BUF, CSRPOS));
getsel(view)->col = -1; // Peg cursor to line end
ensure(view_valid(view));
}
-void view_bof(View* view, bool extsel) {
+void view_bof(View* view, bool extsel)
+{
view_jumpto(view, extsel, 0);
ensure(view_valid(view));
}
-void view_eof(View* view, bool extsel) {
+void view_eof(View* view, bool extsel)
+{
view_jumpto(view, extsel, buf_end(BUF));
ensure(view_valid(view));
}
-void view_setln(View* view, size_t line) {
+void view_setln(View* view, size_t line)
+{
view->sync_flags |= CENTER;
- if (line) {
+ if (line)
+ {
buf_setln(BUF, line);
buf_selln(BUF);
}
ensure(view_valid(view));
}
-void view_undo(View* view) {
+void view_undo(View* view)
+{
buf_undo(BUF);
view->sync_flags |= CURSOR;
- if (!selection_visible(view)) view->sync_flags |= CENTER;
+ if (!selection_visible(view))
+ {
+ view->sync_flags |= CENTER;
+ }
ensure(view_valid(view));
}
-void view_redo(View* view) {
+void view_redo(View* view)
+{
buf_redo(BUF);
view->sync_flags |= CURSOR;
- if (!selection_visible(view)) view->sync_flags |= CENTER;
+ if (!selection_visible(view))
+ {
+ view->sync_flags |= CENTER;
+ }
ensure(view_valid(view));
}
-void view_paste(View* view, char* str) {
+void view_paste(View* view, char* str)
+{
buf_logstart(BUF);
view_putstr(view, str);
buf_logstop(BUF);
ensure(view_valid(view));
}
-void view_putstr(View* view, char* str) {
+void view_putstr(View* view, char* str)
+{
buf_puts(BUF, str);
ensure(view_valid(view));
}
-char* view_getstr(View* view) {
+char* view_getstr(View* view)
+{
return buf_gets(BUF);
}
-char* view_getcmd(View* view) {
+char* view_getcmd(View* view)
+{
if (!view_selsize(view))
+ {
buf_selctx(BUF, riscmd);
+ }
ensure(view_valid(view));
return view_getstr(view);
}
-void view_selctx(View* view) {
+void view_selctx(View* view)
+{
if (!view_selsize(view))
+ {
buf_selctx(BUF, risword);
+ }
ensure(view_valid(view));
}
-char* view_getctx(View* view) {
+char* view_getctx(View* view)
+{
view_selctx(view);
ensure(view_valid(view));
return view_getstr(view);
}
-static void scroll_up(View* view) {
+static void scroll_up(View* view)
+{
if (view->index > 0)
+ {
view->index--;
+ }
else if (view->rows[0]->off > 0)
+ {
resize(view, view->width, view->nvisible, buf_byrune(BUF, view->rows[0]->off, LEFT));
+ }
}
-static void scroll_dn(View* view) {
- if (view->nrows <= 1) return;
+static void scroll_dn(View* view)
+{
+ if (view->nrows <= 1)
+ {
+ return;
+ }
size_t nleft = (view->nrows - view->index);
- if (nleft <= view->nvisible) {
+ if (nleft <= view->nvisible)
+ {
size_t off = view->rows[view->index+1]->off;
resize(view, view->width, view->nvisible, off);
- } else {
+ }
+ else
+ {
view->index++;
}
}
-void view_scroll(View* view, int move) {
+void view_scroll(View* view, int move)
+{
int dir = (move < 0 ? -1 : 1);
move *= dir;
- for (int i = 0; i < move; i++) {
+ for (int i = 0; i < move; i++)
+ {
if (dir < 0)
+ {
scroll_up(view);
+ }
else
+ {
scroll_dn(view);
+ }
}
ensure(view_valid(view));
}
-void view_scrollpage(View* view, int move) {
+void view_scrollpage(View* view, int move)
+{
move = (move < 0 ? -1 : 1) * view->nrows;
view_scroll(view, move);
ensure(view_valid(view));
}
-Rune view_getrune(View* view) {
+Rune view_getrune(View* view)
+{
return buf_getc(BUF);
}
-void view_scrollto(View* view, size_t csr) {
+void view_scrollto(View* view, size_t csr)
+{
Row* lastrow = view->rows[view->nrows-1];
size_t first = view->rows[view->index]->off;
size_t last = lastrow->cols[lastrow->len-1].off;
if (csr < first || csr > last)
+ {
resize(view, view->width, view->nrows, csr);
+ }
ensure(view_valid(view));
}
-void view_selectall(View* view) {
+void view_selectall(View* view)
+{
buf_selall(BUF);
view->sync_flags |= CURSOR;
ensure(view_valid(view));
}
-void view_selectobj(View* view, bool (*istype)(Rune)) {
+void view_selectobj(View* view, bool (*istype)(Rune))
+{
buf_selword(BUF, istype);
view->sync_flags |= CURSOR;
ensure(view_valid(view));