[gnome-builder/wip/chergert/git-oop] more work on moving to git-client apis
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/git-oop] more work on moving to git-client apis
- Date: Fri, 22 Mar 2019 23:01:00 +0000 (UTC)
commit 385cfa129627d04630beff2cabb70a5667ebe2c5
Author: Christian Hergert <chergert redhat com>
Date: Fri Mar 22 16:00:27 2019 -0700
more work on moving to git-client apis
src/plugins/git/gbp-git-buffer-addin.c | 4 +-
src/plugins/git/gbp-git-buffer-change-monitor.c | 961 +++++-------------------
src/plugins/git/gbp-git-buffer-change-monitor.h | 17 +-
src/plugins/git/gbp-git-client.c | 2 +-
src/plugins/git/gbp-git-client.h | 3 +
src/plugins/git/gbp-git-vcs.c | 67 +-
src/plugins/git/gbp-git-vcs.h | 2 -
src/plugins/git/gbp-git-workbench-addin.c | 11 +-
src/plugins/git/gbp-git.c | 30 +
9 files changed, 264 insertions(+), 833 deletions(-)
---
diff --git a/src/plugins/git/gbp-git-buffer-addin.c b/src/plugins/git/gbp-git-buffer-addin.c
index 9d21af2ba..46e17bd03 100644
--- a/src/plugins/git/gbp-git-buffer-addin.c
+++ b/src/plugins/git/gbp-git-buffer-addin.c
@@ -36,7 +36,7 @@ struct _GbpGitBufferAddin
};
static void
-gbp_git_buffer_addin_file_laoded (IdeBufferAddin *addin,
+gbp_git_buffer_addin_file_loaded (IdeBufferAddin *addin,
IdeBuffer *buffer,
GFile *file)
{
@@ -153,7 +153,7 @@ gbp_git_buffer_addin_settle_finish (IdeBufferAddin *addin,
static void
buffer_addin_iface_init (IdeBufferAddinInterface *iface)
{
- iface->file_loaded = gbp_git_buffer_addin_file_laoded;
+ iface->file_loaded = gbp_git_buffer_addin_file_loaded;
iface->file_saved = gbp_git_buffer_addin_file_saved;
iface->unload = gbp_git_buffer_addin_unload;
iface->settle_async = gbp_git_buffer_addin_settle_async;
diff --git a/src/plugins/git/gbp-git-buffer-change-monitor.c b/src/plugins/git/gbp-git-buffer-change-monitor.c
index 72f3ce13f..e80e6d4a9 100644
--- a/src/plugins/git/gbp-git-buffer-change-monitor.c
+++ b/src/plugins/git/gbp-git-buffer-change-monitor.c
@@ -1,6 +1,6 @@
/* gbp-git-buffer-change-monitor.c
*
- * Copyright 2015-2019 Christian Hergert <christian hergert me>
+ * Copyright 2015-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
@@ -18,437 +18,183 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
-/* Some code from this file is loosely based around the git-diff
- * plugin from Atom. Namely, API usage for iterating through hunks
- * containing changes. It's license is provided below.
- */
-
-/*
- * Copyright (c) 2014 GitHub Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
-
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
#define G_LOG_DOMAIN "gbp-git-buffer-change-monitor"
+#include "config.h"
+
#include <dazzle.h>
-#include <glib/gi18n.h>
-#include <libgit2-glib/ggit.h>
-#include <stdlib.h>
+#include "gbp-git-client.h"
#include "gbp-git-buffer-change-monitor.h"
-#include "gbp-git-vcs.h"
-
#include "line-cache.h"
#define DELAY_CHANGED_SEC 1
-/**
- * SECTION:gbp-git-buffer-change-monitor
- *
- * This module provides line change monitoring when used in conjunction with an
- * GbpGitVcs. The changes are generated by comparing the buffer contents to
- * the version found inside of the git repository.
- *
- * To enable us to avoid blocking the main loop, the actual diff is performed
- * in a background thread. To avoid threading issues with the rest of LibGBP,
- * this module creates a copy of the loaded repository. A single thread will be
- * dispatched for the context and all reload tasks will be performed from that
- * thread.
- *
- * Upon completion of the diff, the results will be passed back to the primary
- * thread and the state updated for use by line change renderer in the source
- * view.
- *
- * Since: 3.32
- */
-
struct _GbpGitBufferChangeMonitor
{
IdeBufferChangeMonitor parent_instance;
-
- DzlSignalGroup *signal_group;
-
- GgitRepository *repository;
- GArray *lines;
-
- GgitBlob *cached_blob;
+ DzlSignalGroup *signals;
LineCache *cache;
-
- GQueue wait_tasks;
-
- guint changed_timeout;
-
- guint state_dirty : 1;
- guint in_calculation : 1;
guint delete_range_requires_recalculation : 1;
- guint is_child_of_workdir : 1;
- guint in_failed_state : 1;
};
-typedef struct
-{
- GgitRepository *repository;
- LineCache *cache;
- GFile *file;
- GBytes *content;
- GgitBlob *blob;
- IdeObject *lock_object;
- guint is_child_of_workdir : 1;
-} DiffTask;
-
-typedef struct
-{
- gint old_start;
- gint old_lines;
- gint new_start;
- gint new_lines;
-} Range;
-
G_DEFINE_TYPE (GbpGitBufferChangeMonitor, gbp_git_buffer_change_monitor, IDE_TYPE_BUFFER_CHANGE_MONITOR)
-DZL_DEFINE_COUNTER (instances, "GbpGitBufferChangeMonitor", "Instances", "The number of git buffer change
monitor instances.");
-
-enum {
- PROP_0,
- PROP_REPOSITORY,
- LAST_PROP
-};
-
-static GParamSpec *properties [LAST_PROP];
-static GAsyncQueue *work_queue;
-static GThread *work_thread;
-
static void
-diff_task_free (gpointer data)
+gbp_git_buffer_change_monitor_recalculate (GbpGitBufferChangeMonitor *self)
{
- DiffTask *diff = data;
+ g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- if (diff)
- {
- g_clear_object (&diff->file);
- g_clear_object (&diff->blob);
- g_clear_object (&diff->repository);
- g_clear_object (&diff->lock_object);
- g_clear_pointer (&diff->cache, line_cache_free);
- g_clear_pointer (&diff->content, g_bytes_unref);
- g_slice_free (DiffTask, diff);
- }
+ gbp_git_buffer_change_monitor_wait_async (self, NULL, NULL, NULL);
}
static void
-complete_wait_tasks (GbpGitBufferChangeMonitor *self,
- GParamSpec *pspec,
- IdeTask *calculate_task)
+gbp_git_buffer_change_monitor_load (IdeBufferChangeMonitor *monitor,
+ IdeBuffer *buffer)
{
- gpointer taskptr;
+ GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
- g_assert (IDE_IS_MAIN_THREAD ());
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (IDE_IS_TASK (calculate_task));
-
- while ((taskptr = g_queue_pop_head (&self->wait_tasks)))
- {
- g_autoptr(IdeTask) task = taskptr;
+ g_assert (DZL_IS_SIGNAL_GROUP (self->signals));
+ g_assert (IDE_IS_BUFFER (buffer));
- ide_task_return_boolean (task, TRUE);
- }
+ dzl_signal_group_set_target (self->signals, buffer);
}
-static LineCache *
-gbp_git_buffer_change_monitor_calculate_finish (GbpGitBufferChangeMonitor *self,
- GAsyncResult *result,
- GError **error)
+static void
+gbp_git_buffer_change_monitor_reload (IdeBufferChangeMonitor *monitor)
{
- IdeTask *task = (IdeTask *)result;
- DiffTask *diff;
-
- g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (IDE_IS_TASK (result));
-
- if (ide_object_set_error_if_destroyed (IDE_OBJECT (self), error))
- return NULL;
-
- diff = ide_task_get_task_data (task);
-
- if (diff != NULL)
- {
- g_assert (GGIT_IS_REPOSITORY (diff->repository));
- g_assert (G_IS_FILE (diff->file));
- g_assert (diff->content != NULL);
- g_assert (GBP_IS_GIT_VCS (diff->lock_object));
-
- /* Keep the blob around for future use */
- if (diff->blob != self->cached_blob)
- g_set_object (&self->cached_blob, diff->blob);
+ GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
- /* If the file is a child of the working directory, we need to know */
- self->is_child_of_workdir = diff->is_child_of_workdir;
- }
+ g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (monitor));
- return ide_task_propagate_pointer (task, error);
+ g_clear_pointer (&self->cache, line_cache_free);
}
-static void
-gbp_git_buffer_change_monitor_calculate_async (GbpGitBufferChangeMonitor *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+static IdeBufferLineChange
+translate_mark (LineMark mark)
{
- g_autoptr(IdeTask) task = NULL;
- g_autoptr(IdeContext) context = NULL;
- GbpGitVcs *vcs;
- IdeBuffer *buffer;
- DiffTask *diff;
- GFile *file;
-
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- g_assert (self->repository != NULL);
-
- self->state_dirty = FALSE;
-
- task = ide_task_new (self, cancellable, callback, user_data);
- ide_task_set_source_tag (task, gbp_git_buffer_change_monitor_calculate_async);
-
- g_signal_connect_object (task,
- "notify::completed",
- G_CALLBACK (complete_wait_tasks),
- self,
- G_CONNECT_SWAPPED);
+ IdeBufferLineChange change = 0;
- buffer = ide_buffer_change_monitor_get_buffer (IDE_BUFFER_CHANGE_MONITOR (self));
- g_assert (IDE_IS_BUFFER (buffer));
+ if (mark & LINE_MARK_ADDED)
+ change |= IDE_BUFFER_LINE_CHANGE_ADDED;
- file = ide_buffer_get_file (buffer);
- g_assert (G_IS_FILE (file));
+ if (mark & LINE_MARK_REMOVED)
+ change |= IDE_BUFFER_LINE_CHANGE_DELETED;
- context = ide_object_ref_context (IDE_OBJECT (self));
- vcs = ide_context_peek_child_typed (context, GBP_TYPE_GIT_VCS);
+ if (mark & LINE_MARK_PREVIOUS_REMOVED)
+ change |= IDE_BUFFER_LINE_CHANGE_PREVIOUS_DELETED;
- if (!GBP_IS_GIT_VCS (vcs))
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_CANCELLED,
- "Cannot provide changes, not connected to GbpGitVcs.");
- return;
- }
+ if (mark & LINE_MARK_CHANGED)
+ change |= IDE_BUFFER_LINE_CHANGE_CHANGED;
- diff = g_slice_new0 (DiffTask);
- diff->file = g_object_ref (file);
- diff->repository = g_object_ref (self->repository);
- diff->cache = line_cache_new ();
- diff->content = ide_buffer_dup_content (buffer);
- diff->blob = self->cached_blob ? g_object_ref (self->cached_blob) : NULL;
- diff->lock_object = g_object_ref (IDE_OBJECT (vcs));
+ return change;
+}
- ide_task_set_task_data (task, diff, diff_task_free);
+static IdeBufferLineChange
+gbp_git_buffer_change_monitor_get_change (IdeBufferChangeMonitor *monitor,
+ guint line)
+{
+ GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
- self->in_calculation = TRUE;
+ g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_async_queue_push (work_queue, g_steal_pointer (&task));
+ return self->cache ? translate_mark (line_cache_get_mark (self->cache, line)) : 0;
}
static void
-foreach_cb (gpointer data,
- gpointer user_data)
+gbp_git_buffer_change_monitor_foreach_change_cb (gpointer data,
+ gpointer user_data)
{
const LineEntry *entry = data;
- struct {
+ const struct {
IdeBufferChangeMonitorForeachFunc func;
- gpointer user_data;
+ gpointer data;
} *state = user_data;
- IdeBufferLineChange change = 0;
-
- if (entry->mark & LINE_MARK_ADDED)
- change |= IDE_BUFFER_LINE_CHANGE_ADDED;
-
- if (entry->mark & LINE_MARK_REMOVED)
- change |= IDE_BUFFER_LINE_CHANGE_DELETED;
- if (entry->mark & LINE_MARK_PREVIOUS_REMOVED)
- change |= IDE_BUFFER_LINE_CHANGE_PREVIOUS_DELETED;
-
- if (entry->mark & LINE_MARK_CHANGED)
- change |= IDE_BUFFER_LINE_CHANGE_CHANGED;
+ g_assert (entry != NULL);
+ g_assert (state != NULL);
+ g_assert (state->func != NULL);
- state->func (entry->line, change, state->user_data);
+ state->func (entry->line, translate_mark (entry->mark), state->data);
}
static void
gbp_git_buffer_change_monitor_foreach_change (IdeBufferChangeMonitor *monitor,
- guint begin_line,
- guint end_line,
+ guint line_begin,
+ guint line_end,
IdeBufferChangeMonitorForeachFunc callback,
gpointer user_data)
{
GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
- struct {
- IdeBufferChangeMonitorForeachFunc func;
- gpointer user_data;
- } state = { callback, user_data };
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
g_assert (callback != NULL);
- if (end_line == G_MAXUINT)
- end_line--;
-
- if (self->cache == NULL)
- {
- /* If within working directory, synthesize line addition. */
- if (self->is_child_of_workdir)
- {
- for (guint i = begin_line; i < end_line; i++)
- callback (i, IDE_BUFFER_LINE_CHANGE_ADDED, user_data);
- }
-
- return;
- }
-
- line_cache_foreach_in_range (self->cache, begin_line, end_line, foreach_cb, &state);
-}
-
-static IdeBufferLineChange
-gbp_git_buffer_change_monitor_get_change (IdeBufferChangeMonitor *monitor,
- guint line)
-{
- GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
- guint mark;
-
- /* Don't imply changes we don't know are real, in the case that
- * we failed to communicate with git properly about the blob diff.
- */
- if (self->in_failed_state)
- return IDE_BUFFER_LINE_CHANGE_NONE;
-
- if (self->cache == NULL)
- {
- /* If within working directory, synthesize line addition. */
- if (self->is_child_of_workdir)
- return IDE_BUFFER_LINE_CHANGE_ADDED;
- return IDE_BUFFER_LINE_CHANGE_NONE;
- }
-
- mark = line_cache_get_mark (self->cache, line + 1);
-
- if (mark & LINE_MARK_ADDED)
- return IDE_BUFFER_LINE_CHANGE_ADDED;
- else if (mark & LINE_MARK_REMOVED)
- return IDE_BUFFER_LINE_CHANGE_DELETED;
- else if (mark & LINE_MARK_CHANGED)
- return IDE_BUFFER_LINE_CHANGE_CHANGED;
- else
- return IDE_BUFFER_LINE_CHANGE_NONE;
-}
-
-void
-gbp_git_buffer_change_monitor_set_repository (GbpGitBufferChangeMonitor *self,
- GgitRepository *repository)
-{
- gboolean do_reload;
-
- g_return_if_fail (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_return_if_fail (GGIT_IS_REPOSITORY (repository));
-
- do_reload = self->repository != NULL && repository != NULL;
-
- if (g_set_object (&self->repository, repository))
+ if (self->cache != NULL)
{
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_REPOSITORY]);
-
- if (do_reload)
- ide_buffer_change_monitor_reload (IDE_BUFFER_CHANGE_MONITOR (self));
+ struct {
+ IdeBufferChangeMonitorForeachFunc func;
+ gpointer data;
+ } state = { callback, user_data };
+
+ line_cache_foreach_in_range (self->cache,
+ line_begin,
+ line_end,
+ gbp_git_buffer_change_monitor_foreach_change_cb,
+ &state);
}
}
static void
-gbp_git_buffer_change_monitor__calculate_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data_unused)
+gbp_git_buffer_change_monitor_insert_text_after_cb (GbpGitBufferChangeMonitor *self,
+ const GtkTextIter *location,
+ gchar *text,
+ gint len,
+ IdeBuffer *buffer)
{
- GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)object;
- LineCache *cache;
- g_autoptr(GError) error = NULL;
+ IdeBufferLineChange change;
+ guint line;
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (user_data_unused == NULL);
-
- self->in_calculation = FALSE;
-
- cache = gbp_git_buffer_change_monitor_calculate_finish (self, result, &error);
-
- if (cache == NULL)
- {
- if (!self->in_failed_state && !g_error_matches (error, GGIT_ERROR, GGIT_ERROR_NOTFOUND))
- {
- ide_object_warning (self,
- /* translators: %s is replaced with the error string from git */
- _("There was a failure while calculating line changes from git. The exact
error was: %s"),
- error->message);
- self->in_failed_state = TRUE;
- }
- }
- else
- {
- g_clear_pointer (&self->cache, line_cache_free);
- self->cache = g_steal_pointer (&cache);
- self->in_failed_state = FALSE;
- }
+ g_assert (location != NULL);
+ g_assert (text != NULL);
+ g_assert (IDE_IS_BUFFER (buffer));
- ide_buffer_change_monitor_emit_changed (IDE_BUFFER_CHANGE_MONITOR (self));
+ /*
+ * We need to recalculate the diff when text is inserted if:
+ *
+ * 1) A newline is included in the text.
+ * 2) The line currently has flags of NONE.
+ *
+ * Technically we need to do it on every change to be more correct, but that wastes a lot of
+ * power. So instead, we'll be a bit lazy about it here and pick up the other changes on a much
+ * more conservative timeout, generated by gbp_git_buffer_change_monitor__buffer_changed_cb().
+ */
- /* Recalculate if the buffer has changed since last request. */
- if (self->state_dirty)
- gbp_git_buffer_change_monitor_calculate_async (self,
- NULL,
- gbp_git_buffer_change_monitor__calculate_cb,
- NULL);
-}
+ if (NULL != memmem (text, len, "\n", 1))
+ goto recalculate;
-static void
-gbp_git_buffer_change_monitor_recalculate (GbpGitBufferChangeMonitor *self)
-{
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
+ line = gtk_text_iter_get_line (location);
+ change = gbp_git_buffer_change_monitor_get_change (IDE_BUFFER_CHANGE_MONITOR (self), line);
+ if (change == IDE_BUFFER_LINE_CHANGE_NONE)
+ goto recalculate;
- self->state_dirty = TRUE;
+ return;
- if (!self->in_calculation)
- gbp_git_buffer_change_monitor_calculate_async (self,
- NULL,
- gbp_git_buffer_change_monitor__calculate_cb,
- NULL);
+recalculate:
+ gbp_git_buffer_change_monitor_recalculate (self);
}
static void
-gbp_git_buffer_change_monitor__buffer_delete_range_after_cb (GbpGitBufferChangeMonitor *self,
- GtkTextIter *begin,
- GtkTextIter *end,
- IdeBuffer *buffer)
+gbp_git_buffer_change_monitor_delete_range_after_cb (GbpGitBufferChangeMonitor *self,
+ GtkTextIter *begin,
+ GtkTextIter *end,
+ IdeBuffer *buffer)
{
- IDE_ENTRY;
-
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (begin);
- g_assert (end);
+ g_assert (begin != NULL);
+ g_assert (end != NULL);
g_assert (IDE_IS_BUFFER (buffer));
if (self->delete_range_requires_recalculation)
@@ -456,19 +202,16 @@ gbp_git_buffer_change_monitor__buffer_delete_range_after_cb (GbpGitBufferChangeM
self->delete_range_requires_recalculation = FALSE;
gbp_git_buffer_change_monitor_recalculate (self);
}
-
- IDE_EXIT;
}
static void
-gbp_git_buffer_change_monitor__buffer_delete_range_cb (GbpGitBufferChangeMonitor *self,
- GtkTextIter *begin,
- GtkTextIter *end,
- IdeBuffer *buffer)
+gbp_git_buffer_change_monitor_delete_range_cb (GbpGitBufferChangeMonitor *self,
+ GtkTextIter *begin,
+ GtkTextIter *end,
+ IdeBuffer *buffer)
{
IdeBufferLineChange change;
-
- IDE_ENTRY;
+ guint line;
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
g_assert (begin != NULL);
@@ -481,20 +224,21 @@ gbp_git_buffer_change_monitor__buffer_delete_range_cb (GbpGitBufferChangeMonitor
* 1) The range includes a newline.
* 2) The current line change is set to NONE.
*
- * Technically we need to do it on every change to be more correct, but that wastes a lot of
- * power. So instead, we'll be a bit lazy about it here and pick up the other changes on a much
- * more conservative timeout, generated by gbp_git_buffer_change_monitor__buffer_changed_cb().
+ * Technically we need to do it on every change to be more correct, but
+ * that wastes a lot of power. So instead, we'll be a bit lazy about it
+ * here and pick up the other changes on a much more conservative timeout,
+ * generated by gbp_git_buffer_change_monitor__buffer_changed_cb().
*/
if (gtk_text_iter_get_line (begin) != gtk_text_iter_get_line (end))
- IDE_GOTO (recalculate);
+ goto recalculate;
- change = gbp_git_buffer_change_monitor_get_change (IDE_BUFFER_CHANGE_MONITOR (self),
- gtk_text_iter_get_line (begin));
+ line = gtk_text_iter_get_line (begin);
+ change = gbp_git_buffer_change_monitor_get_change (IDE_BUFFER_CHANGE_MONITOR (self), line);
if (change == IDE_BUFFER_LINE_CHANGE_NONE)
- IDE_GOTO (recalculate);
+ goto recalculate;
- IDE_EXIT;
+ return;
recalculate:
/*
@@ -502,340 +246,16 @@ recalculate:
* gbp_git_buffer_change_monitor__buffer_delete_range_after_cb perform the operation.
*/
self->delete_range_requires_recalculation = TRUE;
-
- IDE_EXIT;
-}
-
-static void
-gbp_git_buffer_change_monitor__buffer_insert_text_after_cb (GbpGitBufferChangeMonitor *self,
- GtkTextIter *location,
- gchar *text,
- gint len,
- IdeBuffer *buffer)
-{
- IdeBufferLineChange change;
-
- IDE_ENTRY;
-
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (location);
- g_assert (text);
- g_assert (IDE_IS_BUFFER (buffer));
-
- /*
- * We need to recalculate the diff when text is inserted if:
- *
- * 1) A newline is included in the text.
- * 2) The line currently has flags of NONE.
- *
- * Technically we need to do it on every change to be more correct, but that wastes a lot of
- * power. So instead, we'll be a bit lazy about it here and pick up the other changes on a much
- * more conservative timeout, generated by gbp_git_buffer_change_monitor__buffer_changed_cb().
- */
-
- if (NULL != memmem (text, len, "\n", 1))
- IDE_GOTO (recalculate);
-
- change = gbp_git_buffer_change_monitor_get_change (IDE_BUFFER_CHANGE_MONITOR (self),
- gtk_text_iter_get_line (location));
- if (change == IDE_BUFFER_LINE_CHANGE_NONE)
- IDE_GOTO (recalculate);
-
- IDE_EXIT;
-
-recalculate:
- gbp_git_buffer_change_monitor_recalculate (self);
-
- IDE_EXIT;
-}
-
-static gboolean
-gbp_git_buffer_change_monitor__changed_timeout_cb (gpointer user_data)
-{
- GbpGitBufferChangeMonitor *self = user_data;
-
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
-
- self->changed_timeout = 0;
- gbp_git_buffer_change_monitor_recalculate (self);
-
- return G_SOURCE_REMOVE;
}
static void
-gbp_git_buffer_change_monitor__buffer_changed_after_cb (GbpGitBufferChangeMonitor *self,
- IdeBuffer *buffer)
+gbp_git_buffer_change_monitor_change_settled_cb (GbpGitBufferChangeMonitor *self,
+ IdeBuffer *buffer)
{
g_assert (IDE_IS_BUFFER_CHANGE_MONITOR (self));
g_assert (IDE_IS_BUFFER (buffer));
- self->state_dirty = TRUE;
-
- if (self->in_calculation)
- return;
-
- dzl_clear_source (&self->changed_timeout);
- self->changed_timeout = g_timeout_add_seconds (DELAY_CHANGED_SEC,
- gbp_git_buffer_change_monitor__changed_timeout_cb,
- self);
-}
-
-static void
-gbp_git_buffer_change_monitor_reload (IdeBufferChangeMonitor *monitor)
-{
- GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
-
- IDE_ENTRY;
-
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
-
- g_clear_object (&self->cached_blob);
gbp_git_buffer_change_monitor_recalculate (self);
-
- IDE_EXIT;
-}
-
-static void
-gbp_git_buffer_change_monitor_load (IdeBufferChangeMonitor *monitor,
- IdeBuffer *buffer)
-{
- GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
-
- IDE_ENTRY;
-
- g_return_if_fail (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_return_if_fail (IDE_IS_BUFFER (buffer));
-
- dzl_signal_group_set_target (self->signal_group, buffer);
-
- IDE_EXIT;
-}
-
-static gint
-diff_hunk_cb (GgitDiffDelta *delta,
- GgitDiffHunk *hunk,
- gpointer user_data)
-{
- GArray *ranges = user_data;
- Range range;
-
- g_assert (delta != NULL);
- g_assert (hunk != NULL);
- g_assert (ranges != NULL);
-
- range.old_start = ggit_diff_hunk_get_old_start (hunk);
- range.old_lines = ggit_diff_hunk_get_old_lines (hunk);
- range.new_start = ggit_diff_hunk_get_new_start (hunk);
- range.new_lines = ggit_diff_hunk_get_new_lines (hunk);
-
- g_array_append_val (ranges, range);
-
- return 0;
-}
-
-static gboolean
-gbp_git_buffer_change_monitor_calculate_threaded (GbpGitBufferChangeMonitor *self,
- DiffTask *diff,
- GError **error)
-{
- g_autofree gchar *relative_path = NULL;
- g_autoptr(GgitDiffOptions) options = NULL;
- g_autoptr(GFile) workdir = NULL;
- g_autoptr(GArray) ranges = NULL;
- LineCache *cache;
- const guint8 *data;
- gsize data_len = 0;
-
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (diff != NULL);
- g_assert (G_IS_FILE (diff->file));
- g_assert (diff->cache != NULL);
- g_assert (GGIT_IS_REPOSITORY (diff->repository));
- g_assert (diff->content != NULL);
- g_assert (!diff->blob || GGIT_IS_BLOB (diff->blob));
- g_assert (error != NULL);
- g_assert (*error == NULL);
-
- workdir = ggit_repository_get_workdir (diff->repository);
-
- if (!workdir)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_FILENAME,
- _("Repository does not have a working directory."));
- return FALSE;
- }
-
- relative_path = g_file_get_relative_path (workdir, diff->file);
-
- if (!relative_path)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_FILENAME,
- _("File is not under control of git working directory."));
- return FALSE;
- }
-
- diff->is_child_of_workdir = TRUE;
-
- /*
- * Find the blob if necessary. This will be cached by the main thread for
- * us on the way out of the async operation.
- */
- if (diff->blob == NULL)
- {
- GgitOId *entry_oid = NULL;
- GgitOId *oid = NULL;
- GgitObject *blob = NULL;
- GgitObject *commit = NULL;
- GgitRef *head = NULL;
- GgitTree *tree = NULL;
- GgitTreeEntry *entry = NULL;
-
- head = ggit_repository_get_head (diff->repository, error);
- if (!head)
- goto cleanup;
-
- oid = ggit_ref_get_target (head);
- if (!oid)
- goto cleanup;
-
- commit = ggit_repository_lookup (diff->repository, oid, GGIT_TYPE_COMMIT, error);
- if (!commit)
- goto cleanup;
-
- tree = ggit_commit_get_tree (GGIT_COMMIT (commit));
- if (!tree)
- goto cleanup;
-
- entry = ggit_tree_get_by_path (tree, relative_path, error);
- if (!entry)
- goto cleanup;
-
- entry_oid = ggit_tree_entry_get_id (entry);
- if (!entry_oid)
- goto cleanup;
-
- blob = ggit_repository_lookup (diff->repository, entry_oid, GGIT_TYPE_BLOB, error);
- if (!blob)
- goto cleanup;
-
- diff->blob = g_object_ref (GGIT_BLOB (blob));
-
- cleanup:
- g_clear_object (&blob);
- g_clear_pointer (&entry_oid, ggit_oid_free);
- g_clear_pointer (&entry, ggit_tree_entry_unref);
- g_clear_object (&tree);
- g_clear_object (&commit);
- g_clear_pointer (&oid, ggit_oid_free);
- g_clear_object (&head);
- }
-
- if (diff->blob == NULL)
- {
- if (*error == NULL)
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_NOT_FOUND,
- _("The requested file does not exist within the git index."));
- return FALSE;
- }
-
- data = g_bytes_get_data (diff->content, &data_len);
-
- ranges = g_array_new (FALSE, FALSE, sizeof (Range));
- options = ggit_diff_options_new ();
-
- ggit_diff_options_set_n_context_lines (options, 0);
-
- ggit_diff_blob_to_buffer (diff->blob,
- relative_path,
- data,
- data_len,
- relative_path,
- options,
- NULL, /* File Callback */
- NULL, /* Binary Callback */
- diff_hunk_cb, /* Hunk Callback */
- NULL,
- ranges,
- error);
-
- cache = diff->cache;
-
- for (guint i = 0; i < ranges->len; i++)
- {
- const Range *range = &g_array_index (ranges, Range, i);
- gint start_line = range->new_start - 1;
- gint end_line = range->new_start + range->new_lines - 1;
-
- if (range->old_lines == 0 && range->new_lines > 0)
- {
- line_cache_mark_range (cache, start_line, end_line, LINE_MARK_ADDED);
- }
- else if (range->new_lines == 0 && range->old_lines > 0)
- {
- if (start_line < 0)
- line_cache_mark_range (cache, 0, 0, LINE_MARK_PREVIOUS_REMOVED);
- else
- line_cache_mark_range (cache, start_line + 1, start_line + 1, LINE_MARK_REMOVED);
- }
- else
- {
- line_cache_mark_range (cache, start_line, end_line, LINE_MARK_CHANGED);
- }
- }
-
- return *error == NULL;
-}
-
-static gpointer
-gbp_git_buffer_change_monitor_worker (gpointer data)
-{
- GAsyncQueue *queue = data;
- gpointer taskptr;
-
- g_assert (queue != NULL);
-
- /*
- * This is a single thread worker that dispatches the particular
- * change to the given change monitor. We require a single thread
- * so that we can mantain the invariant that only a single thread
- * can access a GgitRepository at a time (and change monitors all
- * share the same GgitRepository amongst themselves).
- */
-
- while ((taskptr = g_async_queue_pop (queue)))
- {
- GbpGitBufferChangeMonitor *self;
- g_autoptr(GError) error = NULL;
- g_autoptr(IdeTask) task = taskptr;
- DiffTask *diff;
- gboolean ret;
-
- self = ide_task_get_source_object (task);
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
-
- diff = ide_task_get_task_data (task);
- g_assert (diff != NULL);
-
- /* Acquire the lock for the parent to ensure we have access to repository */
- ide_object_lock (diff->lock_object);
- ret = gbp_git_buffer_change_monitor_calculate_threaded (self, diff, &error);
- ide_object_unlock (diff->lock_object);
-
- if (!ret)
- ide_task_return_error (task, g_steal_pointer (&error));
- else
- ide_task_return_pointer (task,
- g_steal_pointer (&diff->cache),
- line_cache_free);
- }
-
- return NULL;
}
static void
@@ -843,138 +263,136 @@ gbp_git_buffer_change_monitor_destroy (IdeObject *object)
{
GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)object;
- dzl_clear_source (&self->changed_timeout);
+ g_clear_pointer (&self->cache, line_cache_free);
- if (self->signal_group)
+ if (self->signals != NULL)
{
- dzl_signal_group_set_target (self->signal_group, NULL);
- g_clear_object (&self->signal_group);
+ dzl_signal_group_set_target (self->signals, NULL);
+ g_clear_object (&self->signals);
}
- g_clear_object (&self->cached_blob);
- g_clear_object (&self->repository);
- g_clear_pointer (&self->cache, line_cache_free);
-
IDE_OBJECT_CLASS (gbp_git_buffer_change_monitor_parent_class)->destroy (object);
}
-static void
-gbp_git_buffer_change_monitor_finalize (GObject *object)
-{
- G_OBJECT_CLASS (gbp_git_buffer_change_monitor_parent_class)->finalize (object);
-
- DZL_COUNTER_DEC (instances);
-}
-
-static void
-gbp_git_buffer_change_monitor_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GbpGitBufferChangeMonitor *self = GBP_GIT_BUFFER_CHANGE_MONITOR (object);
-
- switch (prop_id)
- {
- case PROP_REPOSITORY:
- gbp_git_buffer_change_monitor_set_repository (self, g_value_get_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
static void
gbp_git_buffer_change_monitor_class_init (GbpGitBufferChangeMonitorClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ IdeBufferChangeMonitorClass *monitor_class = IDE_BUFFER_CHANGE_MONITOR_CLASS (klass);
IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
- IdeBufferChangeMonitorClass *parent_class = IDE_BUFFER_CHANGE_MONITOR_CLASS (klass);
-
- object_class->finalize = gbp_git_buffer_change_monitor_finalize;
- object_class->set_property = gbp_git_buffer_change_monitor_set_property;
i_object_class->destroy = gbp_git_buffer_change_monitor_destroy;
- parent_class->load = gbp_git_buffer_change_monitor_load;
- parent_class->get_change = gbp_git_buffer_change_monitor_get_change;
- parent_class->reload = gbp_git_buffer_change_monitor_reload;
- parent_class->foreach_change = gbp_git_buffer_change_monitor_foreach_change;
-
- properties [PROP_REPOSITORY] =
- g_param_spec_object ("repository",
- "Repository",
- "The repository to use for calculating diffs.",
- GGIT_TYPE_REPOSITORY,
- (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, LAST_PROP, properties);
-
- /* Note: We use a single worker thread so that we can maintain the
- * invariant that only a single thread is touching the GgitRepository
- * at a time. (Also, you can only type in one editor at a time, so
- * on worker thread for interactive blob changes is fine.
- */
- work_queue = g_async_queue_new ();
- work_thread = g_thread_new ("GbpGitBufferChangeMonitorWorker",
- gbp_git_buffer_change_monitor_worker,
- work_queue);
+ monitor_class->load = gbp_git_buffer_change_monitor_load;
+ monitor_class->reload = gbp_git_buffer_change_monitor_reload;
+ monitor_class->get_change = gbp_git_buffer_change_monitor_get_change;
+ monitor_class->foreach_change = gbp_git_buffer_change_monitor_foreach_change;
}
static void
gbp_git_buffer_change_monitor_init (GbpGitBufferChangeMonitor *self)
{
- DZL_COUNTER_INC (instances);
+ self->signals = dzl_signal_group_new (IDE_TYPE_BUFFER);
- self->signal_group = dzl_signal_group_new (IDE_TYPE_BUFFER);
- dzl_signal_group_connect_object (self->signal_group,
+ dzl_signal_group_connect_object (self->signals,
"insert-text",
- G_CALLBACK (gbp_git_buffer_change_monitor__buffer_insert_text_after_cb),
+ G_CALLBACK (gbp_git_buffer_change_monitor_insert_text_after_cb),
self,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
- dzl_signal_group_connect_object (self->signal_group,
+ dzl_signal_group_connect_object (self->signals,
"delete-range",
- G_CALLBACK (gbp_git_buffer_change_monitor__buffer_delete_range_cb),
+ G_CALLBACK (gbp_git_buffer_change_monitor_delete_range_cb),
self,
G_CONNECT_SWAPPED);
- dzl_signal_group_connect_object (self->signal_group,
+ dzl_signal_group_connect_object (self->signals,
"delete-range",
- G_CALLBACK (gbp_git_buffer_change_monitor__buffer_delete_range_after_cb),
+ G_CALLBACK (gbp_git_buffer_change_monitor_delete_range_after_cb),
self,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
- dzl_signal_group_connect_object (self->signal_group,
- "changed",
- G_CALLBACK (gbp_git_buffer_change_monitor__buffer_changed_after_cb),
+ dzl_signal_group_connect_object (self->signals,
+ "change-settled",
+ G_CALLBACK (gbp_git_buffer_change_monitor_change_settled_cb),
self,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
}
+static void
+gbp_git_buffer_change_monitor_wait_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GbpGitClient *client = (GbpGitClient *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ GbpGitBufferChangeMonitor *self;
+ LineCache *cache;
+
+ g_assert (GBP_IS_GIT_CLIENT (client));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ if (!(cache = gbp_git_client_get_changes_finish (client, result, &error)))
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ self = ide_task_get_source_object (task);
+ g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
+ g_clear_pointer (&self->cache, line_cache_free);
+ self->cache = g_steal_pointer (&cache);
+
+ ide_task_return_boolean (task, TRUE);
+
+ ide_buffer_change_monitor_emit_changed (IDE_BUFFER_CHANGE_MONITOR (self));
+}
+
void
gbp_git_buffer_change_monitor_wait_async (GbpGitBufferChangeMonitor *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ g_autofree gchar *path = NULL;
g_autoptr(IdeTask) task = NULL;
+ g_autoptr(GBytes) bytes = NULL;
+ g_autoptr(GFile) workdir = NULL;
+ GbpGitClient *client;
+ IdeContext *context;
+ IdeBuffer *buffer;
+ GFile *file;
- g_return_if_fail (IDE_IS_MAIN_THREAD ());
g_return_if_fail (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+ self->delete_range_requires_recalculation = FALSE;
+
task = ide_task_new (self, cancellable, callback, user_data);
ide_task_set_source_tag (task, gbp_git_buffer_change_monitor_wait_async);
- if (!self->state_dirty && !self->in_calculation)
+ buffer = dzl_signal_group_get_target (self->signals);
+ context = ide_object_get_context (IDE_OBJECT (self));
+ workdir = ide_context_ref_workdir (context);
+ file = ide_buffer_get_file (buffer);
+
+ if (!g_file_has_prefix (file, workdir))
{
- ide_task_return_boolean (task, TRUE);
+ ide_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "File is not within project directory");
return;
}
- g_queue_push_tail (&self->wait_tasks, g_steal_pointer (&task));
+ path = g_file_get_relative_path (workdir, file);
+ bytes = ide_buffer_dup_content (buffer);
+ client = gbp_git_client_from_context (context);
- if (!self->in_calculation)
- gbp_git_buffer_change_monitor_recalculate (self);
+ gbp_git_client_get_changes_async (client,
+ path,
+ (const gchar *)g_bytes_get_data (bytes, NULL),
+ cancellable,
+ gbp_git_buffer_change_monitor_wait_cb,
+ g_steal_pointer (&task));
}
gboolean
@@ -982,7 +400,6 @@ gbp_git_buffer_change_monitor_wait_finish (GbpGitBufferChangeMonitor *self,
GAsyncResult *result,
GError **error)
{
- g_return_val_if_fail (IDE_IS_MAIN_THREAD (), FALSE);
g_return_val_if_fail (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self), FALSE);
g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
diff --git a/src/plugins/git/gbp-git-buffer-change-monitor.h b/src/plugins/git/gbp-git-buffer-change-monitor.h
index c5e620d7d..c35e2869f 100644
--- a/src/plugins/git/gbp-git-buffer-change-monitor.h
+++ b/src/plugins/git/gbp-git-buffer-change-monitor.h
@@ -20,7 +20,6 @@
#pragma once
-#include <libgit2-glib/ggit.h>
#include <libide-code.h>
G_BEGIN_DECLS
@@ -29,14 +28,12 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GbpGitBufferChangeMonitor, gbp_git_buffer_change_monitor, GBP,
GIT_BUFFER_CHANGE_MONITOR, IdeBufferChangeMonitor)
-void gbp_git_buffer_change_monitor_set_repository (GbpGitBufferChangeMonitor *self,
- GgitRepository *repository);
-void gbp_git_buffer_change_monitor_wait_async (GbpGitBufferChangeMonitor *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-gboolean gbp_git_buffer_change_monitor_wait_finish (GbpGitBufferChangeMonitor *self,
- GAsyncResult *result,
- GError **error);
+void gbp_git_buffer_change_monitor_wait_async (GbpGitBufferChangeMonitor *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean gbp_git_buffer_change_monitor_wait_finish (GbpGitBufferChangeMonitor *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/src/plugins/git/gbp-git-client.c b/src/plugins/git/gbp-git-client.c
index 991319495..fda635cad 100644
--- a/src/plugins/git/gbp-git-client.c
+++ b/src/plugins/git/gbp-git-client.c
@@ -90,7 +90,7 @@ gbp_git_client_notification_cb (GbpGitClient *self,
IdeNotification *notif;
g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (GBP_IS_GIT_CLIENT (client));
+ g_assert (GBP_IS_GIT_CLIENT (self));
g_assert (command != NULL);
g_assert (JSONRPC_IS_CLIENT (client));
diff --git a/src/plugins/git/gbp-git-client.h b/src/plugins/git/gbp-git-client.h
index efc2d369f..2390d8e94 100644
--- a/src/plugins/git/gbp-git-client.h
+++ b/src/plugins/git/gbp-git-client.h
@@ -48,6 +48,9 @@ gboolean gbp_git_client_call_finish (GbpGitClient *sel
GAsyncResult *result,
GVariant **reply,
GError **error);
+gboolean gbp_git_client_is_ignored (GbpGitClient *self,
+ const gchar *path,
+ GError **error);
void gbp_git_client_is_ignored_async (GbpGitClient *self,
const gchar *path,
GCancellable *cancellable,
diff --git a/src/plugins/git/gbp-git-vcs.c b/src/plugins/git/gbp-git-vcs.c
index b70e0f683..ee9adf1ca 100644
--- a/src/plugins/git/gbp-git-vcs.c
+++ b/src/plugins/git/gbp-git-vcs.c
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include "gbp-git-branch.h"
+#include "gbp-git-client.h"
#include "gbp-git-tag.h"
#include "gbp-git-vcs.h"
#include "gbp-git-vcs-config.h"
@@ -32,7 +33,7 @@
struct _GbpGitVcs
{
IdeObject parent_instance;
- GgitRepository *repository;
+ GbpGitClient *client;
GFile *location;
GFile *workdir;
gchar *branch;
@@ -54,12 +55,29 @@ G_DEFINE_TYPE_WITH_CODE (GbpGitVcs, gbp_git_vcs, IDE_TYPE_OBJECT,
static GParamSpec *properties [N_PROPS];
+static void
+gbp_git_vcs_parent_set (IdeObject *object,
+ IdeObject *parent)
+{
+ GbpGitVcs *self = (GbpGitVcs *)object;
+ g_autoptr(IdeContext) context = NULL;
+
+ g_assert (GBP_IS_GIT_VCS (self));
+ g_assert (!object || IDE_IS_OBJECT (parent));
+
+ if (object == NULL)
+ return;
+
+ context = ide_object_ref_context (IDE_OBJECT (self));
+ self->client = g_object_ref (gbp_git_client_from_context (context));
+}
+
static void
gbp_git_vcs_finalize (GObject *object)
{
GbpGitVcs *self = (GbpGitVcs *)object;
- g_clear_object (&self->repository);
+ g_clear_object (&self->client);
g_clear_object (&self->location);
g_clear_object (&self->workdir);
g_clear_pointer (&self->branch, g_free);
@@ -85,10 +103,6 @@ gbp_git_vcs_get_property (GObject *object,
g_value_set_object (value, self->location);
break;
- case PROP_REPOSITORY:
- g_value_set_object (value, self->repository);
- break;
-
case PROP_WORKDIR:
g_value_set_object (value, self->workdir);
break;
@@ -116,10 +130,6 @@ gbp_git_vcs_set_property (GObject *object,
self->location = g_value_dup_object (value);
break;
- case PROP_REPOSITORY:
- self->repository = g_value_dup_object (value);
- break;
-
case PROP_WORKDIR:
self->workdir = g_value_dup_object (value);
break;
@@ -133,11 +143,14 @@ static void
gbp_git_vcs_class_init (GbpGitVcsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
object_class->finalize = gbp_git_vcs_finalize;
object_class->get_property = gbp_git_vcs_get_property;
object_class->set_property = gbp_git_vcs_set_property;
+ i_object_class->parent_set = gbp_git_vcs_parent_set;
+
properties [PROP_BRANCH_NAME] =
g_param_spec_string ("branch-name",
"Branch Name",
@@ -152,13 +165,6 @@ gbp_git_vcs_class_init (GbpGitVcsClass *klass)
G_TYPE_FILE,
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
- properties [PROP_REPOSITORY] =
- g_param_spec_object ("repository",
- "Repository",
- "The underlying repository object",
- GGIT_TYPE_REPOSITORY,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
properties [PROP_WORKDIR] =
g_param_spec_object ("workdir",
"Workdir",
@@ -181,13 +187,6 @@ gbp_git_vcs_get_location (GbpGitVcs *self)
return self->location;
}
-GgitRepository *
-gbp_git_vcs_get_repository (GbpGitVcs *self)
-{
- g_return_val_if_fail (GBP_IS_GIT_VCS (self), NULL);
- return self->repository;
-}
-
static GFile *
gbp_git_vcs_get_workdir (IdeVcs *vcs)
{
@@ -233,23 +232,15 @@ gbp_git_vcs_is_ignored (IdeVcs *vcs,
/* self->workdir is not changed after creation, so safe
* to access it from a thread.
*/
- name = g_file_get_relative_path (self->workdir, file);
- if (g_strcmp0 (name, ".git") == 0)
- return TRUE;
-
- /*
- * If we have a valid name to work with, we want to query the
- * repository. But this could be called from a thread, so ensure
- * we are the only thread accessing self->repository right now.
- */
- if (name != NULL)
+ if ((name = g_file_get_relative_path (self->workdir, file)))
{
- ide_object_lock (IDE_OBJECT (self));
- ret = ggit_repository_path_is_ignored (self->repository, name, error);
- ide_object_unlock (IDE_OBJECT (self));
+ if (g_strcmp0 (name, ".git") == 0 ||
+ g_str_has_prefix (name, ".git/") ||
+ gbp_git_client_is_ignored (self->client, file, error))
+ return TRUE;
}
- return ret;
+ return FALSE;
}
typedef struct
diff --git a/src/plugins/git/gbp-git-vcs.h b/src/plugins/git/gbp-git-vcs.h
index cb337921a..843dae7ad 100644
--- a/src/plugins/git/gbp-git-vcs.h
+++ b/src/plugins/git/gbp-git-vcs.h
@@ -20,7 +20,6 @@
#pragma once
-#include <libgit2-glib/ggit.h>
#include <libide-vcs.h>
G_BEGIN_DECLS
@@ -30,7 +29,6 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GbpGitVcs, gbp_git_vcs, GBP, GIT_VCS, IdeObject)
GFile *gbp_git_vcs_get_location (GbpGitVcs *self);
-GgitRepository *gbp_git_vcs_get_repository (GbpGitVcs *self);
void gbp_git_vcs_reload_async (GbpGitVcs *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
diff --git a/src/plugins/git/gbp-git-workbench-addin.c b/src/plugins/git/gbp-git-workbench-addin.c
index 58a14a6cc..7826a6097 100644
--- a/src/plugins/git/gbp-git-workbench-addin.c
+++ b/src/plugins/git/gbp-git-workbench-addin.c
@@ -46,7 +46,7 @@ gbp_git_workbench_addin_discover_cb (GObject *object,
gpointer user_data)
{
GbpGitClient *client = (GbpGitClient *)object;
- g_autoptr(IdeTask) task = NULL;
+ g_autoptr(IdeTask) task = user_data;
g_autoptr(GError) error = NULL;
g_autoptr(IdeVcs) vcs = NULL;
g_autoptr(GFile) workdir = NULL;
@@ -123,18 +123,15 @@ static void
gbp_git_workbench_addin_foreach_buffer_cb (IdeBuffer *buffer,
gpointer user_data)
{
- GgitRepository *repository = user_data;
IdeBufferChangeMonitor *monitor;
g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_BUFFER (buffer));
- g_assert (GGIT_IS_REPOSITORY (repository));
monitor = ide_buffer_get_change_monitor (buffer);
if (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (monitor))
- gbp_git_buffer_change_monitor_set_repository (GBP_GIT_BUFFER_CHANGE_MONITOR (monitor),
- repository);
+ ide_buffer_change_monitor_reload (monitor);
}
static void
@@ -146,7 +143,6 @@ gbp_git_workbench_addin_reload_cb (GObject *object,
g_autoptr(GbpGitWorkbenchAddin) self = user_data;
g_autoptr(GError) error = NULL;
IdeBufferManager *buffer_manager;
- GgitRepository *repository;
IdeContext *context;
g_assert (IDE_IS_MAIN_THREAD ());
@@ -160,13 +156,12 @@ gbp_git_workbench_addin_reload_cb (GObject *object,
if (self->workbench == NULL)
return;
- repository = gbp_git_vcs_get_repository (vcs);
context = ide_workbench_get_context (self->workbench);
buffer_manager = ide_buffer_manager_from_context (context);
ide_buffer_manager_foreach (buffer_manager,
gbp_git_workbench_addin_foreach_buffer_cb,
- repository);
+ NULL);
}
static void
diff --git a/src/plugins/git/gbp-git.c b/src/plugins/git/gbp-git.c
index 679ef112d..e677b4217 100644
--- a/src/plugins/git/gbp-git.c
+++ b/src/plugins/git/gbp-git.c
@@ -18,6 +18,31 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
+/* Some code within this file is based upon libgit2 usage from GitHub. Their
+ * license is retained below, however the combined work is subject to the
+ * GPLv2+ as noted above.
+ *
+ * Copyright (c) 2014 GitHub Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
#define G_LOG_DOMAIN "gbp-git"
#include "config.h"
@@ -111,6 +136,9 @@ gbp_git_monitor_changed_cb (GbpGit *self,
g_assert (GBP_IS_GIT (self));
g_assert (GBP_IS_GIT_INDEX_MONITOR (monitor));
+ g_clear_object (&self->last_blob);
+ g_clear_pointer (&self->last_blob_path, g_free);
+
g_signal_emit (self, signals [CHANGED], 0);
}
@@ -129,6 +157,8 @@ gbp_git_set_workdir (GbpGit *self,
{
g_clear_object (&self->repository);
g_clear_object (&self->monitor);
+ g_clear_object (&self->last_blob);
+ g_clear_pointer (&self->last_blob_path, g_free);
if (workdir != NULL)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]