diff options
| -rw-r--r-- | flake.lock | 6 | ||||
| -rw-r--r-- | src/buffer.c | 10 | ||||
| -rw-r--r-- | src/text.c | 96 | ||||
| -rw-r--r-- | src/text.h | 8 | ||||
| -rw-r--r-- | test/text.c | 33 |
5 files changed, 114 insertions, 39 deletions
@@ -17,11 +17,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1670372410, - "narHash": "sha256-BDiOUkuqgq5DP+E5xfTzIFYYyMb8DpSLYmeaOBeZ0vg=", + "lastModified": 1671040593, + "narHash": "sha256-W5aZNwYBjaEaLifDWGEfecvnCiDkXjI26rHgidSftUM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5528350186a9e826588cee1329640899ca44a0cf", + "rev": "170e39462b516bd1475ce9184f7bb93106d27c59", "type": "github" }, "original": { diff --git a/src/buffer.c b/src/buffer.c index 4e955e6..17d62af 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -148,7 +148,8 @@ struct buffer buffer_from_file(const char *filename, struct reactor *reactor) { uint8_t buff[4096]; int bytes = fread(buff, 1, 4096, file); if (bytes > 0) { - buffer_add_text(&b, buff, bytes); + uint32_t ignore; + text_append(b.text, buff, bytes, &ignore, &ignore); } else if (bytes == 0) { break; // EOF } else { @@ -159,9 +160,6 @@ struct buffer buffer_from_file(const char *filename, struct reactor *reactor) { fclose(file); } - b.dot_col = 0; - b.dot_line = 0; - return b; } @@ -187,8 +185,8 @@ void buffer_to_file(struct buffer *buffer) { int buffer_add_text(struct buffer *buffer, uint8_t *text, uint32_t nbytes) { uint32_t lines_added, cols_added; - text_append(buffer->text, buffer->dot_line, buffer->dot_col, text, nbytes, - &lines_added, &cols_added); + text_append_at(buffer->text, buffer->dot_line, buffer->dot_col, text, nbytes, + &lines_added, &cols_added); movev(buffer, lines_added); if (lines_added > 0) { @@ -4,6 +4,7 @@ #include <stdlib.h> #include <string.h> +#include "bits/stdint-uintn.h" #include "display.h" #include "utf8.h" @@ -80,20 +81,37 @@ uint32_t char_byte_size(struct line *line, uint32_t byte_idx) { return utf8_nbytes(line->data + byte_idx, 1); } -void append_to_line(struct line *line, uint32_t col, uint8_t *text, - uint32_t len, uint32_t nchars) { - - if (len == 0) { +void extend_line(struct line *line, uint32_t nbytes, uint32_t nchars) { + if (nbytes == 0) { return; } - line->nbytes += len; + line->nbytes += nbytes; line->nchars += nchars; line->flags = LineChanged; line->data = realloc(line->data, line->nbytes); +} - uint32_t bytei = charidx_to_byteidx(line, col); +void insert_at(struct line *line, uint32_t byte_index, uint8_t *text, + uint32_t len, uint32_t nchars) { + if (len == 0) { + return; + } + + extend_line(line, len, nchars); + memcpy(line->data + byte_index, text, len); +} +void insert_at_col(struct line *line, uint32_t col, uint8_t *text, uint32_t len, + uint32_t nchars) { + + if (len == 0) { + return; + } + + extend_line(line, len, nchars); + + uint32_t bytei = charidx_to_byteidx(line, col); // move chars out of the way if (col + nchars < line->nchars) { uint32_t nextcbytei = charidx_to_byteidx(line, col + nchars); @@ -129,6 +147,9 @@ void split_line(uint32_t col, struct line *line, struct line *next) { next->nchars = nchars - chari; line->flags = next->flags = line->flags; + next->data = NULL; + line->data = NULL; + // first, handle some cases where the new line or the pre-existing one is // empty if (next->nbytes == 0) { @@ -137,10 +158,10 @@ void split_line(uint32_t col, struct line *line, struct line *next) { next->data = data; } else { // actually split the line - next->data = (uint8_t *)malloc(next->nbytes); + next->data = (uint8_t *)realloc(next->data, next->nbytes); memcpy(next->data, data + bytei, next->nbytes); - line->data = (uint8_t *)malloc(line->nbytes); + line->data = (uint8_t *)realloc(line->data, line->nbytes); memcpy(line->data, data, line->nbytes); free(data); @@ -154,8 +175,8 @@ void mark_lines_changed(struct text *text, uint32_t line, uint32_t nlines) { } void shift_lines(struct text *text, uint32_t start, int32_t direction) { - struct line *dest = text->lines + ((int64_t)start + direction); - struct line *src = text->lines + start; + struct line *dest = &text->lines[((int64_t)start + direction)]; + struct line *src = &text->lines[start]; uint32_t nlines = text->nlines - (dest > src ? (start + direction) : start); memmove(dest, src, nlines * sizeof(struct line)); } @@ -205,8 +226,47 @@ void delete_line(struct text *text, uint32_t line) { } } -void text_append(struct text *text, uint32_t line, uint32_t col, uint8_t *bytes, - uint32_t nbytes, uint32_t *lines_added, uint32_t *cols_added) { +void text_append(struct text *text, uint8_t *bytes, uint32_t nbytes, + uint32_t *lines_added, uint32_t *cols_added) { + + uint32_t linelen = 0, nchars_counted = 0, nlines_added = 0, ncols_added = 0; + uint32_t line = text->nlines - 1; + + for (uint32_t bytei = 0; bytei < nbytes; ++bytei) { + uint8_t byte = bytes[bytei]; + if (byte == '\n') { + insert_at(&text->lines[line], text->lines[line].nbytes, + bytes + (bytei - linelen), linelen, nchars_counted); + + new_line_at(text, line, text->lines[line].nchars); + + ++line; + ++nlines_added; + + linelen = 0; + nchars_counted = 0; + } else { + if (utf8_byte_is_ascii(byte) || utf8_byte_is_unicode_start(byte)) { + ++nchars_counted; + } + ++linelen; + } + } + + // handle remaining + if (linelen > 0) { + insert_at(&text->lines[line], text->lines[line].nbytes, + bytes + (nbytes - linelen), linelen, nchars_counted); + ncols_added = nchars_counted; + } + + *lines_added = nlines_added; + *cols_added = ncols_added; +} + +void text_append_at(struct text *text, uint32_t line, uint32_t col, + uint8_t *bytes, uint32_t nbytes, uint32_t *lines_added, + uint32_t *cols_added) { uint32_t linelen = 0; uint32_t nchars_counted = 0; uint32_t nlines_added = 0; @@ -214,8 +274,8 @@ void text_append(struct text *text, uint32_t line, uint32_t col, uint8_t *bytes, for (uint32_t bytei = 0; bytei < nbytes; ++bytei) { uint8_t byte = bytes[bytei]; if (byte == '\n') { - append_to_line(&text->lines[line], col, bytes + (bytei - linelen), - linelen, nchars_counted); + insert_at_col(&text->lines[line], col, bytes + (bytei - linelen), linelen, + nchars_counted); col += nchars_counted; new_line_at(text, line, col); @@ -235,8 +295,8 @@ void text_append(struct text *text, uint32_t line, uint32_t col, uint8_t *bytes, // handle remaining if (linelen > 0) { - append_to_line(&text->lines[line], col, bytes + (nbytes - linelen), linelen, - nchars_counted); + insert_at_col(&text->lines[line], col, bytes + (nbytes - linelen), linelen, + nchars_counted); ncols_added = nchars_counted; } @@ -281,8 +341,8 @@ void text_delete(struct text *text, uint32_t line, uint32_t col, struct line *lp = &text->lines[line]; uint32_t bytei = charidx_to_byteidx(lp, src_col); if (src_col < lp->nchars) { - append_to_line(&text->lines[initial_line], col, lp->data + bytei, - lp->nbytes - bytei, lp->nchars - src_col); + insert_at_col(&text->lines[initial_line], col, lp->data + bytei, + lp->nbytes - bytei, lp->nchars - src_col); } } @@ -15,8 +15,12 @@ void text_destroy(struct text *text); */ void text_clear(struct text *text); -void text_append(struct text *text, uint32_t line, uint32_t col, uint8_t *bytes, - uint32_t nbytes, uint32_t *lines_added, uint32_t *cols_added); +void text_append_at(struct text *text, uint32_t line, uint32_t col, + uint8_t *bytes, uint32_t nbytes, uint32_t *lines_added, + uint32_t *cols_added); + +void text_append(struct text *text, uint8_t *bytes, uint32_t nbytes, + uint32_t *lines_added, uint32_t *cols_added); void text_delete(struct text *text, uint32_t line, uint32_t col, uint32_t nchars); diff --git a/test/text.c b/test/text.c index 9073553..43decda 100644 --- a/test/text.c +++ b/test/text.c @@ -14,7 +14,8 @@ void test_add_text() { uint32_t lines_added, cols_added; struct text *t = text_create(10); const char *txt = "This is line 1\n"; - text_append(t, 0, 0, (uint8_t *)txt, strlen(txt), &lines_added, &cols_added); + text_append_at(t, 0, 0, (uint8_t *)txt, strlen(txt), &lines_added, + &cols_added); ASSERT(text_num_lines(t) == 2, "Expected text to have two lines after insertion"); @@ -24,13 +25,24 @@ void test_add_text() { "Expected line 1 to be line 1"); const char *txt2 = "This is line 2\n"; - text_append(t, 1, 0, (uint8_t *)txt2, strlen(txt2), &lines_added, - &cols_added); + text_append_at(t, 1, 0, (uint8_t *)txt2, strlen(txt2), &lines_added, + &cols_added); ASSERT(text_num_lines(t) == 3, "Expected text to have three lines after second insertion"); ASSERT_STR_EQ((const char *)text_get_line(t, 1).text, "This is line 2", "Expected line 2 to be line 2"); + // simulate indentation + const char *txt3 = " "; + text_append_at(t, 0, 0, (uint8_t *)txt3, strlen(txt3), &lines_added, + &cols_added); + ASSERT(text_num_lines(t) == 3, + "Expected text to have three lines after second insertion"); + ASSERT_STR_EQ((const char *)text_get_line(t, 0).text, " This is line 1", + "Expected line 1 to be indented"); + ASSERT_STR_EQ((const char *)text_get_line(t, 1).text, "This is line 2", + "Expected line 2 to be line 2 still"); + text_destroy(t); } @@ -38,7 +50,8 @@ void test_delete_text() { uint32_t lines_added, cols_added; struct text *t = text_create(10); const char *txt = "This is line 1"; - text_append(t, 0, 0, (uint8_t *)txt, strlen(txt), &lines_added, &cols_added); + text_append_at(t, 0, 0, (uint8_t *)txt, strlen(txt), &lines_added, + &cols_added); text_delete(t, 0, 12, 2); ASSERT(text_line_length(t, 0) == 12, @@ -52,8 +65,8 @@ void test_delete_text() { "Expected line to be empty after many chars removed"); const char *txt2 = "This is line 1\nThis is line 2\nThis is line 3"; - text_append(t, 0, 0, (uint8_t *)txt2, strlen(txt2), &lines_added, - &cols_added); + text_append_at(t, 0, 0, (uint8_t *)txt2, strlen(txt2), &lines_added, + &cols_added); ASSERT(text_num_lines(t) == 3, "Expected to have three lines after inserting as many"); @@ -73,8 +86,8 @@ void test_delete_text() { struct text *t3 = text_create(10); const char *delete_me = "This is line๐\nQ"; - text_append(t3, 0, 0, (uint8_t *)delete_me, strlen(delete_me), &lines_added, - &cols_added); + text_append_at(t3, 0, 0, (uint8_t *)delete_me, strlen(delete_me), + &lines_added, &cols_added); text_delete(t3, 0, 13, 1); struct text_chunk top_line = text_get_line(t3, 0); ASSERT(strncmp((const char *)top_line.text, "This is line๐Q", @@ -87,8 +100,8 @@ void test_delete_text() { // test utf-8 struct text *t2 = text_create(10); const char *txt3 = "Emojis: ๐ซ๐ฎ ๐ฎ\n"; - text_append(t2, 0, 0, (uint8_t *)txt3, strlen(txt3), &lines_added, - &cols_added); + text_append_at(t2, 0, 0, (uint8_t *)txt3, strlen(txt3), &lines_added, + &cols_added); // TODO: Fix when graphemes are implemented, should be 11, right now it counts // the two unicode code points ๐ซ and ๐ฎ as two chars. |
