[gnome-builder: 46/139] libide-vcs: add libide-vcs static library
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder: 46/139] libide-vcs: add libide-vcs static library
- Date: Thu, 10 Jan 2019 04:21:11 +0000 (UTC)
commit 8d41d9a502896e1f7d8cd984d74c738286ff261a
Author: Christian Hergert <chergert redhat com>
Date: Wed Jan 9 16:36:20 2019 -0800
libide-vcs: add libide-vcs static library
This breaks out the vcs components into a new static library. It also
moves some editor components into a plugin vcsui to bridge between the
libide-vcs layer and the libide-editor layer.
Some simplification of the IdeVcs occurred, and will likely gain more
changes as we add support for more VCS features.
src/libide/vcs/ide-directory-vcs.c | 180 +++++++++++
src/libide/vcs/ide-directory-vcs.h | 36 +++
src/libide/vcs/ide-vcs-cloner.c | 148 +++++++++
src/libide/vcs/ide-vcs-cloner.h | 73 +++++
src/libide/vcs/ide-vcs-config.c | 3 +-
src/libide/vcs/ide-vcs-config.h | 6 +-
src/libide/vcs/ide-vcs-file-info.c | 7 +-
src/libide/vcs/ide-vcs-file-info.h | 6 +-
src/libide/vcs/ide-vcs-initializer.c | 2 +-
src/libide/vcs/ide-vcs-initializer.h | 6 +-
src/libide/vcs/ide-vcs-monitor.c | 392 +++++++++++++++++-------
src/libide/vcs/ide-vcs-monitor.h | 22 +-
src/libide/vcs/ide-vcs-uri.c | 59 +++-
src/libide/vcs/ide-vcs-uri.h | 50 +--
src/libide/vcs/ide-vcs.c | 260 +++++-----------
src/libide/vcs/ide-vcs.h | 29 +-
src/libide/vcs/libide-vcs.h | 38 +++
src/libide/vcs/meson.build | 83 ++++-
src/plugins/vcsui/gbp-vcsui-editor-page-addin.c | 137 +++++++++
src/plugins/vcsui/gbp-vcsui-editor-page-addin.h | 31 ++
src/plugins/vcsui/gbp-vcsui-tree-addin.c | 209 +++++++++++++
src/plugins/vcsui/gbp-vcsui-tree-addin.h | 31 ++
src/plugins/vcsui/gtk/menus.ui | 20 ++
src/plugins/vcsui/meson.build | 13 +
src/plugins/vcsui/vcsui-plugin.c | 42 +++
src/plugins/vcsui/vcsui.gresource.xml | 7 +
src/plugins/vcsui/vcsui.plugin | 11 +
27 files changed, 1537 insertions(+), 364 deletions(-)
---
diff --git a/src/libide/vcs/ide-directory-vcs.c b/src/libide/vcs/ide-directory-vcs.c
new file mode 100644
index 000000000..6311168d8
--- /dev/null
+++ b/src/libide/vcs/ide-directory-vcs.c
@@ -0,0 +1,180 @@
+/* ide-directory-vcs.c
+ *
+ * Copyright 2015-2019 Christian Hergert <christian hergert me>
+ *
+ * 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-directory-vcs"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <libide-threading.h>
+
+#include "ide-context.h"
+
+#include "ide-directory-vcs.h"
+
+struct _IdeDirectoryVcs
+{
+ IdeObject parent_instances;
+ GFile *workdir;
+};
+
+#define LOAD_MAX_FILES 5000
+
+static void vcs_iface_init (IdeVcsInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (IdeDirectoryVcs, ide_directory_vcs, IDE_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_VCS, vcs_iface_init))
+
+enum {
+ PROP_0,
+ N_PROPS,
+
+ /* Override Properties */
+ PROP_BRANCH_NAME,
+ PROP_WORKDIR,
+};
+
+static gchar *
+ide_directory_vcs_get_branch_name (IdeVcs *vcs)
+{
+ return g_strdup (_("unversioned"));
+}
+
+static GFile *
+ide_directory_vcs_get_workdir (IdeVcs *vcs)
+{
+ IdeDirectoryVcs *self = (IdeDirectoryVcs *)vcs;
+
+ g_return_val_if_fail (IDE_IS_DIRECTORY_VCS (vcs), NULL);
+
+ /* Note: This function is expected to be thread-safe for
+ * those holding a reference to @vcs. So
+ * @workdir cannot be changed after creation
+ * and must be valid for the lifetime of @vcs.
+ */
+
+ return self->workdir;
+}
+
+static gboolean
+ide_directory_vcs_is_ignored (IdeVcs *vcs,
+ GFile *file,
+ GError **error)
+{
+ g_autofree gchar *reversed = NULL;
+
+ g_assert (IDE_IS_VCS (vcs));
+ g_assert (G_IS_FILE (file));
+
+ reversed = g_strreverse (g_file_get_basename (file));
+
+ /* check suffixes, in reverse */
+ if ((reversed [0] == '~') ||
+ (strncmp (reversed, "al.", 3) == 0) || /* .la */
+ (strncmp (reversed, "ol.", 3) == 0) || /* .lo */
+ (strncmp (reversed, "o.", 2) == 0) || /* .o */
+ (strncmp (reversed, "pws.", 4) == 0) || /* .swp */
+ (strncmp (reversed, "sped.", 5) == 0) || /* .deps */
+ (strncmp (reversed, "sbil.", 5) == 0) || /* .libs */
+ (strncmp (reversed, "cyp.", 4) == 0) || /* .pyc */
+ (strncmp (reversed, "oyp.", 4) == 0) || /* .pyo */
+ (strncmp (reversed, "omg.", 4) == 0) || /* .gmo */
+ (strncmp (reversed, "tig.", 4) == 0) || /* .git */
+ (strncmp (reversed, "rzb.", 4) == 0) || /* .bzr */
+ (strncmp (reversed, "nvs.", 4) == 0) || /* .svn */
+ (strncmp (reversed, "pmatsrid.", 9) == 0) || /* .dirstamp */
+ (strncmp (reversed, "hcg.", 4) == 0)) /* .gch */
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+ide_directory_vcs_dispose (GObject *object)
+{
+ IdeDirectoryVcs *self = (IdeDirectoryVcs *)object;
+
+ g_clear_object (&self->workdir);
+
+ G_OBJECT_CLASS (ide_directory_vcs_parent_class)->dispose (object);
+}
+
+static void
+ide_directory_vcs_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeDirectoryVcs *self = IDE_DIRECTORY_VCS (object);
+
+ switch (prop_id)
+ {
+ case PROP_BRANCH_NAME:
+ g_value_take_string (value, ide_directory_vcs_get_branch_name (IDE_VCS (self)));
+ break;
+
+ case PROP_WORKDIR:
+ g_value_set_object (value, ide_directory_vcs_get_workdir (IDE_VCS (self)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_directory_vcs_class_init (IdeDirectoryVcsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = ide_directory_vcs_dispose;
+ object_class->get_property = ide_directory_vcs_get_property;
+
+ g_object_class_override_property (object_class, PROP_BRANCH_NAME, "branch-name");
+ g_object_class_override_property (object_class, PROP_WORKDIR, "workdir");
+}
+
+static void
+ide_directory_vcs_init (IdeDirectoryVcs *self)
+{
+}
+
+static gint
+ide_directory_vcs_get_priority (IdeVcs *vcs)
+{
+ return G_MAXINT;
+}
+
+static void
+vcs_iface_init (IdeVcsInterface *iface)
+{
+ iface->get_workdir = ide_directory_vcs_get_workdir;
+ iface->is_ignored = ide_directory_vcs_is_ignored;
+ iface->get_priority = ide_directory_vcs_get_priority;
+ iface->get_branch_name = ide_directory_vcs_get_branch_name;
+}
+
+IdeDirectoryVcs *
+ide_directory_vcs_new (GFile *workdir)
+{
+ IdeDirectoryVcs *self = g_object_new (IDE_TYPE_DIRECTORY_VCS, NULL);
+ self->workdir = g_file_dup (workdir);
+ return self;
+}
diff --git a/src/libide/vcs/ide-directory-vcs.h b/src/libide/vcs/ide-directory-vcs.h
new file mode 100644
index 000000000..3f1b9f575
--- /dev/null
+++ b/src/libide/vcs/ide-directory-vcs.h
@@ -0,0 +1,36 @@
+/* ide-directory-vcs.h
+ *
+ * Copyright 2015-2019 Christian Hergert <christian hergert me>
+ *
+ * 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 <libide-core.h>
+
+#include "ide-vcs.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_DIRECTORY_VCS (ide_directory_vcs_get_type())
+
+IDE_AVAILABLE_IN_3_32
+G_DECLARE_FINAL_TYPE (IdeDirectoryVcs, ide_directory_vcs, IDE, DIRECTORY_VCS, IdeObject)
+
+IdeDirectoryVcs *ide_directory_vcs_new (GFile *workdir);
+
+G_END_DECLS
diff --git a/src/libide/vcs/ide-vcs-cloner.c b/src/libide/vcs/ide-vcs-cloner.c
new file mode 100644
index 000000000..b1c798e89
--- /dev/null
+++ b/src/libide/vcs/ide-vcs-cloner.c
@@ -0,0 +1,148 @@
+/* ide-vcs-cloner.c
+ *
+ * Copyright 2018-2019 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-vcs-cloner"
+
+#include "config.h"
+
+#include <libide-threading.h>
+
+#include "ide-vcs-cloner.h"
+
+G_DEFINE_INTERFACE (IdeVcsCloner, ide_vcs_cloner, G_TYPE_OBJECT)
+
+static void
+ide_vcs_cloner_default_init (IdeVcsClonerInterface *iface)
+{
+}
+
+/**
+ * ide_vcs_cloner_validate_uri:
+ * @self: a #IdeVcsCloner
+ * @uri: a string containing the URI to validate
+ * @errmsg: (out) (optional): a location for an error message
+ *
+ * Checks to see if @uri is valid, and if not, sets @errmsg to a string
+ * describing how the URI is invalid.
+ *
+ * Returns: %TRUE if @uri is valid, otherwise %FALSE and @error is set.
+ *
+ * Since: 3.32
+ */
+gboolean
+ide_vcs_cloner_validate_uri (IdeVcsCloner *self,
+ const gchar *uri,
+ gchar **errmsg)
+{
+ g_return_val_if_fail (IDE_IS_VCS_CLONER (self), FALSE);
+
+ if (errmsg != NULL)
+ *errmsg = NULL;
+
+ if (IDE_VCS_CLONER_GET_IFACE (self)->validate_uri)
+ return IDE_VCS_CLONER_GET_IFACE (self)->validate_uri (self, uri, errmsg);
+
+ return FALSE;
+}
+
+/**
+ * ide_vcs_cloner_clone_async:
+ * @self: an #IdeVcsCloner
+ * @uri: a string containing the URI
+ * @destination: a string containing the destination path
+ * @options: a #GVariantDict containing any user supplied options
+ * @cancellable: (nullable): a #GCancellable
+ * @progress: (out) (optional): a location for an #IdeNotification, or %NULL
+ * @callback: a #GAsyncReadyCallback to execute upon completion
+ * @user_data: closure data for @callback
+ *
+ * Since: 3.32
+ */
+void
+ide_vcs_cloner_clone_async (IdeVcsCloner *self,
+ const gchar *uri,
+ const gchar *destination,
+ GVariantDict *options,
+ GCancellable *cancellable,
+ IdeNotification **progress,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (IDE_IS_VCS_CLONER (self));
+ g_return_if_fail (uri != NULL);
+ g_return_if_fail (destination != NULL);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ if (progress != NULL)
+ *progress = NULL;
+
+ IDE_VCS_CLONER_GET_IFACE (self)->clone_async (self,
+ uri,
+ destination,
+ options,
+ cancellable,
+ progress,
+ callback,
+ user_data);
+}
+
+/**
+ * ide_vcs_cloner_clone_finish:
+ * @self: an #IdeVcsCloner
+ * @result: a #GAsyncResult provided to callback
+ * @error: a location for a #GError, or %NULL
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @error is set.
+ *
+ * Since: 3.32
+ */
+gboolean
+ide_vcs_cloner_clone_finish (IdeVcsCloner *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (IDE_IS_VCS_CLONER (self), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+ return IDE_VCS_CLONER_GET_IFACE (self)->clone_finish (self, result, error);
+}
+
+/**
+ * ide_vcs_cloner_get_title:
+ * @self: a #IdeVcsCloner
+ *
+ * Gets the for the cloner, such as "Git". This may be used to present
+ * a selector to the user based on the backend clone engine. Other suitable
+ * titles might be "Subversion" or "CVS".
+ *
+ * Returns: (transfer full): a string containing the title
+ *
+ * Since: 3.32
+ */
+gchar *
+ide_vcs_cloner_get_title (IdeVcsCloner *self)
+{
+ g_return_val_if_fail (IDE_IS_VCS_CLONER (self), NULL);
+
+ if (IDE_VCS_CLONER_GET_IFACE (self)->get_title)
+ return IDE_VCS_CLONER_GET_IFACE (self)->get_title (self);
+
+ return NULL;
+}
diff --git a/src/libide/vcs/ide-vcs-cloner.h b/src/libide/vcs/ide-vcs-cloner.h
new file mode 100644
index 000000000..69e464c9f
--- /dev/null
+++ b/src/libide/vcs/ide-vcs-cloner.h
@@ -0,0 +1,73 @@
+/* ide-vcs-cloner.h
+ *
+ * Copyright 2018-2019 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 <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_VCS_CLONER (ide_vcs_cloner_get_type())
+
+IDE_AVAILABLE_IN_3_32
+G_DECLARE_INTERFACE (IdeVcsCloner, ide_vcs_cloner, IDE, VCS_CLONER, GObject)
+
+struct _IdeVcsClonerInterface
+{
+ GTypeInterface parent_iface;
+
+ gchar *(*get_title) (IdeVcsCloner *self);
+ gboolean (*validate_uri) (IdeVcsCloner *self,
+ const gchar *uri,
+ gchar **errmsg);
+ void (*clone_async) (IdeVcsCloner *self,
+ const gchar *uri,
+ const gchar *destination,
+ GVariantDict *options,
+ GCancellable *cancellable,
+ IdeNotification **progress,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (*clone_finish) (IdeVcsCloner *self,
+ GAsyncResult *result,
+ GError **error);
+};
+
+IDE_AVAILABLE_IN_3_32
+gchar *ide_vcs_cloner_get_title (IdeVcsCloner *self);
+IDE_AVAILABLE_IN_3_32
+void ide_vcs_cloner_clone_async (IdeVcsCloner *self,
+ const gchar *uri,
+ const gchar *destination,
+ GVariantDict *options,
+ GCancellable *cancellable,
+ IdeNotification **progress,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_3_32
+gboolean ide_vcs_cloner_clone_finish (IdeVcsCloner *self,
+ GAsyncResult *result,
+ GError **error);
+IDE_AVAILABLE_IN_3_32
+gboolean ide_vcs_cloner_validate_uri (IdeVcsCloner *self,
+ const gchar *uri,
+ gchar **errmsg);
+
+G_END_DECLS
diff --git a/src/libide/vcs/ide-vcs-config.c b/src/libide/vcs/ide-vcs-config.c
index b03817e65..8b6c4780a 100644
--- a/src/libide/vcs/ide-vcs-config.c
+++ b/src/libide/vcs/ide-vcs-config.c
@@ -22,7 +22,8 @@
#include "config.h"
-#include "vcs/ide-vcs-config.h"
+#include "ide-vcs-config.h"
+#include "ide-vcs-enums.h"
G_DEFINE_INTERFACE (IdeVcsConfig, ide_vcs_config, G_TYPE_OBJECT)
diff --git a/src/libide/vcs/ide-vcs-config.h b/src/libide/vcs/ide-vcs-config.h
index 387aa331b..457639791 100644
--- a/src/libide/vcs/ide-vcs-config.h
+++ b/src/libide/vcs/ide-vcs-config.h
@@ -20,9 +20,11 @@
#pragma once
-#include <glib-object.h>
+#if !defined (IDE_VCS_INSIDE) && !defined (IDE_VCS_COMPILATION)
+# error "Only <libide-vcs.h> can be included directly."
+#endif
-#include "ide-version-macros.h"
+#include <libide-core.h>
G_BEGIN_DECLS
diff --git a/src/libide/vcs/ide-vcs-file-info.c b/src/libide/vcs/ide-vcs-file-info.c
index 3ed967992..7a2164eeb 100644
--- a/src/libide/vcs/ide-vcs-file-info.c
+++ b/src/libide/vcs/ide-vcs-file-info.c
@@ -22,9 +22,8 @@
#include "config.h"
-#include "ide-enums.h"
-
-#include "vcs/ide-vcs-file-info.h"
+#include "ide-vcs-enums.h"
+#include "ide-vcs-file-info.h"
typedef struct
{
@@ -180,7 +179,7 @@ ide_vcs_file_info_class_init (IdeVcsFileInfoClass *klass)
IDE_TYPE_VCS_FILE_STATUS,
IDE_VCS_FILE_STATUS_UNCHANGED,
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
+
g_object_class_install_properties (object_class, N_PROPS, properties);
}
diff --git a/src/libide/vcs/ide-vcs-file-info.h b/src/libide/vcs/ide-vcs-file-info.h
index 2ba874dfb..0e0600324 100644
--- a/src/libide/vcs/ide-vcs-file-info.h
+++ b/src/libide/vcs/ide-vcs-file-info.h
@@ -20,9 +20,11 @@
#pragma once
-#include <gio/gio.h>
+#if !defined (IDE_VCS_INSIDE) && !defined (IDE_VCS_COMPILATION)
+# error "Only <libide-vcs.h> can be included directly."
+#endif
-#include "ide-version-macros.h"
+#include <libide-core.h>
G_BEGIN_DECLS
diff --git a/src/libide/vcs/ide-vcs-initializer.c b/src/libide/vcs/ide-vcs-initializer.c
index 84bd2f815..9742b845f 100644
--- a/src/libide/vcs/ide-vcs-initializer.c
+++ b/src/libide/vcs/ide-vcs-initializer.c
@@ -22,7 +22,7 @@
#include "config.h"
-#include "vcs/ide-vcs-initializer.h"
+#include "ide-vcs-initializer.h"
G_DEFINE_INTERFACE (IdeVcsInitializer, ide_vcs_initializer, G_TYPE_OBJECT)
diff --git a/src/libide/vcs/ide-vcs-initializer.h b/src/libide/vcs/ide-vcs-initializer.h
index 0649383bb..44193b97e 100644
--- a/src/libide/vcs/ide-vcs-initializer.h
+++ b/src/libide/vcs/ide-vcs-initializer.h
@@ -20,9 +20,11 @@
#pragma once
-#include <gio/gio.h>
+#if !defined (IDE_VCS_INSIDE) && !defined (IDE_VCS_COMPILATION)
+# error "Only <libide-vcs.h> can be included directly."
+#endif
-#include "ide-version-macros.h"
+#include <libide-core.h>
G_BEGIN_DECLS
diff --git a/src/libide/vcs/ide-vcs-monitor.c b/src/libide/vcs/ide-vcs-monitor.c
index d4fb9245c..5bb44902b 100644
--- a/src/libide/vcs/ide-vcs-monitor.c
+++ b/src/libide/vcs/ide-vcs-monitor.c
@@ -23,20 +23,21 @@
#include "config.h"
#include <dazzle.h>
+#include <libide-core.h>
-#include "ide-context.h"
-#include "ide-debug.h"
-
-#include "vcs/ide-vcs.h"
-#include "vcs/ide-vcs-file-info.h"
-#include "vcs/ide-vcs-monitor.h"
+#include "ide-vcs.h"
+#include "ide-vcs-file-info.h"
+#include "ide-vcs-monitor.h"
struct _IdeVcsMonitor
{
IdeObject parent_instance;
GFile *root;
+ IdeVcs *vcs;
+ DzlSignalGroup *vcs_signals;
DzlRecursiveFileMonitor *monitor;
+ DzlSignalGroup *monitor_signals;
GHashTable *status_by_file;
guint cache_source;
@@ -55,6 +56,7 @@ enum {
enum {
PROP_0,
PROP_ROOT,
+ PROP_VCS,
N_PROPS
};
@@ -62,13 +64,14 @@ static GParamSpec *properties [N_PROPS];
static guint signals [N_SIGNALS];
static void
-ide_vcs_monitor_add_parents (GHashTable *hash,
- GFile *file,
- GFile *toplevel,
- IdeVcsFileStatus status)
+ide_vcs_monitor_add_parents_locked (GHashTable *hash,
+ GFile *file,
+ GFile *toplevel,
+ IdeVcsFileStatus status)
{
GFile *parent;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (hash != NULL);
g_assert (G_IS_FILE (file));
g_assert (G_IS_FILE (toplevel));
@@ -110,74 +113,77 @@ ide_vcs_monitor_list_status_cb (GObject *object,
IdeVcs *vcs = (IdeVcs *)object;
g_autoptr(IdeVcsMonitor) self = user_data;
g_autoptr(GListModel) model = NULL;
- g_autoptr(GHashTable) status_by_file = NULL;
- GFile *workdir;
- guint n_items;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_VCS (vcs));
g_assert (IDE_IS_VCS_MONITOR (self));
+ ide_object_lock (IDE_OBJECT (self));
+
self->busy = FALSE;
- model = ide_vcs_list_status_finish (vcs, result, NULL);
- if (model == NULL)
- return;
+ if ((model = ide_vcs_list_status_finish (vcs, result, NULL)))
+ {
+ g_autoptr(GHashTable) status_by_file = NULL;
+ guint n_items;
- n_items = g_list_model_get_n_items (model);
- workdir = ide_vcs_get_working_directory (vcs);
- status_by_file = g_hash_table_new_full (g_file_hash,
- (GEqualFunc) g_file_equal,
- g_object_unref,
- g_object_unref);
+ n_items = g_list_model_get_n_items (model);
+ status_by_file = g_hash_table_new_full (g_file_hash,
+ (GEqualFunc)g_file_equal,
+ g_object_unref,
+ g_object_unref);
- for (guint i = 0; i < n_items; i++)
- {
- g_autoptr(IdeVcsFileInfo) info = NULL;
- IdeVcsFileStatus status;
- GFile *file;
+ for (guint i = 0; i < n_items; i++)
+ {
+ g_autoptr(IdeVcsFileInfo) info = NULL;
+ IdeVcsFileStatus status;
+ GFile *file;
- info = g_list_model_get_item (model, i);
- file = ide_vcs_file_info_get_file (info);
- status = ide_vcs_file_info_get_status (info);
+ info = g_list_model_get_item (model, i);
+ file = ide_vcs_file_info_get_file (info);
+ status = ide_vcs_file_info_get_status (info);
- g_hash_table_insert (status_by_file,
- g_file_dup (file),
- g_steal_pointer (&info));
+ g_hash_table_insert (status_by_file,
+ g_file_dup (file),
+ g_steal_pointer (&info));
- ide_vcs_monitor_add_parents (status_by_file, file, workdir, status);
- }
+ ide_vcs_monitor_add_parents_locked (status_by_file, file, self->root, status);
+ }
- g_clear_pointer (&self->status_by_file, g_hash_table_unref);
- self->status_by_file = g_steal_pointer (&status_by_file);
+ g_clear_pointer (&self->status_by_file, g_hash_table_unref);
+ self->status_by_file = g_steal_pointer (&status_by_file);
- g_signal_emit (self, signals[RELOADED], 0);
+ g_signal_emit (self, signals [RELOADED], 0);
+ }
+
+ ide_object_unlock (IDE_OBJECT (self));
}
static gboolean
ide_vcs_monitor_cache_cb (gpointer data)
{
IdeVcsMonitor *self = data;
- IdeContext *context;
- IdeVcs *vcs;
- GFile *workdir;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_VCS_MONITOR (self));
- self->cache_source = 0;
+ ide_object_lock (IDE_OBJECT (self));
- context = ide_object_get_context (IDE_OBJECT (self));
- vcs = ide_context_get_vcs (context);
- workdir = ide_vcs_get_working_directory (vcs);
+ self->cache_source = 0;
- self->busy = TRUE;
+ if (self->vcs != NULL)
+ {
+ self->busy = TRUE;
+ ide_vcs_list_status_async (self->vcs,
+ self->root,
+ TRUE,
+ G_PRIORITY_LOW,
+ NULL,
+ ide_vcs_monitor_list_status_cb,
+ g_object_ref (self));
+ }
- ide_vcs_list_status_async (vcs,
- workdir,
- TRUE,
- G_PRIORITY_LOW,
- NULL,
- ide_vcs_monitor_list_status_cb,
- g_object_ref (self));
+ ide_object_unlock (IDE_OBJECT (self));
return G_SOURCE_REMOVE;
}
@@ -185,13 +191,16 @@ ide_vcs_monitor_cache_cb (gpointer data)
static void
ide_vcs_monitor_queue_reload (IdeVcsMonitor *self)
{
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_VCS_MONITOR (self));
+ ide_object_lock (IDE_OBJECT (self));
if (self->cache_source == 0 && !self->busy)
self->cache_source = g_idle_add_full (G_PRIORITY_LOW,
ide_vcs_monitor_cache_cb,
g_object_ref (self),
g_object_unref);
+ ide_object_unlock (IDE_OBJECT (self));
}
static void
@@ -203,6 +212,7 @@ ide_vcs_monitor_changed_cb (IdeVcsMonitor *self,
{
IDE_ENTRY;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_VCS_MONITOR (self));
g_assert (G_IS_FILE (file));
g_assert (!other_file || G_IS_FILE (other_file));
@@ -221,12 +231,15 @@ ide_vcs_monitor_vcs_changed_cb (IdeVcsMonitor *self,
{
IDE_ENTRY;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_VCS_MONITOR (self));
g_assert (IDE_IS_VCS (vcs));
/* Everything is invalidated by new VCS index, reload now */
+ ide_object_lock (IDE_OBJECT (self));
g_clear_pointer (&self->status_by_file, g_hash_table_unref);
ide_vcs_monitor_queue_reload (self);
+ ide_object_unlock (IDE_OBJECT (self));
IDE_EXIT;
}
@@ -236,15 +249,15 @@ ide_vcs_monitor_ignore_func (GFile *file,
gpointer data)
{
IdeVcsMonitor *self = data;
- IdeContext *context;
- IdeVcs *vcs;
+ gboolean ret;
g_assert (IDE_IS_VCS_MONITOR (self));
- context = ide_object_get_context (IDE_OBJECT (self));
- vcs = ide_context_get_vcs (context);
+ ide_object_lock (IDE_OBJECT (self));
+ ret = ide_vcs_is_ignored (self->vcs, file, NULL);
+ ide_object_unlock (IDE_OBJECT (self));
- return ide_vcs_is_ignored (vcs, file, NULL);
+ return ret;
}
static void
@@ -256,6 +269,7 @@ ide_vcs_monitor_start_cb (GObject *object,
g_autoptr(IdeVcsMonitor) self = user_data;
g_autoptr(GError) error = NULL;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (DZL_IS_RECURSIVE_FILE_MONITOR (monitor));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_VCS_MONITOR (self));
@@ -267,47 +281,41 @@ ide_vcs_monitor_start_cb (GObject *object,
}
static void
-ide_vcs_monitor_constructed (GObject *object)
+ide_vcs_monitor_maybe_reload_locked (IdeVcsMonitor *self)
{
- IdeVcsMonitor *self = (IdeVcsMonitor *)object;
- IdeContext *context;
- IdeVcs *vcs;
-
- G_OBJECT_CLASS (ide_vcs_monitor_parent_class)->constructed (object);
-
- context = ide_object_get_context (IDE_OBJECT (self));
- vcs = ide_context_get_vcs (context);
-
- g_signal_connect_object (vcs,
- "changed",
- G_CALLBACK (ide_vcs_monitor_vcs_changed_cb),
- self,
- G_CONNECT_SWAPPED);
-
- self->monitor = dzl_recursive_file_monitor_new (self->root);
+ g_assert (IDE_IS_VCS_MONITOR (self));
- dzl_recursive_file_monitor_set_ignore_func (self->monitor,
- ide_vcs_monitor_ignore_func,
- self, NULL);
+ g_clear_pointer (&self->status_by_file, g_hash_table_unref);
+ g_clear_handle_id (&self->cache_source, g_source_remove);
- g_signal_connect_object (self->monitor,
- "changed",
- G_CALLBACK (ide_vcs_monitor_changed_cb),
- self,
- G_CONNECT_SWAPPED);
+ if (self->monitor)
+ {
+ dzl_signal_group_set_target (self->monitor_signals, NULL);
+ dzl_recursive_file_monitor_set_ignore_func (self->monitor, NULL, NULL, NULL);
+ dzl_recursive_file_monitor_cancel (self->monitor);
+ g_clear_object (&self->monitor);
+ }
- dzl_recursive_file_monitor_start_async (self->monitor,
- NULL,
- ide_vcs_monitor_start_cb,
- g_object_ref (self));
+ if (G_IS_FILE (self->root) && IDE_IS_VCS (self->vcs))
+ {
+ self->monitor = dzl_recursive_file_monitor_new (self->root);
+ dzl_recursive_file_monitor_set_ignore_func (self->monitor,
+ ide_vcs_monitor_ignore_func,
+ self, NULL);
+ dzl_signal_group_set_target (self->monitor_signals, self->monitor);
+ dzl_recursive_file_monitor_start_async (self->monitor,
+ NULL,
+ ide_vcs_monitor_start_cb,
+ g_object_ref (self));
+ }
}
static void
-ide_vcs_monitor_dispose (GObject *object)
+ide_vcs_monitor_destroy (IdeObject *object)
{
IdeVcsMonitor *self = (IdeVcsMonitor *)object;
- dzl_clear_source (&self->cache_source);
+ g_clear_handle_id (&self->cache_source, g_source_remove);
g_clear_pointer (&self->status_by_file, g_hash_table_unref);
if (self->monitor != NULL)
@@ -317,9 +325,25 @@ ide_vcs_monitor_dispose (GObject *object)
g_clear_object (&self->monitor);
}
+ dzl_signal_group_set_target (self->monitor_signals, NULL);
+ dzl_signal_group_set_target (self->vcs_signals, NULL);
+
+ g_clear_object (&self->vcs);
+
+ IDE_OBJECT_CLASS (ide_vcs_monitor_parent_class)->destroy (object);
+}
+
+static void
+ide_vcs_monitor_finalize (GObject *object)
+{
+ IdeVcsMonitor *self = (IdeVcsMonitor *)object;
+
+ g_clear_pointer (&self->status_by_file, g_hash_table_unref);
g_clear_object (&self->root);
+ g_clear_object (&self->monitor_signals);
+ g_clear_object (&self->vcs_signals);
- G_OBJECT_CLASS (ide_vcs_monitor_parent_class)->dispose (object);
+ G_OBJECT_CLASS (ide_vcs_monitor_parent_class)->finalize (object);
}
static void
@@ -333,7 +357,11 @@ ide_vcs_monitor_get_property (GObject *object,
switch (prop_id)
{
case PROP_ROOT:
- g_value_set_object (value, self->root);
+ g_value_take_object (value, ide_vcs_monitor_ref_root (self));
+ break;
+
+ case PROP_VCS:
+ g_value_take_object (value, ide_vcs_monitor_ref_vcs (self));
break;
default:
@@ -352,7 +380,11 @@ ide_vcs_monitor_set_property (GObject *object,
switch (prop_id)
{
case PROP_ROOT:
- self->root = g_value_dup_object (value);
+ ide_vcs_monitor_set_root (self, g_value_get_object (value));
+ break;
+
+ case PROP_VCS:
+ ide_vcs_monitor_set_vcs (self, g_value_get_object (value));
break;
default:
@@ -364,21 +396,59 @@ static void
ide_vcs_monitor_class_init (IdeVcsMonitorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
- object_class->constructed = ide_vcs_monitor_constructed;
- object_class->dispose = ide_vcs_monitor_dispose;
+ object_class->finalize = ide_vcs_monitor_finalize;
object_class->get_property = ide_vcs_monitor_get_property;
object_class->set_property = ide_vcs_monitor_set_property;
+ i_object_class->destroy = ide_vcs_monitor_destroy;
+
+ /**
+ * IdeVcsMonitor:root:
+ *
+ * The "root" property is the root of the file-system to begin
+ * monitoring for changes.
+ *
+ * Since: 3.32
+ */
properties [PROP_ROOT] =
g_param_spec_object ("root",
"Root",
"The root of the directory tree",
G_TYPE_FILE,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * IdeVcsMonitor:vcs:
+ *
+ * The "vcs" property is the version control system to be queried for
+ * additional status information when a file has been discovered to
+ * have been changed.
+ *
+ * Since: 3.32
+ */
+ properties [PROP_VCS] =
+ g_param_spec_object ("vcs",
+ "VCS",
+ "The version control system in use",
+ IDE_TYPE_VCS,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
g_object_class_install_properties (object_class, N_PROPS, properties);
+ /**
+ * IdeVcsMonitor::changed:
+ * @self: an #IdeVcsMonitor
+ * @file: a #GFile
+ * @other_file: (nullable): a #GFile or %NULL
+ * @event: a #GFileMonitorEvent
+ *
+ * The "changed" signal is emitted when a file has been discovered to
+ * have been changed on disk.
+ *
+ * Since: 3.32
+ */
signals [CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
@@ -391,6 +461,14 @@ ide_vcs_monitor_class_init (IdeVcsMonitorClass *klass)
G_TYPE_FILE | G_SIGNAL_TYPE_STATIC_SCOPE,
G_TYPE_FILE_MONITOR_EVENT);
+ /**
+ * IdeVcsMonitor::reloaded:
+ * @self: an #IdeVcsMonitor
+ *
+ * The "reloaded" signal is emitted when the monitor has been reloaded.
+ *
+ * Since: 3.32
+ */
signals [RELOADED] =
g_signal_new ("reloaded",
G_TYPE_FROM_CLASS (klass),
@@ -401,10 +479,25 @@ ide_vcs_monitor_class_init (IdeVcsMonitorClass *klass)
static void
ide_vcs_monitor_init (IdeVcsMonitor *self)
{
+ self->monitor_signals = dzl_signal_group_new (DZL_TYPE_RECURSIVE_FILE_MONITOR);
+
+ dzl_signal_group_connect_object (self->monitor_signals,
+ "changed",
+ G_CALLBACK (ide_vcs_monitor_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ self->vcs_signals = dzl_signal_group_new (IDE_TYPE_VCS);
+
+ dzl_signal_group_connect_object (self->vcs_signals,
+ "changed",
+ G_CALLBACK (ide_vcs_monitor_vcs_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
}
/**
- * ide_vcs_monitor_get_info:
+ * ide_vcs_monitor_ref_info:
* @self: a #IdeVcsMonitor
* @file: a #GFile
*
@@ -413,25 +506,112 @@ ide_vcs_monitor_init (IdeVcsMonitor *self)
* If the file information has not been loaded, %NULL is returned. You
* can wait for #IdeVcsMonitor::reloaded and query again if you expect
* the info to be there.
- *
+ *
* Returns: (transfer full) (nullable): an #IdeVcsFileInfo or %NULL
*
* Since: 3.32
*/
IdeVcsFileInfo *
-ide_vcs_monitor_get_info (IdeVcsMonitor *self,
+ide_vcs_monitor_ref_info (IdeVcsMonitor *self,
GFile *file)
{
- IdeVcsFileInfo *info;
+ IdeVcsFileInfo *info = NULL;
+
+ g_return_val_if_fail (IDE_IS_VCS_MONITOR (self), NULL);
+
+ ide_object_lock (IDE_OBJECT (self));
+ if (self->status_by_file != NULL)
+ {
+ if ((info = g_hash_table_lookup (self->status_by_file, file)))
+ g_object_ref (info);
+ }
+ ide_object_unlock (IDE_OBJECT (self));
+
+ return g_steal_pointer (&info);
+}
+
+/**
+ * ide_vcs_monitor_ref_vcs:
+ * @self: a #IdeVcsMonitor
+ *
+ * Increments the reference count of the #IdeVcs monitored using the
+ * #IdeVcsMonitor and returns it.
+ *
+ * Returns: (transfer full) (nullable): an #IdeVcs or %NULL
+ *
+ * Since: 3.32
+ */
+IdeVcs *
+ide_vcs_monitor_ref_vcs (IdeVcsMonitor *self)
+{
+ IdeVcs *ret;
+
+ g_return_val_if_fail (IDE_IS_VCS_MONITOR (self), NULL);
+
+ ide_object_lock (IDE_OBJECT (self));
+ ret = self->vcs ? g_object_ref (self->vcs) : NULL;
+ ide_object_unlock (IDE_OBJECT (self));
+
+ return g_steal_pointer (&ret);
+}
+
+/**
+ * ide_vcs_monitor_ref_root:
+ * @self: a #IdeVcsMonitor
+ *
+ * Gets the #IdeVcsMonitor:root property and increments the reference
+ * count of the #GFile by one.
+ *
+ * Returns: (transfer full) (nullable): a #GFile or %NULL
+ *
+ * Since: 3.32
+ */
+GFile *
+ide_vcs_monitor_ref_root (IdeVcsMonitor *self)
+{
+ GFile *ret;
g_return_val_if_fail (IDE_IS_VCS_MONITOR (self), NULL);
- if (self->status_by_file == NULL)
- return NULL;
+ ide_object_lock (IDE_OBJECT (self));
+ ret = self->root ? g_object_ref (self->root) : NULL;
+ ide_vcs_monitor_maybe_reload_locked (self);
+ ide_object_unlock (IDE_OBJECT (self));
- info = g_hash_table_lookup (self->status_by_file, file);
- if (info == NULL)
- return NULL;
+ return g_steal_pointer (&ret);
+}
+
+void
+ide_vcs_monitor_set_root (IdeVcsMonitor *self,
+ GFile *root)
+{
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
+ g_return_if_fail (IDE_IS_VCS_MONITOR (self));
+ g_return_if_fail (G_IS_FILE (root));
- return g_object_ref (info);
+ ide_object_lock (IDE_OBJECT (self));
+ if (g_set_object (&self->root, root))
+ {
+ ide_object_notify_by_pspec (self, properties [PROP_ROOT]);
+ ide_vcs_monitor_maybe_reload_locked (self);
+ }
+ ide_object_unlock (IDE_OBJECT (self));
+}
+
+void
+ide_vcs_monitor_set_vcs (IdeVcsMonitor *self,
+ IdeVcs *vcs)
+{
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
+ g_return_if_fail (IDE_IS_VCS_MONITOR (self));
+ g_return_if_fail (!vcs || IDE_IS_VCS (vcs));
+
+ ide_object_lock (IDE_OBJECT (self));
+ if (g_set_object (&self->vcs, vcs))
+ {
+ dzl_signal_group_set_target (self->vcs_signals, vcs);
+ ide_object_notify_by_pspec (self, properties [PROP_VCS]);
+ ide_vcs_monitor_maybe_reload_locked (self);
+ }
+ ide_object_unlock (IDE_OBJECT (self));
}
diff --git a/src/libide/vcs/ide-vcs-monitor.h b/src/libide/vcs/ide-vcs-monitor.h
index e9cb83e52..d7835ee8c 100644
--- a/src/libide/vcs/ide-vcs-monitor.h
+++ b/src/libide/vcs/ide-vcs-monitor.h
@@ -20,10 +20,14 @@
#pragma once
-#include "ide-object.h"
-#include "ide-version-macros.h"
+#if !defined (IDE_VCS_INSIDE) && !defined (IDE_VCS_COMPILATION)
+# error "Only <libide-vcs.h> can be included directly."
+#endif
-#include "vcs/ide-vcs-file-info.h"
+#include <libide-core.h>
+
+#include "ide-vcs.h"
+#include "ide-vcs-file-info.h"
G_BEGIN_DECLS
@@ -33,7 +37,17 @@ IDE_AVAILABLE_IN_3_32
G_DECLARE_FINAL_TYPE (IdeVcsMonitor, ide_vcs_monitor, IDE, VCS_MONITOR, IdeObject)
IDE_AVAILABLE_IN_3_32
-IdeVcsFileInfo *ide_vcs_monitor_get_info (IdeVcsMonitor *self,
+IdeVcsFileInfo *ide_vcs_monitor_ref_info (IdeVcsMonitor *self,
+ GFile *file);
+IDE_AVAILABLE_IN_3_32
+GFile *ide_vcs_monitor_ref_root (IdeVcsMonitor *self);
+IDE_AVAILABLE_IN_3_32
+void ide_vcs_monitor_set_root (IdeVcsMonitor *self,
GFile *file);
+IDE_AVAILABLE_IN_3_32
+IdeVcs *ide_vcs_monitor_ref_vcs (IdeVcsMonitor *self);
+IDE_AVAILABLE_IN_3_32
+void ide_vcs_monitor_set_vcs (IdeVcsMonitor *self,
+ IdeVcs *vcs);
G_END_DECLS
diff --git a/src/libide/vcs/ide-vcs-uri.c b/src/libide/vcs/ide-vcs-uri.c
index 52235fe83..db44f23d0 100644
--- a/src/libide/vcs/ide-vcs-uri.c
+++ b/src/libide/vcs/ide-vcs-uri.c
@@ -22,11 +22,10 @@
#include "config.h"
-#include <dazzle.h>
#include <stdlib.h>
#include <string.h>
-#include "vcs/ide-vcs-uri.h"
+#include "ide-vcs-uri.h"
G_DEFINE_BOXED_TYPE (IdeVcsUri, ide_vcs_uri, ide_vcs_uri_ref, ide_vcs_uri_unref)
@@ -156,7 +155,7 @@ ide_vcs_uri_parse (IdeVcsUri *self,
g_free (tmp);
}
- if (!dzl_str_empty0 (portstr) && g_ascii_isdigit (portstr [1]))
+ if (!ide_str_empty0 (portstr) && g_ascii_isdigit (portstr [1]))
port = CLAMP (atoi (&portstr [1]), 1, G_MAXINT16);
ide_vcs_uri_set_scheme (self, scheme);
@@ -220,7 +219,7 @@ ide_vcs_uri_new (const gchar *uri)
{
IdeVcsUri *self;
- self = g_new0 (IdeVcsUri, 1);
+ self = g_slice_new0 (IdeVcsUri);
self->ref_count = 1;
if (ide_vcs_uri_parse (self, uri) && ide_vcs_uri_validate (self))
@@ -229,7 +228,7 @@ ide_vcs_uri_new (const gchar *uri)
return self;
}
- g_free (self);
+ ide_vcs_uri_unref (self);
return NULL;
}
@@ -242,7 +241,7 @@ ide_vcs_uri_finalize (IdeVcsUri *self)
g_free (self->user);
g_free (self->host);
g_free (self->path);
- g_free (self);
+ g_slice_free (IdeVcsUri, self);
}
IdeVcsUri *
@@ -312,7 +311,7 @@ ide_vcs_uri_set_scheme (IdeVcsUri *self,
{
g_return_if_fail (self);
- if (dzl_str_empty0 (scheme))
+ if (ide_str_empty0 (scheme))
scheme = NULL;
if (scheme != self->scheme)
@@ -336,7 +335,7 @@ ide_vcs_uri_set_user (IdeVcsUri *self,
{
g_return_if_fail (self);
- if (dzl_str_empty0 (user))
+ if (ide_str_empty0 (user))
user = NULL;
if (user != self->user)
@@ -360,7 +359,7 @@ ide_vcs_uri_set_host (IdeVcsUri *self,
{
g_return_if_fail (self);
- if (dzl_str_empty0 (host))
+ if (ide_str_empty0 (host))
host = NULL;
if (host != self->host)
@@ -390,7 +389,7 @@ ide_vcs_uri_set_path (IdeVcsUri *self,
{
g_return_if_fail (self);
- if (dzl_str_empty0 (path))
+ if (ide_str_empty0 (path))
path = NULL;
if (path != self->path)
@@ -460,3 +459,43 @@ ide_vcs_uri_is_valid (const gchar *uri_string)
return ret;
}
+
+/**
+ * ide_vcs_uri_get_clone_name:
+ * @self: an #ideVcsUri
+ *
+ * Determines a suggested name for the checkout directory. Some special
+ * handling of suffixes such as ".git" are performed to improve the the
+ * quality of results.
+ *
+ * Returns: (transfer full) (nullable): a string containing the suggested
+ * clone directory name, or %NULL.
+ *
+ * Since: 3.32
+ */
+gchar *
+ide_vcs_uri_get_clone_name (const IdeVcsUri *self)
+{
+ g_autofree gchar *name = NULL;
+ const gchar *path;
+
+ g_return_val_if_fail (self != NULL, NULL);
+
+ if (!(path = ide_vcs_uri_get_path (self)))
+ return NULL;
+
+ if (ide_str_empty0 (path))
+ return NULL;
+
+ if (!(name = g_path_get_basename (path)))
+ return NULL;
+
+ /* Trim trailing ".git" */
+ if (g_str_has_suffix (name, ".git"))
+ *(strrchr (name, '.')) = '\0';
+
+ if (!g_str_equal (name, "/") && !g_str_equal (name, "~"))
+ return g_steal_pointer (&name);
+
+ return NULL;
+}
diff --git a/src/libide/vcs/ide-vcs-uri.h b/src/libide/vcs/ide-vcs-uri.h
index ee29b35a6..119275dbc 100644
--- a/src/libide/vcs/ide-vcs-uri.h
+++ b/src/libide/vcs/ide-vcs-uri.h
@@ -20,9 +20,11 @@
#pragma once
-#include <glib-object.h>
+#if !defined (IDE_VCS_INSIDE) && !defined (IDE_VCS_COMPILATION)
+# error "Only <libide-vcs.h> can be included directly."
+#endif
-#include "ide-version-macros.h"
+#include <libide-core.h>
G_BEGIN_DECLS
@@ -31,42 +33,44 @@ G_BEGIN_DECLS
typedef struct _IdeVcsUri IdeVcsUri;
IDE_AVAILABLE_IN_3_32
-GType ide_vcs_uri_get_type (void);
+GType ide_vcs_uri_get_type (void);
IDE_AVAILABLE_IN_3_32
-IdeVcsUri *ide_vcs_uri_new (const gchar *uri);
+IdeVcsUri *ide_vcs_uri_new (const gchar *uri);
IDE_AVAILABLE_IN_3_32
-IdeVcsUri *ide_vcs_uri_ref (IdeVcsUri *self);
+IdeVcsUri *ide_vcs_uri_ref (IdeVcsUri *self);
IDE_AVAILABLE_IN_3_32
-void ide_vcs_uri_unref (IdeVcsUri *self);
+void ide_vcs_uri_unref (IdeVcsUri *self);
IDE_AVAILABLE_IN_3_32
-const gchar *ide_vcs_uri_get_scheme (const IdeVcsUri *self);
+const gchar *ide_vcs_uri_get_scheme (const IdeVcsUri *self);
IDE_AVAILABLE_IN_3_32
-const gchar *ide_vcs_uri_get_user (const IdeVcsUri *self);
+const gchar *ide_vcs_uri_get_user (const IdeVcsUri *self);
IDE_AVAILABLE_IN_3_32
-const gchar *ide_vcs_uri_get_host (const IdeVcsUri *self);
+const gchar *ide_vcs_uri_get_host (const IdeVcsUri *self);
IDE_AVAILABLE_IN_3_32
-guint ide_vcs_uri_get_port (const IdeVcsUri *self);
+guint ide_vcs_uri_get_port (const IdeVcsUri *self);
IDE_AVAILABLE_IN_3_32
-const gchar *ide_vcs_uri_get_path (const IdeVcsUri *self);
+const gchar *ide_vcs_uri_get_path (const IdeVcsUri *self);
IDE_AVAILABLE_IN_3_32
-void ide_vcs_uri_set_scheme (IdeVcsUri *self,
- const gchar *scheme);
+void ide_vcs_uri_set_scheme (IdeVcsUri *self,
+ const gchar *scheme);
IDE_AVAILABLE_IN_3_32
-void ide_vcs_uri_set_user (IdeVcsUri *self,
- const gchar *user);
+void ide_vcs_uri_set_user (IdeVcsUri *self,
+ const gchar *user);
IDE_AVAILABLE_IN_3_32
-void ide_vcs_uri_set_host (IdeVcsUri *self,
- const gchar *host);
+void ide_vcs_uri_set_host (IdeVcsUri *self,
+ const gchar *host);
IDE_AVAILABLE_IN_3_32
-void ide_vcs_uri_set_port (IdeVcsUri *self,
- guint port);
+void ide_vcs_uri_set_port (IdeVcsUri *self,
+ guint port);
IDE_AVAILABLE_IN_3_32
-void ide_vcs_uri_set_path (IdeVcsUri *self,
- const gchar *path);
+void ide_vcs_uri_set_path (IdeVcsUri *self,
+ const gchar *path);
IDE_AVAILABLE_IN_3_32
-gchar *ide_vcs_uri_to_string (const IdeVcsUri *self);
+gchar *ide_vcs_uri_to_string (const IdeVcsUri *self);
IDE_AVAILABLE_IN_3_32
-gboolean ide_vcs_uri_is_valid (const gchar *uri_string);
+gboolean ide_vcs_uri_is_valid (const gchar *uri_string);
+IDE_AVAILABLE_IN_3_32
+gchar *ide_vcs_uri_get_clone_name (const IdeVcsUri *self);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdeVcsUri, ide_vcs_uri_unref)
diff --git a/src/libide/vcs/ide-vcs.c b/src/libide/vcs/ide-vcs.c
index 2809fdbc1..f4c178efe 100644
--- a/src/libide/vcs/ide-vcs.c
+++ b/src/libide/vcs/ide-vcs.c
@@ -22,13 +22,12 @@
#include "config.h"
+#include <libide-io.h>
#include <string.h>
-#include "ide-context.h"
-
-#include "buffers/ide-buffer.h"
-#include "buffers/ide-buffer-change-monitor.h"
-#include "vcs/ide-vcs.h"
+#include "ide-directory-vcs.h"
+#include "ide-vcs.h"
+#include "ide-vcs-enums.h"
G_DEFINE_INTERFACE (IdeVcs, ide_vcs, IDE_TYPE_OBJECT)
@@ -38,19 +37,6 @@ enum {
};
static guint signals [N_SIGNALS];
-static GPtrArray *ignored;
-
-G_LOCK_DEFINE_STATIC (ignored);
-
-void
-ide_vcs_register_ignored (const gchar *pattern)
-{
- G_LOCK (ignored);
- if (ignored == NULL)
- ignored = g_ptr_array_new ();
- g_ptr_array_add (ignored, g_pattern_spec_new (pattern));
- G_UNLOCK (ignored);
-}
static void
ide_vcs_real_list_status_async (IdeVcs *self,
@@ -93,7 +79,7 @@ ide_vcs_default_init (IdeVcsInterface *iface)
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
g_object_interface_install_property (iface,
- g_param_spec_object ("working-directory",
+ g_param_spec_object ("workdir",
"Working Directory",
"The working directory for the VCS",
G_TYPE_FILE,
@@ -119,14 +105,6 @@ ide_vcs_default_init (IdeVcsInterface *iface)
g_signal_set_va_marshaller (signals [CHANGED],
G_TYPE_FROM_INTERFACE (iface),
g_cclosure_marshal_VOID__VOIDv);
-
-
- /* Ignore Gio temporary files */
- ide_vcs_register_ignored (".goutputstream-*");
-
- /* Ignore minified JS */
- ide_vcs_register_ignored ("*.min.js");
- ide_vcs_register_ignored ("*.min.js.*");
}
/**
@@ -156,54 +134,22 @@ ide_vcs_is_ignored (IdeVcs *self,
GFile *file,
GError **error)
{
- g_autofree gchar *name = NULL;
- g_autofree gchar *reversed = NULL;
- gboolean ret = FALSE;
- gsize len;
-
g_return_val_if_fail (!self || IDE_IS_VCS (self), FALSE);
g_return_val_if_fail (!file || G_IS_FILE (file), FALSE);
if (file == NULL)
return TRUE;
- name = g_file_get_basename (file);
- if (name == NULL || *name == 0)
- return TRUE;
-
- len = strlen (name);
-
- /* Ignore builtin backup files by GIO */
- if (name[len - 1] == '~')
+ if (ide_g_file_is_ignored (file))
return TRUE;
- reversed = g_utf8_strreverse (name, len);
-
- G_LOCK (ignored);
-
- if G_LIKELY (ignored != NULL)
- {
- for (guint i = 0; i < ignored->len; i++)
- {
- GPatternSpec *pattern_spec = g_ptr_array_index (ignored, i);
-
- if (g_pattern_match (pattern_spec, len, name, reversed))
- {
- ret = TRUE;
- break;
- }
- }
- }
-
- G_UNLOCK (ignored);
-
if (self != NULL)
{
- if (!ret && IDE_VCS_GET_IFACE (self)->is_ignored)
- ret = IDE_VCS_GET_IFACE (self)->is_ignored (self, file, error);
+ if (IDE_VCS_GET_IFACE (self)->is_ignored)
+ return IDE_VCS_GET_IFACE (self)->is_ignored (self, file, error);
}
- return ret;
+ return FALSE;
}
/**
@@ -235,9 +181,6 @@ ide_vcs_path_is_ignored (IdeVcs *self,
const gchar *path,
GError **error)
{
- g_autofree gchar *name = NULL;
- g_autofree gchar *reversed = NULL;
- gsize len;
gboolean ret = FALSE;
g_return_val_if_fail (!self || IDE_IS_VCS (self), FALSE);
@@ -245,36 +188,9 @@ ide_vcs_path_is_ignored (IdeVcs *self,
if (path == NULL)
return TRUE;
- name = g_path_get_basename (path);
- if (name == NULL || *name == 0)
+ if (ide_path_is_ignored (path))
return TRUE;
- len = strlen (name);
-
- /* Ignore builtin backup files by GIO */
- if (name[len - 1] == '~')
- return TRUE;
-
- reversed = g_utf8_strreverse (name, len);
-
- G_LOCK (ignored);
-
- if G_LIKELY (ignored != NULL)
- {
- for (guint i = 0; i < ignored->len; i++)
- {
- GPatternSpec *pattern_spec = g_ptr_array_index (ignored, i);
-
- if (g_pattern_match (pattern_spec, len, name, reversed))
- {
- ret = TRUE;
- break;
- }
- }
- }
-
- G_UNLOCK (ignored);
-
if (self != NULL)
{
if (!ret && IDE_VCS_GET_IFACE (self)->is_ignored)
@@ -284,7 +200,7 @@ ide_vcs_path_is_ignored (IdeVcs *self,
if (g_path_is_absolute (path))
file = g_file_new_for_path (path);
else
- file = g_file_get_child (ide_vcs_get_working_directory (self), path);
+ file = g_file_get_child (ide_vcs_get_workdir (self), path);
ret = IDE_VCS_GET_IFACE (self)->is_ignored (self, file, error);
}
@@ -307,7 +223,7 @@ ide_vcs_get_priority (IdeVcs *self)
}
/**
- * ide_vcs_get_working_directory:
+ * ide_vcs_get_workdir:
* @self: An #IdeVcs.
*
* Retrieves the working directory for the context. This is the root of where
@@ -325,94 +241,16 @@ ide_vcs_get_priority (IdeVcs *self)
* implementing #IdeVcs are required to ensure this invariant holds true.
*/
GFile *
-ide_vcs_get_working_directory (IdeVcs *self)
+ide_vcs_get_workdir (IdeVcs *self)
{
g_return_val_if_fail (IDE_IS_VCS (self), NULL);
- if (IDE_VCS_GET_IFACE (self)->get_working_directory)
- return IDE_VCS_GET_IFACE (self)->get_working_directory (self);
+ if (IDE_VCS_GET_IFACE (self)->get_workdir)
+ return IDE_VCS_GET_IFACE (self)->get_workdir (self);
return NULL;
}
-/**
- * ide_vcs_get_buffer_change_monitor:
- *
- * Gets an #IdeBufferChangeMonitor for the buffer provided. If the #IdeVcs implementation does not
- * support change monitoring, or cannot for the current file, then %NULL is returned.
- *
- * Returns: (transfer full) (nullable): An #IdeBufferChangeMonitor or %NULL.
- *
- * Since: 3.32
- */
-IdeBufferChangeMonitor *
-ide_vcs_get_buffer_change_monitor (IdeVcs *self,
- IdeBuffer *buffer)
-{
- IdeBufferChangeMonitor *ret = NULL;
-
- g_return_val_if_fail (IDE_IS_VCS (self), NULL);
- g_return_val_if_fail (IDE_IS_BUFFER (buffer), NULL);
-
- if (IDE_VCS_GET_IFACE (self)->get_buffer_change_monitor)
- ret = IDE_VCS_GET_IFACE (self)->get_buffer_change_monitor (self, buffer);
-
- g_return_val_if_fail (!ret || IDE_IS_BUFFER_CHANGE_MONITOR (ret), NULL);
-
- return ret;
-}
-
-static gint
-sort_by_priority (gconstpointer a,
- gconstpointer b,
- gpointer user_data)
-{
- IdeVcs *vcs_a = *(IdeVcs **)a;
- IdeVcs *vcs_b = *(IdeVcs **)b;
-
- return ide_vcs_get_priority (vcs_a) - ide_vcs_get_priority (vcs_b);
-}
-
-void
-ide_vcs_new_async (IdeContext *context,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- ide_object_new_for_extension_async (IDE_TYPE_VCS,
- sort_by_priority,
- NULL,
- io_priority,
- cancellable,
- callback,
- user_data,
- "context", context,
- NULL);
-}
-
-/**
- * ide_vcs_new_finish:
- *
- * Completes a call to ide_vcs_new_async().
- *
- * Returns: (transfer full): An #IdeVcs.
- *
- * Since: 3.32
- */
-IdeVcs *
-ide_vcs_new_finish (GAsyncResult *result,
- GError **error)
-{
- IdeObject *ret;
-
- g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
-
- ret = ide_object_new_finish (result, error);
-
- return IDE_VCS (ret);
-}
-
void
ide_vcs_emit_changed (IdeVcs *self)
{
@@ -458,12 +296,19 @@ ide_vcs_get_config (IdeVcs *self)
gchar *
ide_vcs_get_branch_name (IdeVcs *self)
{
+ gchar *ret = NULL;
+
g_return_val_if_fail (IDE_IS_VCS (self), NULL);
+ ide_object_lock (IDE_OBJECT (self));
if (IDE_VCS_GET_IFACE (self)->get_branch_name)
- return IDE_VCS_GET_IFACE (self)->get_branch_name (self);
+ ret = IDE_VCS_GET_IFACE (self)->get_branch_name (self);
+ ide_object_unlock (IDE_OBJECT (self));
+
+ if (ret == NULL)
+ ret = g_strdup ("primary");
- return g_strdup ("primary");
+ return ret;
}
/**
@@ -502,7 +347,7 @@ ide_vcs_list_status_async (IdeVcs *self,
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
if (directory_or_file == NULL)
- directory_or_file = ide_vcs_get_working_directory (self);
+ directory_or_file = ide_vcs_get_workdir (self);
IDE_VCS_GET_IFACE (self)->list_status_async (self,
directory_or_file,
@@ -540,3 +385,58 @@ ide_vcs_list_status_finish (IdeVcs *self,
return IDE_VCS_GET_IFACE (self)->list_status_finish (self, result, error);
}
+
+/**
+ * ide_vcs_from_context:
+ * @context: an #IdeContext
+ *
+ * Gets the #IdeVcs for the context.
+ *
+ * Returns: (transfer none): an #IdeVcs
+ *
+ * Since: 3.32
+ */
+IdeVcs *
+ide_vcs_from_context (IdeContext *context)
+{
+ IdeVcs *ret;
+
+ g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
+ g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+ /* Release full reference, into borrowed ref */
+ ret = ide_vcs_ref_from_context (context);
+ g_object_unref (ret);
+
+ return ret;
+}
+
+/**
+ * ide_vcs_ref_from_context:
+ * @context: an #IdeContext
+ *
+ * A thread-safe version of ide_vcs_from_context().
+ *
+ * Returns: (transfer full): an #IdeVcs
+ *
+ * Since: 3.32
+ */
+IdeVcs *
+ide_vcs_ref_from_context (IdeContext *context)
+{
+ IdeVcs *ret;
+
+ g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+ ide_object_lock (IDE_OBJECT (context));
+ ret = ide_object_get_child_typed (IDE_OBJECT (context), IDE_TYPE_VCS);
+ if (ret == NULL)
+ {
+ g_autoptr(GFile) workdir = ide_context_ref_workdir (context);
+ ret = (IdeVcs *)ide_directory_vcs_new (workdir);
+ ide_object_prepend (IDE_OBJECT (context), IDE_OBJECT (ret));
+ }
+ ide_object_unlock (IDE_OBJECT (context));
+
+ return g_steal_pointer (&ret);
+}
diff --git a/src/libide/vcs/ide-vcs.h b/src/libide/vcs/ide-vcs.h
index 22a78d53b..aa5824a0a 100644
--- a/src/libide/vcs/ide-vcs.h
+++ b/src/libide/vcs/ide-vcs.h
@@ -20,12 +20,13 @@
#pragma once
-#include <gio/gio.h>
+#if !defined (IDE_VCS_INSIDE) && !defined (IDE_VCS_COMPILATION)
+# error "Only <libide-vcs.h> can be included directly."
+#endif
-#include "ide-version-macros.h"
+#include <libide-core.h>
-#include "ide-object.h"
-#include "vcs/ide-vcs-config.h"
+#include "ide-vcs-config.h"
G_BEGIN_DECLS
@@ -38,9 +39,7 @@ struct _IdeVcsInterface
{
GTypeInterface parent_interface;
- GFile *(*get_working_directory) (IdeVcs *self);
- IdeBufferChangeMonitor *(*get_buffer_change_monitor) (IdeVcs *self,
- IdeBuffer *buffer);
+ GFile *(*get_workdir) (IdeVcs *self);
gboolean (*is_ignored) (IdeVcs *self,
GFile *file,
GError **error);
@@ -61,21 +60,11 @@ struct _IdeVcsInterface
};
IDE_AVAILABLE_IN_3_32
-void ide_vcs_register_ignored (const gchar *pattern);
+IdeVcs *ide_vcs_from_context (IdeContext *context);
IDE_AVAILABLE_IN_3_32
-IdeBufferChangeMonitor *ide_vcs_get_buffer_change_monitor (IdeVcs *self,
- IdeBuffer *buffer);
+IdeVcs *ide_vcs_ref_from_context (IdeContext *context);
IDE_AVAILABLE_IN_3_32
-GFile *ide_vcs_get_working_directory (IdeVcs *self);
-IDE_AVAILABLE_IN_3_32
-void ide_vcs_new_async (IdeContext *context,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-IDE_AVAILABLE_IN_3_32
-IdeVcs *ide_vcs_new_finish (GAsyncResult *result,
- GError **error);
+GFile *ide_vcs_get_workdir (IdeVcs *self);
IDE_AVAILABLE_IN_3_32
gboolean ide_vcs_is_ignored (IdeVcs *self,
GFile *file,
diff --git a/src/libide/vcs/libide-vcs.h b/src/libide/vcs/libide-vcs.h
new file mode 100644
index 000000000..bc6352468
--- /dev/null
+++ b/src/libide/vcs/libide-vcs.h
@@ -0,0 +1,38 @@
+/* ide-vcs.h
+ *
+ * Copyright 2014-2019 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 <libide-core.h>
+#include <libide-io.h>
+
+#define IDE_VCS_INSIDE
+
+#include "ide-directory-vcs.h"
+#include "ide-vcs-cloner.h"
+#include "ide-vcs-config.h"
+#include "ide-vcs-enums.h"
+#include "ide-vcs-initializer.h"
+#include "ide-vcs-uri.h"
+#include "ide-vcs-file-info.h"
+#include "ide-vcs.h"
+#include "ide-vcs-monitor.h"
+
+#undef IDE_VCS_INSIDE
diff --git a/src/libide/vcs/meson.build b/src/libide/vcs/meson.build
index 551dbaa30..14beb6904 100644
--- a/src/libide/vcs/meson.build
+++ b/src/libide/vcs/meson.build
@@ -1,14 +1,38 @@
-vcs_headers = [
+libide_vcs_header_dir = join_paths(libide_header_dir, 'vcs')
+libide_vcs_header_subdir = join_paths(libide_header_subdir, 'vcs')
+libide_include_directories += include_directories('.')
+
+#
+# Public API Headers
+#
+
+libide_vcs_public_headers = [
+ 'ide-directory-vcs.h',
'ide-vcs-config.h',
+ 'ide-vcs-cloner.h',
'ide-vcs-file-info.h',
'ide-vcs-initializer.h',
'ide-vcs-monitor.h',
'ide-vcs-uri.h',
'ide-vcs.h',
+ 'libide-vcs.h',
+]
+
+libide_vcs_enum_headers = [
+ 'ide-vcs-config.h',
+ 'ide-vcs-file-info.h',
]
-vcs_sources = [
+install_headers(libide_vcs_public_headers, subdir: libide_vcs_header_subdir)
+
+#
+# Sources
+#
+
+libide_vcs_public_sources = [
+ 'ide-directory-vcs.c',
'ide-vcs-config.c',
+ 'ide-vcs-cloner.c',
'ide-vcs-file-info.c',
'ide-vcs-initializer.c',
'ide-vcs-monitor.c',
@@ -16,13 +40,54 @@ vcs_sources = [
'ide-vcs.c',
]
-vcs_enums = [
- 'ide-vcs-config.h',
- 'ide-vcs-file-info.h',
+#
+# Enum generation
+#
+
+libide_vcs_enums = gnome.mkenums_simple('ide-vcs-enums',
+ body_prefix: '#include "config.h"',
+ header_prefix: '#include <libide-core.h>',
+ decorator: '_IDE_EXTERN',
+ sources: libide_vcs_enum_headers,
+ install_header: true,
+ install_dir: libide_vcs_header_dir,
+)
+libide_vcs_generated_sources = [libide_vcs_enums[0]]
+libide_vcs_generated_headers = [libide_vcs_enums[1]]
+
+#
+# Dependencies
+#
+
+libide_vcs_deps = [
+ libgio_dep,
+ libgtk_dep,
+
+ libide_core_dep,
+ libide_io_dep,
+ libide_threading_dep,
]
-libide_public_headers += files(vcs_headers)
-libide_public_sources += files(vcs_sources)
-libide_enum_headers += files(vcs_enums)
+#
+# Library Definitions
+#
+
+libide_vcs = static_library('ide-vcs-' + libide_api_version,
+ libide_vcs_public_sources + libide_vcs_generated_sources + libide_vcs_generated_headers,
+ dependencies: libide_vcs_deps,
+ c_args: libide_args + release_args + ['-DIDE_VCS_COMPILATION'],
+)
+
+libide_vcs_dep = declare_dependency(
+ dependencies: libide_vcs_deps,
+ link_whole: libide_vcs,
+ include_directories: include_directories('.'),
+ sources: libide_vcs_generated_headers,
+)
-install_headers(vcs_headers, subdir: join_paths(libide_header_subdir, 'vcs'))
+gnome_builder_public_sources += files(libide_vcs_public_sources)
+gnome_builder_public_headers += files(libide_vcs_public_headers)
+gnome_builder_generated_headers += libide_vcs_generated_headers
+gnome_builder_generated_sources += libide_vcs_generated_sources
+gnome_builder_include_subdirs += libide_vcs_header_subdir
+gnome_builder_gir_extra_args += ['--c-include=libide-vcs.h', '-DIDE_VCS_COMPILATION']
diff --git a/src/plugins/vcsui/gbp-vcsui-editor-page-addin.c b/src/plugins/vcsui/gbp-vcsui-editor-page-addin.c
new file mode 100644
index 000000000..f952b7582
--- /dev/null
+++ b/src/plugins/vcsui/gbp-vcsui-editor-page-addin.c
@@ -0,0 +1,137 @@
+/* gbp-vcsui-editor-page-addin.c
+ *
+ * Copyright 2018-2019 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 "gbp-vcsui-editor-page-addin"
+
+#include "config.h"
+
+#include <libide-editor.h>
+
+#include "gbp-vcsui-editor-page-addin.h"
+
+struct _GbpVcsuiEditorPageAddin
+{
+ GObject parent_instance;
+};
+
+static void
+on_push_snippet_cb (GbpVcsuiEditorPageAddin *self,
+ IdeSnippet *snippet,
+ GtkTextIter *iter,
+ IdeSourceView *source_view)
+{
+ g_autoptr(IdeVcsConfig) vcs_config = NULL;
+ g_autoptr(IdeContext) ide_context = NULL;
+ IdeSnippetContext *context;
+ IdeBuffer *buffer;
+ IdeVcs *vcs;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_VCSUI_EDITOR_PAGE_ADDIN (self));
+ g_assert (IDE_IS_SNIPPET (snippet));
+ g_assert (iter != NULL);
+ g_assert (IDE_IS_SOURCE_VIEW (source_view));
+
+ buffer = IDE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view)));
+ ide_context = ide_buffer_ref_context (buffer);
+ context = ide_snippet_get_context (snippet);
+
+ if ((vcs = ide_vcs_from_context (ide_context)) &&
+ (vcs_config = ide_vcs_get_config (vcs)))
+ {
+ GValue value = G_VALUE_INIT;
+
+ g_value_init (&value, G_TYPE_STRING);
+
+ ide_vcs_config_get_config (vcs_config, IDE_VCS_CONFIG_FULL_NAME, &value);
+
+ if (!ide_str_empty0 (g_value_get_string (&value)))
+ {
+ ide_snippet_context_add_shared_variable (context, "author", g_value_get_string (&value));
+ ide_snippet_context_add_shared_variable (context, "fullname", g_value_get_string (&value));
+ ide_snippet_context_add_shared_variable (context, "username", g_value_get_string (&value));
+ }
+
+ g_value_reset (&value);
+
+ ide_vcs_config_get_config (vcs_config, IDE_VCS_CONFIG_EMAIL, &value);
+
+ if (!ide_str_empty0 (g_value_get_string (&value)))
+ ide_snippet_context_add_shared_variable (context, "email", g_value_get_string (&value));
+
+ g_value_unset (&value);
+ }
+}
+
+static void
+gbp_vcsui_editor_page_addin_load (IdeEditorPageAddin *addin,
+ IdeEditorPage *page)
+{
+ IdeSourceView *source_view;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IDE_IS_EDITOR_PAGE_ADDIN (addin));
+ g_assert (IDE_IS_EDITOR_PAGE (page));
+
+ source_view = ide_editor_page_get_view (page);
+
+ g_signal_connect_object (source_view,
+ "push-snippet",
+ G_CALLBACK (on_push_snippet_cb),
+ addin,
+ G_CONNECT_SWAPPED);
+}
+
+static void
+gbp_vcsui_editor_page_addin_unload (IdeEditorPageAddin *addin,
+ IdeEditorPage *page)
+{
+ IdeSourceView *source_view;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IDE_IS_EDITOR_PAGE_ADDIN (addin));
+ g_assert (IDE_IS_EDITOR_PAGE (page));
+
+ source_view = ide_editor_page_get_view (page);
+
+ g_signal_handlers_disconnect_by_func (source_view,
+ G_CALLBACK (on_push_snippet_cb),
+ addin);
+}
+
+static void
+editor_page_addin_iface_init (IdeEditorPageAddinInterface *iface)
+{
+ iface->load = gbp_vcsui_editor_page_addin_load;
+ iface->unload = gbp_vcsui_editor_page_addin_unload;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpVcsuiEditorPageAddin, gbp_vcsui_editor_page_addin, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_EDITOR_PAGE_ADDIN, editor_page_addin_iface_init))
+
+static void
+gbp_vcsui_editor_page_addin_class_init (GbpVcsuiEditorPageAddinClass *klass)
+{
+}
+
+static void
+gbp_vcsui_editor_page_addin_init (GbpVcsuiEditorPageAddin *self)
+{
+}
diff --git a/src/plugins/vcsui/gbp-vcsui-editor-page-addin.h b/src/plugins/vcsui/gbp-vcsui-editor-page-addin.h
new file mode 100644
index 000000000..d69bcd0d6
--- /dev/null
+++ b/src/plugins/vcsui/gbp-vcsui-editor-page-addin.h
@@ -0,0 +1,31 @@
+/* gbp-vcsui-editor-page-addin.h
+ *
+ * Copyright 2018-2019 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 <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_VCSUI_EDITOR_PAGE_ADDIN (gbp_vcsui_editor_page_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpVcsuiEditorPageAddin, gbp_vcsui_editor_page_addin, GBP, VCSUI_EDITOR_PAGE_ADDIN,
GObject)
+
+G_END_DECLS
diff --git a/src/plugins/vcsui/gbp-vcsui-tree-addin.c b/src/plugins/vcsui/gbp-vcsui-tree-addin.c
new file mode 100644
index 000000000..37171f618
--- /dev/null
+++ b/src/plugins/vcsui/gbp-vcsui-tree-addin.c
@@ -0,0 +1,209 @@
+/* gbp-vcsui-tree-addin.c
+ *
+ * Copyright 2018-2019 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 "gbp-vcsui-tree-addin"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <libpeas/peas.h>
+#include <libide-foundry.h>
+#include <libide-gui.h>
+#include <libide-plugins.h>
+#include <libide-threading.h>
+#include <libide-tree.h>
+#include <libide-vcs.h>
+
+#include "gbp-vcsui-tree-addin.h"
+
+struct _GbpVcsuiTreeAddin
+{
+ GObject parent_instance;
+
+ IdeTree *tree;
+ IdeTreeModel *model;
+ IdeVcs *vcs;
+ IdeVcsMonitor *monitor;
+
+ GdkRGBA added_color;
+ GdkRGBA changed_color;
+};
+
+static void
+get_foreground_for_class (GtkStyleContext *style_context,
+ const gchar *name,
+ GdkRGBA *rgba)
+{
+ GtkStateFlags state;
+
+ g_assert (GTK_IS_STYLE_CONTEXT (style_context));
+ g_assert (name != NULL);
+ g_assert (rgba != NULL);
+
+ state = gtk_style_context_get_state (style_context);
+ gtk_style_context_save (style_context);
+ gtk_style_context_add_class (style_context, name);
+ gtk_style_context_get_color (style_context, state, rgba);
+ gtk_style_context_restore (style_context);
+}
+
+static void
+on_tree_style_changed_cb (GbpVcsuiTreeAddin *self,
+ GtkStyleContext *context)
+{
+ g_assert (GBP_IS_VCSUI_TREE_ADDIN (self));
+ g_assert (GTK_IS_STYLE_CONTEXT (context));
+
+ get_foreground_for_class (context, "vcs-added", &self->added_color);
+ get_foreground_for_class (context, "vcs-changed", &self->changed_color);
+}
+
+static void
+gbp_vcsui_tree_addin_load (IdeTreeAddin *addin,
+ IdeTree *tree,
+ IdeTreeModel *model)
+{
+ GbpVcsuiTreeAddin *self = (GbpVcsuiTreeAddin *)addin;
+ GtkStyleContext *style_context;
+ IdeWorkbench *workbench;
+ IdeVcsMonitor *monitor;
+ IdeVcs *vcs;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_VCSUI_TREE_ADDIN (self));
+ g_assert (IDE_IS_TREE (tree));
+ g_assert (IDE_IS_TREE_MODEL (model));
+
+ self->model = model;
+ self->tree = tree;
+
+ style_context = gtk_widget_get_style_context (GTK_WIDGET (tree));
+ g_signal_connect_object (style_context,
+ "changed",
+ G_CALLBACK (on_tree_style_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ on_tree_style_changed_cb (self, style_context);
+
+ if ((workbench = ide_widget_get_workbench (GTK_WIDGET (tree))) &&
+ (vcs = ide_workbench_get_vcs (workbench)) &&
+ (monitor = ide_workbench_get_vcs_monitor (workbench)))
+ {
+ self->vcs = g_object_ref (vcs);
+ self->monitor = g_object_ref (monitor);
+ g_signal_connect_object (self->monitor,
+ "changed",
+ G_CALLBACK (gtk_widget_queue_draw),
+ tree,
+ G_CONNECT_SWAPPED);
+ }
+}
+
+static void
+gbp_vcsui_tree_addin_unload (IdeTreeAddin *addin,
+ IdeTree *tree,
+ IdeTreeModel *model)
+{
+ GbpVcsuiTreeAddin *self = (GbpVcsuiTreeAddin *)addin;
+ GtkStyleContext *style_context;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_VCSUI_TREE_ADDIN (self));
+ g_assert (IDE_IS_TREE (tree));
+ g_assert (IDE_IS_TREE_MODEL (model));
+
+ style_context = gtk_widget_get_style_context (GTK_WIDGET (tree));
+ g_signal_handlers_disconnect_by_func (style_context,
+ G_CALLBACK (on_tree_style_changed_cb),
+ self);
+
+ g_clear_object (&self->monitor);
+ g_clear_object (&self->vcs);
+ self->model = NULL;
+ self->tree = NULL;
+}
+
+static void
+gbp_vcsui_tree_addin_selection_changed (IdeTreeAddin *addin,
+ IdeTreeNode *node)
+{
+ GbpVcsuiTreeAddin *self = (GbpVcsuiTreeAddin *)addin;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_VCSUI_TREE_ADDIN (self));
+ g_assert (!node || IDE_IS_TREE_NODE (node));
+
+}
+
+static void
+gbp_vcsui_tree_addin_cell_data_func (IdeTreeAddin *addin,
+ IdeTreeNode *node,
+ GtkCellRenderer *cell)
+{
+ GbpVcsuiTreeAddin *self = (GbpVcsuiTreeAddin *)addin;
+ g_autoptr(IdeVcsFileInfo) info = NULL;
+ g_autoptr(GFile) file = NULL;
+ IdeProjectFile *project_file;
+
+ g_assert (GBP_IS_VCSUI_TREE_ADDIN (self));
+ g_assert (IDE_IS_TREE_NODE (node));
+ g_assert (GTK_IS_CELL_RENDERER (cell));
+
+ if (self->monitor == NULL)
+ return;
+
+ if (!ide_tree_node_holds (node, IDE_TYPE_PROJECT_FILE))
+ return;
+
+ project_file = ide_tree_node_get_item (node);
+ file = ide_project_file_ref_file (project_file);
+
+ if ((info = ide_vcs_monitor_ref_info (self->monitor, file)))
+ {
+ IdeVcsFileStatus status = ide_vcs_file_info_get_status (info);
+
+ if (status == IDE_VCS_FILE_STATUS_ADDED)
+ g_object_set (cell, "foreground-rgba", &self->added_color, NULL);
+ else if (status == IDE_VCS_FILE_STATUS_CHANGED)
+ g_object_set (cell, "foreground-rgba", &self->changed_color, NULL);
+ }
+}
+
+static void
+tree_addin_iface_init (IdeTreeAddinInterface *iface)
+{
+ iface->cell_data_func = gbp_vcsui_tree_addin_cell_data_func;
+ iface->load = gbp_vcsui_tree_addin_load;
+ iface->selection_changed = gbp_vcsui_tree_addin_selection_changed;
+ iface->unload = gbp_vcsui_tree_addin_unload;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpVcsuiTreeAddin, gbp_vcsui_tree_addin, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_TREE_ADDIN, tree_addin_iface_init))
+
+static void
+gbp_vcsui_tree_addin_class_init (GbpVcsuiTreeAddinClass *klass)
+{
+}
+
+static void
+gbp_vcsui_tree_addin_init (GbpVcsuiTreeAddin *self)
+{
+}
diff --git a/src/plugins/vcsui/gbp-vcsui-tree-addin.h b/src/plugins/vcsui/gbp-vcsui-tree-addin.h
new file mode 100644
index 000000000..09a48ded1
--- /dev/null
+++ b/src/plugins/vcsui/gbp-vcsui-tree-addin.h
@@ -0,0 +1,31 @@
+/* gbp-vcsui-tree-addin.h
+ *
+ * Copyright 2018-2019 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 <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_VCSUI_TREE_ADDIN (gbp_vcsui_tree_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpVcsuiTreeAddin, gbp_vcsui_tree_addin, GBP, VCSUI_TREE_ADDIN, GObject)
+
+G_END_DECLS
diff --git a/src/plugins/vcsui/gtk/menus.ui b/src/plugins/vcsui/gtk/menus.ui
new file mode 100644
index 000000000..6d37a1313
--- /dev/null
+++ b/src/plugins/vcsui/gtk/menus.ui
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!--
+ <menu id="project-tree-menu">
+ <section id="project-tree-menu-placeholder2">
+ <submenu id="project-tree-menu-version-control">
+ <attribute name="label" translatable="yes">Version Control</attribute>
+ <item>
+ <attribute name="label" translatable="yes">Restore File</attribute>
+ <attribute name="action">vcsui.restore-file</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Browse History</attribute>
+ <attribute name="action">vcsui.browse-history</attribute>
+ </item>
+ </submenu>
+ </section>
+ </menu>
+ -->
+</interface>
diff --git a/src/plugins/vcsui/meson.build b/src/plugins/vcsui/meson.build
new file mode 100644
index 000000000..0d198a0af
--- /dev/null
+++ b/src/plugins/vcsui/meson.build
@@ -0,0 +1,13 @@
+plugins_sources += files([
+ 'vcsui-plugin.c',
+ 'gbp-vcsui-tree-addin.c',
+ 'gbp-vcsui-editor-page-addin.c',
+])
+
+plugin_vcsui_resources = gnome.compile_resources(
+ 'vcsui-resources',
+ 'vcsui.gresource.xml',
+ c_name: 'gbp_vcsui',
+)
+
+plugins_sources += plugin_vcsui_resources[0]
diff --git a/src/plugins/vcsui/vcsui-plugin.c b/src/plugins/vcsui/vcsui-plugin.c
new file mode 100644
index 000000000..3d9d2f601
--- /dev/null
+++ b/src/plugins/vcsui/vcsui-plugin.c
@@ -0,0 +1,42 @@
+/* vcsui-plugin.c
+ *
+ * Copyright 2018-2019 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 "vcsui-plugin"
+
+#include "config.h"
+
+#include <libpeas/peas.h>
+#include <libide-editor.h>
+#include <libide-gui.h>
+#include <libide-tree.h>
+
+#include "gbp-vcsui-editor-page-addin.h"
+#include "gbp-vcsui-tree-addin.h"
+
+_IDE_EXTERN void
+_gbp_vcsui_register_types (PeasObjectModule *module)
+{
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_EDITOR_PAGE_ADDIN,
+ GBP_TYPE_VCSUI_EDITOR_PAGE_ADDIN);
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_TREE_ADDIN,
+ GBP_TYPE_VCSUI_TREE_ADDIN);
+}
diff --git a/src/plugins/vcsui/vcsui.gresource.xml b/src/plugins/vcsui/vcsui.gresource.xml
new file mode 100644
index 000000000..3dd0a29b3
--- /dev/null
+++ b/src/plugins/vcsui/vcsui.gresource.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/plugins/vcsui">
+ <file>vcsui.plugin</file>
+ <file preprocess="xml-stripblanks">gtk/menus.ui</file>
+ </gresource>
+</gresources>
diff --git a/src/plugins/vcsui/vcsui.plugin b/src/plugins/vcsui/vcsui.plugin
new file mode 100644
index 000000000..8772dac74
--- /dev/null
+++ b/src/plugins/vcsui/vcsui.plugin
@@ -0,0 +1,11 @@
+[Plugin]
+Authors=Christian Hergert <christian hergert me>
+Builtin=true
+Copyright=Copyright © 2015-2018 Christian Hergert
+Depends=editor;project-tree;
+Description=Provides user interface components to display VCS
+Embedded=_gbp_vcsui_register_types
+Hidden=true
+Module=vcsui
+Name=VCS interface extensions
+X-Workspace-Kind=primary;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]