Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}