summaryrefslogtreecommitdiff
path: root/src/text.c
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2023-01-31 00:07:54 +0100
committerAlbert Cervin <albert@acervin.com>2023-01-31 00:12:56 +0100
commit689ceeca3d25cb2f738a6c52776c53912abb797f (patch)
treed61a96445beccae2c5b99c7aa9dee77738a14379 /src/text.c
parentf90d5e1f07fdc9dea7c24b11107049b613a5be7a (diff)
downloaddged-689ceeca3d25cb2f738a6c52776c53912abb797f.tar.gz
dged-689ceeca3d25cb2f738a6c52776c53912abb797f.tar.xz
dged-689ceeca3d25cb2f738a6c52776c53912abb797f.zip
Implement mark and copy-paste
Also fix some memory leaks
Diffstat (limited to 'src/text.c')
-rw-r--r--src/text.c137
1 files changed, 95 insertions, 42 deletions
diff --git a/src/text.c b/src/text.c
index ec80643..6e343ae 100644
--- a/src/text.c
+++ b/src/text.c
@@ -255,56 +255,44 @@ void text_insert_at(struct text *text, uint32_t line, uint32_t col,
*lines_added = line - start_line;
}
-void text_delete(struct text *text, uint32_t line, uint32_t col,
- uint32_t nchars) {
+void text_delete(struct text *text, uint32_t start_line, uint32_t start_col,
+ uint32_t end_line, uint32_t end_col) {
- struct line *lp = &text->lines[line];
- if (col > lp->nchars) {
+ struct line *firstline = &text->lines[start_line];
+ struct line *lastline = &text->lines[end_line];
+ if (start_col > firstline->nchars) {
return;
}
- // delete chars from current line
- uint32_t chars_initial_line =
- col + nchars > lp->nchars ? (lp->nchars - col) : nchars;
- uint32_t bytei = charidx_to_byteidx(lp, col);
- uint32_t nbytes =
- utf8_nbytes(lp->data + bytei, lp->nbytes - bytei, chars_initial_line);
-
- memcpy(lp->data + bytei, lp->data + bytei + nbytes,
- lp->nbytes - (bytei + nbytes));
-
- lp->nbytes -= nbytes;
- lp->nchars -= chars_initial_line;
- lp->flags |= LineChanged;
-
- uint32_t initial_line = line;
- uint32_t left_to_delete = nchars - chars_initial_line;
-
- // grab remaining chars from last line to delete from (if any)
- uint32_t src_col = 0;
- while (left_to_delete > 0 && line < text->nlines) {
- ++line;
- --left_to_delete; // newline char
-
- struct line *lp = &text->lines[line];
- uint32_t deleted_in_line =
- left_to_delete > lp->nchars ? lp->nchars : left_to_delete;
- src_col = deleted_in_line;
- left_to_delete -= deleted_in_line;
+ // handle deletion of newlines
+ if (end_col > lastline->nchars) {
+ ++end_line;
+ end_col = 0;
+ lastline = &text->lines[end_line];
}
- if (line != initial_line) {
- struct line *lp = &text->lines[line];
- uint32_t bytei = charidx_to_byteidx(lp, src_col);
- if (src_col < lp->nchars) {
- insert_at_col(&text->lines[initial_line], col, lp->data + bytei,
- lp->nbytes - bytei, lp->nchars - src_col);
- }
+ uint32_t bytei = utf8_nbytes(lastline->data, lastline->nbytes, end_col);
+ if (lastline == firstline) {
+ // in this case we can "overwrite"
+ uint32_t dstbytei =
+ utf8_nbytes(firstline->data, firstline->nbytes, start_col);
+ memcpy(firstline->data + dstbytei, lastline->data + bytei,
+ lastline->nbytes - bytei);
+ } else {
+ // otherwise we actually have to copy from the last line
+ insert_at_col(firstline, start_col, lastline->data + bytei,
+ lastline->nbytes - bytei, lastline->nchars - end_col);
}
- // delete all lines from current line + 1 to (and including) last line
- for (uint32_t li = initial_line + 1; li <= line && li < text->nlines; ++li) {
- delete_line(text, li);
+ firstline->nchars = start_col + (lastline->nchars - end_col);
+ firstline->nbytes =
+ utf8_nbytes(firstline->data, firstline->nbytes, start_col) +
+ (lastline->nbytes - bytei);
+
+ // delete full lines
+ for (uint32_t linei = start_line + 1;
+ linei <= end_line && linei < text->nlines; ++linei) {
+ delete_line(text, linei);
}
}
@@ -339,6 +327,71 @@ struct text_chunk text_get_line(struct text *text, uint32_t line) {
};
}
+struct copy_cmd {
+ uint32_t line;
+ uint32_t byteindex;
+ uint32_t nbytes;
+};
+
+struct text_chunk text_get_region(struct text *text, uint32_t start_line,
+ uint32_t start_col, uint32_t end_line,
+ uint32_t end_col) {
+ struct copy_cmd *copy_cmds = malloc(end_line - start_line + 1);
+
+ uint32_t total_chars = 0, total_bytes = 0;
+ for (uint32_t line = start_line; line <= end_line; ++line) {
+ struct line *l = &text->lines[line];
+ total_chars += l->nchars;
+ total_bytes += l->nbytes;
+
+ struct copy_cmd *cmd = &copy_cmds[line - start_line];
+ cmd->line = line;
+ cmd->byteindex = 0;
+ cmd->nbytes = l->nbytes;
+
+ ++line;
+ }
+
+ // correct first line
+ struct copy_cmd *cmd_first = &copy_cmds[start_line];
+ struct line *first_line = &text->lines[start_line];
+ uint32_t byteoff =
+ utf8_nbytes(first_line->data, first_line->nbytes, start_col);
+ cmd_first->byteindex += byteoff;
+ cmd_first->nbytes -= byteoff;
+ total_bytes -= byteoff;
+ total_chars -= start_col;
+
+ // correct last line
+ struct copy_cmd *cmd_last = &copy_cmds[end_line];
+ struct line *last_line = &text->lines[end_line];
+ uint32_t byteindex = utf8_nbytes(last_line->data, last_line->nbytes, end_col);
+ cmd_last->nbytes -= (last_line->nchars - end_col);
+ total_bytes -= (last_line->nbytes - byteindex);
+ total_chars -= (last_line->nchars - end_col);
+
+ struct text_chunk txt = {
+ .text = (uint8_t *)malloc(total_bytes + end_line - start_line),
+ .line = 0,
+ .nbytes = total_bytes,
+ .nchars = total_chars,
+ };
+
+ // copy data
+ for (uint32_t cmdi = 0, curr = 0; cmdi <= end_line - start_line; ++cmdi) {
+ struct copy_cmd *c = &copy_cmds[cmdi];
+ struct line *l = &text->lines[c->line];
+ memcpy(txt.text + curr, l->data + c->byteindex, c->nbytes);
+ curr += c->nbytes;
+
+ if (cmdi != end_line - start_line) {
+ txt.text[++curr] = '\n';
+ }
+ }
+
+ return txt;
+}
+
bool text_line_contains_unicode(struct text *text, uint32_t line) {
return text->lines[line].nbytes != text->lines[line].nchars;
}