Add lsp's for many different languages and minor fixes
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"];
|
||||
|
||||
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;
|
||||
|
||||
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<json> 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});
|
||||
}
|
||||
|
||||
|
||||
15
src/ts.cc
15
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<Span> 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<TSSetBase *>(tsset), tsset->tree,
|
||||
item.depth + 1});
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user