summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-12-27 23:15:27 -0500
committerpommicket <pommicket@gmail.com>2022-12-27 23:15:27 -0500
commit47adb1651d35dcc545850916c4a16b747901dba5 (patch)
treef329f973016d15f17b0437202c26f4ca93a0b7be
parente112a90ff73f7f407ed2251f905565713c237bc1 (diff)
more signature help
-rw-r--r--lsp-parse.c75
-rw-r--r--lsp-write.c20
-rw-r--r--lsp.c8
-rw-r--r--lsp.h21
-rw-r--r--main.c1
5 files changed, 109 insertions, 16 deletions
diff --git a/lsp-parse.c b/lsp-parse.c
index 339c490..c340d33 100644
--- a/lsp-parse.c
+++ b/lsp-parse.c
@@ -132,6 +132,18 @@ static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabiliti
}
}
+static JSONString get_markup_content(const JSON *json, JSONValue markup_value) {
+ // some fields are of type string | MarkupContent (e.g. completion documentation)
+ // this converts either one to a string.
+ if (markup_value.type == JSON_STRING) {
+ return markup_value.val.string;
+ } else if (markup_value.type == JSON_OBJECT) {
+ return json_object_get_string(json, markup_value.val.object, "value");
+ } else {
+ return (JSONString){0};
+ }
+}
+
static bool parse_completion(LSP *lsp, const JSON *json, LSPResponse *response) {
// deal with textDocument/completion response.
// result: CompletionItem[] | CompletionList | null
@@ -229,16 +241,8 @@ static bool parse_completion(LSP *lsp, const JSON *json, LSPResponse *response)
item->text_edit.type = (LSPTextEditType)edit_type;
}
- JSONString documentation = {0};
JSONValue documentation_value = json_object_get(json, item_object, "documentation");
- // the "documentation" field is either just a string or an object containing
- // a type ("markdown" or "plaintext") and a string.
- if (documentation_value.type == JSON_STRING) {
- documentation = documentation_value.val.string;
- } else if (documentation_value.type == JSON_OBJECT) {
- documentation = json_object_get_string(json, documentation_value.val.object,
- "value");
- }
+ JSONString documentation = get_markup_content(json, documentation_value);
if (documentation.len) {
if (documentation.len > 1000) {
// rust has some docs which are *20,000* bytes long
@@ -292,6 +296,56 @@ static bool parse_completion(LSP *lsp, const JSON *json, LSPResponse *response)
return true;
}
+static bool parse_signature_help(LSP *lsp, const JSON *json, LSPResponse *response) {
+ JSONObject result = json_force_object(json_get(json, "result"));
+ LSPResponseSignatureHelp *help = &response->data.signature_help;
+
+ u32 active_signature = 0;
+ double active_signature_dbl = json_object_get_number(json, result, "activeSignature");
+ if (isnormal(active_signature_dbl))
+ active_signature = (u32)active_signature_dbl;
+ double active_signature_active_parameter = json_object_get_number(json, result, "activeParameter");
+
+ JSONArray signatures = json_object_get_array(json, result, "signatures");
+ if (active_signature >= signatures.len)
+ active_signature = 0;
+ for (u32 s = 0; s < signatures.len; ++s) {
+ // parse SignatureInformation
+ LSPSignatureInformation *signature_out = arr_addp(help->signatures);
+ JSONObject signature_in = json_array_get_object(json, signatures, s);
+ JSONString label = json_object_get_string(json, signature_in, "label");
+ signature_out->label = lsp_response_add_json_string(response, json, label);
+ JSONString documentation = get_markup_content(json,
+ json_object_get(json, signature_in, "documentation"));
+ if (documentation.len)
+ signature_out->documentation = lsp_response_add_json_string(response, json, documentation);
+
+ JSONArray parameters = json_object_get_array(json, signature_in, "parameters");
+ u32 active_parameter = U32_MAX;
+ double active_parameter_dbl = json_object_get_number(json, signature_in, "activeParameter");
+ if (isnormal(active_parameter_dbl)) {
+ active_parameter = (u32)active_parameter_dbl;
+ }
+ if (s == active_signature && active_parameter == U32_MAX &&
+ isnormal(active_signature_active_parameter)) {
+ active_parameter = (u32)active_parameter_dbl;
+ }
+ if (active_parameter < parameters.len) {
+ JSONObject parameter_info = json_array_get_object(json, parameters, active_parameter);
+ @TODO
+ }
+ }
+
+ if (active_signature != 0) {
+ //make sure active signature is #0
+ LSPSignatureInformation active = help->signatures[active_signature];
+ arr_remove(help->signatures, active_signature);
+ arr_insert(help->signatures, 0, active);
+ }
+
+ return true;
+}
+
// fills request->id/id_string appropriately given the request's json
// returns true on success
static WarnUnusedResult bool parse_id(JSON *json, LSPRequest *request) {
@@ -425,6 +479,9 @@ static void process_message(LSP *lsp, JSON *json) {
case LSP_REQUEST_COMPLETION:
add_to_messages = parse_completion(lsp, json, &response);
break;
+ case LSP_REQUEST_SIGNATURE_HELP:
+ add_to_messages = parse_signature_help(lsp, json, &response);
+ break;
case LSP_REQUEST_INITIALIZE: {
// it's the response to our initialize request!
if (result.type == JSON_OBJECT) {
diff --git a/lsp-write.c b/lsp-write.c
index 835cfce..910eb1b 100644
--- a/lsp-write.c
+++ b/lsp-write.c
@@ -1,5 +1,3 @@
-
-
static const char *lsp_language_id(Language lang) {
switch (lang) {
case LANG_CONFIG:
@@ -228,6 +226,13 @@ static void write_workspace_folders(JSONWriter *o, LSPDocumentID *workspace_fold
write_arr_end(o);
}
+static void write_document_position(JSONWriter *o, LSPDocumentPosition pos) {
+ write_key_obj_start(o, "textDocument");
+ write_key_file_uri(o, "uri", pos.document);
+ write_obj_end(o);
+ write_key_position(o, "position", pos.pos);
+}
+
static const char *lsp_request_method(LSPRequest *request) {
switch (request->type) {
case LSP_REQUEST_NONE: break;
@@ -454,10 +459,7 @@ static void write_request(LSP *lsp, LSPRequest *request) {
case LSP_REQUEST_COMPLETION: {
const LSPRequestCompletion *completion = &request->data.completion;
write_key_obj_start(o, "params");
- write_key_obj_start(o, "textDocument");
- write_key_file_uri(o, "uri", completion->position.document);
- write_obj_end(o);
- write_key_position(o, "position", completion->position.pos);
+ write_document_position(o, completion->position);
const LSPCompletionContext *context = &completion->context;
LSPCompletionTriggerKind trigger_kind = context->trigger_kind;
if (trigger_kind != LSP_TRIGGER_NONE) {
@@ -469,6 +471,12 @@ static void write_request(LSP *lsp, LSPRequest *request) {
}
write_obj_end(o);
} break;
+ case LSP_REQUEST_SIGNATURE_HELP: {
+ const LSPRequestSignatureHelp *help = &request->data.signature_help;
+ write_key_obj_start(o, "params");
+ write_document_position(o, help->position);
+ write_obj_end(o);
+ } break;
case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS: {
const LSPRequestDidChangeWorkspaceFolders *w = &request->data.change_workspace_folders;
write_key_obj_start(o, "params");
diff --git a/lsp.c b/lsp.c
index 9ec7ad7..bd6348a 100644
--- a/lsp.c
+++ b/lsp.c
@@ -1,5 +1,5 @@
// print server-to-client communication
-#define LSP_SHOW_S2C 0
+#define LSP_SHOW_S2C 1
// print client-to-server communication
#define LSP_SHOW_C2S 0
@@ -42,6 +42,7 @@ static void lsp_request_free(LSPRequest *r) {
case LSP_REQUEST_SHUTDOWN:
case LSP_REQUEST_EXIT:
case LSP_REQUEST_COMPLETION:
+ case LSP_REQUEST_SIGNATURE_HELP:
case LSP_REQUEST_DID_CLOSE:
case LSP_REQUEST_WORKSPACE_FOLDERS:
break;
@@ -74,6 +75,9 @@ static void lsp_response_free(LSPResponse *r) {
case LSP_REQUEST_COMPLETION:
arr_free(r->data.completion.items);
break;
+ case LSP_REQUEST_SIGNATURE_HELP:
+ arr_free(r->data.signature_help.signatures);
+ break;
default:
break;
}
@@ -130,6 +134,8 @@ static bool lsp_supports_request(LSP *lsp, const LSPRequest *request) {
return true;
case LSP_REQUEST_COMPLETION:
return cap->completion_support;
+ case LSP_REQUEST_SIGNATURE_HELP:
+ return cap->signature_help_support;
case LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS:
return cap->workspace_folders_support;
}
diff --git a/lsp.h b/lsp.h
index 1c75861..4491cd2 100644
--- a/lsp.h
+++ b/lsp.h
@@ -245,6 +245,26 @@ typedef struct {
LSPCompletionItem *items;
} LSPResponseCompletion;
+typedef struct {
+ LSPString label;
+ LSPString documentation;
+ // NOTE: LSP gives us parameter information for *all*
+ // parameters, but we only really need it for the active parameter.
+
+ // (UTF-16) indices into `label` indicating which
+ // part of it should be highlighted for the active parameter
+ u16 active_start;
+ u16 active_end;
+ // documentation for the active parameter
+ LSPString active_documentation;
+} LSPSignatureInformation;
+
+typedef struct {
+ // NOTE: the "active" signature will be the first one
+ // in this array.
+ LSPSignatureInformation *signatures;
+} LSPResponseSignatureHelp;
+
typedef LSPRequestType LSPResponseType;
typedef struct {
@@ -255,6 +275,7 @@ typedef struct {
char *string_data;
union {
LSPResponseCompletion completion;
+ LSPResponseSignatureHelp signature_help;
} data;
} LSPResponse;
diff --git a/main.c b/main.c
index 3f028f6..3468577 100644
--- a/main.c
+++ b/main.c
@@ -6,6 +6,7 @@
- go to definition using LSP
- find usages
- go through signature help capabilities
+- JSON syntax highlighting
- separate signature-help setting (dont use trigger-characters)
- check if there are any other non-optional/nice-to-have-support-for server-to-client requests
- do something with lsp->error