summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ds.c2
-rw-r--r--ide-definitions.c46
-rw-r--r--lsp-parse.c69
-rw-r--r--lsp-write.c59
-rw-r--r--lsp.c50
-rw-r--r--lsp.h7
-rw-r--r--main.c1
7 files changed, 161 insertions, 73 deletions
diff --git a/ds.c b/ds.c
index 99ad4d3..b599f36 100644
--- a/ds.c
+++ b/ds.c
@@ -100,6 +100,8 @@ static void arr_reserve_(void **arr, size_t member_size, size_t n) {
if (*arr) free(arr_hdr_(*arr));
*arr = NULL;
}
+
+ if (n == 0) return;
if (!*arr) {
// create a new array with capacity n+1
diff --git a/ide-definitions.c b/ide-definitions.c
index a748173..e63e977 100644
--- a/ide-definitions.c
+++ b/ide-definitions.c
@@ -1,3 +1,49 @@
+
+static SymbolKind symbol_kind_to_ted(LSPSymbolKind kind) {
+ switch (kind) {
+ case LSP_SYMBOL_OTHER:
+ case LSP_SYMBOL_FILE:
+ case LSP_SYMBOL_MODULE:
+ case LSB_SYMBOL_NAMESPACE:
+ case LSP_SYMBOL_PACKAGE:
+ return SYMBOL_OTHER;
+
+ case LSP_SYMBOL_CLASS:
+ case LSP_SYMBOL_TYPEPARAMETER:
+ case LSP_SYMBOL_ENUM:
+ case LSP_SYMBOL_INTERFACE:
+ case LSP_SYMBOL_STRUCT:
+ case LSP_SYMBOL_EVENT: // i have no clue what this is. let's say it's a type.
+ return SYMBOL_TYPE;
+
+ case LSP_SYMBOL_PROPERTY:
+ case LSP_SYMBOL_FIELD:
+ case LSP_SYMBOL_KEY:
+ return SYMBOL_FIELD;
+
+ case LSP_SYMBOL_CONSTRUCTOR:
+ case LSP_SYMBOL_FUNCTION:
+ case LSP_SYMBOL_OPERATOR:
+ case LSP_SYMBOL_METHOD:
+ return SYMBOL_FUNCTION;
+
+ case LSP_SYMBOL_VARIABLE:
+ return SYMBOL_VARIABLE;
+
+ case LSP_SYMBOL_CONSTANT:
+ case LSP_SYMBOL_STRING:
+ case LSP_SYMBOL_NUMBER:
+ case LSP_SYMBOL_BOOLEAN:
+ case LSP_SYMBOL_ARRAY:
+ case LSP_SYMBOL_OBJECT:
+ case LSP_SYMBOL_ENUMMEMBER:
+ case LSP_SYMBOL_NULL:
+ return SYMBOL_CONSTANT;
+ }
+
+ return SYMBOL_OTHER;
+}
+
void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition position) {
Definitions *defs = &ted->definitions;
if (lsp) {
diff --git a/lsp-parse.c b/lsp-parse.c
index 42a3c7b..c98ae85 100644
--- a/lsp-parse.c
+++ b/lsp-parse.c
@@ -82,11 +82,8 @@ static bool parse_range(LSP *lsp, const JSON *json, JSONValue range_value, LSPRa
}
static bool parse_document_uri(LSP *lsp, const JSON *json, JSONValue value, LSPDocumentID *id) {
- if (value.type != JSON_STRING) {
- lsp_set_error(lsp, "Expected string for URI, got %s",
- json_type_to_str(value.type));
+ if (!lsp_expect_string(lsp, value, "URI"))
return false;
- }
char *string = json_string_get_alloc(json, value.val.string);
if (!str_has_prefix(string, "file://")) {
lsp_set_error(lsp, "Can't process non-local URI %s",
@@ -262,7 +259,7 @@ static bool parse_completion(LSP *lsp, const JSON *json, LSPResponse *response)
JSONArray tags = json_object_get_array(json, item_object, "tags");
for (u32 i = 0; i < tags.len; ++i) {
double tag = json_array_get_number(json, tags, i);
- if (tag == 1 /* deprecated */) {
+ if (tag == LSP_SYMBOL_TAG_DEPRECATED) {
item->deprecated = true;
}
}
@@ -495,11 +492,8 @@ static bool parse_hover(LSP *lsp, const JSON *json, LSPResponse *response) {
// parse a Location: {uri: DocumentUri, range: Range}
static bool parse_location(LSP *lsp, const JSON *json, JSONValue value, LSPLocation *location) {
- if (value.type != JSON_OBJECT) {
- lsp_set_error(lsp, "Expected object for location but got %s",
- json_type_to_str(value.type));
+ if (!lsp_expect_object(lsp, value, "Location"))
return false;
- }
JSONObject object = value.val.object;
JSONValue uri = json_object_get(json, object, "uri");
if (!parse_document_uri(lsp, json, uri, &location->document))
@@ -534,9 +528,61 @@ static bool parse_definition(LSP *lsp, const JSON *json, LSPResponse *response)
}
}
+// parses SymbolInformation or WorkspaceSymbol
+static bool parse_symbol_information(LSP *lsp, const JSON *json, JSONValue value,
+ LSPResponse *response, LSPSymbolInformation *info) {
+ if (!lsp_expect_object(lsp, value, "SymbolInformation"))
+ return false;
+ JSONObject object = value.val.object;
+
+ // parse name
+ JSONValue name_value = json_object_get(json, object, "name");
+ if (!lsp_expect_string(lsp, name_value, "SymbolInformation.name"))
+ return false;
+ JSONString name = name_value.val.string;
+ info->name = lsp_response_add_json_string(response, json, name);
+
+ // parse kind
+ JSONValue kind_value = json_object_get(json, object, "kind");
+ if (!lsp_expect_number(lsp, kind_value, "SymbolInformation.kind"))
+ return false;
+ double kind = kind_value.val.number;
+ if (isfinite(kind) && kind >= LSP_SYMBOL_KIND_MIN && kind <= LSP_SYMBOL_KIND_MAX)
+ info->kind = (LSPSymbolKind)kind;
+
+ // check if deprecated
+ bool deprecated = json_object_get(json, object, "deprecated").type == JSON_TRUE;
+ JSONArray tags = json_object_get_array(json, object, "tags");
+ for (size_t i = 0; i < tags.len; ++i) {
+ if (json_array_get_number(json, tags, i) == LSP_SYMBOL_TAG_DEPRECATED)
+ deprecated = true;
+ }
+ info->deprecated = deprecated;
+
+ // parse location
+ JSONValue location = json_object_get(json, object, "location");
+ if (!parse_location(lsp, json, location, &info->location))
+ return false;
+
+ return true;
+}
+
+static bool parse_workspace_symbols(LSP *lsp, const JSON *json, LSPResponse *response) {
+ LSPResponseWorkspaceSymbols *syms = &response->data.workspace_symbols;
+ JSONArray result = json_force_array(json_root(json));
+ arr_set_len(syms->symbols, result.len);
+ for (size_t i = 0; i < result.len; ++i) {
+ LSPSymbolInformation *info = &syms->symbols[i];
+ JSONValue value = json_array_get(json, result, i);
+ if (!parse_symbol_information(lsp, json, value, response, info))
+ return false;
+ }
+ 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) {
+static WarnUnusedResult bool parse_id(const JSON *json, LSPRequest *request) {
JSONValue id_value = json_get(json, "id");
switch (id_value.type) {
case JSON_NUMBER: {
@@ -677,6 +723,9 @@ static void process_message(LSP *lsp, JSON *json) {
case LSP_REQUEST_DEFINITION:
add_to_messages = parse_definition(lsp, json, &response);
break;
+ case LSP_REQUEST_WORKSPACE_SYMBOLS:
+ add_to_messages = parse_workspace_symbols(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 4068479..58c5a8f 100644
--- a/lsp-write.c
+++ b/lsp-write.c
@@ -318,6 +318,41 @@ static void message_writer_write_and_free(LSP *lsp, JSONWriter *o) {
str_builder_free(&builder);
}
+static void write_symbol_tag_support(JSONWriter *o) {
+ write_key_obj_start(o, "tagSupport");
+ write_key_arr_start(o, "valueSet");
+ for (int i = LSP_SYMBOL_TAG_MIN; i <= LSP_SYMBOL_TAG_MAX; ++i)
+ write_arr_elem_number(o, i);
+ write_arr_end(o);
+ write_obj_end(o);
+}
+
+
+static void write_completion_item_kind_support(JSONWriter *o) {
+ // "completion item kinds" supported by ted
+ // (these are the little icons displayed for function/variable/etc.)
+ write_key_obj_start(o, "completionItemKind");
+ write_key_arr_start(o, "valueSet");
+ for (int i = LSP_COMPLETION_KIND_MIN;
+ i <= LSP_COMPLETION_KIND_MAX; ++i) {
+ write_arr_elem_number(o, i);
+ }
+ write_arr_end(o);
+ write_obj_end(o);
+}
+
+static void write_symbol_kind_support(JSONWriter *o) {
+ write_key_obj_start(o, "symbolKind");
+ write_key_arr_start(o, "valueSet");
+ for (int i = LSP_SYMBOL_KIND_MIN;
+ i <= LSP_SYMBOL_KIND_MAX;
+ ++i) {
+ write_arr_elem_number(o, i);
+ }
+ write_arr_end(o);
+ write_obj_end(o);
+}
+
// NOTE: don't call lsp_request_free after calling this function.
// I will do it for you.
static void write_request(LSP *lsp, LSPRequest *request) {
@@ -365,24 +400,10 @@ static void write_request(LSP *lsp, LSPRequest *request) {
write_arr_end(o);
write_key_bool(o, "deprecatedSupport", true);
write_key_bool(o, "preselectSupport", false);
- write_key_obj_start(o, "tagSupport");
- write_key_arr_start(o, "valueSet");
- // currently the only tag in the spec
- write_arr_elem_number(o, 1);
- write_arr_end(o);
- write_obj_end(o);
+ write_symbol_tag_support(o);
write_key_bool(o, "insertReplaceSupport", false);
write_obj_end(o);
- // "completion item kinds" supported by ted
- // (these are the little icons displayed for function/variable/etc.)
- write_key_obj_start(o, "completionItemKind");
- write_key_arr_start(o, "valueSet");
- for (int i = LSP_COMPLETION_KIND_MIN;
- i <= LSP_COMPLETION_KIND_MAX; ++i) {
- write_arr_elem_number(o, i);
- }
- write_arr_end(o);
- write_obj_end(o);
+ write_completion_item_kind_support(o);
write_key_bool(o, "contextSupport", true);
write_obj_end(o);
@@ -412,6 +433,12 @@ static void write_request(LSP *lsp, LSPRequest *request) {
write_obj_end(o);
write_key_obj_start(o, "workspace");
write_key_bool(o, "workspaceFolders", true);
+
+ write_key_obj_start(o, "symbol");
+ write_symbol_kind_support(o);
+ write_symbol_tag_support(o);
+ // resolve is kind of a pain to implement. i'm not doing it yet.
+ write_obj_end(o);
write_obj_end(o);
write_obj_end(o);
SDL_LockMutex(lsp->workspace_folders_mutex);
diff --git a/lsp.c b/lsp.c
index 3efa830..c8de1a7 100644
--- a/lsp.c
+++ b/lsp.c
@@ -93,6 +93,9 @@ static void lsp_response_free(LSPResponse *r) {
case LSP_REQUEST_DEFINITION:
arr_free(r->data.definition.locations);
break;
+ case LSP_REQUEST_WORKSPACE_SYMBOLS:
+ arr_free(r->data.workspace_symbols.symbols);
+ break;
default:
break;
}
@@ -537,53 +540,6 @@ void lsp_document_changed(LSP *lsp, const char *document, LSPDocumentChangeEvent
lsp_send_request(lsp, &request);
}
-#if 0
-SymbolKind lsp_symbol_kind_to_ted(LSPSymbolKind kind) {
- switch (kind) {
- case LSP_SYMBOL_OTHER:
- case LSP_SYMBOL_FILE:
- case LSP_SYMBOL_MODULE:
- case LSB_SYMBOL_NAMESPACE:
- case LSP_SYMBOL_PACKAGE:
- return SYMBOL_OTHER;
-
- case LSP_SYMBOL_CLASS:
- case LSP_SYMBOL_TYPEPARAMETER:
- case LSP_SYMBOL_ENUM:
- case LSP_SYMBOL_INTERFACE:
- case LSP_SYMBOL_STRUCT:
- case LSP_SYMBOL_EVENT: // i have no clue what this is. let's say it's a type.
- return SYMBOL_TYPE;
-
- case LSP_SYMBOL_PROPERTY:
- case LSP_SYMBOL_FIELD:
- case LSP_SYMBOL_KEY:
- return SYMBOL_FIELD;
-
- case LSP_SYMBOL_CONSTRUCTOR:
- case LSP_SYMBOL_FUNCTION:
- case LSP_SYMBOL_OPERATOR:
- case LSP_SYMBOL_METHOD:
- return SYMBOL_FUNCTION;
-
- case LSP_SYMBOL_VARIABLE:
- return SYMBOL_VARIABLE;
-
- case LSP_SYMBOL_CONSTANT:
- case LSP_SYMBOL_STRING:
- case LSP_SYMBOL_NUMBER:
- case LSP_SYMBOL_BOOLEAN:
- case LSP_SYMBOL_ARRAY:
- case LSP_SYMBOL_OBJECT:
- case LSP_SYMBOL_ENUMMEMBER:
- case LSP_SYMBOL_NULL:
- return SYMBOL_CONSTANT;
- }
-
- return SYMBOL_OTHER;
-}
-#endif
-
bool lsp_position_eq(LSPPosition a, LSPPosition b) {
return a.line == b.line && a.character == b.character;
}
diff --git a/lsp.h b/lsp.h
index 3529174..b80fbb2 100644
--- a/lsp.h
+++ b/lsp.h
@@ -301,6 +301,12 @@ typedef struct {
LSPLocation *locations;
} LSPResponseDefinition;
+typedef enum {
+ #define LSP_SYMBOL_TAG_MIN 1
+ LSP_SYMBOL_TAG_DEPRECATED = 1
+ #define LSP_SYMBOL_TAG_MAX 1
+} LSPSymbolTag;
+
// SymbolInformation in the LSP spec
typedef struct {
LSPString name;
@@ -327,6 +333,7 @@ typedef struct {
LSPResponseSignatureHelp signature_help;
LSPResponseHover hover;
LSPResponseDefinition definition;
+ LSPResponseWorkspaceSymbols workspace_symbols;
} data;
} LSPResponse;
diff --git a/main.c b/main.c
index 172a415..61b319d 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,6 @@
/*
@TODO:
+- cancelling requests e.g. in ide-definitions.c
- more LSP stuff:
- go to definition using LSP
- find usages