Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Backport fixes from the geany-lsp project
Browse files Browse the repository at this point in the history
techee committed Sep 17, 2024

Verified

This commit was signed with the committer’s verified signature.
fpapon François Papon
1 parent 831c3ac commit 55232c5
Showing 11 changed files with 192 additions and 50 deletions.
14 changes: 12 additions & 2 deletions lsp/data/lsp.conf
Original file line number Diff line number Diff line change
@@ -115,8 +115,8 @@ autocomplete_window_max_entries=20
# Maximum number of autocompletion entries shown without scrolling (defining the
# actual height of the popup)
autocomplete_window_max_displayed=8
# The maximum width of the autocompletion popup in pixels
autocomplete_window_max_width=200
# The maximum width of the autocompletion popup in displayed characters
autocomplete_window_max_width=60
# Whether to automatically apply additional edits defined for the autocompletion
# entry. These are typically imports of the modules where the inserted symbol is
# defined
@@ -368,6 +368,16 @@ use_without_project=true
#show_server_stderr=true


[Nix]
cmd=nil
use_without_project=true
use_outside_project_dir=true
extra_identifier_characters=-'
#rpc_log=stdout
#rpc_log_full=true
#show_server_stderr=true


[PHP]
# Note: Server returns highlighting indices off by 1 and highlighting doesn't work
cmd=phpactor.phar language-server
71 changes: 62 additions & 9 deletions lsp/src/lsp-autocomplete.c
Original file line number Diff line number Diff line change
@@ -94,9 +94,9 @@ static void free_autocomplete_symbol(gpointer data)
}


static const gchar *get_symbol_label(LspServer *server, LspAutocompleteSymbol *sym)
static const gchar *get_label(LspAutocompleteSymbol *sym, gboolean use_label)
{
if (server->config.autocomplete_use_label && sym->label)
if (use_label && sym->label)
return sym->label;

if (sym->text_edit && sym->text_edit->new_text)
@@ -110,6 +110,32 @@ static const gchar *get_symbol_label(LspServer *server, LspAutocompleteSymbol *s
}


static gchar *get_symbol_label(LspServer *server, LspAutocompleteSymbol *sym)
{
gchar *label = g_strdup(get_label(sym, server->config.autocomplete_use_label));
gchar *pos;

// remove stuff after newlines (we don't want them in the popup plus \n
// is used as the autocompletion list separator)
pos = strchr(label, '\n');
if (pos)
*pos = '\0';
pos = strchr(label, '\r');
if (pos)
*pos = '\0';

// ? used by Scintilla for icon specification
pos = strchr(label, '?');
if (pos)
*pos = ' ';
pos = strchr(label, '\t');
if (pos)
*pos = ' ';

return label;
}


static guint get_ident_prefixlen(const gchar *word_chars, GeanyDocument *doc, gint pos)
{
ScintillaObject *sci = doc->editor->sci;
@@ -150,9 +176,9 @@ void lsp_autocomplete_item_selected(LspServer *server, GeanyDocument *doc, guint
if (sel_num == 1 && sym->text_edit && sent_request_id == received_request_id)
{
if (server->config.autocomplete_apply_additional_edits && sym->additional_edits)
lsp_utils_apply_text_edits(sci, sym->text_edit, sym->additional_edits);
lsp_utils_apply_text_edits(sci, sym->text_edit, sym->additional_edits, sym->is_snippet);
else
lsp_utils_apply_text_edit(sci, sym->text_edit, TRUE);
lsp_utils_apply_text_edit(sci, sym->text_edit, sym->is_snippet);
}
else
{
@@ -172,7 +198,7 @@ void lsp_autocomplete_item_selected(LspServer *server, GeanyDocument *doc, guint
text_edit.range.start = lsp_utils_scintilla_pos_to_lsp(sci, pos - rootlen);
text_edit.range.end = lsp_utils_scintilla_pos_to_lsp(sci, pos);

lsp_utils_apply_text_edit(sci, &text_edit, sym->insert_text != NULL);
lsp_utils_apply_text_edit(sci, &text_edit, sym->is_snippet);
}
}

@@ -211,7 +237,7 @@ static void show_tags_list(LspServer *server, GeanyDocument *doc, GPtrArray *sym
ScintillaObject *sci = doc->editor->sci;
gint pos = sci_get_current_position(sci);
GString *words = g_string_sized_new(2000);
const gchar *label;
gchar *label;

for (i = 0; i < symbols->len; i++)
{
@@ -230,6 +256,8 @@ static void show_tags_list(LspServer *server, GeanyDocument *doc, GPtrArray *sym

sprintf(buf, "?%u", icon_id + 1);
g_string_append(words, buf);

g_free(label);
}

lsp_autocomplete_set_displayed_symbols(symbols);
@@ -242,6 +270,7 @@ static void show_tags_list(LspServer *server, GeanyDocument *doc, GPtrArray *sym
//make sure Scintilla selects the first item - see https://sourceforge.net/p/scintilla/bugs/2403/
label = get_symbol_label(server, symbols->pdata[0]);
SSM(sci, SCI_AUTOCSELECT, 0, (sptr_t)label);
g_free(label);
}
#endif

@@ -353,6 +382,27 @@ static gint sort_autocomplete_symbols(gconstpointer a, gconstpointer b, gpointer
}


static gboolean should_add(GPtrArray *symbols, const gchar *prefix)
{
LspAutocompleteSymbol *sym;
const gchar *label;

if (symbols->len == 0)
return FALSE;

if (symbols->len > 1)
return TRUE;

// don't single value with what's already typed unless it's a snippet
sym = symbols->pdata[0];
label = get_label(sym, FALSE);
if (g_strcmp0(label, prefix) != 0)
return TRUE;

return sym->is_snippet || sym->kind == LspCompletionKindSnippet;
}


static void process_response(LspServer *server, GVariant *response, GeanyDocument *doc)
{
//gboolean is_incomplete = FALSE;
@@ -440,14 +490,17 @@ static void process_response(LspServer *server, GVariant *response, GeanyDocumen
for (i = 0; i < symbols->len; i++)
{
LspAutocompleteSymbol *sym = symbols->pdata[i];
const gchar *display_label = get_symbol_label(server, sym);
gchar *display_label = get_symbol_label(server, sym);

if (g_hash_table_contains(entry_set, display_label))
{
free_autocomplete_symbol(sym);
g_free(display_label);
}
else
{
g_ptr_array_add(symbols_filtered, sym);
g_hash_table_insert(entry_set, g_strdup(display_label), NULL);
g_hash_table_insert(entry_set, display_label, NULL);
}
}

@@ -460,7 +513,7 @@ static void process_response(LspServer *server, GVariant *response, GeanyDocumen
/* sort with symbols matching the typed prefix first */
g_ptr_array_sort_with_data(symbols, sort_autocomplete_symbols, &sort_data);

if (symbols->len > 0)
if (should_add(symbols, sort_data.prefix))
show_tags_list(server, doc, symbols);
else
{
3 changes: 2 additions & 1 deletion lsp/src/lsp-extension.c
Original file line number Diff line number Diff line change
@@ -38,7 +38,8 @@ static void goto_cb(GVariant *return_value, GError *error, gpointer user_data)
{
gchar *fname = lsp_utils_get_real_path_from_uri_locale(str);

document_open_file(fname, FALSE, NULL, NULL);
if (fname)
document_open_file(fname, FALSE, NULL, NULL);
g_free(fname);
}
}
2 changes: 1 addition & 1 deletion lsp/src/lsp-format.c
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ static void format_cb(GVariant *return_value, GError *error, gpointer user_data)
edits = lsp_utils_parse_text_edits(&iter);

sci_start_undo_action(doc->editor->sci);
lsp_utils_apply_text_edits(doc->editor->sci, NULL, edits);
lsp_utils_apply_text_edits(doc->editor->sci, NULL, edits, FALSE);
sci_end_undo_action(doc->editor->sci);

g_ptr_array_free(edits, TRUE);
20 changes: 16 additions & 4 deletions lsp/src/lsp-goto.c
Original file line number Diff line number Diff line change
@@ -45,7 +45,10 @@ GPtrArray *last_result;
static void goto_location(GeanyDocument *old_doc, LspLocation *loc)
{
gchar *fname = lsp_utils_get_real_path_from_uri_locale(loc->uri);
GeanyDocument *doc = document_open_file(fname, FALSE, NULL, NULL);
GeanyDocument *doc = NULL;

if (fname)
doc = document_open_file(fname, FALSE, NULL, NULL);

if (doc)
navqueue_goto_line(old_doc, doc, loc->range.start.line + 1);
@@ -70,13 +73,19 @@ static void filter_symbols(const gchar *filter)

static void show_in_msgwin(LspLocation *loc, GHashTable *sci_table)
{
gchar *fname = lsp_utils_get_real_path_from_uri_utf8(loc->uri);
gchar *base_path = lsp_utils_get_project_base_path();
GeanyDocument *doc = document_find_by_filename(fname);
ScintillaObject *sci = NULL;
gint lineno = loc->range.start.line;
gchar *fname, *base_path;
GeanyDocument *doc;
gchar *line_str;

fname = lsp_utils_get_real_path_from_uri_utf8(loc->uri);
if (!fname)
return;

doc = document_find_by_filename(fname);
base_path = lsp_utils_get_project_base_path();

if (doc)
sci = doc->editor->sci;
else
@@ -178,6 +187,9 @@ static void goto_cb(GVariant *return_value, GError *error, gpointer user_data)
LspSymbol *sym;

file_name = lsp_utils_get_real_path_from_uri_utf8(loc->uri);
if (!file_name)
continue;

name = g_path_get_basename(file_name);

sym = lsp_symbol_new(name, "", "", file_name, 0, 0, loc->range.start.line + 1, 0,
28 changes: 17 additions & 11 deletions lsp/src/lsp-rpc.c
Original file line number Diff line number Diff line change
@@ -268,9 +268,12 @@ static GVariant *show_document(LspServer *srv, GVariant *params)
else if (g_str_has_prefix(uri, "file://"))
{
gchar *fname = lsp_utils_get_real_path_from_uri_locale(uri);
document_open_file(fname, FALSE, NULL, NULL);
g_free(fname);
success = TRUE;
if (fname)
{
document_open_file(fname, FALSE, NULL, NULL);
g_free(fname);
success = TRUE;
}
}
}

@@ -487,16 +490,19 @@ void lsp_rpc_notify(LspServer *srv, const gchar *method, GVariant *params,
method, params, NULL, NULL);

/* Two hacks in one:
* 1. gopls requires that the params member is present (jsonrpc-glib removes
* it when there are no parameters which is jsonrpc compliant)
* 2. haskell-language-server also requires params present _unless_ it's the
* "exit" notifications, where, if "params" present, it fails to
* terminate
* 1. some servers (e.g. gopls) require that the params member is present
* (jsonrpc-glib removes it when there are no parameters which is jsonrpc
* compliant)
* 2. haskell-language-server or nil require that the "exit" notification
* has no params member
*/
if (!params && !(srv->filetype == GEANY_FILETYPES_HASKELL && g_strcmp0(method, "exit") == 0))
if (!params && g_strcmp0(method, "exit") != 0)
{
params = JSONRPC_MESSAGE_NEW("gopls_bug_workarond",
JSONRPC_MESSAGE_PUT_STRING("https://github.com/golang/go/issues/57459"));
GVariantDict dict;

g_variant_dict_init(&dict, NULL);
params = g_variant_take_ref(g_variant_dict_end(&dict));

params_added = TRUE;
}

54 changes: 48 additions & 6 deletions lsp/src/lsp-server.c
Original file line number Diff line number Diff line change
@@ -365,6 +365,52 @@ static gboolean use_incremental_sync(GVariant *node)
}


static gboolean send_did_save(GVariant *node)
{
gboolean val;
gboolean success = JSONRPC_MESSAGE_PARSE(node,
"capabilities", "{",
"textDocumentSync", "{",
"save", JSONRPC_MESSAGE_GET_BOOLEAN(&val),
"}",
"}");

if (!success)
{
GVariant *var = NULL;

JSONRPC_MESSAGE_PARSE(node,
"capabilities", "{",
"textDocumentSync", "{",
"save", JSONRPC_MESSAGE_GET_VARIANT(&var),
"}",
"}");

success = val = var != NULL;
if (var)
g_variant_unref(var);
}

return success && val;
}


static gboolean include_text_on_save(GVariant *node)
{
gboolean val;
gboolean success = JSONRPC_MESSAGE_PARSE(node,
"capabilities", "{",
"textDocumentSync", "{",
"save", "{",
"includeText", JSONRPC_MESSAGE_GET_BOOLEAN(&val),
"}",
"}",
"}");

return success && val;
}


static gboolean use_workspace_folders(GVariant *node)
{
gboolean change_notifications = FALSE;
@@ -492,6 +538,8 @@ static void initialize_cb(GVariant *return_value, GError *error, gpointer user_d
update_config(return_value, &s->supports_workspace_symbols, "workspaceSymbolProvider");

s->use_incremental_sync = use_incremental_sync(return_value);
s->send_did_save = send_did_save(return_value);
s->include_text_on_save = include_text_on_save(return_value);
s->use_workspace_folders = use_workspace_folders(return_value);

s->initialize_response = lsp_utils_json_pretty_print(return_value);
@@ -554,8 +602,6 @@ static void perform_initialize(LspServer *server)
"}",
"textDocument", "{",
"synchronization", "{",
"willSave", JSONRPC_MESSAGE_PUT_BOOLEAN(FALSE),
"willSaveWaitUntil", JSONRPC_MESSAGE_PUT_BOOLEAN(FALSE),
"didSave", JSONRPC_MESSAGE_PUT_BOOLEAN(TRUE),
"}",
"completion", "{",
@@ -587,7 +633,6 @@ static void perform_initialize(LspServer *server)
"}",
"semanticTokens", "{",
"requests", "{",
"range", JSONRPC_MESSAGE_PUT_BOOLEAN(FALSE),
"full", "{",
"delta", JSONRPC_MESSAGE_PUT_BOOLEAN(TRUE),
"}",
@@ -624,9 +669,6 @@ static void perform_initialize(LspServer *server)
"formats", "[",
"relative",
"]",
"overlappingTokenSupport", JSONRPC_MESSAGE_PUT_BOOLEAN(FALSE),
"multilineTokenSupport", JSONRPC_MESSAGE_PUT_BOOLEAN(FALSE),
"serverCancelSupport", JSONRPC_MESSAGE_PUT_BOOLEAN(FALSE),
"augmentsSyntaxTokens", JSONRPC_MESSAGE_PUT_BOOLEAN(TRUE),
"}",
"}",
2 changes: 2 additions & 0 deletions lsp/src/lsp-server.h
Original file line number Diff line number Diff line change
@@ -146,6 +146,8 @@ typedef struct LspServer
gchar *signature_trigger_chars;
gchar *initialize_response;
gboolean use_incremental_sync;
gboolean send_did_save;
gboolean include_text_on_save;
gboolean use_workspace_folders;
gboolean supports_workspace_symbols;

35 changes: 25 additions & 10 deletions lsp/src/lsp-sync.c
Original file line number Diff line number Diff line change
@@ -133,24 +133,39 @@ void lsp_sync_text_document_did_close(LspServer *server, GeanyDocument *doc)

void lsp_sync_text_document_did_save(LspServer *server, GeanyDocument *doc)
{
gchar *doc_uri;
GVariant *node;
gchar *doc_uri = lsp_utils_get_doc_uri(doc);
gchar *doc_text = sci_get_contents(doc->editor->sci, -1);

node = JSONRPC_MESSAGE_NEW (
"textDocument", "{",
"uri", JSONRPC_MESSAGE_PUT_STRING(doc_uri),
"}",
"text", JSONRPC_MESSAGE_PUT_STRING(doc_text)
);
if (!server->send_did_save)
return;

doc_uri = lsp_utils_get_doc_uri(doc);

if (server->include_text_on_save)
{
gchar *doc_text = sci_get_contents(doc->editor->sci, -1);
node = JSONRPC_MESSAGE_NEW (
"textDocument", "{",
"uri", JSONRPC_MESSAGE_PUT_STRING(doc_uri),
"}",
"text", JSONRPC_MESSAGE_PUT_STRING(doc_text)
);
g_free(doc_text);
}
else
{
node = JSONRPC_MESSAGE_NEW (
"textDocument", "{",
"uri", JSONRPC_MESSAGE_PUT_STRING(doc_uri),
"}"
);
}

//printf("%s\n\n\n", lsp_utils_json_pretty_print(node));

lsp_rpc_notify(server, "textDocument/didSave", node, NULL, NULL);

g_free(doc_uri);
g_free(doc_text);

g_variant_unref(node);
}

10 changes: 5 additions & 5 deletions lsp/src/lsp-utils.c
Original file line number Diff line number Diff line change
@@ -164,8 +164,6 @@ gchar *lsp_utils_get_real_path_from_uri_locale(const gchar *uri)

SETPTR(fname, utils_get_real_path(fname));

g_return_val_if_fail(fname, NULL);

return fname;
}

@@ -449,7 +447,8 @@ static gint sort_edits(gconstpointer a, gconstpointer b)
}


void lsp_utils_apply_text_edits(ScintillaObject *sci, LspTextEdit *edit, GPtrArray *edits)
void lsp_utils_apply_text_edits(ScintillaObject *sci, LspTextEdit *edit, GPtrArray *edits,
gboolean process_snippets)
{
GPtrArray *arr;
gint i;
@@ -474,7 +473,7 @@ void lsp_utils_apply_text_edits(ScintillaObject *sci, LspTextEdit *edit, GPtrArr
for (i = 0; i < arr->len; i++)
{
LspTextEdit *e = arr->pdata[i];
lsp_utils_apply_text_edit(sci, e, e == edit);
lsp_utils_apply_text_edit(sci, e, process_snippets);
}

g_ptr_array_free(arr, TRUE);
@@ -497,7 +496,7 @@ static void apply_edits_in_file(const gchar *uri, GPtrArray *edits)
sci = lsp_utils_new_sci_from_file(fname);

sci_start_undo_action(sci);
lsp_utils_apply_text_edits(sci, NULL, edits);
lsp_utils_apply_text_edits(sci, NULL, edits, FALSE);
sci_end_undo_action(sci);

if (!doc)
@@ -1074,6 +1073,7 @@ gchar *lsp_utils_process_snippet(const gchar *snippet, GSList **positions)
else // something invalid
{
state = SnippetOuter;
g_string_append_c(res, '$');
g_string_append_c(res, c);
}
break;
3 changes: 2 additions & 1 deletion lsp/src/lsp-utils.h
Original file line number Diff line number Diff line change
@@ -105,7 +105,8 @@ LspLocation *lsp_utils_parse_location(GVariant *variant);
GPtrArray *lsp_utils_parse_locations(GVariantIter *iter);

void lsp_utils_apply_text_edit(ScintillaObject *sci, LspTextEdit *e, gboolean process_snippets);
void lsp_utils_apply_text_edits(ScintillaObject *sci, LspTextEdit *edit, GPtrArray *edits);
void lsp_utils_apply_text_edits(ScintillaObject *sci, LspTextEdit *edit, GPtrArray *edits,
gboolean process_snippets);
gboolean lsp_utils_apply_workspace_edit(GVariant *workspace_edit);

gboolean lsp_utils_wrap_string(gchar *string, gint wrapstart);

0 comments on commit 55232c5

Please sign in to comment.