Modularize insertion/deletion

This commit is contained in:
2025-12-11 18:00:17 +00:00
parent 4e25b28bbe
commit 17e8521f6a
7 changed files with 123 additions and 113 deletions

View File

@@ -115,5 +115,7 @@ void cursor_left(Editor *editor, uint32_t number);
void cursor_right(Editor *editor, uint32_t number);
void ensure_scroll(Editor *editor);
void apply_edit(std::vector<Span> &spans, uint32_t x, int64_t y);
void edit_erase(Editor *editor, uint32_t pos, uint32_t len);
void edit_insert(Editor *editor, uint32_t pos, char *data, uint32_t len);
#endif

View File

@@ -100,7 +100,7 @@ char *read(Knot *root, uint32_t offset, uint32_t len);
void split(Knot *node, uint32_t offset, Knot **left, Knot **right);
// Used to convert a byte offset to a line number that contains that byte
uint32_t byte_to_line(Knot *node, uint32_t offset);
uint32_t byte_to_line(Knot *node, uint32_t offset, uint32_t *out_col);
// Used to convert a line number to a byte offset (start of the line)
// also sets out_len to the length of the line

View File

@@ -36,7 +36,7 @@ struct Coord {
uint32_t col;
};
uint32_t grapheme_strlen(const char *s);
uint32_t visual_width(const char *s);
uint32_t get_visual_col_from_bytes(const char *line, uint32_t byte_limit);
uint32_t get_bytes_from_visual_col(const char *line,
uint32_t target_visual_col);

View File

@@ -75,8 +75,7 @@ void scroll_up(Editor *editor, uint32_t number) {
if (fold_state == 2) {
stack.push_back({1, current_idx});
} else if (fold_state == 0) {
uint32_t len =
(line_content != nullptr) ? grapheme_strlen(line_content) : 0;
uint32_t len = (line_content != nullptr) ? visual_width(line_content) : 0;
stack.push_back({len, current_idx});
}
if (line_content)
@@ -135,7 +134,7 @@ void scroll_down(Editor *editor, uint32_t number) {
if (fold_state == 2) {
segments = 1;
} else {
uint32_t len = grapheme_strlen(line_content);
uint32_t len = visual_width(line_content);
segments = (len > 0) ? (len + wrap_limit - 1) / wrap_limit : 1;
}
uint32_t start_seg = (current_row == editor->scroll.row)
@@ -353,7 +352,7 @@ void ensure_scroll(Editor *editor) {
char *line = next_line(it);
if (!line)
break;
uint32_t len = grapheme_strlen(line);
uint32_t len = visual_width(line);
visual_delta += (len + editor->size.col - 1) / editor->size.col;
free(line);
}
@@ -378,7 +377,7 @@ void ensure_scroll(Editor *editor) {
free(line);
break;
}
uint32_t len = grapheme_strlen(line);
uint32_t len = visual_width(line);
uint32_t visible_len = len - offset;
if (visible_len == 0)
visible_len = 1;
@@ -436,6 +435,75 @@ void apply_edit(std::vector<Span> &spans, uint32_t x, int64_t y) {
}
}
void edit_erase(Editor *editor, uint32_t pos, uint32_t len) {
if (len == 0)
return;
std::shared_lock lock_1(editor->knot_mtx);
uint32_t col;
uint32_t row = byte_to_line(editor->root, pos, &col);
TSPoint start_point = {row, col};
row = byte_to_line(editor->root, pos + len, &col);
TSPoint old_end_point = {row, col};
lock_1.unlock();
std::unique_lock lock_2(editor->knot_mtx);
editor->root = erase(editor->root, pos, len);
lock_2.unlock();
if (editor->tree) {
TSInputEdit edit = {
.start_byte = pos,
.old_end_byte = pos + len,
.new_end_byte = pos,
.start_point = start_point,
.old_end_point = old_end_point,
.new_end_point = start_point,
};
editor->edit_queue.push(edit);
}
std::unique_lock lock_3(editor->spans.mtx);
apply_edit(editor->spans.spans, pos, -(int32_t)len);
if (editor->spans.mid_parse)
editor->spans.edits.push({pos, -(int32_t)len});
}
void edit_insert(Editor *editor, uint32_t pos, char *data, uint32_t len) {
std::shared_lock lock_1(editor->knot_mtx);
uint32_t col;
uint32_t row = byte_to_line(editor->root, pos, &col);
TSPoint start_point = {row, col};
lock_1.unlock();
std::unique_lock lock_2(editor->knot_mtx);
editor->root = insert(editor->root, pos, data, len);
if (memchr(data, '\n', len))
editor->folded.resize(editor->root->line_count + 2);
lock_2.unlock();
uint32_t cols = 0;
uint32_t rows = 0;
for (uint32_t i = 0; i < len; i++) {
if (data[i] == '\n') {
rows++;
cols = 0;
} else {
cols++;
}
}
if (editor->tree) {
TSInputEdit edit = {
.start_byte = pos,
.old_end_byte = pos,
.new_end_byte = pos + len,
.start_point = start_point,
.old_end_point = start_point,
.new_end_point = {start_point.row + rows,
(rows == 0) ? (start_point.column + cols) : cols},
};
editor->edit_queue.push(edit);
}
std::unique_lock lock_3(editor->spans.mtx);
apply_edit(editor->spans.spans, pos, len);
if (editor->spans.mid_parse)
editor->spans.edits.push({pos, len});
}
void render_editor(Editor *editor) {
Coord cursor = {UINT32_MAX, UINT32_MAX};
uint32_t line_index = editor->scroll.row;

View File

@@ -391,25 +391,42 @@ static uint32_t find_nth_newline_offset(Knot *node, uint32_t n) {
}
}
uint32_t byte_to_line(Knot *node, uint32_t offset) {
if (!node)
uint32_t byte_to_line(Knot *node, uint32_t offset, uint32_t *out_col) {
if (!node) {
if (out_col)
*out_col = 0;
return 0;
if (offset >= node->char_count)
}
if (offset >= node->char_count) {
if (out_col)
*out_col = 0;
return node->line_count;
}
if (node->depth == 0) {
uint32_t lines_before = 0;
uint32_t limit = (offset < node->char_count) ? offset : node->char_count;
for (uint32_t i = 0; i < limit; i++)
if (node->data[i] == '\n')
lines_before++;
return lines_before;
uint32_t line = 0;
uint32_t col = 0;
for (uint32_t i = 0; i < offset; i++) {
if (node->data[i] == '\n') {
line++;
col = 0;
} else {
col++;
}
}
if (out_col)
*out_col = col;
return line;
}
uint32_t left_chars = node->left ? node->left->char_count : 0;
if (offset < left_chars) {
return byte_to_line(node->left, offset);
return byte_to_line(node->left, offset, out_col);
} else {
uint32_t left_lines = node->left ? node->left->line_count : 0;
return left_lines + byte_to_line(node->right, offset - left_chars);
uint32_t sub_col = 0;
uint32_t line = (node->left ? node->left->line_count : 0) +
byte_to_line(node->right, offset - left_chars, &sub_col);
if (out_col)
*out_col = sub_col;
return line;
}
}

View File

@@ -1,10 +1,8 @@
#include "../include/editor.h"
#include "../include/ts.h"
#include "../include/ui.h"
#include "../libs/tree-sitter/lib/include/tree_sitter/api.h"
#include <atomic>
#include <chrono>
#include <cstdint>
#include <sys/ioctl.h>
#include <thread>
@@ -51,107 +49,32 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
event.c == ':' || event.c == '\'' || event.c == '"' || event.c == ',' ||
event.c == '.' || event.c == '<' || event.c == '>' || event.c == '/' ||
event.c == '?' || event.c == '`' || event.c == '~')) {
std::shared_lock lock_1(editor->knot_mtx);
uint32_t pos = line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col;
lock_1.unlock();
std::unique_lock lock_2(editor->knot_mtx);
editor->root = insert(editor->root, pos, &event.c, 1);
lock_2.unlock();
if (editor->tree) {
TSInputEdit edit = {
.start_byte = pos,
.old_end_byte = pos,
.new_end_byte = pos + 1,
.start_point = {editor->cursor.row, editor->cursor.col},
.old_end_point = {editor->cursor.row, editor->cursor.col},
.new_end_point = {editor->cursor.row, editor->cursor.col + 1},
};
editor->edit_queue.push(edit);
}
edit_insert(editor,
line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col,
&event.c, 1);
cursor_right(editor, 1);
apply_edit(editor->spans.spans, pos, 1);
if (editor->spans.mid_parse)
editor->spans.edits.push({pos, 1});
}
if (event.key_type == KEY_CHAR && event.c == '\t') {
std::shared_lock lock_1(editor->knot_mtx);
uint32_t pos = line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col;
lock_1.unlock();
std::unique_lock lock_2(editor->knot_mtx);
editor->root = insert(editor->root, pos, (char *)" ", 2);
lock_2.unlock();
if (editor->tree) {
TSInputEdit edit = {
.start_byte = pos,
.old_end_byte = pos,
.new_end_byte = pos + 2,
.start_point = {editor->cursor.row, editor->cursor.col},
.old_end_point = {editor->cursor.row, editor->cursor.col},
.new_end_point = {editor->cursor.row, editor->cursor.col + 2},
};
editor->edit_queue.push(edit);
}
edit_insert(editor,
line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col,
(char *)" ", 2);
cursor_right(editor, 2);
std::unique_lock lock_3(editor->spans.mtx);
apply_edit(editor->spans.spans, pos, 2);
if (editor->spans.mid_parse)
editor->spans.edits.push({pos, 2});
}
if (event.key_type == KEY_CHAR && (event.c == '\n' || event.c == '\r')) {
std::shared_lock lock_1(editor->knot_mtx);
uint32_t pos = line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col;
lock_1.unlock();
std::unique_lock lock_2(editor->knot_mtx);
editor->root = insert(editor->root, pos, (char *)"\n", 1);
editor->folded.resize(editor->root->line_count + 2);
lock_2.unlock();
if (editor->tree) {
TSInputEdit edit = {
.start_byte = pos,
.old_end_byte = pos,
.new_end_byte = pos + 1,
.start_point = {editor->cursor.row, editor->cursor.col},
.old_end_point = {editor->cursor.row, editor->cursor.col},
.new_end_point = {editor->cursor.row + 1, 0},
};
editor->edit_queue.push(edit);
}
edit_insert(editor,
line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col,
(char *)"\n", 1);
cursor_right(editor, 1);
std::unique_lock lock_3(editor->spans.mtx);
apply_edit(editor->spans.spans, pos + 1, 1);
if (editor->spans.mid_parse)
editor->spans.edits.push({pos + 1, 1});
}
if (event.key_type == KEY_CHAR && event.c == 0x7F) {
std::shared_lock lock_1(editor->knot_mtx);
uint32_t pos = line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col;
TSPoint old_point = {editor->cursor.row, editor->cursor.col};
edit_erase(editor,
line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col,
1);
cursor_left(editor, 1);
uint32_t start = line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col;
lock_1.unlock();
std::unique_lock lock_2(editor->knot_mtx);
editor->root = erase(editor->root, start, pos - start);
lock_2.unlock();
if (editor->tree) {
TSInputEdit edit = {
.start_byte = start,
.old_end_byte = pos,
.new_end_byte = start,
.start_point = {editor->cursor.row, editor->cursor.col},
.old_end_point = old_point,
.new_end_point = {editor->cursor.row, editor->cursor.col},
};
editor->edit_queue.push(edit);
}
std::unique_lock lock_3(editor->spans.mtx);
apply_edit(editor->spans.spans, start, start - pos);
if (editor->spans.mid_parse)
editor->spans.edits.push({start, start - pos});
}
ensure_scroll(editor);
}

View File

@@ -25,7 +25,7 @@ std::string get_exe_dir() {
return path.substr(0, path.find_last_of('/'));
}
uint32_t grapheme_strlen(const char *s) {
uint32_t visual_width(const char *s) {
if (!s)
return 0;
uint32_t count = 0;