Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c778c1aa82 | |||
| 255c28f26c | |||
| d86d2af6d0 | |||
| 81229426da |
7 changed files with 143 additions and 28 deletions
2
Makefile
2
Makefile
|
|
@ -18,7 +18,7 @@ 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
|
src/pawn_ls.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))))
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# Pawn Language Server
|
# Pawn Language Server
|
||||||
|
|
||||||
`pawn_lsp` is a project to provide basic LSP functionality for the
|
`pawn_ls` is a project to provide basic language server functionality for the
|
||||||
[Pawn scripting language](https://codeberg.org/compuphase/pawn).
|
[Pawn scripting language](https://codeberg.org/compuphase/pawn).
|
||||||
|
|
||||||
`pawn_lsp` is currently in development and has no releases, refer to the
|
`pawn_ls` is currently in development and has no releases, refer to the
|
||||||
repository work items for development status.
|
repository work items for development status.
|
||||||
|
|
||||||
|
|
|
||||||
12
src/main.c
12
src/main.c
|
|
@ -6,12 +6,12 @@
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "json_rpc.h"
|
#include "json_rpc.h"
|
||||||
#include "pawn_lsp.h"
|
#include "pawn_ls.h"
|
||||||
|
|
||||||
void sighandler(int signal);
|
void sighandler(int signal);
|
||||||
|
|
||||||
static json_rpc_t jrpc;
|
static json_rpc_t jrpc;
|
||||||
static pawn_lsp_t pawn;
|
static pawn_ls_t pawn;
|
||||||
|
|
||||||
FILE *logger = NULL;
|
FILE *logger = NULL;
|
||||||
|
|
||||||
|
|
@ -22,11 +22,11 @@ main(int argc, char **argv)
|
||||||
struct termios term_new;
|
struct termios term_new;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
fprintf(stderr, "Usage: pawn_lsp <pawncc> [...pawncc options]\r\n");
|
fprintf(stderr, "Usage: pawn_ls <pawncc> [...pawncc options]\r\n");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger = fopen("pawn_lsp.log", "w");
|
logger = fopen("pawn_ls.log", "w");
|
||||||
|
|
||||||
if (signal(SIGINT, sighandler) == SIG_ERR) {
|
if (signal(SIGINT, sighandler) == SIG_ERR) {
|
||||||
log_error("Failed to intialize signal handling\r\n");
|
log_error("Failed to intialize signal handling\r\n");
|
||||||
|
|
@ -45,13 +45,13 @@ main(int argc, char **argv)
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pawn_lsp_init(&pawn, &jrpc, argv[1], &argv[2], argc - 2)) {
|
if (pawn_ls_init(&pawn, &jrpc, argv[1], &argv[2], argc - 2)) {
|
||||||
log_error("Failed to register Pawn language server\r\n");
|
log_error("Failed to register Pawn language server\r\n");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
json_rpc_run(&jrpc);
|
json_rpc_run(&jrpc);
|
||||||
pawn_lsp_deinit(&pawn);
|
pawn_ls_deinit(&pawn);
|
||||||
|
|
||||||
if (logger) {
|
if (logger) {
|
||||||
fclose(logger);
|
fclose(logger);
|
||||||
|
|
|
||||||
0
src/pawn_engine.c
Normal file
0
src/pawn_engine.c
Normal file
59
src/pawn_engine.h
Normal file
59
src/pawn_engine.h
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
#ifndef _PAWN_ENGINE_H_
|
||||||
|
#define _PAWN_ENGINE_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct str_struct {
|
||||||
|
/** Actual value of the string */
|
||||||
|
char *val;
|
||||||
|
/** Current length of the string in bytes */
|
||||||
|
size_t len;
|
||||||
|
/** Capacity of the string buffer */
|
||||||
|
size_t cap;
|
||||||
|
} str_t;
|
||||||
|
|
||||||
|
typedef struct file_position_struct {
|
||||||
|
/** Line number in the file (1-indexed) */
|
||||||
|
size_t line;
|
||||||
|
/** Column number in the file (1-indexed) */
|
||||||
|
size_t column;
|
||||||
|
} file_position_t;
|
||||||
|
|
||||||
|
typedef struct file_range_struct {
|
||||||
|
/** Start of the range, inclusive */
|
||||||
|
file_position_t start;
|
||||||
|
/** End of the range, inclusive */
|
||||||
|
file_position_t end;
|
||||||
|
} file_range_t;
|
||||||
|
|
||||||
|
typedef struct file_diagnostic_struct {
|
||||||
|
/** Message for the diagnostic */
|
||||||
|
str_t message;
|
||||||
|
/** Range of text the diagnostic applies to */
|
||||||
|
file_range_t range;
|
||||||
|
} file_diagnostic_t;
|
||||||
|
|
||||||
|
typedef struct pawn_diagnostics_struct {
|
||||||
|
/** Errors present in a Pawn script */
|
||||||
|
file_diagnostic_t *errors;
|
||||||
|
/** Number of errors */
|
||||||
|
size_t errors_len;
|
||||||
|
/** Warnings present in a Pawn script */
|
||||||
|
file_diagnostic_t *warnings;
|
||||||
|
/** Number of warnings */
|
||||||
|
size_t warnings_len;
|
||||||
|
} pawn_diagnostics_t;
|
||||||
|
|
||||||
|
typedef struct pawn_engine_settings_struct {
|
||||||
|
/** Path to the pawncc executable */
|
||||||
|
const char *pawncc;
|
||||||
|
/** Extra options to run pawncc with, not including the pawncc or script paths */
|
||||||
|
const char **argv;
|
||||||
|
/** Number of extra options */
|
||||||
|
int argc;
|
||||||
|
} pawn_engine_settings_t;
|
||||||
|
|
||||||
|
pawn_diagnostics_t *pawn_engine_compile(const char *path, pawn_engine_settings_t *settings);
|
||||||
|
|
||||||
|
#endif /* _PAWN_ENGINE_H_ */
|
||||||
|
|
||||||
|
|
@ -4,10 +4,10 @@
|
||||||
#include "cJSON/cJSON.h"
|
#include "cJSON/cJSON.h"
|
||||||
#include "json_rpc.h"
|
#include "json_rpc.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "pawn_lsp.h"
|
#include "pawn_ls.h"
|
||||||
|
|
||||||
#define PAWN_LSP_VESRION "v0.0.1"
|
#define PAWN_LS_VESRION "v0.0.1"
|
||||||
#define PAWN_LSP_NAME "pawn_lsp"
|
#define PAWN_LS_NAME "pawn_ls"
|
||||||
|
|
||||||
|
|
||||||
static int _request_handler(json_rpc_request_t *req, cJSON **resp, void *arg);
|
static int _request_handler(json_rpc_request_t *req, cJSON **resp, void *arg);
|
||||||
|
|
@ -16,10 +16,11 @@ 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 _initialize(json_rpc_request_t *req, cJSON **resp, void *arg);
|
||||||
static int _shutdown(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);
|
static void _exit_notf(json_rpc_request_t *req, void *arg);
|
||||||
|
|
||||||
int
|
int
|
||||||
pawn_lsp_init(pawn_lsp_t *pawn,
|
pawn_ls_init(pawn_ls_t *pawn,
|
||||||
json_rpc_t *jrpc,
|
json_rpc_t *jrpc,
|
||||||
const char *pawncc,
|
const char *pawncc,
|
||||||
char **pawn_args,
|
char **pawn_args,
|
||||||
|
|
@ -45,7 +46,7 @@ pawn_lsp_init(pawn_lsp_t *pawn,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pawn_lsp_deinit(pawn_lsp_t *pawn)
|
pawn_ls_deinit(pawn_ls_t *pawn)
|
||||||
{
|
{
|
||||||
free(pawn->pawncc);
|
free(pawn->pawncc);
|
||||||
for (int i = 0; pawn->pawn_args[i] != NULL; i++) {
|
for (int i = 0; pawn->pawn_args[i] != NULL; i++) {
|
||||||
|
|
@ -79,7 +80,9 @@ _notify_handler(json_rpc_request_t *req, void *arg)
|
||||||
|
|
||||||
log_info("Handle notification \"%s\"\r\n", method);
|
log_info("Handle notification \"%s\"\r\n", method);
|
||||||
|
|
||||||
if (!strcmp(method, "exit")) {
|
if (!strcmp(method, "textDocument/didOpen")) {
|
||||||
|
_didopen_notf(req, arg);
|
||||||
|
} else if (!strcmp(method, "exit")) {
|
||||||
_exit_notf(req, arg);
|
_exit_notf(req, arg);
|
||||||
} else {
|
} else {
|
||||||
log_warn("Unrecognized notification method\r\n");
|
log_warn("Unrecognized notification method\r\n");
|
||||||
|
|
@ -90,26 +93,54 @@ _notify_handler(json_rpc_request_t *req, void *arg)
|
||||||
int
|
int
|
||||||
_initialize(json_rpc_request_t *req, cJSON **resp, void *arg)
|
_initialize(json_rpc_request_t *req, cJSON **resp, void *arg)
|
||||||
{
|
{
|
||||||
|
cJSON *capabilities;
|
||||||
cJSON *val;
|
cJSON *val;
|
||||||
|
|
||||||
(*resp) = cJSON_CreateObject();
|
(*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");
|
val = cJSON_AddObjectToObject((*resp), "serverInfo");
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cJSON_AddStringToObject(val, "name", PAWN_LSP_NAME) == NULL) ||
|
if ((cJSON_AddStringToObject(val, "name", PAWN_LS_NAME) == NULL) ||
|
||||||
(cJSON_AddStringToObject(val, "version", PAWN_LSP_VESRION) == 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 (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,10 +154,35 @@ _shutdown(json_rpc_request_t *req, cJSON **resp, void *arg)
|
||||||
return (0);
|
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
|
static void
|
||||||
_exit_notf(json_rpc_request_t *req, void *arg)
|
_exit_notf(json_rpc_request_t *req, void *arg)
|
||||||
{
|
{
|
||||||
pawn_lsp_t *pawn = arg;
|
pawn_ls_t *pawn = arg;
|
||||||
json_rpc_cancel(pawn->jrpc);
|
json_rpc_cancel(pawn->jrpc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,27 +1,27 @@
|
||||||
#ifndef _PAWN_LSP_H_
|
#ifndef _PAWN_LS_H_
|
||||||
#define _PAWN_LSP_H_
|
#define _PAWN_LS_H_
|
||||||
|
|
||||||
#include "json_rpc.h"
|
#include "json_rpc.h"
|
||||||
|
|
||||||
typedef struct pawn_lsp_struct {
|
typedef struct pawn_ls_struct {
|
||||||
/** Active JRPC instance */
|
/** Active JRPC instance */
|
||||||
json_rpc_t *jrpc;
|
json_rpc_t *jrpc;
|
||||||
/** Path to the pawncc compiler */
|
/** Path to the pawncc compiler */
|
||||||
char *pawncc;
|
char *pawncc;
|
||||||
/** User provided args for pawncc */
|
/** User provided args for pawncc */
|
||||||
char **pawn_args;
|
char **pawn_args;
|
||||||
} pawn_lsp_t;
|
} pawn_ls_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register JSON RPC methods for the Pawn language server
|
* @brief Register JSON RPC methods for the Pawn language server
|
||||||
*/
|
*/
|
||||||
int pawn_lsp_init(pawn_lsp_t *pawn,
|
int pawn_ls_init(pawn_ls_t *pawn,
|
||||||
json_rpc_t *jrpc,
|
json_rpc_t *jrpc,
|
||||||
const char *pawncc,
|
const char *pawncc,
|
||||||
char **pawn_argv,
|
char **pawn_argv,
|
||||||
int pawn_argc);
|
int pawn_argc);
|
||||||
|
|
||||||
void pawn_lsp_deinit(pawn_lsp_t *pawn);
|
void pawn_ls_deinit(pawn_ls_t *pawn);
|
||||||
|
|
||||||
#endif /* _PAWN_LSP_H_ */
|
#endif /* _PAWN_LS_H_ */
|
||||||
|
|
||||||
Loading…
Reference in a new issue