#include "editor/decl.h" #include "editor/editor.h" #include "utils/utils.h" void apply_lsp_edits(Editor *editor, std::vector edits, bool move) { if (!edits.size()) return; TextEdit first = edits[0]; Coord cursor = editor->cursor; std::sort( edits.begin(), edits.end(), [](const TextEdit &a, const TextEdit &b) { return a.start > b.start; }); for (const auto &edit : edits) edit_replace(editor, edit.start, edit.end, edit.text.c_str(), edit.text.size()); if (move) { std::shared_lock lock(editor->knot_mtx); editor->cursor = first.start; editor->cursor = move_right(editor, editor->cursor, count_clusters(first.text.c_str(), first.text.size(), 0, first.text.size())); } else { if (cursor.row >= editor->root->line_count) { editor->cursor.row = editor->root->line_count - 1; editor->cursor.col = 0; } else { std::shared_lock lock(editor->knot_mtx); uint32_t len; line_to_byte(editor->root, cursor.row, &len); len--; editor->cursor.row = cursor.row; editor->cursor.col = cursor.col < len ? cursor.col : len; } } } void editor_lsp_handle(Editor *editor, json msg) { if (msg.contains("method") && msg["method"] == "textDocument/publishDiagnostics") { std::unique_lock lock(editor->v_mtx); editor->warnings.clear(); json diagnostics = msg["params"]["diagnostics"]; for (size_t i = 0; i < diagnostics.size(); i++) { json d = diagnostics[i]; VWarn w; w.line = d["range"]["start"]["line"]; w.start = d["range"]["start"]["character"]; std::shared_lock lock(editor->knot_mtx); LineIterator *it = begin_l_iter(editor->root, w.line); if (!it) continue; uint32_t len; char *line = next_line(it, &len); if (!line) { free(it->buffer); free(it); continue; } if (len > 0 && line[len - 1] == '\n') --len; lock.unlock(); w.start = utf16_offset_to_utf8(line, len, w.start); uint32_t end = d["range"]["end"]["character"]; if (d["range"]["end"]["line"] == w.line) w.end = utf16_offset_to_utf8(line, len, end); free(it->buffer); free(it); std::string text = trim(d["message"].get()); w.text_full = text; auto pos = text.find('\n'); w.text = (pos == std::string::npos) ? text : text.substr(0, pos); if (d.contains("source")) w.source = d["source"].get(); if (d.contains("code")) { w.code = "["; if (d["code"].is_string()) w.code += d["code"].get() + "] "; else if (d["code"].is_number()) w.code += std::to_string(d["code"].get()) + "] "; else w.code.clear(); if (d.contains("codeDescription") && d["codeDescription"].contains("href")) w.code += d["codeDescription"]["href"].get(); } if (d.contains("relatedInformation")) { json related = d["relatedInformation"]; for (size_t j = 0; j < related.size(); j++) { json rel = related[j]; std::string message = rel["message"].get(); auto pos = message.find('\n'); message = (pos == std::string::npos) ? message : message.substr(0, pos); std::string uri = filename_from_path( percent_decode(rel["location"]["uri"].get())); std::string row = std::to_string( rel["location"]["range"]["start"]["line"].get()); w.see_also.push_back(uri + ":" + row + ": " + message); } } w.type = 1; if (d.contains("severity")) w.type = d["severity"].get(); editor->warnings.push_back(w); } std::sort(editor->warnings.begin(), editor->warnings.end()); editor->warnings_dirty = true; } }