Modularize insertion/deletion
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
41
src/knot.cc
41
src/knot.cc
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
109
src/main.cc
109
src/main.cc
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user