Notification support
This commit is contained in:
parent
64db0526ad
commit
297c8f800e
7 changed files with 286 additions and 102 deletions
3
Makefile
3
Makefile
|
|
@ -17,7 +17,8 @@ INCLUDES= \
|
||||||
SRCS= \
|
SRCS= \
|
||||||
libraries/cJSON/cJSON.c \
|
libraries/cJSON/cJSON.c \
|
||||||
src/json_rpc.c \
|
src/json_rpc.c \
|
||||||
src/main.c
|
src/main.c \
|
||||||
|
src/pawn_lsp.c
|
||||||
|
|
||||||
OBJS=$(addprefix $(BUILD_DIR)/,$(addsuffix .o,$(basename $(SRCS))))
|
OBJS=$(addprefix $(BUILD_DIR)/,$(addsuffix .o,$(basename $(SRCS))))
|
||||||
DEPS=$(addprefix $(BUILD_DIR)/,$(addsuffix .d,$(basename $(SRCS))))
|
DEPS=$(addprefix $(BUILD_DIR)/,$(addsuffix .d,$(basename $(SRCS))))
|
||||||
|
|
|
||||||
180
src/json_rpc.c
180
src/json_rpc.c
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "cJSON/cJSON.h"
|
#include "cJSON/cJSON.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "lsp.h"
|
||||||
#include "json_rpc.h"
|
#include "json_rpc.h"
|
||||||
|
|
||||||
static void _service_request(json_rpc_t *jrpc);
|
static void _service_request(json_rpc_t *jrpc);
|
||||||
|
|
@ -39,12 +40,22 @@ json_rpc_init(json_rpc_t *jrpc, int infd, int outfd)
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
json_rpc_add_method(json_rpc_t *jrpc, const char *method,
|
json_rpc_set_request_handler(json_rpc_t *jrpc,
|
||||||
int (*callback)(json_rpc_request_t *req, cJSON **response, void *arg),
|
int (*callback)(json_rpc_request_t *req, cJSON **resp, void *arg),
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
return (-1);
|
jrpc->req_handler.callback = callback;
|
||||||
|
jrpc->req_handler.arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
json_rpc_set_notify_handler(json_rpc_t *jrpc,
|
||||||
|
void (*callback)(json_rpc_request_t *req, void *arg),
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
jrpc->notf_handler.callback = callback;
|
||||||
|
jrpc->notf_handler.arg = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -73,12 +84,6 @@ json_rpc_run(json_rpc_t *jrpc)
|
||||||
|
|
||||||
sched_yield();
|
sched_yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
free(jrpc->buf);
|
|
||||||
for (size_t i = 0; i < jrpc->method_cnt; i++) {
|
|
||||||
free(jrpc->methods[i].method);
|
|
||||||
}
|
|
||||||
free(jrpc->methods);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -89,68 +94,88 @@ json_rpc_cancel(json_rpc_t *jrpc)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
_read_headers(int fd, char *buf, size_t len, size_t *content_len, char **content_type)
|
||||||
|
{
|
||||||
|
size_t p = 0;
|
||||||
|
|
||||||
|
(*content_len) = 0;
|
||||||
|
(*content_type) = NULL;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
size_t rlen = _read_until(fd, &buf[p], len - p, '\n', 1000);
|
||||||
|
|
||||||
|
if ((rlen < 2) || (buf[p + rlen - 1] != '\n')) {
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "Content-Length: <val>\r\n" */
|
||||||
|
if ((rlen > 18) && (!memcmp(&buf[p], "Content-Length: ", 16))) {
|
||||||
|
(*content_len) = strtoul(&buf[p + 16], NULL, 10);
|
||||||
|
}
|
||||||
|
/* "Content-Type: <val>\r\n" */
|
||||||
|
else if ((rlen > 16) && (!memcmp(&buf[p], "Content-Type: ", 14))) {
|
||||||
|
(*content_type) = &buf[p + 14];
|
||||||
|
buf[p + rlen - 2] = '\0';
|
||||||
|
}
|
||||||
|
else if (rlen == 2) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
p += rlen;
|
||||||
|
if (p >= len) {
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_service_request(json_rpc_t *jrpc)
|
_service_request(json_rpc_t *jrpc)
|
||||||
{
|
{
|
||||||
char *buf = jrpc->buf;
|
char headers[1024] = { 0 };
|
||||||
char *len_str;
|
size_t content_length = 0;
|
||||||
char *content;
|
char *content_type = NULL;
|
||||||
size_t p = 0;
|
size_t rlen;
|
||||||
size_t ret;
|
|
||||||
long content_len;
|
|
||||||
json_rpc_request_t request;
|
json_rpc_request_t request;
|
||||||
|
|
||||||
/* read Content-Length: ...\r\n */
|
if (_read_headers(jrpc->infd, headers, sizeof(headers), &content_length, &content_type)) {
|
||||||
ret = _read_bytes(jrpc->infd, &buf[p], 16, 1000);
|
log_error("Failed to read/parse headers\r\n");
|
||||||
if ((ret != 16) || (memcmp(&buf[p], "Content-Length: ", 16))) {
|
|
||||||
log_error("Failed to read request header\r\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
p += ret;
|
log_info("Request { length: %ld, type: %s }\r\n", content_length, content_type);
|
||||||
len_str = &buf[p];
|
if (content_length == 0) {
|
||||||
|
log_error("Content-Length of 0\r\n");
|
||||||
ret = _read_until(jrpc->infd, &buf[p], jrpc->bufsz - p, '\n', 1000);
|
return;
|
||||||
p += ret;
|
}
|
||||||
if ((ret == 0) || (buf[p-1] != '\n')) {
|
else if (content_length > jrpc->bufsz) {
|
||||||
log_error("Failed to read content length value\r\n");
|
log_error("Content length too long!\r\n");
|
||||||
|
while (content_length > 0) {
|
||||||
|
size_t rlen = content_length > jrpc->bufsz ? jrpc->bufsz : content_length;
|
||||||
|
rlen = _read_bytes(jrpc->infd, jrpc->buf, rlen, 1000);
|
||||||
|
content_length -= rlen;
|
||||||
|
if (rlen == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* TODO error response */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
content_len = strtol(len_str, NULL, 10);
|
memset(jrpc->buf, 0, jrpc->bufsz);
|
||||||
if (content_len < 0) {
|
rlen = _read_bytes(jrpc->infd, jrpc->buf, content_length, 1000);
|
||||||
log_warn("Invalid content length %ld\r\n", content_len);
|
if (rlen != content_length) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (content_len > (jrpc->bufsz - p - 3)) {
|
|
||||||
log_warn("Content too long (%ld)\r\n", content_len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read empty CRLF */
|
|
||||||
ret = _read_bytes(jrpc->infd, &buf[p], 2, 1000);
|
|
||||||
if (ret != 2) {
|
|
||||||
log_error("Failed to read blank line\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p += ret;
|
|
||||||
|
|
||||||
content = &buf[p];
|
|
||||||
ret = _read_bytes(jrpc->infd, &buf[p], content_len, 1000);
|
|
||||||
if (ret != content_len) {
|
|
||||||
log_error("Failed to read all of content, exp %ld, got %ld\r\n",
|
log_error("Failed to read all of content, exp %ld, got %ld\r\n",
|
||||||
content_len, ret);
|
content_length, rlen);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p += ret;
|
|
||||||
buf[p] = '\0';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* JSON parsing */
|
/* JSON parsing */
|
||||||
request.request = cJSON_Parse(content);
|
request.request = cJSON_Parse(jrpc->buf);
|
||||||
if ((!request.request) || (!cJSON_IsObject(request.request))) {
|
if ((!request.request) || (!cJSON_IsObject(request.request))) {
|
||||||
log_error("Failed to parse request %s\r\n", buf);
|
log_error("Failed to parse request %s\r\n", jrpc->buf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,8 +189,9 @@ _service_request(json_rpc_t *jrpc)
|
||||||
}
|
}
|
||||||
|
|
||||||
request.id = cJSON_GetObjectItem(request.request, "id");
|
request.id = cJSON_GetObjectItem(request.request, "id");
|
||||||
if ((!request.id) ||
|
if ((request.id != NULL) &&
|
||||||
((!cJSON_IsNumber(request.id)) && (!cJSON_IsString(request.id)))) {
|
(!cJSON_IsNumber(request.id)) &&
|
||||||
|
(!cJSON_IsString(request.id))) {
|
||||||
log_error("Invalid ID format\r\n");
|
log_error("Invalid ID format\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -177,19 +203,19 @@ _service_request(json_rpc_t *jrpc)
|
||||||
}
|
}
|
||||||
|
|
||||||
request.params = cJSON_GetObjectItem(request.request, "params");
|
request.params = cJSON_GetObjectItem(request.request, "params");
|
||||||
if (request.params) {
|
if ((request.params != NULL) &&
|
||||||
if ((!cJSON_IsArray(request.params)) && (!cJSON_IsObject(request.params))) {
|
(!cJSON_IsArray(request.params)) &&
|
||||||
log_error("Invalid params format\r\n");
|
(!cJSON_IsObject(request.params))) {
|
||||||
return;
|
log_error("Invalid params format\r\n");
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (request.id) {
|
||||||
|
/* Request */
|
||||||
cJSON *response = cJSON_CreateObject();
|
cJSON *response = cJSON_CreateObject();
|
||||||
cJSON *val = NULL;
|
cJSON *val = NULL;
|
||||||
cJSON *body = NULL;
|
cJSON *body = NULL;
|
||||||
const char *resp_token = "error";
|
const char *resp_token = "error";
|
||||||
json_rpc_method_t *method = NULL;
|
|
||||||
|
|
||||||
if (response == NULL) {
|
if (response == NULL) {
|
||||||
cJSON_Delete(request.request);
|
cJSON_Delete(request.request);
|
||||||
|
|
@ -207,24 +233,14 @@ _service_request(json_rpc_t *jrpc)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < jrpc->method_cnt; i++) {
|
if (cJSON_AddStringToObject(response, "jsonrpc", "2.0") == NULL) {
|
||||||
if (!strcmp(jrpc->methods[i].method, request.method->valuestring)) {
|
cJSON_Delete(response);
|
||||||
method = &jrpc->methods[i];
|
cJSON_Delete(request.request);
|
||||||
break;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!method) {
|
if (jrpc->req_handler.callback(&request, &body, jrpc->req_handler.arg) == 0) {
|
||||||
log_warn("No handler for method \"%s\"\r\n", request.method->valuestring);
|
resp_token = "result";
|
||||||
} else if (method->callback(&request, &body, method->arg) == 0) {
|
|
||||||
resp_token = "response";
|
|
||||||
|
|
||||||
if (body == NULL) {
|
|
||||||
log_error("No response body given for successful callback\r\n");
|
|
||||||
cJSON_Delete(response);
|
|
||||||
cJSON_Delete(request.request);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body) {
|
if (body) {
|
||||||
|
|
@ -238,7 +254,7 @@ _service_request(json_rpc_t *jrpc)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cJSON_AddNumberToObject(body, "code", -32601) == NULL) ||
|
if ((cJSON_AddNumberToObject(body, "code", LSP_ERR_MethodNotFound) == NULL) ||
|
||||||
(cJSON_AddStringToObject(body, "message", "Not implemented.") == NULL)) {
|
(cJSON_AddStringToObject(body, "message", "Not implemented.") == NULL)) {
|
||||||
cJSON_Delete(body);
|
cJSON_Delete(body);
|
||||||
cJSON_Delete(response);
|
cJSON_Delete(response);
|
||||||
|
|
@ -269,8 +285,10 @@ _service_request(json_rpc_t *jrpc)
|
||||||
free(resp_str);
|
free(resp_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
cJSON_Delete(body);
|
|
||||||
cJSON_Delete(response);
|
cJSON_Delete(response);
|
||||||
|
} else {
|
||||||
|
/* Notify */
|
||||||
|
jrpc->notf_handler.callback(&request, jrpc->notf_handler.arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
cJSON_Delete(request.request);
|
cJSON_Delete(request.request);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@
|
||||||
typedef struct json_rpc_request_struct {
|
typedef struct json_rpc_request_struct {
|
||||||
/** Base request structure, guaranteed to be an object */
|
/** Base request structure, guaranteed to be an object */
|
||||||
cJSON *request;
|
cJSON *request;
|
||||||
/** Reference to the value of the ID field, guaranteed to be a string or number */
|
/** Reference to the value of the ID field, guaranteed to be a string, or
|
||||||
|
* number for requests, and NULL for notifications. */
|
||||||
cJSON *id;
|
cJSON *id;
|
||||||
/** Reference to the value of the method field, guaranteed to be a string */
|
/** Reference to the value of the method field, guaranteed to be a string */
|
||||||
cJSON *method;
|
cJSON *method;
|
||||||
|
|
@ -18,26 +19,21 @@ typedef struct json_rpc_request_struct {
|
||||||
cJSON *params;
|
cJSON *params;
|
||||||
} json_rpc_request_t;
|
} json_rpc_request_t;
|
||||||
|
|
||||||
typedef struct json_rpc_method_struct {
|
|
||||||
/** "method" field to match on */
|
|
||||||
char *method;
|
|
||||||
/** User arg to pass into callback */
|
|
||||||
void *arg;
|
|
||||||
/** Callback to handle the method - 0 return indicates to send back a
|
|
||||||
* successful result, non-zero will treat the response object as a response
|
|
||||||
* error object */
|
|
||||||
int (*callback)(json_rpc_request_t *req, cJSON **response, void *arg);
|
|
||||||
} json_rpc_method_t;
|
|
||||||
|
|
||||||
typedef struct json_rpc_struct {
|
typedef struct json_rpc_struct {
|
||||||
/** Socket to read requests from */
|
/** Socket to read requests from */
|
||||||
int infd;
|
int infd;
|
||||||
/** Socket to write responses to */
|
/** Socket to write responses to */
|
||||||
int outfd;
|
int outfd;
|
||||||
/** List of methods added */
|
/** Registered request handler info */
|
||||||
json_rpc_method_t *methods;
|
struct {
|
||||||
/** Number of methods added */
|
int (*callback)(json_rpc_request_t *, cJSON **, void *);
|
||||||
size_t method_cnt;
|
void *arg;
|
||||||
|
} req_handler;
|
||||||
|
/** Registered notification handler info */
|
||||||
|
struct {
|
||||||
|
void (*callback)(json_rpc_request_t *, void *);
|
||||||
|
void *arg;
|
||||||
|
} notf_handler;
|
||||||
/** Main server thread */
|
/** Main server thread */
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
/** Allocated buffer for reading requests */
|
/** Allocated buffer for reading requests */
|
||||||
|
|
@ -53,9 +49,13 @@ typedef struct json_rpc_struct {
|
||||||
|
|
||||||
int json_rpc_init(json_rpc_t *jrpc, int infd, int outfd);
|
int json_rpc_init(json_rpc_t *jrpc, int infd, int outfd);
|
||||||
|
|
||||||
int json_rpc_add_method(json_rpc_t *jrpc, const char *method,
|
void json_rpc_set_request_handler(json_rpc_t *jrpc,
|
||||||
int (*callback)(json_rpc_request_t *req, cJSON **response, void *arg),
|
int (*callback)(json_rpc_request_t *req, cJSON **resp, void *arg),
|
||||||
void *arg);
|
void *arg);
|
||||||
|
|
||||||
|
void json_rpc_set_notify_handler(json_rpc_t *jrpc,
|
||||||
|
void (*callback)(json_rpc_request_t *req, void *arg),
|
||||||
|
void *arg);
|
||||||
|
|
||||||
void json_rpc_run(json_rpc_t *jrpc);
|
void json_rpc_run(json_rpc_t *jrpc);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,6 @@
|
||||||
#ifndef _LSP_H_
|
#ifndef _LSP_H_
|
||||||
#define _LSP_H_
|
#define _LSP_H_
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* Ref: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/ */
|
/* Ref: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/ */
|
||||||
|
|
||||||
typedef enum lsp_error_enum {
|
typedef enum lsp_error_enum {
|
||||||
|
|
|
||||||
10
src/main.c
10
src/main.c
|
|
@ -1,14 +1,17 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "json_rpc.h"
|
#include "json_rpc.h"
|
||||||
|
#include "pawn_lsp.h"
|
||||||
|
|
||||||
void sighandler(int signal);
|
void sighandler(int signal);
|
||||||
|
|
||||||
static json_rpc_t jrpc;
|
static json_rpc_t jrpc;
|
||||||
|
static pawn_lsp_t pawn;
|
||||||
|
|
||||||
FILE *logger = NULL;
|
FILE *logger = NULL;
|
||||||
|
|
||||||
|
|
@ -42,11 +45,18 @@ main(int argc, char **argv)
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pawn_lsp_init(&pawn, &jrpc, argv[1], &argv[2], argc - 2)) {
|
||||||
|
log_error("Failed to register Pawn language server\r\n");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
json_rpc_run(&jrpc);
|
json_rpc_run(&jrpc);
|
||||||
|
pawn_lsp_deinit(&pawn);
|
||||||
|
|
||||||
if (logger) {
|
if (logger) {
|
||||||
fclose(logger);
|
fclose(logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_orig);
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_orig);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
132
src/pawn_lsp.c
Normal file
132
src/pawn_lsp.c
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cJSON/cJSON.h"
|
||||||
|
#include "json_rpc.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "pawn_lsp.h"
|
||||||
|
|
||||||
|
#define PAWN_LSP_VESRION "v0.0.1"
|
||||||
|
#define PAWN_LSP_NAME "pawn_lsp"
|
||||||
|
|
||||||
|
|
||||||
|
static int _request_handler(json_rpc_request_t *req, cJSON **resp, void *arg);
|
||||||
|
static void _notify_handler(json_rpc_request_t *req, void *arg);
|
||||||
|
|
||||||
|
static int _initialize(json_rpc_request_t *req, cJSON **resp, void *arg);
|
||||||
|
static int _shutdown(json_rpc_request_t *req, cJSON **resp, void *arg);
|
||||||
|
|
||||||
|
static void _exit_notf(json_rpc_request_t *req, void *arg);
|
||||||
|
|
||||||
|
int
|
||||||
|
pawn_lsp_init(pawn_lsp_t *pawn,
|
||||||
|
json_rpc_t *jrpc,
|
||||||
|
const char *pawncc,
|
||||||
|
char **pawn_args,
|
||||||
|
int pawn_argc)
|
||||||
|
{
|
||||||
|
pawn->jrpc = jrpc;
|
||||||
|
pawn->pawncc = strdup(pawncc);
|
||||||
|
|
||||||
|
/* execv(pawncc <filename> -d0 -v=2 -o/tmp/... [...args] <NULL>)*/
|
||||||
|
pawn->pawn_args = calloc(pawn_argc + 5, sizeof(char *));
|
||||||
|
/* pawn->pawn_args[0] = <filename>, set when compiling */
|
||||||
|
pawn->pawn_args[1] = strdup("-d0");
|
||||||
|
pawn->pawn_args[2] = strdup("-v=2");
|
||||||
|
/* pawn->pawn_args[3] = -o/tmp/..., set when compiling */
|
||||||
|
for (int i = 0; i < pawn_argc; i++) {
|
||||||
|
pawn->pawn_args[i + 4] = strdup(pawn_args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
json_rpc_set_request_handler(jrpc, _request_handler, &pawn);
|
||||||
|
json_rpc_set_notify_handler(jrpc, _notify_handler, &pawn);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pawn_lsp_deinit(pawn_lsp_t *pawn)
|
||||||
|
{
|
||||||
|
free(pawn->pawncc);
|
||||||
|
for (int i = 0; pawn->pawn_args[i] != NULL; i++) {
|
||||||
|
free(pawn->pawn_args[i]);
|
||||||
|
}
|
||||||
|
free(pawn->pawn_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_request_handler(json_rpc_request_t *req, cJSON **resp, void *arg)
|
||||||
|
{
|
||||||
|
char *method = req->method->valuestring;
|
||||||
|
|
||||||
|
log_info("Handle request \"%s\"\r\n", method);
|
||||||
|
|
||||||
|
if (!strcmp(method, "initialize")) {
|
||||||
|
return _initialize(req, resp, arg);
|
||||||
|
} else if (!strcmp(method, "shutdown")) {
|
||||||
|
return _shutdown(req, resp, arg);
|
||||||
|
} else {
|
||||||
|
log_warn("Unrecognized request method\r\n");
|
||||||
|
(*resp) = cJSON_CreateNull();
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_notify_handler(json_rpc_request_t *req, void *arg)
|
||||||
|
{
|
||||||
|
char *method = req->method->valuestring;
|
||||||
|
|
||||||
|
log_info("Handle notification \"%s\"\r\n", method);
|
||||||
|
|
||||||
|
if (!strcmp(method, "exit")) {
|
||||||
|
_exit_notf(req, arg);
|
||||||
|
} else {
|
||||||
|
log_warn("Unrecognized notification method\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
_initialize(json_rpc_request_t *req, cJSON **resp, void *arg)
|
||||||
|
{
|
||||||
|
cJSON *val;
|
||||||
|
|
||||||
|
(*resp) = cJSON_CreateObject();
|
||||||
|
|
||||||
|
val = cJSON_AddObjectToObject((*resp), "capabilities");
|
||||||
|
if (val == NULL) {
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cJSON_AddStringToObject(val, "positionEncoding", "utf-8") == NULL) {
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = cJSON_AddObjectToObject((*resp), "serverInfo");
|
||||||
|
if (val == NULL) {
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cJSON_AddStringToObject(val, "name", PAWN_LSP_NAME) == NULL) ||
|
||||||
|
(cJSON_AddStringToObject(val, "version", PAWN_LSP_VESRION) == NULL)) {
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_shutdown(json_rpc_request_t *req, cJSON **resp, void *arg)
|
||||||
|
{
|
||||||
|
(*resp) = cJSON_CreateNull();
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_exit_notf(json_rpc_request_t *req, void *arg)
|
||||||
|
{
|
||||||
|
pawn_lsp_t *pawn = arg;
|
||||||
|
json_rpc_cancel(pawn->jrpc);
|
||||||
|
}
|
||||||
|
|
||||||
27
src/pawn_lsp.h
Normal file
27
src/pawn_lsp.h
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef _PAWN_LSP_H_
|
||||||
|
#define _PAWN_LSP_H_
|
||||||
|
|
||||||
|
#include "json_rpc.h"
|
||||||
|
|
||||||
|
typedef struct pawn_lsp_struct {
|
||||||
|
/** Active JRPC instance */
|
||||||
|
json_rpc_t *jrpc;
|
||||||
|
/** Path to the pawncc compiler */
|
||||||
|
char *pawncc;
|
||||||
|
/** User provided args for pawncc */
|
||||||
|
char **pawn_args;
|
||||||
|
} pawn_lsp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register JSON RPC methods for the Pawn language server
|
||||||
|
*/
|
||||||
|
int pawn_lsp_init(pawn_lsp_t *pawn,
|
||||||
|
json_rpc_t *jrpc,
|
||||||
|
const char *pawncc,
|
||||||
|
char **pawn_argv,
|
||||||
|
int pawn_argc);
|
||||||
|
|
||||||
|
void pawn_lsp_deinit(pawn_lsp_t *pawn);
|
||||||
|
|
||||||
|
#endif /* _PAWN_LSP_H_ */
|
||||||
|
|
||||||
Loading…
Reference in a new issue