Minor fixes and optimizations

This commit is contained in:
2025-12-26 22:13:11 +00:00
parent 655f0e7d77
commit a38ba1f813
6 changed files with 59 additions and 48 deletions

View File

@@ -6,14 +6,12 @@ A TUI IDE.
# TODO # TODO
- [ ] Get lsp warnings byte offsets/lengths and render them as background color.
- [ ] Add support for LSP & autocomplete / snippets. - [ ] Add support for LSP & autocomplete / snippets.
- First research - First research
- `textDocument/documentHighlight` - for highlighting stuff (probably tree-sitter is enough) - `textDocument/documentHighlight` - for highlighting stuff (probably tree-sitter is enough)
- `textDocument/selectionRange` // - `textDocument/selectionRange` //
- `textDocument/completion` - Obviously - `textDocument/completion` - Obviously
- `textDocument/onTypeFormatting` - seems promising for auto formatting (indentation etc) - `textDocument/onTypeFormatting` - seems promising for auto formatting (indentation etc)
- `textDocument/inlayHint` & `textDocument/inlineHint` & `textDocument/codeLens`
- `textDocument/formatting` & `textDocument/rangeFormatting` - `textDocument/formatting` & `textDocument/rangeFormatting`
- `textDocument/semanticTokens/*` (probably tree-sitter is enough) - `textDocument/semanticTokens/*` (probably tree-sitter is enough)
- `textDocument/linkedEditingRange` - probably useful - `textDocument/linkedEditingRange` - probably useful
@@ -28,9 +26,6 @@ A TUI IDE.
2. One for stuff that only affects highlighting and styles . like symbol highlighting etc. 2. One for stuff that only affects highlighting and styles . like symbol highlighting etc.
3. One for Warnings/errors and inlay hints etc. (stuff that adds virtual text to the editor) 3. One for Warnings/errors and inlay hints etc. (stuff that adds virtual text to the editor)
4. One for fromatting and stuff like that. (stuff that edits the buffer text) 4. One for fromatting and stuff like that. (stuff that edits the buffer text)
- [ ] Make tree sitter spans truly incremental - or atleast make them pos based and not byte so minor changes only shifts inline
- And make inner trees incremental too
- [ ] Use LSP to add inlay hints in order to test virtual text. then make an iterator over screen that mimics the renderer for scrolling functions.
- [ ] Add codeium/copilot support for auto-completion (uses the VAI virtual text) as a test phase. - [ ] Add codeium/copilot support for auto-completion (uses the VAI virtual text) as a test phase.
- [ ] Add a whitespace highlighter (nerd font). for spaces and tabs at start/end of line. not as virtual but instead at render time. - [ ] Add a whitespace highlighter (nerd font). for spaces and tabs at start/end of line. not as virtual but instead at render time.
- [ ] Once renderer is proven to work well (i.e. redo this commit) merge `experimental` branch into `main`. commit `43f443e` on `experimental`. - [ ] Once renderer is proven to work well (i.e. redo this commit) merge `experimental` branch into `main`. commit `43f443e` on `experimental`.
@@ -42,7 +37,6 @@ A TUI IDE.
- [ ] Add alt + click to set multiple cursors. - [ ] Add alt + click to set multiple cursors.
- [ ] Add search / replace along with search / virtual cursors are searched pos. - [ ] Add search / replace along with search / virtual cursors are searched pos.
- [ ] Add support for undo/redo. - [ ] Add support for undo/redo.
- [ ] Add `.scm` files for all the supported languages. (2/14) Done.
- [ ] Add splash screen / minigame jumping. - [ ] Add splash screen / minigame jumping.
- [ ] Normalize / validate unicode on file open. - [ ] Normalize / validate unicode on file open.
- [ ] Add git stuff. - [ ] Add git stuff.

View File

@@ -14,7 +14,7 @@
(#match? @variable.builtin (#match? @variable.builtin
"^(arguments|console|window|document|globalThis|process|module|exports)$")) "^(arguments|console|window|document|globalThis|process|module|exports)$"))
;; #59C2FF #000000 0 0 0 3 ;; #59C2FF #000000 0 0 0 1
((identifier) @constructor ((identifier) @constructor
(#match? @constructor "^[A-Z][a-zA-Z0-9]*$")) (#match? @constructor "^[A-Z][a-zA-Z0-9]*$"))
@@ -84,12 +84,11 @@
key: (property_identifier) @name key: (property_identifier) @name
value: [(arrow_function) (function_expression)]) @definition.function value: [(arrow_function) (function_expression)]) @definition.function
;; #59C2FF #000000 0 0 0 2 ;; #59C2FF #000000 0 0 0 0
( (
(call_expression (call_expression
function: (identifier) @name) @reference.call function: (identifier) @name) @reference.call
(#not-match? @name "^(require)$") (#not-match? @name "^(require)$"))
)
;; #7dcfff #000000 0 0 0 2 ;; #7dcfff #000000 0 0 0 2
(new_expression (new_expression

View File

@@ -94,17 +94,12 @@ struct SpanCursor {
} }
}; };
struct VHint {
Coord pos;
std::string hint;
bool operator<(const VHint &other) const { return pos < other.pos; }
};
struct VWarn { struct VWarn {
uint32_t line; uint32_t line;
std::string text; std::string text;
int8_t type; // For hl int8_t type;
uint32_t start;
uint32_t end{UINT32_MAX};
bool operator<(const VWarn &other) const { return line < other.line; } bool operator<(const VWarn &other) const { return line < other.line; }
}; };
@@ -123,6 +118,7 @@ struct TSSetBase {
TSParser *parser; TSParser *parser;
std::string query_file; std::string query_file;
TSQuery *query; TSQuery *query;
TSTree *tree;
std::map<uint16_t, Highlight> query_map; std::map<uint16_t, Highlight> query_map;
std::map<uint16_t, Language> injection_map; std::map<uint16_t, Language> injection_map;
const TSLanguage *language; const TSLanguage *language;
@@ -133,7 +129,6 @@ struct TSSet : TSSetBase {
}; };
struct TSSetMain : TSSetBase { struct TSSetMain : TSSetBase {
TSTree *tree;
std::unordered_map<std::string, TSSet> injections; std::unordered_map<std::string, TSSet> injections;
}; };
@@ -158,7 +153,6 @@ struct Editor {
uint32_t hooks[94]; uint32_t hooks[94];
bool jumper_set; bool jumper_set;
std::shared_mutex v_mtx; std::shared_mutex v_mtx;
std::vector<VHint> hints;
std::vector<VWarn> warnings; std::vector<VWarn> warnings;
VAI ai; VAI ai;
std::shared_mutex lsp_mtx; std::shared_mutex lsp_mtx;

View File

@@ -253,6 +253,25 @@ void render_editor(Editor *editor) {
if (editor->selection_active && absolute_byte_pos >= sel_start && if (editor->selection_active && absolute_byte_pos >= sel_start &&
absolute_byte_pos < sel_end) absolute_byte_pos < sel_end)
bg = 0x555555; bg = 0x555555;
for (const auto &w : line_warnings) {
if (w.start <= current_byte_offset + local_render_offset &&
current_byte_offset + local_render_offset < w.end) {
switch (w.type) {
case 1:
bg = 0x500000;
break;
case 2:
bg = 0x505000;
break;
case 3:
bg = 0x500050;
break;
case 4:
bg = 0x505050;
break;
}
}
}
uint32_t cluster_len = grapheme_next_character_break_utf8( uint32_t cluster_len = grapheme_next_character_break_utf8(
line + current_byte_offset + local_render_offset, line_left); line + current_byte_offset + local_render_offset, line_left);
std::string cluster(line + current_byte_offset + local_render_offset, std::string cluster(line + current_byte_offset + local_render_offset,

View File

@@ -611,6 +611,10 @@ void editor_lsp_handle(Editor *editor, json msg) {
json d = diagnostics[i]; json d = diagnostics[i];
VWarn w; VWarn w;
w.line = d["range"]["start"]["line"]; w.line = d["range"]["start"]["line"];
w.start = d["range"]["start"]["character"];
uint32_t end = d["range"]["end"]["character"];
if (d["range"]["end"]["line"] == w.line)
w.end = end;
std::string text = d["message"].get<std::string>(); std::string text = d["message"].get<std::string>();
auto pos = text.find('\n'); auto pos = text.find('\n');
w.text = (pos == std::string::npos) ? text : text.substr(0, pos); w.text = (pos == std::string::npos) ? text : text.substr(0, pos);

View File

@@ -204,35 +204,40 @@ void ts_collect_spans(Editor *editor) {
.encoding = TSInputEncodingUTF8, .encoding = TSInputEncodingUTF8,
.decode = nullptr, .decode = nullptr,
}; };
TSTree *tree = nullptr;
TSTree *copy = nullptr;
std::unique_lock knot_mtx(editor->knot_mtx);
if (editor->ts.tree)
copy = ts_tree_copy(editor->ts.tree);
knot_mtx.unlock();
std::vector<TSInputEdit> edits; std::vector<TSInputEdit> edits;
TSInputEdit edit; TSInputEdit edit;
if (copy) if (!editor->edit_queue.empty()) {
while (editor->edit_queue.pop(edit)) { while (editor->edit_queue.pop(edit))
edits.push_back(edit); edits.push_back(edit);
ts_tree_edit(copy, &edits.back()); if (editor->ts.tree) {
for (auto &e : edits)
ts_tree_edit(editor->ts.tree, &e);
} }
if (copy && edits.empty() && parse_counter < 64) { for (auto &inj : editor->ts.injections) {
if (inj.second.tree) {
for (auto &e : edits) {
TSInputEdit inj_edit = e;
for (auto &r : inj.second.ranges) {
if (e.start_byte >= r.start_byte && e.start_byte <= r.end_byte) {
inj_edit.start_byte -= r.start_byte;
inj_edit.old_end_byte -= r.start_byte;
inj_edit.new_end_byte -= r.start_byte;
}
}
ts_tree_edit(inj.second.tree, &inj_edit);
}
}
}
} else if (editor->ts.tree && parse_counter < 64) {
parse_counter++; parse_counter++;
ts_tree_delete(copy);
return; return;
} }
parse_counter = 0; parse_counter = 0;
editor->spans.mid_parse = true; editor->spans.mid_parse = true;
std::shared_lock lock(editor->knot_mtx); std::shared_lock lock(editor->knot_mtx);
tree = ts_parser_parse(editor->ts.parser, copy, tsinput); editor->ts.tree =
ts_parser_parse(editor->ts.parser, editor->ts.tree, tsinput);
lock.unlock(); lock.unlock();
if (copy)
ts_tree_delete(copy);
if (editor->ts.tree)
ts_tree_delete(editor->ts.tree);
editor->ts.tree = tree;
copy = ts_tree_copy(tree);
std::vector<Span> new_spans; std::vector<Span> new_spans;
new_spans.reserve(4096); new_spans.reserve(4096);
struct PendingRanges { struct PendingRanges {
@@ -243,12 +248,11 @@ void ts_collect_spans(Editor *editor) {
TSSetBase *tsset; TSSetBase *tsset;
TSTree *tree; TSTree *tree;
int depth; int depth;
TSSet *as_injection;
}; };
const int kMaxInjectionDepth = 4; const int kMaxInjectionDepth = 4;
std::vector<WorkItem> work; std::vector<WorkItem> work;
work.push_back( work.push_back(
{reinterpret_cast<TSSetBase *>(&editor->ts), copy, 0, nullptr}); {reinterpret_cast<TSSetBase *>(&editor->ts), editor->ts.tree, 0});
auto overlaps = [](const Span &s, const TSRange &r) { auto overlaps = [](const Span &s, const TSRange &r) {
return !(s.end <= r.start_byte || s.start >= r.end_byte); return !(s.end <= r.start_byte || s.start >= r.end_byte);
}; };
@@ -268,12 +272,10 @@ void ts_collect_spans(Editor *editor) {
WorkItem item = work.back(); WorkItem item = work.back();
work.pop_back(); work.pop_back();
TSQuery *q = item.tsset->query; TSQuery *q = item.tsset->query;
if (!q) { if (!q)
ts_tree_delete(item.tree);
continue; continue;
}
TSQueryCursor *cursor = ts_query_cursor_new(); TSQueryCursor *cursor = ts_query_cursor_new();
ts_query_cursor_exec(cursor, q, ts_tree_root_node(item.tree)); ts_query_cursor_exec(cursor, q, ts_tree_root_node(item.tsset->tree));
std::unordered_map<std::string, PendingRanges> pending_injections; std::unordered_map<std::string, PendingRanges> pending_injections;
TSQueryMatch match; TSQueryMatch match;
while (ts_query_cursor_next_match(cursor, &match)) { while (ts_query_cursor_next_match(cursor, &match)) {
@@ -322,13 +324,12 @@ void ts_collect_spans(Editor *editor) {
ts_parser_set_included_ranges(tsset->parser, tsset->ranges.data(), ts_parser_set_included_ranges(tsset->parser, tsset->ranges.data(),
tsset->ranges.size()); tsset->ranges.size());
lock.lock(); lock.lock();
TSTree *inj_tree = ts_parser_parse(tsset->parser, nullptr, tsinput); tsset->tree = ts_parser_parse(tsset->parser, tsset->tree, tsinput);
lock.unlock(); lock.unlock();
work.push_back({reinterpret_cast<TSSetBase *>(tsset), inj_tree, work.push_back({reinterpret_cast<TSSetBase *>(tsset), tsset->tree,
item.depth + 1, tsset}); item.depth + 1});
} }
} }
ts_tree_delete(item.tree);
} }
std::pair<uint32_t, int64_t> span_edit; std::pair<uint32_t, int64_t> span_edit;
while (editor->spans.edits.pop(span_edit)) while (editor->spans.edits.pop(span_edit))