diff options
| author | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-20 13:14:07 +0000 |
|---|---|---|
| committer | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-20 13:14:07 +0000 |
| commit | 50e2dde008820ef5ae8bd502d2646e00e5139bc4 (patch) | |
| tree | 71ae2721c7788b699eca28a0902f7c7b22cee54e /src/lsp/json_rpc.c | |
| parent | b106fe19b55e9fe3348b3a5c9992c21dac27b02c (diff) | |
Using cJSON for the LSP
Diffstat (limited to 'src/lsp/json_rpc.c')
| -rw-r--r-- | src/lsp/json_rpc.c | 292 |
1 files changed, 102 insertions, 190 deletions
diff --git a/src/lsp/json_rpc.c b/src/lsp/json_rpc.c index c8c9a3b..9b281bc 100644 --- a/src/lsp/json_rpc.c +++ b/src/lsp/json_rpc.c @@ -1,176 +1,90 @@ - #include "json_rpc.h" +#include "cJSON.h" +#include "lsp_project.h" #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <ctype.h> -// Helper to skip whitespace -const char *skip_ws(const char *p) +void lsp_check_file(const char *uri, const char *src); +void lsp_goto_definition(const char *uri, int line, int col); +void lsp_hover(const char *uri, int line, int col); +void lsp_completion(const char *uri, int line, int col); +void lsp_document_symbol(const char *uri); +void lsp_references(const char *uri, int line, int col); +void lsp_signature_help(const char *uri, int line, int col); + +// Helper to extract textDocument params +static void get_params(cJSON *root, char **uri, int *line, int *col) { - while (*p && isspace(*p)) + cJSON *params = cJSON_GetObjectItem(root, "params"); + if (!params) { - p++; + return; } - return p; -} -// Robust JSON string extractor -// Finds "key" ... : ... "value" -char *get_json_string(const char *json, const char *key) -{ - char key_pattern[256]; - sprintf(key_pattern, "\"%s\"", key); - - char *p = strstr(json, key_pattern); - while (p) + cJSON *doc = cJSON_GetObjectItem(params, "textDocument"); + if (doc) { - const char *cursor = p + strlen(key_pattern); - cursor = skip_ws(cursor); - if (*cursor == ':') + cJSON *u = cJSON_GetObjectItem(doc, "uri"); + if (u && u->valuestring) { - cursor++; // skip : - cursor = skip_ws(cursor); - if (*cursor == '"') - { - // Found start of value - cursor++; - const char *start = cursor; - // Find end " (handling escapes?) - // MVP: just find next " that is not escaped - while (*cursor) - { - if (*cursor == '"' && *(cursor - 1) != '\\') - { - break; - } - cursor++; - } - - int len = cursor - start; - char *res = malloc(len + 1); - strncpy(res, start, len); - res[len] = 0; - return res; - } + *uri = strdup(u->valuestring); } - // False positive? Find next - p = strstr(p + 1, key_pattern); } - return NULL; -} -// Extract nested "text" from params... -// Since "text" might be huge and contain anything, we need to be careful. -char *get_text_content(const char *json) -{ - // Search for "text" key - char *res = get_json_string(json, "text"); - if (!res) + cJSON *pos = cJSON_GetObjectItem(params, "position"); + if (pos) { - return NULL; - } - - size_t len = strlen(res); - char *unescaped = malloc(len + 1); - char *dst = unescaped; - char *src = res; - while (*src) - { - if (*src == '\\') + cJSON *l = cJSON_GetObjectItem(pos, "line"); + cJSON *c = cJSON_GetObjectItem(pos, "character"); + if (l) { - src++; - if (*src == 'n') - { - *dst++ = '\n'; - } - else if (*src == 'r') - { - *dst++ = '\r'; - } - else if (*src == 't') - { - *dst++ = '\t'; - } - else if (*src == '"') - { - *dst++ = '"'; - } - else if (*src == '\\') - { - *dst++ = '\\'; - } - else - { - *dst++ = *src; - } + *line = l->valueint; } - else + if (c) { - *dst++ = *src; + *col = c->valueint; } - src++; } - *dst = 0; - free(res); - return unescaped; } -void get_json_position(const char *json, int *line, int *col) +void handle_request(const char *json_str) { - // Search for "line" and "character" - // Note: they are integers - - char *p = strstr(json, "\"line\""); - if (p) + cJSON *json = cJSON_Parse(json_str); + if (!json) { - p += 6; // skip "line" - p = (char *)skip_ws(p); - if (*p == ':') - { - p++; - p = (char *)skip_ws(p); - *line = atoi(p); - } + return; } - p = strstr(json, "\"character\""); - if (p) + cJSON *method_item = cJSON_GetObjectItem(json, "method"); + if (!method_item || !method_item->valuestring) { - p += 11; - p = (char *)skip_ws(p); - if (*p == ':') - { - p++; - p = (char *)skip_ws(p); - *col = atoi(p); - } + cJSON_Delete(json); + return; } -} - -void lsp_check_file(const char *uri, const char *src); -void lsp_goto_definition(const char *uri, int line, int col); -void lsp_hover(const char *uri, int line, int col); -void lsp_completion(const char *uri, int line, int col); -void lsp_document_symbol(const char *uri); -void lsp_references(const char *uri, int line, int col); -void lsp_signature_help(const char *uri, int line, int col); + char *method = method_item->valuestring; -#include "lsp_project.h" - -void handle_request(const char *json_str) -{ - // Looser method detection - if (strstr(json_str, "initialize")) + if (strcmp(method, "initialize") == 0) { - // Extract rootPath or rootUri - char *root = get_json_string(json_str, "rootPath"); - if (!root) + cJSON *params = cJSON_GetObjectItem(json, "params"); + char *root = NULL; + if (params) { - root = get_json_string(json_str, "rootUri"); + cJSON *rp = cJSON_GetObjectItem(params, "rootPath"); + if (rp && rp->valuestring) + { + root = strdup(rp->valuestring); + } + else + { + cJSON *ru = cJSON_GetObjectItem(params, "rootUri"); + if (ru && ru->valuestring) + { + root = strdup(ru->valuestring); + } + } } - // Clean up URI if needed if (root && strncmp(root, "file://", 7) == 0) { char *clean = strdup(root + 7); @@ -178,119 +92,117 @@ void handle_request(const char *json_str) root = clean; } + lsp_project_init(root ? root : "."); if (root) { - lsp_project_init(root); free(root); } - else - { - lsp_project_init("."); - } const char *response = "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{" "\"capabilities\":{\"textDocumentSync\":1," "\"definitionProvider\":true,\"hoverProvider\":true," + "\"referencesProvider\":true,\"documentSymbolProvider\":true," + "\"signatureHelpProvider\":{\"triggerCharacters\":[\"(\"]}," "\"completionProvider\":{" "\"triggerCharacters\":[\".\"]}}}}"; fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", strlen(response), response); fflush(stdout); - return; } - - if (strstr(json_str, "didOpen") || strstr(json_str, "didChange")) + else if (strcmp(method, "textDocument/didOpen") == 0 || + strcmp(method, "textDocument/didChange") == 0) { - char *uri = get_json_string(json_str, "uri"); - char *text = get_text_content(json_str); - - if (uri && text) + cJSON *params = cJSON_GetObjectItem(json, "params"); + if (params) { - // fprintf(stderr, "zls: Checking %s\n", uri); - lsp_check_file(uri, text); - } + cJSON *doc = cJSON_GetObjectItem(params, "textDocument"); + if (doc) + { + cJSON *uri = cJSON_GetObjectItem(doc, "uri"); + cJSON *text = cJSON_GetObjectItem(doc, "text"); + // For didChange, text is inside contentChanges + if (!text && strcmp(method, "textDocument/didChange") == 0) + { + cJSON *changes = cJSON_GetObjectItem(params, "contentChanges"); + if (changes && cJSON_GetArraySize(changes) > 0) + { + cJSON *change = cJSON_GetArrayItem(changes, 0); + text = cJSON_GetObjectItem(change, "text"); + } + } - if (uri) - { - free(uri); - } - if (text) - { - free(text); + if (uri && uri->valuestring && text && text->valuestring) + { + lsp_check_file(uri->valuestring, text->valuestring); + } + } } } - - if (strstr(json_str, "textDocument/definition")) + else if (strcmp(method, "textDocument/definition") == 0) { - char *uri = get_json_string(json_str, "uri"); + char *uri = NULL; int line = 0, col = 0; - get_json_position(json_str, &line, &col); - + get_params(json, &uri, &line, &col); if (uri) { lsp_goto_definition(uri, line, col); free(uri); } } - - if (strstr(json_str, "textDocument/hover")) + else if (strcmp(method, "textDocument/hover") == 0) { - char *uri = get_json_string(json_str, "uri"); + char *uri = NULL; int line = 0, col = 0; - get_json_position(json_str, &line, &col); - + get_params(json, &uri, &line, &col); if (uri) { lsp_hover(uri, line, col); free(uri); } } - - if (strstr(json_str, "textDocument/completion")) + else if (strcmp(method, "textDocument/completion") == 0) { - char *uri = get_json_string(json_str, "uri"); + char *uri = NULL; int line = 0, col = 0; - get_json_position(json_str, &line, &col); - + get_params(json, &uri, &line, &col); if (uri) { lsp_completion(uri, line, col); free(uri); } } - - if (strstr(json_str, "textDocument/documentSymbol")) + else if (strcmp(method, "textDocument/documentSymbol") == 0) { - char *uri = get_json_string(json_str, "uri"); + char *uri = NULL; + int line = 0, col = 0; // Unused for outline + get_params(json, &uri, &line, &col); if (uri) { lsp_document_symbol(uri); free(uri); } } - - if (strstr(json_str, "textDocument/references")) + else if (strcmp(method, "textDocument/references") == 0) { - char *uri = get_json_string(json_str, "uri"); + char *uri = NULL; int line = 0, col = 0; - get_json_position(json_str, &line, &col); - + get_params(json, &uri, &line, &col); if (uri) { lsp_references(uri, line, col); free(uri); } } - - if (strstr(json_str, "textDocument/signatureHelp")) + else if (strcmp(method, "textDocument/signatureHelp") == 0) { - char *uri = get_json_string(json_str, "uri"); + char *uri = NULL; int line = 0, col = 0; - get_json_position(json_str, &line, &col); - + get_params(json, &uri, &line, &col); if (uri) { lsp_signature_help(uri, line, col); free(uri); } } + + cJSON_Delete(json); } |
