#include #include #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 -d0 -v=2 -o/tmp/... [...args] )*/ pawn->pawn_args = calloc(pawn_argc + 5, sizeof(char *)); /* pawn->pawn_args[0] = , 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); }