buf->insert_mode = false;
}
-void buf_initsz(Buf* buf, size_t sz) {
- buf->insert_mode = false;
- buf->bufsize = sz;
- buf->bufstart = (Rune*)malloc(buf->bufsize * sizeof(Rune));
- buf->bufend = buf->bufstart + buf->bufsize;
- buf->gapstart = buf->bufstart;
- buf->gapend = buf->bufend;
+void buf_resize(Buf* buf, size_t sz) {
+ /* allocate the new buffer and gap */
+ Buf copy = *buf;
+ copy.bufsize = sz;
+ copy.bufstart = (Rune*)malloc(copy.bufsize * sizeof(Rune));
+ copy.bufend = copy.bufstart + copy.bufsize;
+ copy.gapstart = copy.bufstart;
+ copy.gapend = copy.bufend;
+ /* copy the data from the old buffer to the new one */
+ for (Rune* curr = buf->bufstart; curr < buf->gapstart; curr++)
+ *(copy.gapstart++) = *(curr);
+ for (Rune* curr = buf->gapend; curr < buf->bufend; curr++)
+ *(copy.gapstart++) = *(curr);
+ /* free the buffer and commit the changes */
+ free(buf->bufstart);
+ *buf = copy;
}
static void syncgap(Buf* buf, unsigned off) {
assert(off <= buf_end(buf));
/* If the buffer is full, resize it before syncing */
- if (0 == (buf->gapend - buf->gapstart)) {
- Buf newbuf;
- buf_initsz(&newbuf, buf->bufsize << 1);
-
- for (Rune* curr = buf->bufstart; curr < buf->gapstart; curr++)
- *(newbuf.gapstart++) = *(curr);
- for (Rune* curr = buf->gapend; curr < buf->bufend; curr++)
- *(newbuf.gapstart++) = *(curr);
-
- free(buf->bufstart);
- *buf = newbuf;
- }
-
+ if (0 == (buf->gapend - buf->gapstart))
+ buf_resize(buf, buf->bufsize << 1);
/* Move the gap to the desired offset */
Rune* newpos = (buf->bufstart + off);
if (newpos < buf->gapstart) {
}
void buf_init(Buf* buf) {
- buf_initsz(buf, BufSize);
+ buf->insert_mode = false;
+ buf->bufsize = BufSize;
+ buf->bufstart = (Rune*)malloc(buf->bufsize * sizeof(Rune));
+ buf->bufend = buf->bufstart + buf->bufsize;
+ buf->gapstart = buf->bufstart;
+ buf->gapend = buf->bufend;
}
void buf_clr(Buf* buf) {
}
void buf_del(Buf* buf, unsigned off) {
- if (!buf->insert_mode) return;
+ if (!buf->insert_mode) { return; }
syncgap(buf, off);
buf->gapend++;
}
void buf_ins(Buf* buf, unsigned off, Rune rune) {
- if (!buf->insert_mode) return;
+ if (!buf->insert_mode) { return; }
syncgap(buf, off);
*(buf->gapstart++) = rune;
}
}
unsigned buf_byrune(Buf* buf, unsigned pos, int count) {
- (void)buf;
int move = (count < 0 ? -1 : 1);
- count *= move;
+ count *= move; // remove the sign if there is one
for (; count > 0; count--)
if (move < 0) {
if (pos > 0) pos--;
for (; count > 0; count--) {
if (move < 0) {
if (pos > buf_eol(buf, 0))
- pos = buf_bol(buf, pos)-1;
+ pos = buf_bol(buf, buf_bol(buf, pos)-1);
} else {
unsigned next = buf_eol(buf, pos)+1;
if (next < buf_end(buf))
} Buf;
void buf_load(Buf* buf, char* path);
-void buf_initsz(Buf* buf, size_t sz);
void buf_init(Buf* buf);
void buf_clr(Buf* buf);
void buf_del(Buf* buf, unsigned pos);
}
}
+static unsigned prev_screen_line(Buf* buf, unsigned bol, unsigned off) {
+ unsigned pos = bol;
+ while (true) {
+ //printf("bol: %u, pos: %u, off: %u\n", bol, pos, off);
+ unsigned x = 0;
+ for (; x < NumCols && (pos + x) < off; x++) {
+ Rune r = buf_get(buf, pos+x);
+ x += (r == '\t' ? (TabWidth - (x % TabWidth)) : 1);
+ }
+ if ((pos + x) >= off) break;
+ pos += x;
+ }
+ return pos;
+}
+
static void scroll_up(Buf* buf, unsigned csr, unsigned first) {
while (csr < first) {
+ unsigned bol = buf_bol(buf, first);
+ unsigned prevln = (first == bol ? buf_byline(buf, bol, -1) : bol);
+ prevln = prev_screen_line(buf, prevln, first);
/* delete the last row and shift the others */
free(Rows[NumRows - 1]);
memmove(&Rows[2], &Rows[1], sizeof(Row*) * (NumRows-2));
Rows[1] = calloc(1, sizeof(Row) + (NumCols * sizeof(Rune)));
- Rows[1]->off = buf_byline(buf, Rows[2]->off, -1);
+ Rows[1]->off = prevln;
/* fill in row content */
fill_row(buf, 1, Rows[1]->off);
first = Rows[1]->off;
}
- screen_reflow(buf);
}
static void scroll_dn(Buf* buf, unsigned csr, unsigned last) {
}
TEST_SUITE(BufferTests) {
- /* Init and Clear
- *************************************************************************/
- TEST(buf_initsz should init the buffer to the given size) {
- buf_initsz(&TestBuf, 1024);
- CHECK(TestBuf.bufsize == 1024);
- CHECK(TestBuf.bufstart == TestBuf.gapstart);
- CHECK(TestBuf.bufend == TestBuf.gapend);
- CHECK(TestBuf.bufend - TestBuf.bufstart == 1024);
- CHECK(TestBuf.gapend - TestBuf.gapstart == 1024);
- free(TestBuf.bufstart);
- }
-
- TEST(buf_init should init the buffer to the default size) {
- buf_init(&TestBuf);
- CHECK(TestBuf.bufsize == BufSize);
- CHECK(TestBuf.bufstart == TestBuf.gapstart);
- CHECK(TestBuf.bufend == TestBuf.gapend);
- CHECK(TestBuf.bufend - TestBuf.bufstart == BufSize);
- CHECK(TestBuf.gapend - TestBuf.gapstart == BufSize);
- }
-
- TEST(buf_clr should clear the buffer) {
- buf_initsz(&TestBuf, 1024);
- buf_clr(&TestBuf);
- CHECK(TestBuf.bufsize == BufSize);
- CHECK(TestBuf.bufstart == TestBuf.gapstart);
- CHECK(TestBuf.bufend == TestBuf.gapend);
- CHECK(TestBuf.bufend - TestBuf.bufstart == BufSize);
- CHECK(TestBuf.gapend - TestBuf.gapstart == BufSize);
- }
-
/* Insertions
*************************************************************************/
TEST(buf_ins should insert at 0 in empty buf) {
CHECK(1 == buf_bol(&TestBuf, 1));
}
- TEST(buf_eol should move to last non newline character of line) {
+ TEST(buf_eol should move to last character of line) {
set_buffer_text("\nabc\n");
- CHECK(3 == buf_eol(&TestBuf, 1));
+ CHECK(4 == buf_eol(&TestBuf, 1));
}
TEST(buf_eol should do nothing for blank line) {