pawn_ls/src/pawn_ls.c

188 lines
4.7 KiB
C

#include <stdlib.h>
#include <string.h>
#include "cJSON/cJSON.h"
#include "json_rpc.h"
#include "log.h"
#include "pawn_ls.h"
#define PAWN_LS_VESRION "v0.0.1"
#define PAWN_LS_NAME "pawn_ls"
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 _didopen_notf(json_rpc_request_t *req, void *arg);
static void _exit_notf(json_rpc_request_t *req, void *arg);
int
pawn_ls_init(pawn_ls_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_ls_deinit(pawn_ls_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, "textDocument/didOpen")) {
_didopen_notf(req, arg);
} else 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 *capabilities;
cJSON *val;
(*resp) = cJSON_CreateObject();
val = cJSON_AddObjectToObject((*resp), "serverInfo");
if (val == NULL) {
return (-1);
}
if ((cJSON_AddStringToObject(val, "name", PAWN_LS_NAME) == NULL) ||
(cJSON_AddStringToObject(val, "version", PAWN_LS_VESRION) == NULL)) {
return (-1);
}
/* All capabilities */
capabilities = cJSON_AddObjectToObject((*resp), "capabilities");
if (capabilities == NULL) {
return (-1);
}
/* utf-8 encoding only */
if (cJSON_AddStringToObject(capabilities, "positionEncoding", "utf-8") == NULL) {
return (-1);
}
/* TextDocumentSync */
val = cJSON_AddObjectToObject(capabilities, "textDocumentSync");
if (val == NULL) {
return (-1);
}
if ((cJSON_AddTrueToObject(val, "openClose") == NULL) ||
/* 1 = full content */
(cJSON_AddNumberToObject(val, "change", 1) == NULL)) {
return (-1);
}
/* Hover */
if (cJSON_AddTrueToObject(capabilities, "hoverProvider") == NULL) {
return (-1);
}
/* Go to's */
if ((cJSON_AddTrueToObject(capabilities, "declarationProvider") == NULL) ||
(cJSON_AddTrueToObject(capabilities, "definitionProvider") == NULL)) {
return (-1);
}
return (0);
}
static int
_shutdown(json_rpc_request_t *req, cJSON **resp, void *arg)
{
(*resp) = cJSON_CreateNull();
return (0);
}
static void
_didopen_notf(json_rpc_request_t *req, void *arg) {
cJSON *textdoc = cJSON_GetObjectItem(req->params, "textDocument");
cJSON *val;
if ((textdoc == NULL) || (!cJSON_IsObject(textdoc))) {
log_error("Invalid textDocument field\r\n");
return;
}
val = cJSON_GetObjectItem(textdoc, "uri");
if (val && cJSON_IsString(val)) {
log_info("textdoc uri: %s\r\n", val->valuestring);
} else {
log_warn("Invalid uri\r\n");
}
val = cJSON_GetObjectItem(textdoc, "text");
if (val && cJSON_IsString(val)) {
log_info("textdoc text: \"%s\"\r\n", val->valuestring);
} else {
log_warn("Invalid text\r\n");
}
}
static void
_exit_notf(json_rpc_request_t *req, void *arg)
{
pawn_ls_t *pawn = arg;
json_rpc_cancel(pawn->jrpc);
}