Add lsp's for many different languages and minor fixes

This commit is contained in:
2025-12-27 04:31:08 +00:00
parent a38ba1f813
commit bfaba81317
16 changed files with 369 additions and 131 deletions

View File

@@ -27,6 +27,7 @@ A TUI IDE.
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)
- [ ] 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.
- [ ] 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. - [ ] 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`.
- [ ] Add snippets from wherever i get them. (like luasnip or vsnip) - [ ] 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 search / replace along with search / virtual cursors are searched pos.
- [ ] Add support for undo/redo. - [ ] Add support for undo/redo.
- [ ] Add splash screen / minigame jumping. - [ ] 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 git stuff.
- [ ] Add SQL support. (viewer and basic editor) - [ ] Add SQL support. (viewer and basic editor)
- [ ] Add color picker/palette for hex or other css colors. - [ ] Add color picker/palette for hex or other css colors.

View File

@@ -221,21 +221,6 @@
_ @type.builtin _ @type.builtin
type: _?) 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 ;; #9AD4FF #000000 0 0 0 2
(namespace_identifier) @module (namespace_identifier) @module

View File

@@ -221,21 +221,6 @@
_ @type.builtin _ @type.builtin
type: _?) 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 ;; #9AD4FF #000000 0 0 0 2
(namespace_identifier) @module (namespace_identifier) @module

View File

@@ -221,21 +221,6 @@
_ @type.builtin _ @type.builtin
type: _?) 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 ;; #9AD4FF #000000 0 0 0 2
(namespace_identifier) @module (namespace_identifier) @module

View File

@@ -298,18 +298,18 @@
; JSX ; JSX
; ============================================================ ; ============================================================
;; #59C2FF #000000 0 0 0 2 ;; #59C2FF #000000 0 0 0 4
(jsx_opening_element (identifier) @tag (#match? @tag "^[a-z][^.]*$")) (jsx_opening_element (identifier) @tag2)
(jsx_closing_element (identifier) @tag (#match? @tag "^[a-z][^.]*$")) (jsx_closing_element (identifier) @tag2)
(jsx_self_closing_element (identifier) @tag (#match? @tag "^[a-z][^.]*$")) (jsx_self_closing_element (identifier) @tag2)
;; #F07178 #000000 0 0 0 1 ;; #F07178 #000000 0 0 0 3
(jsx_attribute (property_identifier) @attribute) (jsx_attribute (property_identifier) @attribute2)
;; #BFBDB6 #000000 0 0 0 1 ;; #BFBDB6 #000000 0 0 0 3
(jsx_opening_element (["<" ">"]) @punctuation.bracket) (jsx_opening_element (["<" ">"]) @punctuation.bracket2)
(jsx_closing_element (["</" ">"]) @punctuation.bracket) (jsx_closing_element (["</" ">"]) @punctuation.bracket2)
(jsx_self_closing_element (["<" "/>"]) @punctuation.bracket) (jsx_self_closing_element (["<" "/>"]) @punctuation.bracket2)
; Injections ; Injections

View File

@@ -30,6 +30,7 @@ struct LSPInstance {
int stdin_fd{-1}; int stdin_fd{-1};
int stdout_fd{-1}; int stdout_fd{-1};
bool initialized = false; bool initialized = false;
bool incremental_sync = true;
uint32_t last_id = 0; uint32_t last_id = 0;
Queue<json> inbox; Queue<json> inbox;
Queue<json> outbox; Queue<json> outbox;

View File

@@ -19,41 +19,177 @@ static const std::unordered_map<uint8_t, LSP> kLsps = {
"--log=error", "--log=error",
nullptr, 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<std::string, Language> kLanguages = { static const std::unordered_map<std::string, Language> kLanguages = {
{"bash", {"bash", LANG(bash)}}, {"bash", {"bash", LANG(bash), 4}},
{"c", {"c", LANG(cpp), 1}}, {"c", {"c", LANG(cpp), 1}},
{"cpp", {"cpp", LANG(cpp), 1}}, {"cpp", {"cpp", LANG(cpp), 1}},
{"h", {"h", LANG(cpp), 1}}, {"h", {"h", LANG(cpp), 1}},
{"css", {"css", LANG(css)}}, {"css", {"css", LANG(css), 5}},
{"fish", {"fish", LANG(fish)}}, {"fish", {"fish", LANG(fish), 7}},
{"go", {"go", LANG(go)}}, {"go", {"go", LANG(go), 8}},
{"haskell", {"haskell", LANG(haskell)}}, {"gomod", {"gomod", LANG(gomod), 8}},
{"html", {"html", LANG(html)}}, {"haskell", {"haskell", LANG(haskell), 9}},
{"javascript", {"javascript", LANG(javascript)}}, {"html", {"html", LANG(html), 10}},
{"json", {"json", LANG(json)}}, {"javascript", {"javascript", LANG(javascript), 11}},
{"lua", {"lua", LANG(lua)}}, {"json", {"json", LANG(json), 6}},
{"make", {"make", LANG(make)}}, {"erb", {"erb", LANG(embedded_template), 10}},
{"python", {"python", LANG(python)}}, {"ruby", {"ruby", LANG(ruby), 3}},
{"ruby", {"ruby", LANG(ruby)}}, {"lua", {"lua", LANG(lua), 12}},
{"rust", {"rust", LANG(rust)}}, {"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)}}, {"diff", {"diff", LANG(diff)}},
{"embedded_template", {"embedded_template", LANG(embedded_template)}},
{"gdscript", {"gdscript", LANG(gdscript)}},
{"gitattributes", {"gitattributes", LANG(gitattributes)}}, {"gitattributes", {"gitattributes", LANG(gitattributes)}},
{"gitignore", {"gitignore", LANG(gitignore)}}, {"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)}}, {"query", {"query", LANG(query)}},
{"regex", {"regex", LANG(regex)}}, {"regex", {"regex", LANG(regex)}},
{"sql", {"sql", LANG(sql)}}, {"ini", {"ini", LANG(ini)}},
{"toml", {"toml", LANG(toml)}},
{"yaml", {"yaml", LANG(yaml)}},
}; };
static const std::unordered_map<std::string, std::string> kExtToLang = { static const std::unordered_map<std::string, std::string> kExtToLang = {
@@ -85,8 +221,7 @@ static const std::unordered_map<std::string, std::string> kExtToLang = {
{"rs", "rust"}, {"rs", "rust"},
{"diff", "diff"}, {"diff", "diff"},
{"patch", "diff"}, {"patch", "diff"},
{"erb", "embedded_template"}, {"erb", "erb"},
{"etlua", "embedded_template"},
{"gd", "gdscript"}, {"gd", "gdscript"},
{"gitattributes", "gitattributes"}, {"gitattributes", "gitattributes"},
{"gitignore", "gitignore"}, {"gitignore", "gitignore"},
@@ -120,7 +255,6 @@ static const std::unordered_map<std::string, std::string> kMimeToLang = {
{"text/x-rust", "rust"}, {"text/x-rust", "rust"},
{"text/x-lua", "lua"}, {"text/x-lua", "lua"},
{"text/x-diff", "diff"}, {"text/x-diff", "diff"},
{"text/x-embedded-template", "embedded_template"},
{"text/x-gdscript", "gdscript"}, {"text/x-gdscript", "gdscript"},
{"text/x-gitattributes", "gitattributes"}, {"text/x-gitattributes", "gitattributes"},
{"text/x-gitignore", "gitignore"}, {"text/x-gitignore", "gitignore"},

View File

@@ -52,6 +52,7 @@ struct Coord {
bool operator>=(const Coord &other) const { return !(*this < other); } 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_abs(const std::string &path_str);
std::string path_to_file_uri(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); int display_width(const char *str, size_t len);

66
samples/yaml.yaml Normal file
View File

@@ -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"

View File

@@ -29,6 +29,8 @@ Editor *new_editor(const char *filename_arg, Coord position, Coord size) {
editor->ts.parser = ts_parser_new(); editor->ts.parser = ts_parser_new();
editor->ts.language = language.fn(); editor->ts.language = language.fn();
ts_parser_set_language(editor->ts.parser, editor->ts.language); 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 = editor->ts.query_file =
get_exe_dir() + "/../grammar/" + language.name + ".scm"; get_exe_dir() + "/../grammar/" + language.name + ".scm";
request_add_to_lsp(language, editor); request_add_to_lsp(language, editor);
@@ -48,6 +50,8 @@ void free_tsset(TSSetMain *set) {
ts_parser_delete(inj.second.parser); ts_parser_delete(inj.second.parser);
if (inj.second.query) if (inj.second.query)
ts_query_delete(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); std::ofstream out(editor->filename);
out.write(str, editor->root->char_count); out.write(str, editor->root->char_count);
free(str); 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) { void render_editor(Editor *editor) {
@@ -83,6 +92,7 @@ void render_editor(Editor *editor) {
auto hook_it = v.begin(); auto hook_it = v.begin();
while (hook_it != v.end() && hook_it->first <= editor->scroll.row) while (hook_it != v.end() && hook_it->first <= editor->scroll.row)
++hook_it; ++hook_it;
std::unique_lock warn_lock(editor->v_mtx);
auto warn_it = editor->warnings.begin(); auto warn_it = editor->warnings.begin();
while (warn_it != editor->warnings.end() && while (warn_it != editor->warnings.end() &&
warn_it->line < editor->scroll.row) 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); uint32_t global_byte_offset = line_to_byte(editor->root, line_index, nullptr);
span_cursor.sync(global_byte_offset); span_cursor.sync(global_byte_offset);
def_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) { while (rendered_rows < editor->size.row) {
const Fold *fold = fold_for_line(editor->folds, line_index); const Fold *fold = fold_for_line(editor->folds, line_index);
if (fold) { if (fold) {
@@ -370,6 +379,9 @@ void render_editor(Editor *editor) {
cluster.c_str(), fg_color, color, 0); cluster.c_str(), fg_color, color, 0);
col += width; col += width;
warn_idx += cluster_len; 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) { while (col < render_width) {

View File

@@ -394,15 +394,29 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
editor->edit_queue.push(edit); editor->edit_queue.push(edit);
} }
if (do_lsp) { if (do_lsp) {
json message = { if (editor->lsp->incremental_sync) {
{"jsonrpc", "2.0"}, json message = {
{"method", "textDocument/didChange"}, {"jsonrpc", "2.0"},
{"params", {"method", "textDocument/didChange"},
{{"textDocument", {"params",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, {{"textDocument",
{"contentChanges", {{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
json::array({{{"range", lsp_range}, {"text", ""}}})}}}}; {"contentChanges",
lsp_send(editor->lsp, message, nullptr); 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); std::unique_lock lock_3(editor->spans.mtx);
apply_edit(editor->spans.spans, start, start - byte_pos); 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); editor->edit_queue.push(edit);
} }
if (do_lsp) { if (do_lsp) {
json message = { if (editor->lsp->incremental_sync) {
{"jsonrpc", "2.0"}, json message = {
{"method", "textDocument/didChange"}, {"jsonrpc", "2.0"},
{"params", {"method", "textDocument/didChange"},
{{"textDocument", {"params",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, {{"textDocument",
{"contentChanges", {{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
json::array({{{"range", lsp_range}, {"text", ""}}})}}}}; {"contentChanges",
lsp_send(editor->lsp, message, nullptr); 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); std::unique_lock lock_3(editor->spans.mtx);
apply_edit(editor->spans.spans, byte_pos, byte_pos - end); 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); editor->edit_queue.push(edit);
} }
if (editor->lsp) { if (editor->lsp) {
lock_1.lock(); if (editor->lsp->incremental_sync) {
LineIterator *it = begin_l_iter(editor->root, pos.row); lock_1.lock();
char *line = next_line(it, nullptr); LineIterator *it = begin_l_iter(editor->root, pos.row);
int utf16_col = 0; char *line = next_line(it, nullptr);
if (line) int utf16_col = 0;
utf16_col = utf8_byte_offset_to_utf16(line, pos.col); if (line)
free(it->buffer); utf16_col = utf8_byte_offset_to_utf16(line, pos.col);
free(it); free(it->buffer);
lock_1.unlock(); free(it);
json message = { lock_1.unlock();
{"jsonrpc", "2.0"}, json message = {
{"method", "textDocument/didChange"}, {"jsonrpc", "2.0"},
{"params", {"method", "textDocument/didChange"},
{{"textDocument", {"params",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}}, {{"textDocument",
{"contentChanges", {{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
json::array( {"contentChanges",
{{{"range", json::array(
{{"start", {{"line", pos.row}, {"character", utf16_col}}}, {{{"range",
{"end", {{"line", pos.row}, {"character", utf16_col}}}}}, {{"start", {{"line", pos.row}, {"character", utf16_col}}},
{"text", std::string(data, len)}}})}}}}; {"end", {{"line", pos.row}, {"character", utf16_col}}}}},
lsp_send(editor->lsp, message, nullptr); {"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); std::unique_lock lock_3(editor->spans.mtx);
apply_edit(editor->spans.spans, byte_pos, len); apply_edit(editor->spans.spans, byte_pos, len);

View File

@@ -610,6 +610,8 @@ void editor_lsp_handle(Editor *editor, json msg) {
for (size_t i = 0; i < diagnostics.size(); i++) { for (size_t i = 0; i < diagnostics.size(); i++) {
json d = diagnostics[i]; json d = diagnostics[i];
VWarn w; 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.line = d["range"]["start"]["line"];
w.start = d["range"]["start"]["character"]; w.start = d["range"]["start"]["character"];
uint32_t end = d["range"]["end"]["character"]; uint32_t end = d["range"]["end"]["character"];

View File

@@ -13,6 +13,7 @@ std::unordered_map<uint8_t, LSPInstance *> active_lsps;
Queue<LSPOpenRequest> lsp_open_queue; Queue<LSPOpenRequest> lsp_open_queue;
static bool init_lsp(LSPInstance *lsp) { static bool init_lsp(LSPInstance *lsp) {
log("initializing %s\n", lsp->lsp->command);
int in_pipe[2]; int in_pipe[2];
int out_pipe[2]; int out_pipe[2];
if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1) { if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1) {
@@ -59,23 +60,35 @@ LSPInstance *get_or_init_lsp(uint8_t lsp_id) {
delete lsp; delete lsp;
return nullptr; return nullptr;
} }
log("starting %s\n", lsp->lsp->command);
LSPPending *pending = new LSPPending(); LSPPending *pending = new LSPPending();
pending->method = "initialize"; pending->method = "initialize";
pending->editor = nullptr; 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; lsp->initialized = true;
json initialized = {{"jsonrpc", "2.0"}, json initialized = {{"jsonrpc", "2.0"},
{"method", "initialized"}, {"method", "initialized"},
{"params", json::object()}}; {"params", json::object()}};
lsp_send(lsp, initialized, nullptr); lsp_send(lsp, initialized, nullptr);
log("initialized %s\n", lsp->lsp->command);
}; };
json init_message = { json init_message = {
{"jsonrpc", "2.0"}, {"jsonrpc", "2.0"},
{"method", "initialize"}, {"method", "initialize"},
{"params", {"params",
{{"processId", getpid()}, {{"processId", getpid()},
{"rootUri", "file://" + std::filesystem::current_path().string()}, {"rootUri", "file://" + percent_encode(path_abs("."))},
{"capabilities", json::object()}}}}; {"capabilities",
{{"textDocument",
{{"publishDiagnostics", {{"relatedInformation", true}}}}}}}}}};
lsp_send(lsp, init_message, pending); lsp_send(lsp, init_message, pending);
active_lsps[lsp_id] = lsp; active_lsps[lsp_id] = lsp;
return lsp; return lsp;
@@ -160,6 +173,7 @@ static std::optional<json> read_lsp_message(int fd) {
return std::nullopt; return std::nullopt;
got += n; got += n;
} }
log("%s\n", body.c_str());
return json::parse(body); return json::parse(body);
} }
@@ -249,6 +263,7 @@ void lsp_worker() {
} }
void request_add_to_lsp(Language language, Editor *editor) { 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}); lsp_open_queue.push({language, editor});
} }

View File

@@ -235,8 +235,12 @@ void ts_collect_spans(Editor *editor) {
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);
editor->ts.tree = TSTree *tree = ts_parser_parse(editor->ts.parser, editor->ts.tree, tsinput);
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(); lock.unlock();
std::vector<Span> new_spans; std::vector<Span> new_spans;
new_spans.reserve(4096); new_spans.reserve(4096);
@@ -324,7 +328,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();
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(); lock.unlock();
work.push_back({reinterpret_cast<TSSetBase *>(tsset), tsset->tree, work.push_back({reinterpret_cast<TSSetBase *>(tsset), tsset->tree,
item.depth + 1}); item.depth + 1});

View File

@@ -5,7 +5,7 @@ extern "C" {
#include "../include/maps.h" #include "../include/maps.h"
#include "../include/utils.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"; static const char *hex = "0123456789ABCDEF";
std::string out; std::string out;
for (unsigned char c : s) { for (unsigned char c : s) {