diff --git a/include/editor.h b/include/editor.h index ce2a80a..37401b2 100644 --- a/include/editor.h +++ b/include/editor.h @@ -3,9 +3,11 @@ #include "./rope.h" #include "./ui.h" #include "./utils.h" +#include #include #include #include +#include struct Highlight { uint32_t fg; @@ -22,37 +24,71 @@ struct Span { bool operator<(const Span &other) const { return start < other.start; } }; +struct Spans { + std::vector spans; + Queue> edits; + bool mid_parse = false; + std::shared_mutex mtx; + + void apply(uint32_t x, int64_t y) { + std::unique_lock lock(mtx); + auto it = std::lower_bound( + spans.begin(), spans.end(), Span{.start = x, .end = 0, .hl = nullptr}, + [](auto &a, auto &b) { return a.start < b.start; }); + while (it != spans.begin()) { + auto prev = std::prev(it); + if (prev->end <= x) + break; + it = prev; + } + while (it != spans.end()) { + if (it->start < x && it->end > x) { + it->end += y; + } else if (it->start > x) { + it->start += y; + it->end += y; + } + if (it->end <= it->start) + it = spans.erase(it); + else + ++it; + } + } +}; + struct SpanCursor { - const std::vector &spans; + Spans &spans; size_t index = 0; std::vector active; + std::shared_lock lock; - SpanCursor(const std::vector &s) : spans(s) {} + SpanCursor(Spans &s) : spans(s) {} Highlight *get_highlight(uint32_t byte_offset) { for (int i = (int)active.size() - 1; i >= 0; i--) if (active[i]->end <= byte_offset) active.erase(active.begin() + i); - while (index < spans.size() && spans[index].start <= byte_offset) { - if (spans[index].end > byte_offset) - active.push_back(const_cast(&spans[index])); + while (index < spans.spans.size() && + spans.spans[index].start <= byte_offset) { + if (spans.spans[index].end > byte_offset) + active.push_back(const_cast(&spans.spans[index])); index++; } Highlight *best = nullptr; int max_prio = -1; - for (auto *s : active) { + for (auto *s : active) if (s->hl->priority > max_prio) { max_prio = s->hl->priority; best = s->hl; } - } return best; } void sync(uint32_t byte_offset) { + lock = std::shared_lock(spans.mtx); active.clear(); - size_t left = 0, right = spans.size(); + size_t left = 0, right = spans.spans.size(); while (left < right) { size_t mid = (left + right) / 2; - if (spans[mid].start <= byte_offset) + if (spans.spans[mid].start <= byte_offset) left = mid + 1; else right = mid; @@ -60,9 +96,9 @@ struct SpanCursor { index = left; while (left > 0) { left--; - if (spans[left].end > byte_offset) - active.push_back(const_cast(&spans[left])); - else if (byte_offset - spans[left].end > 1000) + if (spans.spans[left].end > byte_offset) + active.push_back(const_cast(&spans.spans[left])); + else if (byte_offset - spans.spans[left].end > 1000) break; } } @@ -72,7 +108,6 @@ struct Editor { const char *filename; // Filename of the editor Knot *root; // A rope std::shared_mutex knot_mtx; // A mutex - std::shared_mutex span_mtx; // A mutex Coord cursor; // position of the cursor uint32_t cursor_preffered; // preffered visual column Coord selection; // position of the selection @@ -87,7 +122,7 @@ struct Editor { Queue edit_queue; // Tree-sitter edit queue std::vector query_map; // Tree-sitter query map std::vector folded; // folded lines indexed by line number - std::vector spans; // Highlighted spans + Spans spans; // Highlighted spans std::map folded_node; // maps content hash to fold state // - built by tree-sitter helpers }; diff --git a/src/editor.cc b/src/editor.cc index ecfb30c..5071bbd 100644 --- a/src/editor.cc +++ b/src/editor.cc @@ -382,7 +382,6 @@ void render_editor(Editor *editor) { uint32_t line_index = editor->scroll.row; SpanCursor span_cursor(editor->spans); std::shared_lock knot_lock(editor->knot_mtx); - std::shared_lock span_lock(editor->span_mtx); LineIterator *it = begin_l_iter(editor->root, line_index); if (!it) return; diff --git a/src/main.cc b/src/main.cc index 8b22ce0..f600911 100644 --- a/src/main.cc +++ b/src/main.cc @@ -75,6 +75,9 @@ void handle_editor_event(Editor *editor, KeyEvent event) { }; editor->edit_queue.push(edit); } + editor->spans.apply(pos, 1); + if (editor->spans.mid_parse) + editor->spans.edits.push({pos, 1}); cursor_right(editor, 1); } if (event.key_type == KEY_CHAR && event.c == '\t') { @@ -96,6 +99,9 @@ void handle_editor_event(Editor *editor, KeyEvent event) { }; editor->edit_queue.push(edit); } + editor->spans.apply(pos, 2); + if (editor->spans.mid_parse) + editor->spans.edits.push({pos, 2}); cursor_right(editor, 2); } if (event.key_type == KEY_CHAR && (event.c == '\n' || event.c == '\r')) { @@ -118,6 +124,9 @@ void handle_editor_event(Editor *editor, KeyEvent event) { }; editor->edit_queue.push(edit); } + editor->spans.apply(pos + 1, 1); + if (editor->spans.mid_parse) + editor->spans.edits.push({pos + 1, 1}); cursor_right(editor, 1); } if (event.key_type == KEY_CHAR && event.c == 0x7F) { @@ -143,6 +152,9 @@ void handle_editor_event(Editor *editor, KeyEvent event) { }; editor->edit_queue.push(edit); } + editor->spans.apply(start, start - pos); + if (editor->spans.mid_parse) + editor->spans.edits.push({start, start - pos}); } ensure_scroll(editor); } diff --git a/src/ts.cc b/src/ts.cc index da9c22a..582da90 100644 --- a/src/ts.cc +++ b/src/ts.cc @@ -1,6 +1,7 @@ #include "../include/ts.h" #include "../include/editor.h" #include "../include/rope.h" +#include #include #include #include @@ -177,10 +178,10 @@ void ts_collect_spans(Editor *editor) { .decode = nullptr, }; TSTree *tree, *copy = nullptr; - std::unique_lock lock_0(editor->knot_mtx); + std::unique_lock knot_mtx(editor->knot_mtx); if (editor->tree) copy = ts_tree_copy(editor->tree); - lock_0.unlock(); + knot_mtx.unlock(); if (!running) return; std::vector edits; @@ -189,21 +190,17 @@ void ts_collect_spans(Editor *editor) { while (editor->edit_queue.pop(edit)) { edits.push_back(edit); ts_tree_edit(copy, &edits.back()); - } + }; + editor->spans.mid_parse = true; tree = ts_parser_parse(editor->parser, copy, tsinput); if (copy) ts_tree_delete(copy); - while (editor->edit_queue.pop(edit)) { - edits.push_back(edit); - ts_tree_edit(tree, &edits.back()); - } - lock_0.lock(); + knot_mtx.lock(); if (editor->tree) ts_tree_delete(editor->tree); editor->tree = tree; copy = ts_tree_copy(tree); - lock_0.unlock(); - std::shared_lock lock_1(editor->span_mtx); + knot_mtx.unlock(); TSQueryCursor *cursor = ts_query_cursor_new(); ts_query_cursor_exec(cursor, editor->query, ts_tree_root_node(copy)); std::vector new_spans; @@ -232,12 +229,16 @@ void ts_collect_spans(Editor *editor) { free(load.prev); return; } - lock_1.unlock(); std::sort(new_spans.begin(), new_spans.end()); - std::unique_lock lock_2(editor->span_mtx); - editor->spans.swap(new_spans); - lock_2.unlock(); + std::unique_lock span_mtx(editor->spans.mtx); + editor->spans.mid_parse = false; + editor->spans.spans.swap(new_spans); + span_mtx.unlock(); + std::pair span_edit; + while (editor->spans.edits.pop(span_edit)) + editor->spans.apply(span_edit.first, span_edit.second); ts_query_cursor_delete(cursor); + ts_tree_delete(copy); if (load.prev) free(load.prev); }