[gnome-builder: 1/6] lsp: allow nested lsp project



commit 6d13199df0609160b8c7dbdbdafb9e296677b608
Author: Günther Wagner <info gunibert de>
Date:   Tue Jun 30 22:48:18 2020 +0200

    lsp: allow nested lsp project
    
    Its possible to set the root directory for the lsp now from the caller.
    This way we can determine the root directory from a lsp plugin and
    therefore enable nested projects.

 src/libide/lsp/ide-lsp-client.c                   | 37 ++++++++++++++++-
 src/libide/lsp/ide-lsp-client.h                   |  3 ++
 src/plugins/rust-analyzer/rust-analyzer-service.c | 50 ++++++++++++++++++++---
 3 files changed, 83 insertions(+), 7 deletions(-)
---
diff --git a/src/libide/lsp/ide-lsp-client.c b/src/libide/lsp/ide-lsp-client.c
index e73ef6d13..e6a0efc76 100644
--- a/src/libide/lsp/ide-lsp-client.c
+++ b/src/libide/lsp/ide-lsp-client.c
@@ -51,6 +51,7 @@ typedef struct
   GPtrArray      *languages;
   GVariant       *server_capabilities;
   IdeLspTrace     trace;
+  gchar          *root_uri;
 } IdeLspClientPrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (IdeLspClient, ide_lsp_client, IDE_TYPE_OBJECT)
@@ -79,6 +80,7 @@ enum {
   PROP_IO_STREAM,
   PROP_SERVER_CAPABILITIES,
   PROP_TRACE,
+  PROP_ROOT_URI,
   N_PROPS
 };
 
@@ -1034,6 +1036,7 @@ ide_lsp_client_finalize (GObject *object)
   g_clear_pointer (&priv->diagnostics_by_file, g_hash_table_unref);
   g_clear_pointer (&priv->server_capabilities, g_variant_unref);
   g_clear_pointer (&priv->languages, g_ptr_array_unref);
+  g_clear_pointer (&priv->root_uri, g_free);
   g_clear_object (&priv->rpc_client);
   g_clear_object (&priv->buffer_manager_signals);
   g_clear_object (&priv->project_signals);
@@ -1085,6 +1088,9 @@ ide_lsp_client_get_property (GObject    *object,
       g_value_set_enum (value, ide_lsp_client_get_trace (self));
       break;
 
+    case PROP_ROOT_URI:
+      g_value_set_string (value, priv->root_uri);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -1109,6 +1115,10 @@ ide_lsp_client_set_property (GObject      *object,
       ide_lsp_client_set_trace (self, g_value_get_enum (value));
       break;
 
+    case PROP_ROOT_URI:
+      ide_lsp_client_set_root_uri (self, g_value_get_string (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -1149,6 +1159,13 @@ ide_lsp_client_class_init (IdeLspClientClass *klass)
                        IDE_LSP_TRACE_OFF,
                        (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_ROOT_URI] =
+    g_param_spec_string ("root-uri",
+                         "Root Uri",
+                         "The root uri the LSP should work on",
+                         "",
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_properties (object_class, N_PROPS, properties);
 
 
@@ -1397,7 +1414,9 @@ ide_lsp_client_start (IdeLspClient *self)
 
   workdir = ide_context_ref_workdir (context);
   root_path = g_file_get_path (workdir);
-  root_uri = g_file_get_uri (workdir);
+  root_uri = priv->root_uri;
+  if (root_uri == NULL)
+    root_uri = g_file_get_uri (workdir);
 
   switch (priv->trace)
     {
@@ -1910,6 +1929,22 @@ ide_lsp_client_set_trace (IdeLspClient *self,
     }
 }
 
+void
+ide_lsp_client_set_root_uri (IdeLspClient *self,
+                             const gchar  *root_uri)
+{
+  IdeLspClientPrivate *priv = ide_lsp_client_get_instance_private (self);
+
+  g_return_if_fail (IDE_IS_LSP_CLIENT (self));
+
+  if (!ide_str_equal0 (priv->root_uri, root_uri))
+    {
+      g_free (priv->root_uri);
+      priv->root_uri = g_strdup (root_uri);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ROOT_URI]);
+    }
+}
+
 /**
  * ide_lsp_client_get_server_capabilities:
  * @self: a #IdeLspClient
diff --git a/src/libide/lsp/ide-lsp-client.h b/src/libide/lsp/ide-lsp-client.h
index e6e1bfb55..66a4ea74e 100644
--- a/src/libide/lsp/ide-lsp-client.h
+++ b/src/libide/lsp/ide-lsp-client.h
@@ -71,6 +71,9 @@ GVariant     *ide_lsp_client_get_server_capabilities  (IdeLspClient         *sel
 IDE_AVAILABLE_IN_3_32
 void          ide_lsp_client_add_language             (IdeLspClient         *self,
                                                        const gchar          *language_id);
+IDE_AVAILABLE_IN_3_38
+void          ide_lsp_client_set_root_uri             (IdeLspClient         *self,
+                                                       const gchar          *root_uri);
 IDE_AVAILABLE_IN_3_32
 void          ide_lsp_client_start                    (IdeLspClient         *self);
 IDE_AVAILABLE_IN_3_32
diff --git a/src/plugins/rust-analyzer/rust-analyzer-service.c 
b/src/plugins/rust-analyzer/rust-analyzer-service.c
index 3a1948e22..76368b12b 100644
--- a/src/plugins/rust-analyzer/rust-analyzer-service.c
+++ b/src/plugins/rust-analyzer/rust-analyzer-service.c
@@ -29,6 +29,7 @@
 #include <jsonrpc-glib.h>
 #include <glib/gi18n.h>
 #include <libide-search.h>
+#include <libide-io.h>
 #include "rust-analyzer-search-provider.h"
 
 struct _RustAnalyzerService
@@ -91,6 +92,34 @@ _get_search_engine (RustAnalyzerService *self)
   return ide_object_get_child_typed (IDE_OBJECT (context), IDE_TYPE_SEARCH_ENGINE);
 }
 
+static GFile *
+rust_analyzer_service_determine_workdir (RustAnalyzerService *self)
+{
+  g_autoptr(GFile) workdir = NULL;
+  g_autoptr(GPtrArray) possible_workdirs = NULL;
+  IdeContext *context = NULL;
+
+  g_assert (RUST_IS_ANALYZER_SERVICE (self));
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  workdir = ide_context_ref_workdir (context);
+
+  possible_workdirs = ide_g_file_find_with_depth (workdir, "Cargo.toml", 5, NULL);
+  IDE_PTR_ARRAY_SET_FREE_FUNC (possible_workdirs, g_object_unref);
+
+  if (possible_workdirs->len > 0)
+    {
+      // take the first directory with a Cargo.toml file as root. Multiple workspaces are only
+      // supported if a Cargo-workspace exists.
+      g_autoptr(GFile) parent = NULL;
+      parent = g_file_get_parent (g_ptr_array_index (possible_workdirs, 0));
+
+      return g_steal_pointer (&parent);
+    }
+
+  return g_steal_pointer (&workdir);
+}
+
 static GVariant *
 rust_analyzer_service_load_configuration (IdeLspClient *client,
                                           gpointer      user_data)
@@ -270,7 +299,11 @@ rust_analyzer_service_set_client (RustAnalyzerService *self,
 
   if (g_set_object (&self->client, client))
     {
-      g_signal_connect (self->client, "load-configuration", G_CALLBACK 
(rust_analyzer_service_load_configuration), self);
+      g_signal_connect_object (self->client,
+                               "load-configuration",
+                               G_CALLBACK (rust_analyzer_service_load_configuration),
+                               self,
+                               G_CONNECT_AFTER);
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CLIENT]);
     }
 }
@@ -296,6 +329,8 @@ rust_analyzer_service_lsp_started (IdeSubprocessSupervisor *supervisor,
 {
   RustAnalyzerService *self = user_data;
   g_autoptr(GIOStream) io_stream = NULL;
+  g_autoptr(GFile) workdir = NULL;
+  g_autofree gchar *root_uri = NULL;
   GInputStream *input;
   GOutputStream *output;
   IdeLspClient *client = NULL;
@@ -319,6 +354,9 @@ rust_analyzer_service_lsp_started (IdeSubprocessSupervisor *supervisor,
   rust_analyzer_service_set_client (self, client);
   ide_object_append (IDE_OBJECT (self), IDE_OBJECT (client));
   ide_lsp_client_add_language (client, "rust");
+  workdir = rust_analyzer_service_determine_workdir (self);
+  root_uri = g_file_get_uri (workdir);
+  ide_lsp_client_set_root_uri (client, root_uri);
   ide_lsp_client_start (client);
 
   // register SearchProvider
@@ -404,18 +442,18 @@ rust_analyzer_service_ensure_started (RustAnalyzerService *self)
   else if (self->state == RUST_ANALYZER_SERVICE_READY)
     {
       g_autofree gchar *newpath = NULL;
+      g_autoptr(GFile) workdir = NULL;
+      g_autofree gchar *root_path = NULL;
       g_autoptr(IdeSubprocessLauncher) launcher = NULL;
-      IdeContext *context = NULL;
-      GFile *workdir = NULL;
       const gchar *oldpath = NULL;
 
       launcher = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE | 
G_SUBPROCESS_FLAGS_STDIN_PIPE);
       ide_subprocess_launcher_set_run_on_host (launcher, TRUE);
       ide_subprocess_launcher_set_clear_env (launcher, TRUE);
 
-      context = ide_object_get_context (IDE_OBJECT (self));
-      workdir = ide_context_ref_workdir (context);
-      ide_subprocess_launcher_set_cwd (launcher, g_file_get_path (workdir));
+      workdir = rust_analyzer_service_determine_workdir (self);
+      root_path = g_file_get_path (workdir);
+      ide_subprocess_launcher_set_cwd (launcher, root_path);
       oldpath = g_getenv ("PATH");
       newpath = g_strdup_printf ("%s/%s:%s", g_get_home_dir (), ".cargo/bin", oldpath);
       ide_subprocess_launcher_setenv (launcher, "PATH", newpath, TRUE);


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