Skip to content

Commit

Permalink
More lsp protocol/transport work
Browse files Browse the repository at this point in the history
  • Loading branch information
abbec committed Oct 10, 2024
1 parent 370c70d commit ccc3a30
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 45 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ ASAN ?= false
.endif

.if $(LSP_ENABLE) == true
HEADERS += src/dged/lsp.h src/main/lsp.h src/dged/json.h
SOURCES += src/dged/lsp.c src/dged/json.c
HEADERS += src/dged/lsp.h src/main/lsp.h src/dged/json.h src/dged/jsonrpc.h
SOURCES += src/dged/lsp.c src/dged/json.c src/dged/jsonrpc.c
MAIN_SOURCES += src/main/lsp.c
TEST_SOURCES += test/json.c
CFLAGS += -DLSP_ENABLED
Expand Down
15 changes: 12 additions & 3 deletions src/dged/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,7 @@ uint64_t json_len(struct json_object *obj) {
return HASHMAP_SIZE(&obj->members);
}

uint64_t json_empty(struct json_object *obj) {
return json_len(obj) == 0;
}
bool json_empty(struct json_object *obj) { return json_len(obj) == 0; }

bool json_contains(struct json_object *obj, struct s8 key) {
// TODO: get rid of alloc
Expand All @@ -346,3 +344,14 @@ struct json_value *json_get(struct json_object *obj, struct s8 key) {

return result;
}

void json_set(struct json_object *obj, struct s8 key_, struct json_value val) {
// TODO: get rid of alloc
char *k = s8tocstr(key_);
uint32_t hash = 0;
HASHMAP_INSERT(&obj->members, struct json_object_member, k, val, hash);

(void)hash;
(void)key;
free(k);
}
11 changes: 10 additions & 1 deletion src/dged/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void json_destroy(struct json_value *value);
*
* @returns True if @ref obj is empty, false otherwise.
*/
void json_empty(struct json_object *obj);
bool json_empty(struct json_object *obj);

/**
* Return the number of members in a JSON object.
Expand Down Expand Up @@ -93,6 +93,15 @@ bool json_contains(struct json_object *obj, struct s8 key);
*/
struct json_value *json_get(struct json_object *obj, struct s8 key);

/**
* Set a value in a JSON object.
*
* @param [in] obj The JSON object to set in.
* @param [in] key The key of the value to set.
* @param [in] value The JSON value to set.
*/
void json_set(struct json_object *obj, struct s8 key, struct json_value val);

/**
* Get the length of a JSON array.
*
Expand Down
25 changes: 25 additions & 0 deletions src/dged/jsonrpc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "jsonrpc.h"

#include <stddef.h>

struct jsonrpc_request jsonrpc_request_create(struct json_value id,
struct s8 method,
struct json_object *params) {
return (struct jsonrpc_request){
.id = id,
.method = method,
.params = params,
};
}

struct jsonrpc_response jsonrpc_parse_response(const uint8_t *buf,
uint64_t size) {
(void)buf;
(void)size;
return (struct jsonrpc_response){};
}

struct s8 jsonrpc_request_to_string(const struct jsonrpc_request *request) {
(void)request;
return (struct s8){.l = 0, .s = NULL};
}
23 changes: 14 additions & 9 deletions src/dged/jsonrpc.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef _JSONRPC_H
#define _JSONRPC_H

#include <stdint.h>

#include "json.h"
#include "s8.h"

Expand All @@ -10,6 +12,12 @@ struct jsonrpc_request {
struct json_object *params;
};

struct jsonrpc_error {
int code;
struct s8 message;
struct json_value data;
};

struct jsonrpc_response {
struct json_value id;
bool ok;
Expand All @@ -19,14 +27,11 @@ struct jsonrpc_response {
} value;
};

struct jsonrpc_error {
int code;
struct s8 message;
struct json_value data;
};

struct jsonrpc_request jsonrpc_request_create(struct s8 method, struct json_object *params);
struct jsonrpc_response jsonrpc_parse_response(const uint8_t *buf, uint64_t size);
struct s8 jsonrpc_request_to_string(const struct jsonprc_request *request);
struct jsonrpc_request jsonrpc_request_create(struct json_value id,
struct s8 method,
struct json_object *params);
struct jsonrpc_response jsonrpc_parse_response(const uint8_t *buf,
uint64_t size);
struct s8 jsonrpc_request_to_string(const struct jsonrpc_request *request);

#endif
93 changes: 93 additions & 0 deletions src/dged/lsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,25 @@
#include <unistd.h>

#include "buffer.h"
#include "jsonrpc.h"
#include "process.h"
#include "reactor.h"

struct pending_write {
char headers[256];
uint64_t headers_len;
uint64_t request_id;
uint64_t written;
struct s8 payload;
};

struct pending_read {
uint64_t request_id;
struct s8 payload;
};

typedef VEC(struct pending_write) write_vec;

struct lsp {
const char *name;
char *const *command;
Expand All @@ -19,6 +35,11 @@ struct lsp {
uint32_t stdin_event;
uint32_t stdout_event;
uint32_t stderr_event;

request_id current_id;

write_vec writes;
VEC(struct pending_read) reads;
};

struct lsp *lsp_create(char *const command[], struct reactor *reactor,
Expand Down Expand Up @@ -65,6 +86,7 @@ struct lsp *lsp_create(char *const command[], struct reactor *reactor,
lsp->stdin_event = -1;
lsp->stdout_event = -1;
lsp->stderr_event = -1;
lsp->current_id = 0;

return lsp;
}
Expand Down Expand Up @@ -109,6 +131,49 @@ uint32_t lsp_update(struct lsp *lsp, struct lsp_response **responses,
}
}

// write pending requests
if (reactor_poll_event(lsp->reactor, lsp->stdin_event)) {
VEC_FOR_EACH(&lsp->writes, struct pending_write * w) {
size_t written = 0;
uint64_t to_write = 0;
if (w->written < w->headers_len) {
to_write = w->headers_len - w->written;
written = write(lsp->process->stdin, w->headers + w->written, to_write);
} else {
to_write = w->payload.l + w->headers_len - w->written;
written = write(lsp->process->stdin, w->payload.s, to_write);

if (to_write == written) {
VEC_APPEND(&lsp->reads, struct pending_read * r);
r->request_id = w->request_id;
}
}

w->written += written;

// if this happens, we ran out of buffer space
if (written < to_write) {
goto cleanup_writes;
}
}
}

cleanup_writes:
/* lsp->writes = filter(&lsp->writes, x: x.written < x.payload.l +
* x.headers_len) */
write_vec writes = lsp->writes;
VEC_INIT(&lsp->writes, VEC_SIZE(&writes));

VEC_FOR_EACH(&writes, struct pending_write * w) {
if (w->written < w->payload.l + w->headers_len) {
// copying 256 bytes, goodbye vaccuum tubes...
VEC_PUSH(&lsp->writes, *w);
}
}
VEC_DESTROY(&writes);

// TODO: process incoming responses

return 0;
}

Expand All @@ -125,6 +190,12 @@ int lsp_start_server(struct lsp *lsp) {
memcpy(lsp->process, &p, sizeof(struct process));
lsp->stderr_event = reactor_register_interest(
lsp->reactor, lsp->process->stderr, ReadInterest);
lsp->stdin_event = reactor_register_interest(
lsp->reactor, lsp->process->stdin, WriteInterest);

if (lsp->stdin_event == (uint32_t)-1) {
return -2;
}

return 0;
}
Expand Down Expand Up @@ -161,3 +232,25 @@ uint64_t lsp_server_pid(const struct lsp *lsp) {
}

const char *lsp_server_name(const struct lsp *lsp) { return lsp->name; }

request_id lsp_request(struct lsp *lsp, struct lsp_request request) {
struct json_value js_id = {
.type = Json_Number,
.value.number = (double)lsp->current_id,
.parent = NULL,
};

struct jsonrpc_request req =
jsonrpc_request_create(js_id, request.method, request.params);
struct s8 payload = jsonrpc_request_to_string(&req);

VEC_APPEND(&lsp->writes, struct pending_write * w);
w->headers_len =
snprintf(w->headers, 256, "Content-Length: %d\r\n\r\n", payload.l);
w->request_id = lsp->current_id;
w->payload = payload;

++lsp->current_id;

return w->request_id;
}
43 changes: 13 additions & 30 deletions src/dged/lsp.h
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
#ifndef _LSP_H
#define _LSP_H

#include "json.h"
#include "location.h"
#include "s8.h"

struct buffer;
struct lsp;
struct reactor;

typedef uint32_t request_id;
typedef uint64_t request_id;

struct lsp_response_error {};

struct lsp_response {
request_id id;

bool ok;
union payload_data {
void *result;
struct s8 error;
struct json_value result;
struct lsp_response_error error;
} payload;
};

struct lsp_request {
struct s8 method;
struct json_object *params;
};

struct lsp_notification {
int something;
};
Expand All @@ -27,30 +36,6 @@ struct lsp_client {
void (*log_message)(int type, struct s8 msg);
};

struct hover {
struct s8 contents;

bool has_range;
struct region *range;
};

struct text_doc_item {
struct s8 uri;
struct s8 language_id;
uint32_t version;
struct s8 text;
};

struct text_doc_position {
struct s8 uri;
struct location pos;
};

struct initialize_params {
struct s8 client_name;
struct s8 client_version;
};

// lifecycle functions
struct lsp *lsp_create(char *const command[], struct reactor *reactor,
struct buffer *stderr_buffer,
Expand All @@ -68,8 +53,6 @@ uint64_t lsp_server_pid(const struct lsp *lsp);
const char *lsp_server_name(const struct lsp *lsp);

// protocol functions
void lsp_initialize(struct lsp *lsp, struct initialize_params);
void lsp_did_open_document(struct lsp *lsp, struct text_doc_item document);
request_id lsp_hover(struct lsp *lsp, struct text_doc_position);
request_id lsp_request(struct lsp *lsp, struct lsp_request request);

#endif

0 comments on commit ccc3a30

Please sign in to comment.