summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-12-30 21:49:05 -0500
committerpommicket <pommicket@gmail.com>2022-12-30 21:49:05 -0500
commitf69275faee4cd3045389a98fefefb0c683757a5c (patch)
treec7b0e5cfe59205554e3b5fc5410d3bff9fe89599
parenta997d4106a397c785473bec5862c91bdf49f06ee (diff)
start document highlights
-rw-r--r--ide-highlights.c32
-rw-r--r--lsp-parse.c39
-rw-r--r--lsp-write.c8
-rw-r--r--lsp.c7
-rw-r--r--lsp.h26
-rw-r--r--main.c4
-rw-r--r--ted.h5
7 files changed, 114 insertions, 7 deletions
diff --git a/ide-highlights.c b/ide-highlights.c
new file mode 100644
index 0000000..4246c66
--- /dev/null
+++ b/ide-highlights.c
@@ -0,0 +1,32 @@
+void highlights_send_request(Ted *ted, TextBuffer *buffer) {
+ Highlights *hls = &ted->highlights;
+ if (!buffer) return;
+ LSP *lsp = buffer_lsp(buffer);
+ if (!lsp) return;
+ LSPDocumentPosition pos = buffer_cursor_pos_as_lsp_document_position(buffer);
+ LSPRequest request = {.type = LSP_REQUEST_HIGHLIGHT};
+ request.data.highlight.position = pos;
+ hls->last_request_id = lsp_send_request(lsp, &request);
+}
+
+void highlights_close(Ted *ted) {
+ arr_clear(ted->highlights.highlights);
+}
+
+void highlights_process_lsp_response(Ted *ted, LSPResponse *response) {
+ Highlights *hls = &ted->highlights;
+ if (response->request.type != LSP_REQUEST_HIGHLIGHT)
+ return; // not a highlight request
+ if (response->request.id != hls->last_request_id)
+ return; // old request
+ const LSPResponseHighlight *hl_response = &response->data.highlight;
+ arr_set_len(hls->highlights, arr_len(hl_response->highlights));
+ // type-safe memcpy
+ for (u32 i = 0; i < arr_len(hl_response->highlights); ++i)
+ hls->highlights[i] = hl_response->highlights[i];
+}
+
+void highlights_frame(Ted *ted) {
+ Highlights *hls = &ted->highlights;
+
+}
diff --git a/lsp-parse.c b/lsp-parse.c
index 3834cd0..7a0c630 100644
--- a/lsp-parse.c
+++ b/lsp-parse.c
@@ -124,7 +124,7 @@ static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabiliti
// check CompletionOptions
JSONValue completion_value = json_object_get(json, capabilities, "completionProvider");
- if (completion_value.type == JSON_OBJECT) {
+ if (completion_value.type == JSON_OBJECT && completion_value.type != JSON_FALSE) {
cap->completion_support = true;
JSONObject completion = completion_value.val.object;
@@ -134,7 +134,7 @@ static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabiliti
// check SignatureHelpOptions
JSONValue signature_help_value = json_object_get(json, capabilities, "signatureHelpProvider");
- if (signature_help_value.type == JSON_OBJECT) {
+ if (signature_help_value.type == JSON_OBJECT && signature_help_value.type != JSON_FALSE) {
cap->signature_help_support = true;
JSONObject signature_help = signature_help_value.val.object;
JSONArray trigger_chars = json_object_get_array(json, signature_help, "triggerCharacters");
@@ -148,25 +148,31 @@ static void parse_capabilities(LSP *lsp, const JSON *json, JSONObject capabiliti
// check for hover support
JSONValue hover_value = json_object_get(json, capabilities, "hoverProvider");
- if (hover_value.type != JSON_UNDEFINED) {
+ if (hover_value.type != JSON_UNDEFINED && hover_value.type != JSON_FALSE) {
cap->hover_support = true;
}
// check for definition support
JSONValue definition_value = json_object_get(json, capabilities, "definitionProvider");
- if (definition_value.type != JSON_UNDEFINED) {
+ if (definition_value.type != JSON_UNDEFINED && definition_value.type != JSON_FALSE) {
cap->definition_support = true;
}
+ // check for textDocument/documentHighlight support
+ JSONValue highlight_value = json_object_get(json, capabilities, "documentHighlightProvider");
+ if (highlight_value.type != JSON_UNDEFINED && highlight_value.type != JSON_FALSE) {
+ cap->highlight_support = true;
+ }
+
// check for textDocument/rename support
JSONValue rename_value = json_object_get(json, capabilities, "renameProvider");
- if (rename_value.type != JSON_UNDEFINED) {
+ if (rename_value.type != JSON_UNDEFINED && rename_value.type != JSON_FALSE) {
cap->rename_support = true;
}
// check for workspace/symbol support
JSONValue workspace_symbol_value = json_object_get(json, capabilities, "workspaceSymbolProvider");
- if (workspace_symbol_value.type != JSON_UNDEFINED) {
+ if (workspace_symbol_value.type != JSON_UNDEFINED && workspace_symbol_value.type != JSON_FALSE) {
cap->workspace_symbols_support = true;
}
@@ -767,6 +773,24 @@ static bool parse_rename(LSP *lsp, const JSON *json, LSPResponse *response) {
return parse_workspace_edit(lsp, response, json, result, &response->data.rename);
}
+static bool parse_highlight(LSP *lsp, const JSON *json, LSPResponse *response) {
+ LSPResponseHighlight *hl = &response->data.highlight;
+ JSONArray result = json_force_array(json_get(json, "result"));
+ for (u32 h = 0; h < result.len; ++h) {
+ JSONObject highlight_in = json_array_get_object(json, result, h);
+ LSPHighlight *highlight_out = arr_addp(hl->highlights);
+ double kind = json_object_get_number(json, highlight_in, "kind");
+ if (isfinite(kind) && kind >= LSP_HIGHLIGHT_MAX && kind <= LSP_HIGHLIGHT_MAX) {
+ highlight_out->kind = (LSPHighlightKind)kind;
+ } else {
+ highlight_out->kind = LSP_HIGHLIGHT_TEXT;
+ }
+ JSONValue range = json_object_get(json, highlight_in, "range");
+ if (!parse_range(lsp, json, range, &highlight_out->range))
+ return false;
+ }
+ return true;
+}
static void process_message(LSP *lsp, JSON *json) {
@@ -820,6 +844,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_HIGHLIGHT:
+ add_to_messages = parse_highlight(lsp, json, &response);
+ break;
case LSP_REQUEST_WORKSPACE_SYMBOLS:
add_to_messages = parse_workspace_symbols(lsp, json, &response);
break;
diff --git a/lsp-write.c b/lsp-write.c
index fb65c2d..3255ec0 100644
--- a/lsp-write.c
+++ b/lsp-write.c
@@ -273,6 +273,8 @@ static const char *lsp_request_method(LSPRequest *request) {
return "textDocument/hover";
case LSP_REQUEST_DEFINITION:
return "textDocument/definition";
+ case LSP_REQUEST_HIGHLIGHT:
+ return "textDocument/documentHighlight";
case LSP_REQUEST_RENAME:
return "textDocument/rename";
case LSP_REQUEST_WORKSPACE_FOLDERS:
@@ -544,6 +546,12 @@ static void write_request(LSP *lsp, LSPRequest *request) {
write_document_position(o, def->position);
write_obj_end(o);
} break;
+ case LSP_REQUEST_HIGHLIGHT: {
+ const LSPRequestHighlight *hl = &request->data.highlight;
+ write_key_obj_start(o, "params");
+ write_document_position(o, hl->position);
+ write_obj_end(o);
+ } break;
case LSP_REQUEST_RENAME: {
const LSPRequestRename *rename = &request->data.rename;
write_key_obj_start(o, "params");
diff --git a/lsp.c b/lsp.c
index 253d465..23b1023 100644
--- a/lsp.c
+++ b/lsp.c
@@ -52,6 +52,7 @@ static void lsp_request_free(LSPRequest *r) {
case LSP_REQUEST_SIGNATURE_HELP:
case LSP_REQUEST_HOVER:
case LSP_REQUEST_DEFINITION:
+ case LSP_REQUEST_HIGHLIGHT:
case LSP_REQUEST_DID_CLOSE:
case LSP_REQUEST_WORKSPACE_FOLDERS:
case LSP_REQUEST_JDTLS_CONFIGURATION:
@@ -103,6 +104,9 @@ static void lsp_response_free(LSPResponse *r) {
case LSP_REQUEST_RENAME:
arr_free(r->data.rename.changes);
break;
+ case LSP_REQUEST_HIGHLIGHT:
+ arr_free(r->data.highlight.highlights);
+ break;
default:
break;
}
@@ -176,6 +180,8 @@ static bool lsp_supports_request(LSP *lsp, const LSPRequest *request) {
return cap->workspace_symbols_support;
case LSP_REQUEST_RENAME:
return cap->rename_support;
+ case LSP_REQUEST_HIGHLIGHT:
+ return cap->highlight_support;
}
assert(0);
return false;
@@ -204,6 +210,7 @@ static bool request_type_is_notification(LSPRequestType type) {
case LSP_REQUEST_SHOW_MESSAGE:
case LSP_REQUEST_LOG_MESSAGE:
case LSP_REQUEST_COMPLETION:
+ case LSP_REQUEST_HIGHLIGHT:
case LSP_REQUEST_SIGNATURE_HELP:
case LSP_REQUEST_HOVER:
case LSP_REQUEST_DEFINITION:
diff --git a/lsp.h b/lsp.h
index e9278a7..d52c20b 100644
--- a/lsp.h
+++ b/lsp.h
@@ -52,7 +52,7 @@ typedef enum {
LSP_REQUEST_SIGNATURE_HELP, // textDocument/signatureHelp
LSP_REQUEST_HOVER, // textDocument/hover
LSP_REQUEST_DEFINITION, // textDocument/definition
- //LSP_REQUEST_HIGHLIGHT,
+ LSP_REQUEST_HIGHLIGHT, // textDocument/documentHighlight
LSP_REQUEST_RENAME, // textDocument/rename
LSP_REQUEST_WORKSPACE_SYMBOLS, // workspace/symbol
LSP_REQUEST_DID_CHANGE_WORKSPACE_FOLDERS, // workspace/didChangeWorkspaceFolders
@@ -150,6 +150,10 @@ typedef struct {
} LSPRequestDefinition;
typedef struct {
+ LSPDocumentPosition position;
+} LSPRequestHighlight;
+
+typedef struct {
char *query;
} LSPRequestWorkspaceSymbols;
@@ -177,6 +181,7 @@ typedef struct {
LSPRequestSignatureHelp signature_help;
LSPRequestHover hover;
LSPRequestDefinition definition;
+ LSPRequestHighlight highlight;
LSPRequestWorkspaceSymbols workspace_symbols;
// LSP_REQUEST_SHOW_MESSAGE or LSP_REQUEST_LOG_MESSAGE
LSPRequestMessage message;
@@ -329,6 +334,23 @@ typedef struct {
} LSPResponseDefinition;
typedef enum {
+#define LSP_HIGHLIGHT_MIN 1
+ LSP_HIGHLIGHT_TEXT = 1,
+ LSP_HIGHLIGHT_READ = 2,
+ LSP_HIGHLIGHT_WRITE = 3,
+#define LSP_HIGHLIGHT_MAX 3
+} LSPHighlightKind;
+
+typedef struct {
+ LSPRange range;
+ LSPHighlightKind kind;
+} LSPHighlight;
+
+typedef struct {
+ LSPHighlight *highlights;
+} LSPResponseHighlight;
+
+typedef enum {
#define LSP_SYMBOL_TAG_MIN 1
LSP_SYMBOL_TAG_DEPRECATED = 1
#define LSP_SYMBOL_TAG_MAX 1
@@ -409,6 +431,7 @@ typedef struct {
LSPResponseDefinition definition;
LSPResponseWorkspaceSymbols workspace_symbols;
LSPResponseRename rename;
+ LSPResponseHighlight highlight;
} data;
} LSPResponse;
@@ -431,6 +454,7 @@ typedef struct {
bool hover_support;
bool definition_support;
bool workspace_symbols_support;
+ bool highlight_support;
// support for multiple root folders
// sadly, as of me writing this, clangd and rust-analyzer don't support this
// (but jdtls and gopls do)
diff --git a/main.c b/main.c
index 4c380ea..daf483f 100644
--- a/main.c
+++ b/main.c
@@ -39,6 +39,7 @@ FUTURE FEATURES:
- :set-build-command
- document links using LSP textDocument/documentLink request
- rename using LSP (textDocument/rename)
+ - we have request writing & response parsing support for it, but that hasn't been tested yet
- i'm putting this off for now since it seems hard to have undo support for it.
- add numlock as a key modifier? (but make sure "Ctrl+S" handles both "No NumLock+Ctrl+S" and "NumLock+Ctrl+S")
- better undo chaining (dechain on backspace?)
@@ -153,6 +154,7 @@ bool tag_goto(Ted *ted, char const *tag);
#include "ide-signature-help.c"
#include "ide-hover.c"
#include "ide-definitions.c"
+#include "ide-highlights.c"
#include "command.c"
#include "config.c"
#include "session.c"
@@ -1152,7 +1154,9 @@ int main(int argc, char **argv) {
if (ted->menu)
menu_close(ted);
hover_close(ted);
+ signature_help_close(ted);
autocomplete_close(ted);
+ highlights_close(ted);
session_write(ted);
for (int i = 0; i < TED_LSP_MAX; ++i) {
diff --git a/ted.h b/ted.h
index 5acbba4..7a3dddd 100644
--- a/ted.h
+++ b/ted.h
@@ -437,6 +437,10 @@ typedef struct {
SymbolInfo *selector_all_definitions; // an array of all definitions
} Definitions;
+typedef struct {
+ LSPHighlight *highlights;
+ LSPRequestID last_request_id;
+} Highlights;
typedef struct Ted {
LSP *lsps[TED_LSP_MAX + 1];
@@ -494,6 +498,7 @@ typedef struct Ted {
SignatureHelp signature_help;
Hover hover;
Definitions definitions;
+ Highlights highlights;
FILE *log;