From: Michael D. Lowis Date: Fri, 7 Oct 2016 02:36:07 +0000 (-0400) Subject: fixed the scrolling logic and line chopping issue for lines with tabs X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=1b79b6da59a39a98ad395ae23c0c5e63e5cfceb8;p=projs%2Ftide.git fixed the scrolling logic and line chopping issue for lines with tabs --- diff --git a/buf.c b/buf.c index c8c5296..846ec93 100644 --- a/buf.c +++ b/buf.c @@ -12,31 +12,29 @@ void buf_load(Buf* buf, char* path) { 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) { @@ -49,7 +47,12 @@ static void syncgap(Buf* buf, unsigned off) { } 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) { @@ -58,13 +61,13 @@ 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; } @@ -95,9 +98,8 @@ unsigned buf_end(Buf* buf) { } 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--; @@ -113,7 +115,7 @@ unsigned buf_byline(Buf* buf, unsigned pos, int count) { 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)) diff --git a/edit.h b/edit.h index d159651..b442ce2 100644 --- a/edit.h +++ b/edit.h @@ -130,7 +130,6 @@ typedef struct 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); diff --git a/screen.c b/screen.c index 8030085..eb74f5d 100644 --- a/screen.c +++ b/screen.c @@ -117,18 +117,35 @@ static void fill_row(Buf* buf, unsigned row, 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) { diff --git a/tests/buf.c b/tests/buf.c index a77c750..8621735 100644 --- a/tests/buf.c +++ b/tests/buf.c @@ -22,37 +22,6 @@ static bool buf_text_eq(char* str) { } 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) { @@ -111,9 +80,9 @@ TEST_SUITE(BufferTests) { 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) {