Add lsp's for many different languages and minor fixes
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
188
include/maps.h
188
include/maps.h
@@ -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"},
|
||||||
|
|||||||
@@ -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
66
samples/yaml.yaml
Normal 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"
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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"];
|
||||||
|
|||||||
21
src/lsp.cc
21
src/lsp.cc
@@ -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});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
src/ts.cc
15
src/ts.cc
@@ -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});
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user