From bfaba813173659afc6160cb1e7317a3bd262cf7d Mon Sep 17 00:00:00 2001 From: Syed Daanish Date: Sat, 27 Dec 2025 04:31:08 +0000 Subject: [PATCH] Add lsp's for many different languages and minor fixes --- README.md | 3 +- grammar/c.scm | 15 -- grammar/cpp.scm | 15 -- grammar/{embedded_template.scm => erb.scm} | 0 grammar/h.scm | 15 -- grammar/javascript.scm | 20 +-- include/lsp.h | 1 + include/maps.h | 188 ++++++++++++++++++--- include/utils.h | 1 + samples/yaml.yaml | 66 ++++++++ src/editor.cc | 14 +- src/editor_ctrl.cc | 122 ++++++++----- src/editor_events.cc | 2 + src/lsp.cc | 21 ++- src/ts.cc | 15 +- src/utils.cc | 2 +- 16 files changed, 369 insertions(+), 131 deletions(-) rename grammar/{embedded_template.scm => erb.scm} (100%) create mode 100644 samples/yaml.yaml diff --git a/README.md b/README.md index ddab1f9..ed4d508 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ A TUI IDE. 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) - [ ] Add codeium/copilot support for auto-completion (uses the VAI virtual text) as a test phase. +- [ ] Redo cpp/c/h scm file . also pretty much all of them do manually - [ ] 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`. - [ ] Add snippets from wherever i get them. (like luasnip or vsnip) @@ -38,7 +39,7 @@ A TUI IDE. - [ ] Add search / replace along with search / virtual cursors are searched pos. - [ ] Add support for undo/redo. - [ ] Add splash screen / minigame jumping. -- [ ] Normalize / validate unicode on file open. +- [ ] Normalize / validate unicode on file open. so use utf8 purely and fix other types of files - [ ] Add git stuff. - [ ] Add SQL support. (viewer and basic editor) - [ ] Add color picker/palette for hex or other css colors. diff --git a/grammar/c.scm b/grammar/c.scm index 31215ae..7f3842e 100644 --- a/grammar/c.scm +++ b/grammar/c.scm @@ -221,21 +221,6 @@ _ @type.builtin type: _?) -;; #C4B5FF #000000 0 0 0 2 -(type_definition declarator: (type_identifier) @name) @definition.type - -;; #C4B5FF #000000 0 0 0 2 -(enum_specifier name: (type_identifier) @name) @definition.type - -;; #C4B5FF #000000 0 0 0 2 -(class_specifier name: (type_identifier) @name) @definition.class - -;; #C4B5FF #000000 0 0 0 2 -(struct_specifier name: (type_identifier) @name body:(_)) @definition.class - -;; #C4B5FF #000000 0 0 0 2 -(declaration type: (union_specifier name: (type_identifier) @name)) @definition.class - ;; #9AD4FF #000000 0 0 0 2 (namespace_identifier) @module diff --git a/grammar/cpp.scm b/grammar/cpp.scm index 31215ae..7f3842e 100644 --- a/grammar/cpp.scm +++ b/grammar/cpp.scm @@ -221,21 +221,6 @@ _ @type.builtin type: _?) -;; #C4B5FF #000000 0 0 0 2 -(type_definition declarator: (type_identifier) @name) @definition.type - -;; #C4B5FF #000000 0 0 0 2 -(enum_specifier name: (type_identifier) @name) @definition.type - -;; #C4B5FF #000000 0 0 0 2 -(class_specifier name: (type_identifier) @name) @definition.class - -;; #C4B5FF #000000 0 0 0 2 -(struct_specifier name: (type_identifier) @name body:(_)) @definition.class - -;; #C4B5FF #000000 0 0 0 2 -(declaration type: (union_specifier name: (type_identifier) @name)) @definition.class - ;; #9AD4FF #000000 0 0 0 2 (namespace_identifier) @module diff --git a/grammar/embedded_template.scm b/grammar/erb.scm similarity index 100% rename from grammar/embedded_template.scm rename to grammar/erb.scm diff --git a/grammar/h.scm b/grammar/h.scm index 31215ae..7f3842e 100644 --- a/grammar/h.scm +++ b/grammar/h.scm @@ -221,21 +221,6 @@ _ @type.builtin type: _?) -;; #C4B5FF #000000 0 0 0 2 -(type_definition declarator: (type_identifier) @name) @definition.type - -;; #C4B5FF #000000 0 0 0 2 -(enum_specifier name: (type_identifier) @name) @definition.type - -;; #C4B5FF #000000 0 0 0 2 -(class_specifier name: (type_identifier) @name) @definition.class - -;; #C4B5FF #000000 0 0 0 2 -(struct_specifier name: (type_identifier) @name body:(_)) @definition.class - -;; #C4B5FF #000000 0 0 0 2 -(declaration type: (union_specifier name: (type_identifier) @name)) @definition.class - ;; #9AD4FF #000000 0 0 0 2 (namespace_identifier) @module diff --git a/grammar/javascript.scm b/grammar/javascript.scm index 50fad16..98ebddd 100644 --- a/grammar/javascript.scm +++ b/grammar/javascript.scm @@ -298,18 +298,18 @@ ; JSX ; ============================================================ -;; #59C2FF #000000 0 0 0 2 -(jsx_opening_element (identifier) @tag (#match? @tag "^[a-z][^.]*$")) -(jsx_closing_element (identifier) @tag (#match? @tag "^[a-z][^.]*$")) -(jsx_self_closing_element (identifier) @tag (#match? @tag "^[a-z][^.]*$")) +;; #59C2FF #000000 0 0 0 4 +(jsx_opening_element (identifier) @tag2) +(jsx_closing_element (identifier) @tag2) +(jsx_self_closing_element (identifier) @tag2) -;; #F07178 #000000 0 0 0 1 -(jsx_attribute (property_identifier) @attribute) +;; #F07178 #000000 0 0 0 3 +(jsx_attribute (property_identifier) @attribute2) -;; #BFBDB6 #000000 0 0 0 1 -(jsx_opening_element (["<" ">"]) @punctuation.bracket) -(jsx_closing_element ([""]) @punctuation.bracket) -(jsx_self_closing_element (["<" "/>"]) @punctuation.bracket) +;; #BFBDB6 #000000 0 0 0 3 +(jsx_opening_element (["<" ">"]) @punctuation.bracket2) +(jsx_closing_element ([""]) @punctuation.bracket2) +(jsx_self_closing_element (["<" "/>"]) @punctuation.bracket2) ; Injections diff --git a/include/lsp.h b/include/lsp.h index 30435bb..766ae3e 100644 --- a/include/lsp.h +++ b/include/lsp.h @@ -30,6 +30,7 @@ struct LSPInstance { int stdin_fd{-1}; int stdout_fd{-1}; bool initialized = false; + bool incremental_sync = true; uint32_t last_id = 0; Queue inbox; Queue outbox; diff --git a/include/maps.h b/include/maps.h index 8b3674f..f387a8b 100644 --- a/include/maps.h +++ b/include/maps.h @@ -19,41 +19,177 @@ static const std::unordered_map kLsps = { "--log=error", nullptr, }}}, + {2, + {"ruby-lsp", + { + "ruby-lsp", + nullptr, + }}}, + {3, + {"solargraph", + { + "solargraph", + "stdio", + nullptr, + }}}, + {4, + {"bash-language-server", + { + "bash-language-server", + "start", + nullptr, + }}}, + {5, + {"vscode-css-language-server", + { + "vscode-css-language-server", + "--stdio", + nullptr, + }}}, + {6, + {"vscode-json-language-server", + { + "vscode-json-language-server", + "--stdio", + nullptr, + }}}, + {7, + {"fish-lsp", + { + "fish-lsp", + "start", + nullptr, + }}}, + {8, + {"gopls", + { + "gopls", + "serve", + nullptr, + }}}, + {9, + {"haskell-language-server", + { + "haskell-language-server", + "lsp", + nullptr, + }}}, + {10, + {"emmet-ls", + { + "emmet-ls", + "--stdio", + nullptr, + }}}, + {11, + {"typescript-language-server", + { + "typescript-language-server", + "--stdio", + nullptr, + }}}, + {12, + {"lua-language-server", + { + "lua-language-server", + nullptr, + }}}, + {13, + {"pyright-langserver", + { + "pyright-langserver", + "--stdio", + nullptr, + }}}, + {14, + {"rust-analyzer", + { + "rust-analyzer", + nullptr, + }}}, + {15, + {"intelephense", + { + "intelephense", + "--stdio", + nullptr, + }}}, + {16, + {"marksman", + { + "marksman", + "server", + nullptr, + }}}, + {17, + {"nginx-language-server", + { + "nginx-language-server", + nullptr, + }}}, + {18, + {"taplo", + { + "taplo", + "lsp", + "stdio", + nullptr, + }}}, + {19, + {"yaml-language-server", + { + "yaml-language-server", + "--stdio", + nullptr, + }}}, + {20, + {"sqls", + { + "sqls", + "serve", + nullptr, + }}}, + {21, + {"make-language-server", + { + "make-language-server", + nullptr, + }}}, }; static const std::unordered_map kLanguages = { - {"bash", {"bash", LANG(bash)}}, + {"bash", {"bash", LANG(bash), 4}}, {"c", {"c", LANG(cpp), 1}}, {"cpp", {"cpp", LANG(cpp), 1}}, {"h", {"h", LANG(cpp), 1}}, - {"css", {"css", LANG(css)}}, - {"fish", {"fish", LANG(fish)}}, - {"go", {"go", LANG(go)}}, - {"haskell", {"haskell", LANG(haskell)}}, - {"html", {"html", LANG(html)}}, - {"javascript", {"javascript", LANG(javascript)}}, - {"json", {"json", LANG(json)}}, - {"lua", {"lua", LANG(lua)}}, - {"make", {"make", LANG(make)}}, - {"python", {"python", LANG(python)}}, - {"ruby", {"ruby", LANG(ruby)}}, - {"rust", {"rust", LANG(rust)}}, + {"css", {"css", LANG(css), 5}}, + {"fish", {"fish", LANG(fish), 7}}, + {"go", {"go", LANG(go), 8}}, + {"gomod", {"gomod", LANG(gomod), 8}}, + {"haskell", {"haskell", LANG(haskell), 9}}, + {"html", {"html", LANG(html), 10}}, + {"javascript", {"javascript", LANG(javascript), 11}}, + {"json", {"json", LANG(json), 6}}, + {"erb", {"erb", LANG(embedded_template), 10}}, + {"ruby", {"ruby", LANG(ruby), 3}}, + {"lua", {"lua", LANG(lua), 12}}, + {"python", {"python", LANG(python), 13}}, + {"rust", {"rust", LANG(rust), 14}}, + {"php", {"php", LANG(php), 15}}, + {"markdown", {"markdown", LANG(markdown), 16}}, + {"markdown_inline", {"markdown_inline", LANG(markdown_inline), 16}}, + {"nginx", {"nginx", LANG(nginx), 17}}, + {"toml", {"toml", LANG(toml), 18}}, + {"yaml", {"yaml", LANG(yaml), 19}}, + {"sql", {"sql", LANG(sql), 20}}, + {"make", {"make", LANG(make), 21}}, + {"gdscript", {"gdscript", LANG(gdscript)}}, // TODO: connect to godot {"diff", {"diff", LANG(diff)}}, - {"embedded_template", {"embedded_template", LANG(embedded_template)}}, - {"gdscript", {"gdscript", LANG(gdscript)}}, {"gitattributes", {"gitattributes", LANG(gitattributes)}}, {"gitignore", {"gitignore", LANG(gitignore)}}, - {"gomod", {"gomod", LANG(gomod)}}, - {"ini", {"ini", LANG(ini)}}, - {"markdown", {"markdown", LANG(markdown)}}, - {"markdown_inline", {"markdown_inline", LANG(markdown_inline)}}, - {"nginx", {"nginx", LANG(nginx)}}, - {"php", {"php", LANG(php)}}, {"query", {"query", LANG(query)}}, {"regex", {"regex", LANG(regex)}}, - {"sql", {"sql", LANG(sql)}}, - {"toml", {"toml", LANG(toml)}}, - {"yaml", {"yaml", LANG(yaml)}}, + {"ini", {"ini", LANG(ini)}}, }; static const std::unordered_map kExtToLang = { @@ -85,8 +221,7 @@ static const std::unordered_map kExtToLang = { {"rs", "rust"}, {"diff", "diff"}, {"patch", "diff"}, - {"erb", "embedded_template"}, - {"etlua", "embedded_template"}, + {"erb", "erb"}, {"gd", "gdscript"}, {"gitattributes", "gitattributes"}, {"gitignore", "gitignore"}, @@ -120,7 +255,6 @@ static const std::unordered_map kMimeToLang = { {"text/x-rust", "rust"}, {"text/x-lua", "lua"}, {"text/x-diff", "diff"}, - {"text/x-embedded-template", "embedded_template"}, {"text/x-gdscript", "gdscript"}, {"text/x-gitattributes", "gitattributes"}, {"text/x-gitignore", "gitignore"}, diff --git a/include/utils.h b/include/utils.h index 611ac33..c0c07f1 100644 --- a/include/utils.h +++ b/include/utils.h @@ -52,6 +52,7 @@ struct Coord { bool operator>=(const Coord &other) const { return !(*this < other); } }; +std::string percent_encode(const std::string &s); std::string path_abs(const std::string &path_str); std::string path_to_file_uri(const std::string &path_str); int display_width(const char *str, size_t len); diff --git a/samples/yaml.yaml b/samples/yaml.yaml new file mode 100644 index 0000000..b6fe7d2 --- /dev/null +++ b/samples/yaml.yaml @@ -0,0 +1,66 @@ +# ============================================================ +# Basic types +# ============================================================ + +title: "Example YAML Configuration" +enabled: true +count: 42 +pi: 3.14159 +empty: "" + +# ============================================================ +# Arrays / Lists +# ============================================================ +fruits: + - apple + - banana + - cherry + +numbers: + - 1 + - 2 + - 3 + - 4 + - 5 + +matrix: + - [1, 2] + - [3, 4] + +# ============================================================ +# Nested objects / maps +# ============================================================ +owner: + name: Alice + dob: 1979-05-27T07:32:00Z + +database: + server: 192.168.1.1 + ports: + - 8001 + - 8001 + - 8002 + connection_max: 5000 + enabled: true + +servers: + alpha: + ip: 10.0.0.1 + dc: east + beta: + ip: 10.0.0.2 + dc: west + +# ============================================================ +# Multiline string +# ============================================================ +description: | + This is a YAML file + used for testing syntax highlighting. + It supports multiple lines. + +# ============================================================ +# Special characters +# ============================================================ +regex_pattern: "^[A-Za-z0-9_]+$" +path: "C:\\Users\\Alice\\Documents" diff --git a/src/editor.cc b/src/editor.cc index 7d2c5a0..9d10a94 100644 --- a/src/editor.cc +++ b/src/editor.cc @@ -29,6 +29,8 @@ Editor *new_editor(const char *filename_arg, Coord position, Coord size) { editor->ts.parser = ts_parser_new(); editor->ts.language = language.fn(); ts_parser_set_language(editor->ts.parser, editor->ts.language); + log("set language %s\n", language.name.c_str()); + log("lsp_id: %d\n", language.lsp_id); editor->ts.query_file = get_exe_dir() + "/../grammar/" + language.name + ".scm"; request_add_to_lsp(language, editor); @@ -48,6 +50,8 @@ void free_tsset(TSSetMain *set) { ts_parser_delete(inj.second.parser); if (inj.second.query) ts_query_delete(inj.second.query); + if (inj.second.tree) + ts_tree_delete(inj.second.tree); } } @@ -67,6 +71,11 @@ void save_file(Editor *editor) { std::ofstream out(editor->filename); out.write(str, editor->root->char_count); free(str); + json msg = {{"jsonrpc", "2.0"}, + {"method", "textDocument/didSave"}, + {"params", {{"textDocument", {{"uri", editor->uri}}}}}}; + if (editor->lsp) + lsp_send(editor->lsp, msg, nullptr); } void render_editor(Editor *editor) { @@ -83,6 +92,7 @@ void render_editor(Editor *editor) { auto hook_it = v.begin(); while (hook_it != v.end() && hook_it->first <= editor->scroll.row) ++hook_it; + std::unique_lock warn_lock(editor->v_mtx); auto warn_it = editor->warnings.begin(); while (warn_it != editor->warnings.end() && warn_it->line < editor->scroll.row) @@ -147,7 +157,6 @@ void render_editor(Editor *editor) { uint32_t global_byte_offset = line_to_byte(editor->root, line_index, nullptr); span_cursor.sync(global_byte_offset); def_span_cursor.sync(global_byte_offset); - std::shared_lock v_lock(editor->v_mtx); while (rendered_rows < editor->size.row) { const Fold *fold = fold_for_line(editor->folds, line_index); if (fold) { @@ -370,6 +379,9 @@ void render_editor(Editor *editor) { cluster.c_str(), fg_color, color, 0); col += width; warn_idx += cluster_len; + while (width-- > 1) + update(editor->position.row + rendered_rows, render_x + col - width, + "\x1b", fg_color, color, 0); } } while (col < render_width) { diff --git a/src/editor_ctrl.cc b/src/editor_ctrl.cc index f3eabbb..4920b31 100644 --- a/src/editor_ctrl.cc +++ b/src/editor_ctrl.cc @@ -394,15 +394,29 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) { editor->edit_queue.push(edit); } if (do_lsp) { - json message = { - {"jsonrpc", "2.0"}, - {"method", "textDocument/didChange"}, - {"params", - {{"textDocument", - {{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, - {"contentChanges", - json::array({{{"range", lsp_range}, {"text", ""}}})}}}}; - lsp_send(editor->lsp, message, nullptr); + if (editor->lsp->incremental_sync) { + json message = { + {"jsonrpc", "2.0"}, + {"method", "textDocument/didChange"}, + {"params", + {{"textDocument", + {{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, + {"contentChanges", + json::array({{{"range", lsp_range}, {"text", ""}}})}}}}; + lsp_send(editor->lsp, message, nullptr); + } else { + char *buf = read(editor->root, 0, editor->root->char_count); + std::string text(buf); + free(buf); + json message = { + {"jsonrpc", "2.0"}, + {"method", "textDocument/didChange"}, + {"params", + {{"textDocument", + {{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, + {"contentChanges", json::array({{{"text", text}}})}}}}; + lsp_send(editor->lsp, message, nullptr); + } } std::unique_lock lock_3(editor->spans.mtx); apply_edit(editor->spans.spans, start, start - byte_pos); @@ -469,15 +483,29 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) { editor->edit_queue.push(edit); } if (do_lsp) { - json message = { - {"jsonrpc", "2.0"}, - {"method", "textDocument/didChange"}, - {"params", - {{"textDocument", - {{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, - {"contentChanges", - json::array({{{"range", lsp_range}, {"text", ""}}})}}}}; - lsp_send(editor->lsp, message, nullptr); + if (editor->lsp->incremental_sync) { + json message = { + {"jsonrpc", "2.0"}, + {"method", "textDocument/didChange"}, + {"params", + {{"textDocument", + {{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, + {"contentChanges", + json::array({{{"range", lsp_range}, {"text", ""}}})}}}}; + lsp_send(editor->lsp, message, nullptr); + } else { + char *buf = read(editor->root, 0, editor->root->char_count); + std::string text(buf); + free(buf); + json message = { + {"jsonrpc", "2.0"}, + {"method", "textDocument/didChange"}, + {"params", + {{"textDocument", + {{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, + {"contentChanges", json::array({{{"text", text}}})}}}}; + lsp_send(editor->lsp, message, nullptr); + } } std::unique_lock lock_3(editor->spans.mtx); apply_edit(editor->spans.spans, byte_pos, byte_pos - end); @@ -530,28 +558,42 @@ void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len) { editor->edit_queue.push(edit); } if (editor->lsp) { - lock_1.lock(); - LineIterator *it = begin_l_iter(editor->root, pos.row); - char *line = next_line(it, nullptr); - int utf16_col = 0; - if (line) - utf16_col = utf8_byte_offset_to_utf16(line, pos.col); - free(it->buffer); - free(it); - lock_1.unlock(); - json message = { - {"jsonrpc", "2.0"}, - {"method", "textDocument/didChange"}, - {"params", - {{"textDocument", - {{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, - {"contentChanges", - json::array( - {{{"range", - {{"start", {{"line", pos.row}, {"character", utf16_col}}}, - {"end", {{"line", pos.row}, {"character", utf16_col}}}}}, - {"text", std::string(data, len)}}})}}}}; - lsp_send(editor->lsp, message, nullptr); + if (editor->lsp->incremental_sync) { + lock_1.lock(); + LineIterator *it = begin_l_iter(editor->root, pos.row); + char *line = next_line(it, nullptr); + int utf16_col = 0; + if (line) + utf16_col = utf8_byte_offset_to_utf16(line, pos.col); + free(it->buffer); + free(it); + lock_1.unlock(); + json message = { + {"jsonrpc", "2.0"}, + {"method", "textDocument/didChange"}, + {"params", + {{"textDocument", + {{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, + {"contentChanges", + json::array( + {{{"range", + {{"start", {{"line", pos.row}, {"character", utf16_col}}}, + {"end", {{"line", pos.row}, {"character", utf16_col}}}}}, + {"text", std::string(data, len)}}})}}}}; + lsp_send(editor->lsp, message, nullptr); + } else { + char *buf = read(editor->root, 0, editor->root->char_count); + std::string text(buf); + free(buf); + json message = { + {"jsonrpc", "2.0"}, + {"method", "textDocument/didChange"}, + {"params", + {{"textDocument", + {{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, + {"contentChanges", json::array({{{"text", text}}})}}}}; + lsp_send(editor->lsp, message, nullptr); + } } std::unique_lock lock_3(editor->spans.mtx); apply_edit(editor->spans.spans, byte_pos, len); diff --git a/src/editor_events.cc b/src/editor_events.cc index 2bff03d..c840641 100644 --- a/src/editor_events.cc +++ b/src/editor_events.cc @@ -610,6 +610,8 @@ void editor_lsp_handle(Editor *editor, json msg) { for (size_t i = 0; i < diagnostics.size(); i++) { json d = diagnostics[i]; VWarn w; + // HACK: convert back to utf-8 but as this is only visually affecting it + // is not worth the performance hit w.line = d["range"]["start"]["line"]; w.start = d["range"]["start"]["character"]; uint32_t end = d["range"]["end"]["character"]; diff --git a/src/lsp.cc b/src/lsp.cc index 8ddd910..7a72aa6 100644 --- a/src/lsp.cc +++ b/src/lsp.cc @@ -13,6 +13,7 @@ std::unordered_map active_lsps; Queue lsp_open_queue; static bool init_lsp(LSPInstance *lsp) { + log("initializing %s\n", lsp->lsp->command); int in_pipe[2]; int out_pipe[2]; if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1) { @@ -59,23 +60,35 @@ LSPInstance *get_or_init_lsp(uint8_t lsp_id) { delete lsp; return nullptr; } + log("starting %s\n", lsp->lsp->command); LSPPending *pending = new LSPPending(); pending->method = "initialize"; pending->editor = nullptr; - pending->callback = [lsp](Editor *, std::string, json) { + pending->callback = [lsp](Editor *, std::string, json msg) { + if (msg.contains("result") && msg["result"].contains("capabilities")) { + auto &caps = msg["result"]["capabilities"]; + if (caps.contains("textDocumentSync") && + caps["textDocumentSync"].contains("change")) { + int change_type = caps["textDocumentSync"]["change"]; + lsp->incremental_sync = (change_type == 2); + } + } lsp->initialized = true; json initialized = {{"jsonrpc", "2.0"}, {"method", "initialized"}, {"params", json::object()}}; lsp_send(lsp, initialized, nullptr); + log("initialized %s\n", lsp->lsp->command); }; json init_message = { {"jsonrpc", "2.0"}, {"method", "initialize"}, {"params", {{"processId", getpid()}, - {"rootUri", "file://" + std::filesystem::current_path().string()}, - {"capabilities", json::object()}}}}; + {"rootUri", "file://" + percent_encode(path_abs("."))}, + {"capabilities", + {{"textDocument", + {{"publishDiagnostics", {{"relatedInformation", true}}}}}}}}}}; lsp_send(lsp, init_message, pending); active_lsps[lsp_id] = lsp; return lsp; @@ -160,6 +173,7 @@ static std::optional read_lsp_message(int fd) { return std::nullopt; got += n; } + log("%s\n", body.c_str()); return json::parse(body); } @@ -249,6 +263,7 @@ void lsp_worker() { } void request_add_to_lsp(Language language, Editor *editor) { + log("request_add_to_lsp %d\n", language.lsp_id); lsp_open_queue.push({language, editor}); } diff --git a/src/ts.cc b/src/ts.cc index e03a929..908f4ee 100644 --- a/src/ts.cc +++ b/src/ts.cc @@ -235,8 +235,12 @@ void ts_collect_spans(Editor *editor) { parse_counter = 0; editor->spans.mid_parse = true; std::shared_lock lock(editor->knot_mtx); - editor->ts.tree = - ts_parser_parse(editor->ts.parser, editor->ts.tree, tsinput); + TSTree *tree = ts_parser_parse(editor->ts.parser, editor->ts.tree, tsinput); + if (!tree) + return; + if (editor->ts.tree) + ts_tree_delete(editor->ts.tree); + editor->ts.tree = tree; lock.unlock(); std::vector new_spans; new_spans.reserve(4096); @@ -324,7 +328,12 @@ void ts_collect_spans(Editor *editor) { ts_parser_set_included_ranges(tsset->parser, tsset->ranges.data(), tsset->ranges.size()); lock.lock(); - tsset->tree = ts_parser_parse(tsset->parser, tsset->tree, tsinput); + TSTree *tree = ts_parser_parse(tsset->parser, tsset->tree, tsinput); + if (!tree) + continue; + if (tsset->tree) + ts_tree_delete(tsset->tree); + tsset->tree = tree; lock.unlock(); work.push_back({reinterpret_cast(tsset), tsset->tree, item.depth + 1}); diff --git a/src/utils.cc b/src/utils.cc index d5fd518..0607a46 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -5,7 +5,7 @@ extern "C" { #include "../include/maps.h" #include "../include/utils.h" -static std::string percent_encode(const std::string &s) { +std::string percent_encode(const std::string &s) { static const char *hex = "0123456789ABCDEF"; std::string out; for (unsigned char c : s) {