Step 92: LSP auto-completion

This commit is contained in:
Bill
2026-02-09 09:59:25 -07:00
parent e3439b2a3d
commit 0916026448
5 changed files with 228 additions and 24 deletions

View File

@@ -41,6 +41,14 @@ public:
std::string source;
};
struct CompletionItem {
std::string label;
int kind = 0;
std::string detail;
std::string insertText;
std::string filterText;
};
void initialize(const std::string& rootUri,
const std::string& clientName,
int processId) {
@@ -94,6 +102,15 @@ public:
sendNotification("textDocument/didSave", params);
}
int requestCompletion(const std::string& uri, int line, int character) {
nlohmann::json params;
params["textDocument"] = {{"uri", uri}};
params["position"] = {{"line", line}, {"character", character}};
int id = sendRequest("textDocument/completion", params);
lastCompletionRequestId_ = id;
return id;
}
void handleMessage(const std::string& msg) {
nlohmann::json j;
try {
@@ -101,35 +118,62 @@ public:
} catch (...) {
return;
}
if (!j.contains("method")) return;
if (j["method"].get<std::string>() != "textDocument/publishDiagnostics") return;
if (!j.contains("params")) return;
const auto& params = j["params"];
if (!params.contains("uri") || !params.contains("diagnostics")) return;
if (j.contains("method")) {
if (j["method"].get<std::string>() != "textDocument/publishDiagnostics") return;
if (!j.contains("params")) return;
const auto& params = j["params"];
if (!params.contains("uri") || !params.contains("diagnostics")) return;
std::string uri = params["uri"].get<std::string>();
std::vector<Diagnostic> parsed;
for (const auto& diag : params["diagnostics"]) {
Diagnostic d;
d.uri = uri;
if (diag.contains("range")) {
const auto& range = diag["range"];
if (range.contains("start")) {
d.range.start.line = range["start"].value("line", 0);
d.range.start.character = range["start"].value("character", 0);
}
if (range.contains("end")) {
d.range.end.line = range["end"].value("line", 0);
d.range.end.character = range["end"].value("character", 0);
std::string uri = params["uri"].get<std::string>();
std::vector<Diagnostic> parsed;
for (const auto& diag : params["diagnostics"]) {
Diagnostic d;
d.uri = uri;
if (diag.contains("range")) {
const auto& range = diag["range"];
if (range.contains("start")) {
d.range.start.line = range["start"].value("line", 0);
d.range.start.character = range["start"].value("character", 0);
}
if (range.contains("end")) {
d.range.end.line = range["end"].value("line", 0);
d.range.end.character = range["end"].value("character", 0);
}
}
d.severity = diag.value("severity", 0);
d.message = diag.value("message", "");
d.source = diag.value("source", "");
parsed.push_back(std::move(d));
}
d.severity = diag.value("severity", 0);
d.message = diag.value("message", "");
d.source = diag.value("source", "");
parsed.push_back(std::move(d));
diagnosticsByUri_[uri] = std::move(parsed);
return;
}
diagnosticsByUri_[uri] = std::move(parsed);
if (j.contains("id") && j.contains("result")) {
int id = j["id"].get<int>();
if (lastCompletionRequestId_ > 0 && id != lastCompletionRequestId_) return;
const auto& result = j["result"];
const nlohmann::json* items = nullptr;
if (result.is_array()) {
items = &result;
} else if (result.is_object() && result.contains("items")) {
items = &result["items"];
}
if (!items || !items->is_array()) return;
std::vector<CompletionItem> parsed;
for (const auto& item : *items) {
CompletionItem ci;
ci.label = item.value("label", "");
ci.kind = item.value("kind", 0);
ci.detail = item.value("detail", "");
ci.insertText = item.value("insertText", ci.label);
ci.filterText = item.value("filterText", "");
parsed.push_back(std::move(ci));
}
completionItems_ = std::move(parsed);
}
}
std::vector<Diagnostic> getDiagnostics() const {
@@ -146,6 +190,14 @@ public:
return it->second;
}
std::vector<CompletionItem> getCompletionItems() const {
return completionItems_;
}
void clearCompletionItems() {
completionItems_.clear();
}
void sendNotification(const std::string& method, const nlohmann::json& params) {
nlohmann::json msg;
msg["jsonrpc"] = "2.0";
@@ -175,4 +227,6 @@ private:
std::shared_ptr<LSPTransport> transport_;
int nextId_ = 1;
std::unordered_map<std::string, std::vector<Diagnostic>> diagnosticsByUri_;
int lastCompletionRequestId_ = -1;
std::vector<CompletionItem> completionItems_;
};