summaryrefslogtreecommitdiff
path: root/lsp.h
diff options
context:
space:
mode:
Diffstat (limited to 'lsp.h')
-rw-r--r--lsp.h293
1 files changed, 293 insertions, 0 deletions
diff --git a/lsp.h b/lsp.h
new file mode 100644
index 0000000..1c6076a
--- /dev/null
+++ b/lsp.h
@@ -0,0 +1,293 @@
+// @TODO:
+// - use document IDs instead of strings (also lets us use real document version numbers)
+// - document this and lsp.c.
+// - deal with "Save as" (generate didOpen)
+// - maximum queue size for requests/responses just in case?
+// - delete old sent requests
+// (if the server never sends a response)
+// - TESTING: make rust-analyzer-slow (waits 10s before sending response)
+
+typedef u32 LSPDocumentID;
+
+typedef enum {
+ LSP_REQUEST,
+ LSP_RESPONSE
+} LSPMessageType;
+
+typedef struct {
+ u32 offset;
+} LSPString;
+
+typedef struct {
+ u32 line;
+ // NOTE: this is the UTF-16 character index!
+ u32 character;
+} LSPPosition;
+
+typedef struct {
+ LSPPosition start;
+ LSPPosition end;
+} LSPRange;
+
+typedef enum {
+ LSP_REQUEST_NONE,
+
+ // client-to-server
+ LSP_REQUEST_INITIALIZE,
+ LSP_REQUEST_INITIALIZED,
+ LSP_REQUEST_DID_OPEN,
+ LSP_REQUEST_DID_CLOSE,
+ LSP_REQUEST_DID_CHANGE,
+ LSP_REQUEST_COMPLETION,
+ LSP_REQUEST_SHUTDOWN,
+ LSP_REQUEST_EXIT,
+
+ // server-to-client
+ LSP_REQUEST_SHOW_MESSAGE,
+ LSP_REQUEST_LOG_MESSAGE,
+} LSPRequestType;
+
+typedef struct {
+ Language language;
+ LSPDocumentID document;
+ // freed by lsp_request_free
+ char *file_contents;
+} LSPRequestDidOpen;
+
+typedef struct {
+ LSPDocumentID document;
+} LSPRequestDidClose;
+
+// see TextDocumentContentChangeEvent in the LSP spec
+typedef struct {
+ LSPRange range;
+ // new text. will be freed. you can use NULL for the empty string.
+ char *text;
+} LSPDocumentChangeEvent;
+
+typedef struct {
+ LSPDocumentID document;
+ LSPDocumentChangeEvent *changes; // dynamic array
+} LSPRequestDidChange;
+
+typedef enum {
+ ERROR = 1,
+ WARNING = 2,
+ INFO = 3,
+ LOG = 4
+} LSPWindowMessageType;
+
+typedef struct {
+ LSPWindowMessageType type;
+ // freed by lsp_request_free
+ char *message;
+} LSPRequestMessage;
+
+typedef struct {
+ LSPDocumentID document;
+ LSPPosition pos;
+} LSPDocumentPosition;
+
+typedef struct {
+ LSPDocumentPosition position;
+} LSPRequestCompletion;
+
+typedef struct {
+ // id is set by lsp.c; you shouldn't set it.
+ u32 id;
+ LSPRequestType type;
+ union {
+ LSPRequestDidOpen open;
+ LSPRequestDidClose close;
+ LSPRequestDidChange change;
+ LSPRequestCompletion completion;
+ // for LSP_SHOW_MESSAGE and LSP_LOG_MESSAGE
+ LSPRequestMessage message;
+ } data;
+} LSPRequest;
+
+typedef enum {
+ // LSP doesn't actually define this but this will be used for unrecognized values
+ // (in case they add more symbol kinds in the future)
+ LSP_SYMBOL_OTHER = 0,
+
+ #define LSP_SYMBOL_KIND_MIN 1
+ LSP_SYMBOL_FILE = 1,
+ LSP_SYMBOL_MODULE = 2,
+ LSB_SYMBOL_NAMESPACE = 3,
+ LSP_SYMBOL_PACKAGE = 4,
+ LSP_SYMBOL_CLASS = 5,
+ LSP_SYMBOL_METHOD = 6,
+ LSP_SYMBOL_PROPERTY = 7,
+ LSP_SYMBOL_FIELD = 8,
+ LSP_SYMBOL_CONSTRUCTOR = 9,
+ LSP_SYMBOL_ENUM = 10,
+ LSP_SYMBOL_INTERFACE = 11,
+ LSP_SYMBOL_FUNCTION = 12,
+ LSP_SYMBOL_VARIABLE = 13,
+ LSP_SYMBOL_CONSTANT = 14,
+ LSP_SYMBOL_STRING = 15,
+ LSP_SYMBOL_NUMBER = 16,
+ LSP_SYMBOL_BOOLEAN = 17,
+ LSP_SYMBOL_ARRAY = 18,
+ LSP_SYMBOL_OBJECT = 19,
+ LSP_SYMBOL_KEY = 20,
+ LSP_SYMBOL_NULL = 21,
+ LSP_SYMBOL_ENUMMEMBER = 22,
+ LSP_SYMBOL_STRUCT = 23,
+ LSP_SYMBOL_EVENT = 24,
+ LSP_SYMBOL_OPERATOR = 25,
+ LSP_SYMBOL_TYPEPARAMETER = 26,
+ #define LSP_SYMBOL_KIND_MAX 26
+} LSPSymbolKind;
+
+typedef enum {
+ #define LSP_COMPLETION_KIND_MIN 1
+ LSP_COMPLETION_TEXT = 1,
+ LSP_COMPLETION_METHOD = 2,
+ LSP_COMPLETION_FUNCTION = 3,
+ LSP_COMPLETION_CONSTRUCTOR = 4,
+ LSP_COMPLETION_FIELD = 5,
+ LSP_COMPLETION_VARIABLE = 6,
+ LSP_COMPLETION_CLASS = 7,
+ LSP_COMPLETION_INTERFACE = 8,
+ LSP_COMPLETION_MODULE = 9,
+ LSP_COMPLETION_PROPERTY = 10,
+ LSP_COMPLETION_UNIT = 11,
+ LSP_COMPLETION_VALUE = 12,
+ LSP_COMPLETION_ENUM = 13,
+ LSP_COMPLETION_KEYWORD = 14,
+ LSP_COMPLETION_SNIPPET = 15,
+ LSP_COMPLETION_COLOR = 16,
+ LSP_COMPLETION_FILE = 17,
+ LSP_COMPLETION_REFERENCE = 18,
+ LSP_COMPLETION_FOLDER = 19,
+ LSP_COMPLETION_ENUMMEMBER = 20,
+ LSP_COMPLETION_CONSTANT = 21,
+ LSP_COMPLETION_STRUCT = 22,
+ LSP_COMPLETION_EVENT = 23,
+ LSP_COMPLETION_OPERATOR = 24,
+ LSP_COMPLETION_TYPEPARAMETER = 25,
+ #define LSP_COMPLETION_KIND_MAX 25
+} LSPCompletionKind;
+
+
+// see InsertTextFormat in the LSP spec.
+typedef enum {
+ // plain text
+ LSP_TEXT_EDIT_PLAIN = 1,
+ // snippet e.g. "some_method($1, $2)$0"
+ LSP_TEXT_EDIT_SNIPPET = 2
+} LSPTextEditType;
+
+typedef struct {
+ LSPTextEditType type;
+
+ // if set to true, `range` should be ignored
+ // -- this is a completion which uses insertText.
+ // how to handle this:
+ // "VS Code when code complete is requested in this example
+ // `con<cursor position>` and a completion item with an `insertText` of
+ // `console` is provided it will only insert `sole`"
+ bool at_cursor;
+
+ LSPRange range;
+ LSPString new_text;
+} LSPTextEdit;
+
+typedef struct {
+ // display text for this completion
+ LSPString label;
+ // text used to filter completions
+ LSPString filter_text;
+ // more detail for this item, e.g. the signature of a function
+ LSPString detail;
+ // documentation for this item (typically from a doc comment)
+ LSPString documentation;
+ // the edit to be applied when this completion is selected.
+ LSPTextEdit text_edit;
+ // note: the items are sorted here in this file,
+ // so you probably don't need to access this.
+ LSPString sort_text;
+ // is this function/type/whatever deprecated?
+ bool deprecated;
+ // type of completion
+ LSPCompletionKind kind;
+} LSPCompletionItem;
+
+typedef struct {
+ // dynamic array
+ LSPCompletionItem *items;
+} LSPResponseCompletion;
+
+typedef LSPRequestType LSPResponseType;
+typedef struct {
+ LSPRequest request; // the request which this is a response to
+ // LSP responses tend to have a lot of strings.
+ // to avoid doing a ton of allocations+frees,
+ // they're all stored here.
+ char *string_data;
+ union {
+ LSPResponseCompletion completion;
+ } data;
+} LSPResponse;
+
+typedef struct {
+ LSPMessageType type;
+ union {
+ LSPRequest request;
+ LSPResponse response;
+ } u;
+} LSPMessage;
+
+typedef struct {
+ char *path;
+ u32 version_number; // for LSP
+} LSPDocumentData;
+
+typedef struct LSP {
+ Process process;
+ u32 request_id;
+ StrHashTable document_ids; // values are u32. they are indices into document_data.
+ // this is a dynamic array which just keeps growing.
+ // but the user isn't gonna open millions of files so it's fine.
+ LSPDocumentData *document_data;
+ LSPMessage *messages;
+ SDL_mutex *messages_mutex;
+ LSPRequest *requests_client2server;
+ LSPRequest *requests_server2client;
+ // we keep track of client-to-server requests
+ // so that we can process responses.
+ // also fucking rust-analyzer gives "waiting for cargo metadata or cargo check"
+ // WHY NOT JUST WAIT UNTIL YOUVE DONE THAT BEFORE SENDING THE INITIALIZE RESPONSE. YOU HAVE NOT FINISHED INITIALIZATION. YOU ARE LYING.
+ // YOU GIVE A -32801 ERROR CODE WHICH IS "ContentModified" -- WHAT THE FUCK? THATS JUST COMPLETLY WRONG
+ // so we need to re-send requests in that case.
+ LSPRequest *requests_sent;
+ SDL_mutex *requests_mutex;
+ bool initialized; // has the response to the initialize request been sent?
+ SDL_Thread *communication_thread;
+ SDL_sem *quit_sem;
+ char *received_data; // dynamic array
+ bool provides_completion; // can this LSP server handle completion requests?
+ char32_t *trigger_chars; // dynamic array of "trigger characters"
+ SDL_mutex *error_mutex;
+ char error[256];
+} LSP;
+
+// @TODO: function declarations
+
+// returns true if there's an error.
+// returns false and sets error to "" if there's no error.
+// if clear = true, the error will be cleared.
+// you can set error = NULL, error_size = 0, clear = true to just clear the error
+bool lsp_get_error(LSP *lsp, char *error, size_t error_size, bool clear);
+void lsp_message_free(LSPMessage *message);
+u32 lsp_document_id(LSP *lsp, const char *path);
+void lsp_send_request(LSP *lsp, const LSPRequest *request);
+const char *lsp_response_string(const LSPResponse *response, LSPString string);
+bool lsp_create(LSP *lsp, const char *analyzer_command);
+bool lsp_next_message(LSP *lsp, LSPMessage *message);
+void lsp_document_changed(LSP *lsp, const char *document, LSPDocumentChangeEvent change);
+void lsp_free(LSP *lsp);
+SymbolKind lsp_symbol_kind_to_ted(LSPSymbolKind kind);
+SymbolKind lsp_completion_kind_to_ted(LSPCompletionKind kind);