static void ide_lsp_formatter_apply_changes (IdeLspFormatter *self, IdeBuffer *buffer, GVariant *text_edits) { g_autoptr(GPtrArray) edits = NULL; g_autoptr(IdeContext) context = NULL; IdeBufferManager *buffer_manager; GVariant *text_edit; GFile *file; GVariantIter iter; IDE_ENTRY; g_assert (IDE_IS_LSP_FORMATTER (self)); g_assert (text_edits != NULL); if (!g_variant_is_container (text_edits)) { g_warning ("variant is not a container, ignoring"); IDE_EXIT; } file = ide_buffer_get_file (buffer); edits = g_ptr_array_new_with_free_func (g_object_unref); g_variant_iter_init (&iter, text_edits); while (g_variant_iter_loop (&iter, "v", &text_edit)) { g_autoptr(IdeLocation) begin_location = NULL; g_autoptr(IdeLocation) end_location = NULL; g_autoptr(IdeRange) range = NULL; const gchar *new_text = NULL; gboolean success; struct { gint64 line; gint64 column; } begin, end; success = JSONRPC_MESSAGE_PARSE (text_edit, "range", "{", "start", "{", "line", JSONRPC_MESSAGE_GET_INT64 (&begin.line), "character", JSONRPC_MESSAGE_GET_INT64 (&begin.column), "}", "end", "{", "line", JSONRPC_MESSAGE_GET_INT64 (&end.line), "character", JSONRPC_MESSAGE_GET_INT64 (&end.column), "}", "}", "newText", JSONRPC_MESSAGE_GET_STRING (&new_text) ); if (!success) { IDE_TRACE_MSG ("Failed to extract change from variant"); continue; } begin_location = ide_location_new (file, begin.line, begin.column); end_location = ide_location_new (file, end.line, end.column); range = ide_range_new (begin_location, end_location); g_ptr_array_add (edits, ide_text_edit_new (range, new_text)); } context = ide_buffer_ref_context (buffer); buffer_manager = ide_buffer_manager_from_context (context); ide_buffer_manager_apply_edits_async (buffer_manager, IDE_PTR_ARRAY_STEAL_FULL (&edits), NULL, NULL, NULL); IDE_EXIT; }
static void ide_langserv_completion_provider_complete_cb (GObject *object, GAsyncResult *result, gpointer user_data) { IdeLangservClient *client = (IdeLangservClient *)object; g_autoptr(CompletionState) state = user_data; g_autoptr(GVariant) return_value = NULL; g_autoptr(GError) error = NULL; GVariant *node; GList *list = NULL; GVariantIter iter; IDE_ENTRY; g_assert (IDE_IS_LANGSERV_CLIENT (client)); g_assert (G_IS_ASYNC_RESULT (result)); g_assert (state != NULL); g_assert (IDE_IS_LANGSERV_COMPLETION_PROVIDER (state->self)); g_assert (GTK_SOURCE_IS_COMPLETION_CONTEXT (state->context)); if (!ide_langserv_client_call_finish (client, result, &return_value, &error)) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_message ("%s", error->message); IDE_GOTO (failure); } /* * TODO: We will want to make a much more optimized version of this using * the other completion result work we've done. */ g_variant_iter_init (&iter, return_value); while (g_variant_iter_loop (&iter, "v", &node)) { g_autoptr(GtkSourceCompletionItem) item = NULL; g_autofree gchar *full_label = NULL; const gchar *label; const gchar *detail; const gchar *icon_name = NULL; gboolean success; gint64 kind = 0; success = JSONRPC_MESSAGE_PARSE (node, "label", JSONRPC_MESSAGE_GET_STRING (&label), "detail", JSONRPC_MESSAGE_GET_STRING (&detail) ); if (!success) { IDE_TRACE_MSG ("Failed to extract completion item from node"); continue; } /* Optional kind field */ JSONRPC_MESSAGE_PARSE (node, "kind", JSONRPC_MESSAGE_GET_INT64 (&kind)); kind = ide_langserv_decode_completion_kind (kind); if (kind != IDE_SYMBOL_NONE) icon_name = ide_symbol_kind_get_icon_name (kind); if (label != NULL && detail != NULL) full_label = g_strdup_printf ("%s : %s", label, detail); else full_label = g_strdup (label); //item = gtk_source_completion_item_new (full_label, label, NULL, NULL); item = g_object_new (GTK_SOURCE_TYPE_COMPLETION_ITEM, "icon-name", icon_name, "label", full_label, "text", label, NULL); list = g_list_prepend (list, g_steal_pointer (&item)); } failure: gtk_source_completion_context_add_proposals (state->context, GTK_SOURCE_COMPLETION_PROVIDER (state->self), list, TRUE); g_list_free_full (list, g_object_unref); IDE_EXIT; }
static void ide_langserv_symbol_resolver_document_symbol_cb (GObject *object, GAsyncResult *result, gpointer user_data) { IdeLangservClient *client = (IdeLangservClient *)object; g_autoptr(GTask) task = user_data; g_autoptr(IdeLangservSymbolTree) tree = NULL; g_autoptr(GError) error = NULL; g_autoptr(GVariant) return_value = NULL; g_autoptr(GPtrArray) symbols = NULL; GVariantIter iter; GVariant *node; IDE_ENTRY; g_assert (IDE_IS_LANGSERV_CLIENT (client)); g_assert (G_IS_TASK (task)); if (!ide_langserv_client_call_finish (client, result, &return_value, &error)) { g_task_return_error (task, g_steal_pointer (&error)); IDE_EXIT; } if (!g_variant_is_of_type (return_value, G_VARIANT_TYPE ("av"))) { g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid result for textDocument/documentSymbol"); IDE_EXIT; } symbols = g_ptr_array_new_with_free_func (g_object_unref); g_variant_iter_init (&iter, return_value); while (g_variant_iter_loop (&iter, "v", &node)) { g_autoptr(IdeLangservSymbolNode) symbol = NULL; g_autoptr(GFile) file = NULL; const gchar *name = NULL; const gchar *container_name = NULL; const gchar *uri = NULL; gboolean success; gint64 kind = -1; struct { gint64 line; gint64 column; } begin, end; /* Mandatory fields */ success = JSONRPC_MESSAGE_PARSE (node, "name", JSONRPC_MESSAGE_GET_STRING (&name), "kind", JSONRPC_MESSAGE_GET_INT64 (&kind), "location", "{", "uri", JSONRPC_MESSAGE_GET_STRING (&uri), "range", "{", "start", "{", "line", JSONRPC_MESSAGE_GET_INT64 (&begin.line), "character", JSONRPC_MESSAGE_GET_INT64 (&begin.column), "}", "end", "{", "line", JSONRPC_MESSAGE_GET_INT64 (&end.line), "character", JSONRPC_MESSAGE_GET_INT64 (&end.column), "}", "}", "}" ); if (!success) { IDE_TRACE_MSG ("Failed to parse reply from language server"); continue; } /* Optional fields */ JSONRPC_MESSAGE_PARSE (node, "containerName", JSONRPC_MESSAGE_GET_STRING (&container_name)); file = g_file_new_for_uri (uri); symbol = ide_langserv_symbol_node_new (file, name, container_name, kind, begin.line, begin.column, end.line, end.column); g_ptr_array_add (symbols, g_steal_pointer (&symbol)); } tree = ide_langserv_symbol_tree_new (g_steal_pointer (&symbols)); g_task_return_pointer (task, g_steal_pointer (&tree), g_object_unref); IDE_EXIT; }
static void ide_langserv_symbol_resolver_find_references_cb (GObject *object, GAsyncResult *result, gpointer user_data) { IdeLangservClient *client = (IdeLangservClient *)object; g_autoptr(GTask) task = user_data; g_autoptr(GVariant) reply = NULL; g_autoptr(GPtrArray) references = NULL; g_autoptr(GError) error = NULL; IdeLangservSymbolResolver *self; GVariant *locationv; GVariantIter iter; IDE_ENTRY; g_assert (IDE_IS_LANGSERV_CLIENT (client)); g_assert (G_IS_ASYNC_RESULT (result)); g_assert (G_IS_TASK (task)); self = g_task_get_source_object (task); if (!ide_langserv_client_call_finish (client, result, &reply, &error)) { g_task_return_error (task, g_steal_pointer (&error)); IDE_EXIT; } if (!g_variant_is_of_type (reply, G_VARIANT_TYPE ("av"))) { g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid reply type from peer: %s", g_variant_get_type_string (reply)); IDE_EXIT; } references = g_ptr_array_new_with_free_func ((GDestroyNotify)ide_source_range_unref); g_variant_iter_init (&iter, reply); while (g_variant_iter_loop (&iter, "v", &locationv)) { g_autoptr(IdeSourceLocation) begin_loc = NULL; g_autoptr(IdeSourceLocation) end_loc = NULL; g_autoptr(IdeSourceRange) range = NULL; g_autoptr(IdeFile) ifile = NULL; const gchar *uri = NULL; GFile *gfile; gboolean success; struct { gint64 line; gint64 line_offset; } begin, end; success = JSONRPC_MESSAGE_PARSE (locationv, "uri", JSONRPC_MESSAGE_GET_STRING (&uri), "range", "{", "start", "{", "line", JSONRPC_MESSAGE_GET_INT64 (&begin.line), "character", JSONRPC_MESSAGE_GET_INT64 (&begin.line_offset), "}", "end", "{", "line", JSONRPC_MESSAGE_GET_INT64 (&end.line), "character", JSONRPC_MESSAGE_GET_INT64 (&end.line_offset), "}", "}" ); if (!success) { g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Failed to parse location object"); IDE_EXIT; } gfile = g_file_new_for_uri (uri); ifile = ide_file_new (ide_object_get_context (IDE_OBJECT (self)), gfile); begin_loc = ide_source_location_new (ifile, begin.line, begin.line_offset, 0); end_loc = ide_source_location_new (ifile, end.line, end.line_offset, 0); range = ide_source_range_new (begin_loc, end_loc); g_ptr_array_add (references, g_steal_pointer (&range)); } g_task_return_pointer (task, g_steal_pointer (&references), (GDestroyNotify)g_ptr_array_unref); IDE_EXIT; }
static void ide_langserv_symbol_resolver_definition_cb (GObject *object, GAsyncResult *result, gpointer user_data) { IdeLangservClient *client = (IdeLangservClient *)object; IdeLangservSymbolResolver *self; g_autoptr(GTask) task = user_data; g_autoptr(GError) error = NULL; g_autoptr(GVariant) return_value = NULL; g_autoptr(IdeSymbol) symbol = NULL; g_autoptr(IdeFile) ifile = NULL; g_autoptr(GFile) gfile = NULL; g_autoptr(IdeSourceLocation) location = NULL; g_autoptr(GVariant) variant = NULL; GVariantIter iter; const gchar *uri; struct { gint64 line; gint64 column; } begin, end; gboolean success = FALSE; IDE_ENTRY; g_assert (IDE_IS_LANGSERV_CLIENT (client)); g_assert (G_IS_ASYNC_RESULT (result)); g_assert (G_IS_TASK (task)); self = g_task_get_source_object (task); g_assert (IDE_IS_LANGSERV_SYMBOL_RESOLVER (self)); if (!ide_langserv_client_call_finish (client, result, &return_value, &error)) { g_task_return_error (task, g_steal_pointer (&error)); IDE_EXIT; } #if 0 { g_autofree gchar *str = g_variant_print (return_value, TRUE); IDE_TRACE_MSG ("Got reply: %s", str); } #endif g_variant_iter_init (&iter, return_value); if (g_variant_iter_next (&iter, "v", &variant)) { success = JSONRPC_MESSAGE_PARSE (variant, "uri", JSONRPC_MESSAGE_GET_STRING (&uri), "range", "{", "start", "{", "line", JSONRPC_MESSAGE_GET_INT64 (&begin.line), "character", JSONRPC_MESSAGE_GET_INT64 (&begin.column), "}", "end", "{", "line", JSONRPC_MESSAGE_GET_INT64 (&end.line), "character", JSONRPC_MESSAGE_GET_INT64 (&end.column), "}", "}" ); } if (!success) { g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Got invalid reply for textDocument/definition"); IDE_EXIT; } IDE_TRACE_MSG ("Definition location is %s %d:%d", uri, (gint)begin.line + 1, (gint)begin.column + 1); gfile = g_file_new_for_uri (uri); ifile = ide_file_new (ide_object_get_context (IDE_OBJECT (self)), gfile); location = ide_source_location_new (ifile, begin.line, begin.column, 0); symbol = ide_symbol_new ("", IDE_SYMBOL_NONE, IDE_SYMBOL_FLAGS_NONE, location, location, location); g_task_return_pointer (task, g_steal_pointer (&symbol), (GDestroyNotify)ide_symbol_unref); IDE_EXIT; }