[gnome-builder/wip/chergert/lsp-plugin-loader: 1/2] libide/lsp: implement generic LSP server support




commit 19ca128205640a9d19c913ddab0c15126192a216
Author: Christian Hergert <chergert redhat com>
Date:   Tue Oct 11 10:34:21 2022 -0500

    libide/lsp: implement generic LSP server support
    
    This is unfinished, but starts to get scaffolding into place to support
    new language servers with very minimal code in the plugin. The idea is
    that we define the necessities in the .plugin file and
    ide_lsp_plugin_register_types() will generate custom GType for all of
    the supported extension types.
    
    Currently, this requires using Embedded=ide_lsp_plugin_register_types
    in the .plugin file, which means it will only work when the .plugin
    is a resource. It would be nice to simplify that if/when we bring back
    additional scripting so that the amount of code stays small, even if we
    use something like Lua or GJS as a peas module loader.
    
    WORKING:
    
      * IDE_LSP_PLUGIN_FEATURES_COMPLETION
    
    TODO:
    
      * IDE_LSP_PLUGIN_FEATURES_DIAGNOSTICS
      * IDE_LSP_PLUGIN_FEATURES_SYMBOL_RESOLVER
      * IDE_LSP_PLUGIN_FEATURES_HIGHLIGHTER
      * IDE_LSP_PLUGIN_FEATURES_FORMATTER
      * IDE_LSP_PLUGIN_FEATURES_HOVER
      * IDE_LSP_PLUGIN_FEATURES_RENAME
      * IDE_LSP_PLUGIN_FEATURES_CODE_ACTION

 .../lsp/ide-lsp-plugin-completion-provider.c       |  89 +++++
 src/libide/lsp/ide-lsp-plugin-private.h            |  51 +++
 src/libide/lsp/ide-lsp-plugin.c                    | 427 +++++++++++++++++++++
 src/libide/lsp/ide-lsp-plugin.h                    |  32 ++
 src/libide/lsp/libide-lsp.h                        |   1 +
 src/libide/lsp/meson.build                         |   4 +
 src/libide/plugins/ide-extension-set-adapter.c     |   3 +-
 .../bash-language-server-plugin.c                  |  34 --
 .../bash-language-server.gresource.xml             |   1 +
 .../bash-language-server.plugin                    |   7 +-
 src/plugins/bash-language-server/settings.json     |   4 +
 11 files changed, 616 insertions(+), 37 deletions(-)
---
diff --git a/src/libide/lsp/ide-lsp-plugin-completion-provider.c 
b/src/libide/lsp/ide-lsp-plugin-completion-provider.c
new file mode 100644
index 000000000..2db770fcc
--- /dev/null
+++ b/src/libide/lsp/ide-lsp-plugin-completion-provider.c
@@ -0,0 +1,89 @@
+/* ide-lsp-plugin-completion-provider.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-lsp-plugin-completion-provider"
+
+#include "config.h"
+
+#include <libpeas/peas.h>
+
+#include "ide-lsp-completion-provider.h"
+#include "ide-lsp-plugin-private.h"
+#include "ide-lsp-service.h"
+
+typedef struct _IdeLspPluginCompletionProviderClass
+{
+  IdeLspCompletionProviderClass  parent_class;
+  IdeLspPluginInfo              *info;
+} IdeLspPluginCompletionProviderClass;
+
+static void
+ide_lsp_plugin_completion_provider_load (IdeLspCompletionProvider *provider)
+{
+  IdeLspPluginCompletionProviderClass *klass = (IdeLspPluginCompletionProviderClass *)(((GTypeInstance 
*)provider)->g_class);
+  g_autoptr(IdeLspServiceClass) service_class = g_type_class_ref (klass->info->service_type);
+
+  ide_lsp_service_class_bind_client (service_class, IDE_OBJECT (provider));
+}
+
+static void
+ide_lsp_plugin_completion_provider_class_init (IdeLspPluginCompletionProviderClass *klass,
+                                               IdeLspPluginInfo                    *info)
+{
+  IdeLspCompletionProviderClass *completion_class = IDE_LSP_COMPLETION_PROVIDER_CLASS (klass);
+
+  completion_class->load = ide_lsp_plugin_completion_provider_load;
+
+  klass->info = info;
+}
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+GObject *
+ide_lsp_plugin_create_completion_provider (guint             n_parameters,
+                                           GParameter       *parameters,
+                                           IdeLspPluginInfo *info)
+{
+  ide_lsp_plugin_remove_plugin_info_param (&n_parameters, parameters);
+
+  if G_UNLIKELY (info->completion_provider_type == G_TYPE_INVALID)
+    {
+      g_autofree char *name = g_strconcat (info->module_name, "+CompletionProvider", NULL);
+
+      info->completion_provider_type =
+        g_type_register_static (IDE_TYPE_LSP_COMPLETION_PROVIDER,
+                                name,
+                                &(GTypeInfo) {
+                                  sizeof (IdeLspPluginCompletionProviderClass),
+                                  NULL,
+                                  NULL,
+                                  (GClassInitFunc)ide_lsp_plugin_completion_provider_class_init,
+                                  NULL,
+                                  ide_lsp_plugin_info_ref (info),
+                                  sizeof (IdeLspCompletionProvider),
+                                  0,
+                                  NULL,
+                                  NULL,
+                                },
+                                G_TYPE_FLAG_FINAL);
+    }
+
+  return g_object_newv (info->completion_provider_type, n_parameters, parameters);
+}
+G_GNUC_END_IGNORE_DEPRECATIONS
diff --git a/src/libide/lsp/ide-lsp-plugin-private.h b/src/libide/lsp/ide-lsp-plugin-private.h
new file mode 100644
index 000000000..f2236dc46
--- /dev/null
+++ b/src/libide/lsp/ide-lsp-plugin-private.h
@@ -0,0 +1,51 @@
+/* ide-lsp-plugin-private.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+
+#include "ide-lsp-plugin.h"
+
+G_BEGIN_DECLS
+
+typedef struct _IdeLspPluginInfo
+{
+  char *module_name;
+  char **command;
+  char **languages;
+  GBytes *default_settings;
+  GType service_type;
+  GType completion_provider_type;
+  GType diagnostic_provider_type;
+} IdeLspPluginInfo;
+
+IdeLspPluginInfo *ide_lsp_plugin_info_ref                   (IdeLspPluginInfo *info);
+void              ide_lsp_plugin_info_unref                 (IdeLspPluginInfo *info);
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+void              ide_lsp_plugin_remove_plugin_info_param   (guint            *n_parameters,
+                                                             GParameter       *parameters);
+GObject          *ide_lsp_plugin_create_completion_provider (guint             n_parameters,
+                                                             GParameter       *parameters,
+                                                             IdeLspPluginInfo *info);
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+G_END_DECLS
diff --git a/src/libide/lsp/ide-lsp-plugin.c b/src/libide/lsp/ide-lsp-plugin.c
new file mode 100644
index 000000000..fdcecb1f7
--- /dev/null
+++ b/src/libide/lsp/ide-lsp-plugin.c
@@ -0,0 +1,427 @@
+/* ide-lsp-plugin.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-lsp-plugin"
+
+#include "config.h"
+
+#include "ide-lsp-diagnostic-provider.h"
+#include "ide-lsp-symbol-resolver.h"
+#include "ide-lsp-highlighter.h"
+#include "ide-lsp-formatter.h"
+#include "ide-lsp-hover-provider.h"
+#include "ide-lsp-rename-provider.h"
+#include "ide-lsp-code-action-provider.h"
+#include "ide-lsp-plugin-private.h"
+#include "ide-lsp-service.h"
+
+static const char *intern_plugin_info;
+static GType info_type;
+
+typedef enum _IdeLspPluginFeatures
+{
+  IDE_LSP_PLUGIN_FEATURES_DIAGNOSTICS     = 1 << 0,
+  IDE_LSP_PLUGIN_FEATURES_COMPLETION      = 1 << 1,
+  IDE_LSP_PLUGIN_FEATURES_SYMBOL_RESOLVER = 1 << 2,
+  IDE_LSP_PLUGIN_FEATURES_HIGHLIGHTER     = 1 << 3,
+  IDE_LSP_PLUGIN_FEATURES_FORMATTER       = 1 << 4,
+  IDE_LSP_PLUGIN_FEATURES_HOVER           = 1 << 5,
+  IDE_LSP_PLUGIN_FEATURES_RENAME          = 1 << 6,
+  IDE_LSP_PLUGIN_FEATURES_CODE_ACTION     = 1 << 7,
+  IDE_LSP_PLUGIN_FEATURES_ALL = ~0,
+} IdeLspPluginFeatures;
+
+IdeLspPluginInfo *
+ide_lsp_plugin_info_ref (IdeLspPluginInfo *self)
+{
+  return g_atomic_rc_box_acquire (self);
+}
+
+static void
+ide_lsp_plugin_info_finalize (gpointer data)
+{
+  IdeLspPluginInfo *self = data;
+
+  g_clear_pointer (&self->command, g_strfreev);
+  g_clear_pointer (&self->languages, g_strfreev);
+  g_clear_pointer (&self->default_settings, g_bytes_unref);
+  g_clear_pointer (&self->module_name, g_free);
+}
+
+void
+ide_lsp_plugin_info_unref (IdeLspPluginInfo *info)
+{
+  g_atomic_rc_box_release_full (info, ide_lsp_plugin_info_finalize);
+}
+
+static IdeLspPluginInfo *
+ide_lsp_plugin_info_new (void)
+{
+  return g_atomic_rc_box_new0 (IdeLspPluginInfo);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdeLspPluginInfo, ide_lsp_plugin_info_unref)
+
+static GBytes *
+load_bytes (const char *path)
+{
+  if (path == NULL)
+    {
+      return NULL;
+    }
+  else if (g_str_has_prefix (path, "resource://"))
+    {
+      return g_resources_lookup_data (path, 0, NULL);
+    }
+  else
+    {
+      g_autoptr(GFile) file = g_file_new_for_path (path);
+      return g_file_load_bytes (file, NULL, NULL, NULL);
+    }
+}
+
+typedef struct _IdeLspPluginService
+{
+  IdeLspService parent_instance;
+} IdeLspPluginService;
+
+typedef struct _IdeLspPluginServiceClass
+{
+  IdeLspServiceClass parent_class;
+  IdeLspPluginInfo *info;
+} IdeLspPluginServiceClass;
+
+static void
+ide_lsp_plugin_service_configure_client (IdeLspService *service,
+                                         IdeLspClient  *client)
+{
+  IdeLspPluginService *self = (IdeLspPluginService *)service;
+  //IdeLspPluginServiceClass *klass = (IdeLspPluginServiceClass *)((GTypeInstance *)service)->g_class;
+  g_autoptr(GVariant) options = NULL;
+  IdeContext *context;
+
+  g_assert (IDE_IS_LSP_SERVICE (self));
+  g_assert (IDE_IS_LSP_CLIENT (client));
+
+  if (!(context = ide_object_get_context (IDE_OBJECT (service))))
+    return;
+
+  /* TODO: User configurable settings */
+
+#if 0
+  if (klass->info->default_settings)
+    ide_lsp_client_set_initialization_options (client, klass->data->default_settings);
+#endif
+}
+
+static void
+ide_lsp_plugin_service_prepare_run_context (IdeLspService *service,
+                                            IdePipeline   *pipeline,
+                                            IdeRunContext *run_context)
+{
+  IdeLspPluginServiceClass *klass;
+
+  g_assert (IDE_IS_LSP_SERVICE (service));
+  g_assert (!pipeline || IDE_IS_PIPELINE (pipeline));
+  g_assert (IDE_IS_RUN_CONTEXT (run_context));
+
+  klass = (IdeLspPluginServiceClass *)G_OBJECT_GET_CLASS (service);
+
+  if (klass->info->command[0] && klass->info->command[1])
+    ide_run_context_append_args (run_context, (const char * const *)&klass->info->command[1]);
+}
+
+static void
+ide_lsp_plugin_service_class_init (IdeLspPluginServiceClass *klass,
+                                   IdeLspPluginInfo         *info)
+{
+  IdeLspServiceClass *service_class = IDE_LSP_SERVICE_CLASS (klass);
+
+  klass->info = info;
+
+  service_class->configure_client = ide_lsp_plugin_service_configure_client;
+  service_class->prepare_run_context = ide_lsp_plugin_service_prepare_run_context;
+}
+
+static void
+ide_lsp_plugin_service_init (IdeLspPluginService      *self,
+                             IdeLspPluginServiceClass *klass)
+{
+  ide_lsp_service_set_program (IDE_LSP_SERVICE (self), klass->info->command[0]);
+}
+
+static GType
+ide_lsp_plugin_register_service_gtype (IdeLspPluginInfo *info)
+{
+  g_autofree char *type_name = g_strconcat (info->module_name, "+IdeLspPluginService", NULL);
+  GTypeInfo type_info =
+  {
+    sizeof (IdeLspPluginServiceClass),
+    NULL,
+    NULL,
+    (GClassInitFunc)ide_lsp_plugin_service_class_init,
+    NULL,
+    ide_lsp_plugin_info_ref (info),
+    sizeof (IdeLspPluginService),
+    0,
+    (GInstanceInitFunc)ide_lsp_plugin_service_init,
+    NULL,
+  };
+  return g_type_register_static (IDE_TYPE_LSP_SERVICE, type_name, &type_info, G_TYPE_FLAG_FINAL);
+}
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+static GObject *
+ide_lsp_plugin_factory (IdeLspPluginInfo *info,
+                        GType             type,
+                        guint             n_parameters,
+                        GParameter       *parameters)
+{
+  return NULL;
+}
+
+
+static GObject *
+ide_lsp_plugin_diagnostic_factory (guint       n_parameters,
+                                   GParameter *parameters,
+                                   gpointer    user_data)
+{
+  return ide_lsp_plugin_factory (user_data, IDE_TYPE_LSP_DIAGNOSTIC_PROVIDER, n_parameters, parameters);
+}
+
+static GObject *
+ide_lsp_plugin_symbol_resolver_factory (guint       n_parameters,
+                                        GParameter *parameters,
+                                        gpointer    user_data)
+{
+  return ide_lsp_plugin_factory (user_data, IDE_TYPE_LSP_SYMBOL_RESOLVER, n_parameters, parameters);
+}
+
+static GObject *
+ide_lsp_plugin_highlighter_factory (guint       n_parameters,
+                                    GParameter *parameters,
+                                    gpointer    user_data)
+{
+  return ide_lsp_plugin_factory (user_data, IDE_TYPE_LSP_HIGHLIGHTER, n_parameters, parameters);
+}
+
+static GObject *
+ide_lsp_plugin_formatter_factory (guint       n_parameters,
+                                  GParameter *parameters,
+                                  gpointer    user_data)
+{
+  return ide_lsp_plugin_factory (user_data, IDE_TYPE_LSP_FORMATTER, n_parameters, parameters);
+}
+
+static GObject *
+ide_lsp_plugin_hover_factory (guint       n_parameters,
+                              GParameter *parameters,
+                              gpointer    user_data)
+{
+  return ide_lsp_plugin_factory (user_data, IDE_TYPE_LSP_HOVER_PROVIDER, n_parameters, parameters);
+}
+
+static GObject *
+ide_lsp_plugin_rename_factory (guint       n_parameters,
+                               GParameter *parameters,
+                               gpointer    user_data)
+{
+  return ide_lsp_plugin_factory (user_data, IDE_TYPE_LSP_RENAME_PROVIDER, n_parameters, parameters);
+}
+
+static GObject *
+ide_lsp_plugin_code_action_factory (guint       n_parameters,
+                                    GParameter *parameters,
+                                    gpointer    user_data)
+{
+  return ide_lsp_plugin_factory (user_data, IDE_TYPE_LSP_CODE_ACTION_PROVIDER, n_parameters, parameters);
+}
+
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+static void
+ide_lsp_plugin_register (PeasObjectModule     *object_module,
+                         IdeLspPluginFeatures  features,
+                         const char * const   *command,
+                         const char * const   *languages,
+                         GBytes               *default_settings)
+{
+  g_autoptr(IdeLspPluginInfo) info = NULL;
+
+  g_return_if_fail (PEAS_IS_OBJECT_MODULE (object_module));
+
+  info = ide_lsp_plugin_info_new ();
+  info->module_name = g_strdup (peas_object_module_get_module_name (object_module));
+  info->command = g_strdupv ((char **)command);
+  info->languages = g_strdupv ((char **)languages);
+  info->default_settings = default_settings ? g_bytes_ref (default_settings) : NULL;
+  info->service_type = ide_lsp_plugin_register_service_gtype (info);
+
+  g_log (info->module_name,
+         G_LOG_LEVEL_DEBUG,
+         "Registered type %s",
+         g_type_name (info->service_type));
+
+  if ((features & IDE_LSP_PLUGIN_FEATURES_DIAGNOSTICS) != 0)
+    peas_object_module_register_extension_factory (object_module,
+                                                   IDE_TYPE_DIAGNOSTIC_PROVIDER,
+                                                   ide_lsp_plugin_diagnostic_factory,
+                                                   ide_lsp_plugin_info_ref (info),
+                                                   (GDestroyNotify)ide_lsp_plugin_info_unref);
+
+  if ((features & IDE_LSP_PLUGIN_FEATURES_COMPLETION) != 0)
+    peas_object_module_register_extension_factory (object_module,
+                                                   GTK_SOURCE_TYPE_COMPLETION_PROVIDER,
+                                                   
(PeasFactoryFunc)ide_lsp_plugin_create_completion_provider,
+                                                   ide_lsp_plugin_info_ref (info),
+                                                   (GDestroyNotify)ide_lsp_plugin_info_unref);
+
+  if ((features & IDE_LSP_PLUGIN_FEATURES_SYMBOL_RESOLVER) != 0)
+    peas_object_module_register_extension_factory (object_module,
+                                                   IDE_TYPE_SYMBOL_RESOLVER,
+                                                   ide_lsp_plugin_symbol_resolver_factory,
+                                                   ide_lsp_plugin_info_ref (info),
+                                                   (GDestroyNotify)ide_lsp_plugin_info_unref);
+
+  if ((features & IDE_LSP_PLUGIN_FEATURES_HIGHLIGHTER) != 0)
+    peas_object_module_register_extension_factory (object_module,
+                                                   IDE_TYPE_HIGHLIGHTER,
+                                                   ide_lsp_plugin_highlighter_factory,
+                                                   ide_lsp_plugin_info_ref (info),
+                                                   (GDestroyNotify)ide_lsp_plugin_info_unref);
+
+  if ((features & IDE_LSP_PLUGIN_FEATURES_FORMATTER) != 0)
+    peas_object_module_register_extension_factory (object_module,
+                                                   IDE_TYPE_FORMATTER,
+                                                   ide_lsp_plugin_formatter_factory,
+                                                   ide_lsp_plugin_info_ref (info),
+                                                   (GDestroyNotify)ide_lsp_plugin_info_unref);
+
+  if ((features & IDE_LSP_PLUGIN_FEATURES_HOVER) != 0)
+    peas_object_module_register_extension_factory (object_module,
+                                                   GTK_SOURCE_TYPE_HOVER_PROVIDER,
+                                                   ide_lsp_plugin_hover_factory,
+                                                   ide_lsp_plugin_info_ref (info),
+                                                   (GDestroyNotify)ide_lsp_plugin_info_unref);
+
+  if ((features & IDE_LSP_PLUGIN_FEATURES_RENAME) != 0)
+    peas_object_module_register_extension_factory (object_module,
+                                                   IDE_TYPE_RENAME_PROVIDER,
+                                                   ide_lsp_plugin_rename_factory,
+                                                   ide_lsp_plugin_info_ref (info),
+                                                   (GDestroyNotify)ide_lsp_plugin_info_unref);
+
+  if ((features & IDE_LSP_PLUGIN_FEATURES_CODE_ACTION) != 0)
+    peas_object_module_register_extension_factory (object_module,
+                                                   IDE_TYPE_CODE_ACTION_PROVIDER,
+                                                   ide_lsp_plugin_code_action_factory,
+                                                   ide_lsp_plugin_info_ref (info),
+                                                   (GDestroyNotify)ide_lsp_plugin_info_unref);
+}
+
+void
+ide_lsp_plugin_register_types (PeasObjectModule *object_module)
+{
+  g_autofree char *x_lsp_languages = NULL;
+  g_autofree char *settings_path = NULL;
+  g_autoptr(GBytes) default_settings = NULL;
+  g_autoptr(GError) error = NULL;
+  g_auto(GStrv) argv = NULL;
+  g_auto(GStrv) languages = NULL;
+  PeasPluginInfo *plugin_info;
+  PeasEngine *engine;
+  const char *data_dir;
+  const char *module_name;
+  const char *x_lsp_command;
+  const char *x_lsp_settings;
+  int argc;
+
+  g_return_if_fail (PEAS_IS_OBJECT_MODULE (object_module));
+
+  if G_UNLIKELY (intern_plugin_info)
+    intern_plugin_info = g_intern_string ("plugin-info");
+
+  if G_UNLIKELY (info_type == G_TYPE_INVALID)
+    info_type = PEAS_TYPE_PLUGIN_INFO;
+
+  engine = peas_engine_get_default ();
+  module_name = peas_object_module_get_module_name (object_module);
+  plugin_info = peas_engine_get_plugin_info (engine, module_name);
+  x_lsp_command = peas_plugin_info_get_external_data (plugin_info, "LSP-Command");
+  x_lsp_languages = g_strdup (peas_plugin_info_get_external_data (plugin_info, "LSP-Languages"));
+  x_lsp_settings = peas_plugin_info_get_external_data (plugin_info, "LSP-Settings");
+  data_dir = peas_plugin_info_get_data_dir (plugin_info);
+
+  if (x_lsp_command == NULL)
+    {
+      g_critical ("Plugin %s missing X-LSP-Command=", module_name);
+      return;
+    }
+
+  if (x_lsp_languages == NULL)
+    {
+      g_critical ("Plugin %s missing X-LSP-Languages=", module_name);
+      return;
+    }
+
+  languages = g_strsplit (g_strdelimit (x_lsp_languages, ",", ';'), ";", 0);
+
+  if (!g_shell_parse_argv (x_lsp_command, &argc, &argv, &error))
+    {
+      g_critical ("Plugin %s provides invalid X-LSP-Command=%s: %s",
+                  module_name, x_lsp_command, error->message);
+      return;
+    }
+
+  if (x_lsp_settings == NULL)
+    x_lsp_settings = "settings.json";
+
+  settings_path = g_build_filename (data_dir, x_lsp_settings, NULL);
+  default_settings = load_bytes (settings_path);
+
+  ide_lsp_plugin_register (object_module,
+                           IDE_LSP_PLUGIN_FEATURES_ALL,
+                           (const char * const *)argv,
+                           (const char * const *)languages,
+                           default_settings);
+}
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+void
+ide_lsp_plugin_remove_plugin_info_param (guint      *n_parameters,
+                                         GParameter *parameters)
+{
+  static GType plugin_info_type;
+  const GParameter *param;
+
+  if (*n_parameters == 0)
+    return;
+
+  if G_UNLIKELY (plugin_info_type == G_TYPE_INVALID)
+    plugin_info_type = PEAS_TYPE_PLUGIN_INFO;
+
+  param = &parameters[(*n_parameters) - 1];
+
+  if (G_VALUE_TYPE (&param->value) == plugin_info_type &&
+      strcmp (param->name, "plugin-info") == 0)
+    (*n_parameters)--;
+}
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
diff --git a/src/libide/lsp/ide-lsp-plugin.h b/src/libide/lsp/ide-lsp-plugin.h
new file mode 100644
index 000000000..6c2284632
--- /dev/null
+++ b/src/libide/lsp/ide-lsp-plugin.h
@@ -0,0 +1,32 @@
+/* ide-lsp-plugin.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libpeas/peas.h>
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+IDE_AVAILABLE_IN_44
+void ide_lsp_plugin_register_types (PeasObjectModule *object_module);
+
+G_END_DECLS
diff --git a/src/libide/lsp/libide-lsp.h b/src/libide/lsp/libide-lsp.h
index 765bd7176..362fad933 100644
--- a/src/libide/lsp/libide-lsp.h
+++ b/src/libide/lsp/libide-lsp.h
@@ -38,6 +38,7 @@
 #include "ide-lsp-formatter.h"
 #include "ide-lsp-highlighter.h"
 #include "ide-lsp-hover-provider.h"
+#include "ide-lsp-plugin.h"
 #include "ide-lsp-rename-provider.h"
 #include "ide-lsp-search-provider.h"
 #include "ide-lsp-service.h"
diff --git a/src/libide/lsp/meson.build b/src/libide/lsp/meson.build
index f623287d5..3e769d2f9 100644
--- a/src/libide/lsp/meson.build
+++ b/src/libide/lsp/meson.build
@@ -19,6 +19,7 @@ libide_lsp_public_headers = [
   'ide-lsp-formatter.h',
   'ide-lsp-highlighter.h',
   'ide-lsp-hover-provider.h',
+  'ide-lsp-plugin.h',
   'ide-lsp-rename-provider.h',
   'ide-lsp-search-provider.h',
   'ide-lsp-service.h',
@@ -31,6 +32,7 @@ libide_lsp_public_headers = [
 ]
 
 libide_lsp_private_headers = [
+  'ide-lsp-plugin-private.h',
   'ide-lsp-symbol-node-private.h',
   'ide-lsp-symbol-tree-private.h',
 ]
@@ -53,6 +55,8 @@ libide_lsp_public_sources = [
   'ide-lsp-formatter.c',
   'ide-lsp-highlighter.c',
   'ide-lsp-hover-provider.c',
+  'ide-lsp-plugin.c',
+  'ide-lsp-plugin-completion-provider.c',
   'ide-lsp-rename-provider.c',
   'ide-lsp-search-provider.c',
   'ide-lsp-search-result.c',
diff --git a/src/libide/plugins/ide-extension-set-adapter.c b/src/libide/plugins/ide-extension-set-adapter.c
index ad9fe72be..75e8e5ad5 100644
--- a/src/libide/plugins/ide-extension-set-adapter.c
+++ b/src/libide/plugins/ide-extension-set-adapter.c
@@ -225,7 +225,8 @@ ide_extension_set_adapter_reload (IdeExtensionSetAdapter *self)
                                          self->interface_type,
                                          NULL);
 
-              add_extension (self, plugin_info, exten);
+              if (exten != NULL)
+                add_extension (self, plugin_info, exten);
             }
         }
       else
diff --git a/src/plugins/bash-language-server/bash-language-server-plugin.c 
b/src/plugins/bash-language-server/bash-language-server-plugin.c
index 284366753..19211d7ef 100644
--- a/src/plugins/bash-language-server/bash-language-server-plugin.c
+++ b/src/plugins/bash-language-server/bash-language-server-plugin.c
@@ -28,41 +28,7 @@
 #include <libide-foundry.h>
 #include <libide-lsp.h>
 
-#include "gbp-bash-service.h"
-#include "gbp-bash-completion-provider.h"
-#include "gbp-bash-diagnostic-provider.h"
-#include "gbp-bash-symbol-resolver.h"
-#include "gbp-bash-highlighter.h"
-#include "gbp-bash-formatter.h"
-#include "gbp-bash-rename-provider.h"
-#include "gbp-bash-hover-provider.h"
-#include "gbp-bash-code-action-provider.h"
-
 _IDE_EXTERN void
 _gbp_bash_register_types (PeasObjectModule *module)
 {
-  peas_object_module_register_extension_type (module,
-                                              IDE_TYPE_DIAGNOSTIC_PROVIDER,
-                                              GBP_TYPE_BASH_DIAGNOSTIC_PROVIDER);
-  peas_object_module_register_extension_type (module,
-                                              GTK_SOURCE_TYPE_COMPLETION_PROVIDER,
-                                              GBP_TYPE_BASH_COMPLETION_PROVIDER);
-  peas_object_module_register_extension_type (module,
-                                              IDE_TYPE_SYMBOL_RESOLVER,
-                                              GBP_TYPE_BASH_SYMBOL_RESOLVER);
-  peas_object_module_register_extension_type (module,
-                                              IDE_TYPE_HIGHLIGHTER,
-                                              GBP_TYPE_BASH_HIGHLIGHTER);
-  peas_object_module_register_extension_type (module,
-                                              IDE_TYPE_FORMATTER,
-                                              GBP_TYPE_BASH_FORMATTER);
-  peas_object_module_register_extension_type (module,
-                                              GTK_SOURCE_TYPE_HOVER_PROVIDER,
-                                              GBP_TYPE_BASH_HOVER_PROVIDER);
-  peas_object_module_register_extension_type (module,
-                                              IDE_TYPE_RENAME_PROVIDER,
-                                              GBP_TYPE_BASH_RENAME_PROVIDER);
-  peas_object_module_register_extension_type (module,
-                                              IDE_TYPE_CODE_ACTION_PROVIDER,
-                                              GBP_TYPE_BASH_CODE_ACTION_PROVIDER);
 }
diff --git a/src/plugins/bash-language-server/bash-language-server.gresource.xml 
b/src/plugins/bash-language-server/bash-language-server.gresource.xml
index 3f77de6c9..494413573 100644
--- a/src/plugins/bash-language-server/bash-language-server.gresource.xml
+++ b/src/plugins/bash-language-server/bash-language-server.gresource.xml
@@ -2,5 +2,6 @@
 <gresources>
   <gresource prefix="/plugins/bash-language-server">
     <file>bash-language-server.plugin</file>
+    <file>settings.json</file>
   </gresource>
 </gresources>
diff --git a/src/plugins/bash-language-server/bash-language-server.plugin 
b/src/plugins/bash-language-server/bash-language-server.plugin
index 0ee5bcea1..a7c2ffdc2 100644
--- a/src/plugins/bash-language-server/bash-language-server.plugin
+++ b/src/plugins/bash-language-server/bash-language-server.plugin
@@ -1,11 +1,14 @@
 [Plugin]
 Builtin=true
-Copyright=Copyright © 2021 Günther Wagner, Copyright © 2022 Christian Hergert
+Copyright=Copyright © 2022 Christian Hergert
 Description=Provides integration with bash-language-server for Bash
-Embedded=_gbp_bash_register_types
+Embedded=ide_lsp_plugin_register_types
 Module=bash-language-server
 Name=Bash Language Server
 X-Category=lsps
+X-LSP-Command=bash-language-server start
+X-LSP-Languages=sh
+X-LSP-Settings=settings.json
 X-Completion-Provider-Languages=sh
 X-Symbol-Resolver-Languages=sh
 X-Diagnostic-Provider-Languages=sh
diff --git a/src/plugins/bash-language-server/settings.json b/src/plugins/bash-language-server/settings.json
new file mode 100644
index 000000000..2c2e02b96
--- /dev/null
+++ b/src/plugins/bash-language-server/settings.json
@@ -0,0 +1,4 @@
+{
+    "bash-language-server" : {
+    }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]