[gnome-builder/wip/chergert/completion] snippets: add completion provider as a plugin
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/completion] snippets: add completion provider as a plugin
- Date: Fri, 1 Jun 2018 11:39:33 +0000 (UTC)
commit 24a1e7e22eaff013a517e80d8ea654b79661db3f
Author: Christian Hergert <chergert redhat com>
Date: Fri Jun 1 04:38:42 2018 -0700
snippets: add completion provider as a plugin
We still keep all the snippet plumbing internal, but this moves the
provider into the src/plugins/ directory so we dont have to mix plumbing
and plugin stuff in the same directory in libide. They all get dynamically
linked together anyway.
meson_options.txt | 1 +
src/libide/ide.h | 1 +
.../snippets/ide-snippet-completion-provider.c | 58 ------
src/libide/snippets/ide-snippet-storage.c | 2 +-
src/libide/snippets/ide-snippet.c | 25 ++-
src/libide/snippets/ide-snippet.h | 30 +--
src/libide/snippets/meson.build | 10 +-
src/plugins/meson.build | 1 +
.../snippets/ide-snippet-completion-provider.c | 213 +++++++++++++++++++++
.../snippets/ide-snippet-completion-provider.h | 10 +-
src/plugins/snippets/meson.build | 17 ++
src/plugins/snippets/snippets-plugin.c | 30 +++
src/plugins/snippets/snippets.gresource.xml | 8 +
src/plugins/snippets/snippets.plugin | 11 ++
14 files changed, 324 insertions(+), 93 deletions(-)
---
diff --git a/meson_options.txt b/meson_options.txt
index c1dac3790..43dedfae0 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -71,6 +71,7 @@ option('with_retab', type: 'boolean')
option('with_rust_langserv', type: 'boolean')
option('with_rustup', type: 'boolean')
option('with_spellcheck', type: 'boolean')
+option('with_snippets', type: 'boolean')
option('with_support', type: 'boolean')
option('with_symbol_tree', type: 'boolean')
option('with_sysmon', type: 'boolean')
diff --git a/src/libide/ide.h b/src/libide/ide.h
index 52741e32d..e17092e31 100644
--- a/src/libide/ide.h
+++ b/src/libide/ide.h
@@ -162,6 +162,7 @@ G_BEGIN_DECLS
#include "snippets/ide-snippet.h"
#include "snippets/ide-snippet-chunk.h"
#include "snippets/ide-snippet-context.h"
+#include "snippets/ide-snippet-model.h"
#include "snippets/ide-snippet-storage.h"
#include "sourceview/ide-indenter.h"
#include "sourceview/ide-language.h"
diff --git a/src/libide/snippets/ide-snippet-storage.c b/src/libide/snippets/ide-snippet-storage.c
index f318babd3..a23edd09b 100644
--- a/src/libide/snippets/ide-snippet-storage.c
+++ b/src/libide/snippets/ide-snippet-storage.c
@@ -230,7 +230,7 @@ ide_snippet_storage_add (IdeSnippetStorage *self,
}
/**
- * ide_snippet_storage_query:
+ * ide_snippet_storage_foreach:
* @self: a #IdeSnippetStorage
* @foreach: (scope call): the closure to call for each info
* @user_data: closure data for @foreach
diff --git a/src/libide/snippets/ide-snippet.c b/src/libide/snippets/ide-snippet.c
index a285a72ae..66f3919e0 100644
--- a/src/libide/snippets/ide-snippet.c
+++ b/src/libide/snippets/ide-snippet.c
@@ -25,10 +25,11 @@
#include "ide-debug.h"
-#include "ide-snippet.h"
-#include "ide-snippet-private.h"
-#include "ide-snippet-chunk.h"
-#include "ide-snippet-context.h"
+#include "completion/ide-completion-proposal.h"
+#include "snippets/ide-snippet.h"
+#include "snippets/ide-snippet-private.h"
+#include "snippets/ide-snippet-chunk.h"
+#include "snippets/ide-snippet-context.h"
/**
* SECTION:ide-snippet
@@ -74,7 +75,21 @@ enum {
LAST_PROP
};
-G_DEFINE_TYPE (IdeSnippet, ide_snippet, G_TYPE_OBJECT)
+static gchar *
+ide_snippet_get_comment (IdeCompletionProposal *proposal)
+{
+ return g_strdup (IDE_SNIPPET (proposal)->description);
+}
+
+static void
+proposal_iface_init (IdeCompletionProposalInterface *iface)
+{
+ iface->get_comment = ide_snippet_get_comment;
+}
+
+G_DEFINE_TYPE_WITH_CODE (IdeSnippet, ide_snippet, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_COMPLETION_PROPOSAL,
+ proposal_iface_init))
DZL_DEFINE_COUNTER (instances, "Snippets", "N Snippets", "Number of IdeSnippet instances.");
diff --git a/src/libide/snippets/ide-snippet.h b/src/libide/snippets/ide-snippet.h
index 7de541a85..003f2ada7 100644
--- a/src/libide/snippets/ide-snippet.h
+++ b/src/libide/snippets/ide-snippet.h
@@ -27,45 +27,45 @@ G_BEGIN_DECLS
#define IDE_TYPE_SNIPPET (ide_snippet_get_type())
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
G_DECLARE_FINAL_TYPE (IdeSnippet, ide_snippet, IDE, SNIPPET, GObject)
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
IdeSnippet *ide_snippet_new (const gchar *trigger,
const gchar *language);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
IdeSnippet *ide_snippet_copy (IdeSnippet *self);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
const gchar *ide_snippet_get_trigger (IdeSnippet *self);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
void ide_snippet_set_trigger (IdeSnippet *self,
const gchar *trigger);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
const gchar *ide_snippet_get_language (IdeSnippet *self);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
void ide_snippet_set_language (IdeSnippet *self,
const gchar *language);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
const gchar *ide_snippet_get_description (IdeSnippet *self);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
void ide_snippet_set_description (IdeSnippet *self,
const gchar *description);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
void ide_snippet_add_chunk (IdeSnippet *self,
IdeSnippetChunk *chunk);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
guint ide_snippet_get_n_chunks (IdeSnippet *self);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
gint ide_snippet_get_tab_stop (IdeSnippet *self);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
IdeSnippetChunk *ide_snippet_get_nth_chunk (IdeSnippet *self,
guint n);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
void ide_snippet_get_chunk_range (IdeSnippet *self,
IdeSnippetChunk *chunk,
GtkTextIter *begin,
GtkTextIter *end);
-IDE_AVAILABLE_IN_ALL
+IDE_AVAILABLE_IN_3_30
IdeSnippetContext *ide_snippet_get_context (IdeSnippet *self);
G_END_DECLS
diff --git a/src/libide/snippets/meson.build b/src/libide/snippets/meson.build
index dfb7d2612..551023575 100644
--- a/src/libide/snippets/meson.build
+++ b/src/libide/snippets/meson.build
@@ -7,11 +7,6 @@ snippets_headers = [
]
snippets_sources = [
- 'ide-snippet-parser.h',
- 'ide-snippet-private.h',
-]
-
-snippets_private_sources = [
'ide-snippet.c',
'ide-snippet-chunk.c',
'ide-snippet-context.c',
@@ -20,6 +15,11 @@ snippets_private_sources = [
'ide-snippet-storage.c',
]
+snippets_private_sources = [
+ 'ide-snippet-parser.h',
+ 'ide-snippet-private.h',
+]
+
libide_public_headers += files(snippets_headers)
libide_public_sources += files(snippets_sources)
libide_private_sources += files(snippets_private_sources)
diff --git a/src/plugins/meson.build b/src/plugins/meson.build
index 776636ef7..dd37b30ae 100644
--- a/src/plugins/meson.build
+++ b/src/plugins/meson.build
@@ -63,6 +63,7 @@ subdir('retab')
subdir('rust-langserv')
subdir('rustup')
subdir('spellcheck')
+subdir('snippets')
subdir('support')
subdir('symbol-tree')
subdir('sysmon')
diff --git a/src/plugins/snippets/ide-snippet-completion-provider.c
b/src/plugins/snippets/ide-snippet-completion-provider.c
new file mode 100644
index 000000000..66e87bbd8
--- /dev/null
+++ b/src/plugins/snippets/ide-snippet-completion-provider.c
@@ -0,0 +1,213 @@
+/* ide-snippet-completion-provider.c
+ *
+ * Copyright © 2018 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/>.
+ */
+
+#define G_LOG_DOMAIN "ide-snippet-completion-provider.h"
+
+#include "ide-snippet-completion-provider.h"
+
+struct _IdeSnippetCompletionProvider
+{
+ IdeObject parent_instance;
+ IdeSnippetModel *model;
+};
+
+static void provider_iface_init (IdeCompletionProviderInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (IdeSnippetCompletionProvider,
+ ide_snippet_completion_provider,
+ IDE_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_COMPLETION_PROVIDER, provider_iface_init))
+
+static void
+ide_snippet_completion_provider_finalize (GObject *object)
+{
+ IdeSnippetCompletionProvider *self = (IdeSnippetCompletionProvider *)object;
+
+ g_clear_object (&self->model);
+
+ G_OBJECT_CLASS (ide_snippet_completion_provider_parent_class)->finalize (object);
+}
+
+static void
+ide_snippet_completion_provider_class_init (IdeSnippetCompletionProviderClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = ide_snippet_completion_provider_finalize;
+}
+
+static void
+ide_snippet_completion_provider_init (IdeSnippetCompletionProvider *self)
+{
+}
+
+static void
+ide_snippet_completion_provider_load (IdeCompletionProvider *provider,
+ IdeContext *context)
+{
+ IdeSnippetCompletionProvider *self = (IdeSnippetCompletionProvider *)provider;
+ IdeSnippetStorage *storage;
+
+ g_assert (IDE_IS_SNIPPET_COMPLETION_PROVIDER (self));
+ g_assert (IDE_IS_CONTEXT (context));
+
+ storage = ide_context_get_snippets (context);
+ self->model = ide_snippet_model_new (storage);
+}
+
+static gint
+ide_snippet_completion_provider_get_priority (IdeCompletionProvider *provider)
+{
+ return -100;
+}
+
+static gchar *
+ide_snippet_completion_provider_get_title (IdeCompletionProvider *provider)
+{
+ return g_strdup ("Snippets");
+}
+
+static void
+ide_snippet_completion_provider_populate_async (IdeCompletionProvider *provider,
+ IdeCompletionContext *context,
+ GCancellable *cancellable,
+ GListModel **proposals,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ IdeSnippetCompletionProvider *self = (IdeSnippetCompletionProvider *)provider;
+ g_autoptr(IdeTask) task = NULL;
+ g_autofree gchar *prefix = NULL;
+ GtkSourceLanguage *lang;
+ GtkTextBuffer *buffer;
+ const gchar *lang_id = NULL;
+ GtkTextIter begin, end;
+
+ g_assert (IDE_IS_SNIPPET_COMPLETION_PROVIDER (self));
+ g_assert (IDE_IS_COMPLETION_CONTEXT (context));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, ide_snippet_completion_provider_populate_async);
+
+ *proposals = g_object_ref (G_LIST_MODEL (self->model));
+
+ if (ide_completion_context_get_bounds (context, &begin, &end))
+ prefix = gtk_text_iter_get_slice (&begin, &end);
+
+ if ((buffer = ide_completion_context_get_buffer (context)) &&
+ GTK_SOURCE_IS_BUFFER (buffer) &&
+ (lang = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buffer))))
+ lang_id = gtk_source_language_get_id (lang);
+
+ ide_snippet_model_set_language (self->model, lang_id);
+ ide_snippet_model_set_prefix (self->model, prefix);
+
+ ide_task_return_pointer (task, g_object_ref (self->model), g_object_unref);
+}
+
+static GListModel *
+ide_snippet_completion_provider_populate_finish (IdeCompletionProvider *provider,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_assert (IDE_IS_SNIPPET_COMPLETION_PROVIDER (provider));
+ g_assert (IDE_IS_TASK (result));
+
+ return ide_task_propagate_pointer (IDE_TASK (result), error);
+}
+
+static gboolean
+ide_snippet_completion_provider_refilter (IdeCompletionProvider *provider,
+ IdeCompletionContext *context,
+ GListModel *proposals)
+{
+ g_autofree gchar *prefix = NULL;
+ GtkTextIter begin, end;
+
+ g_assert (IDE_IS_SNIPPET_COMPLETION_PROVIDER (provider));
+ g_assert (IDE_IS_COMPLETION_CONTEXT (context));
+ g_assert (IDE_IS_SNIPPET_MODEL (proposals));
+
+ if (ide_completion_context_get_bounds (context, &begin, &end))
+ prefix = gtk_text_iter_get_slice (&begin, &end);
+
+ ide_snippet_model_set_prefix (IDE_SNIPPET_MODEL (proposals), prefix);
+
+ return TRUE;
+}
+
+static void
+ide_snippet_completion_provider_display_proposal (IdeCompletionProvider *provider,
+ IdeCompletionListBoxRow *row,
+ IdeCompletionContext *context,
+ const gchar *typed_text,
+ IdeCompletionProposal *proposal)
+{
+ const gchar *trigger;
+
+ g_assert (IDE_IS_SNIPPET_COMPLETION_PROVIDER (provider));
+ g_assert (IDE_IS_COMPLETION_LIST_BOX_ROW (row));
+ g_assert (IDE_IS_COMPLETION_CONTEXT (context));
+ g_assert (IDE_IS_SNIPPET (proposal));
+
+ trigger = ide_snippet_get_trigger (IDE_SNIPPET (proposal));
+
+ /* TODO: have jimmac make us a real icon */
+ ide_completion_list_box_row_set_icon_name (row, "ui-section-symbolic");
+ ide_completion_list_box_row_set_left (row, NULL);
+ ide_completion_list_box_row_set_center (row, trigger);
+ ide_completion_list_box_row_set_right (row, NULL);
+}
+
+static void
+ide_snippet_completion_provider_activate_proposal (IdeCompletionProvider *provider,
+ IdeCompletionContext *context,
+ IdeCompletionProposal *proposal,
+ const GdkEventKey *key)
+{
+ GtkTextIter begin, end;
+ GtkTextBuffer *buffer;
+ GtkTextView *view;
+
+ g_assert (IDE_IS_SNIPPET_COMPLETION_PROVIDER (provider));
+ g_assert (IDE_IS_COMPLETION_CONTEXT (context));
+ g_assert (IDE_IS_SNIPPET (proposal));
+
+ buffer = ide_completion_context_get_buffer (context);
+ view = ide_completion_context_get_view (context);
+
+ gtk_text_buffer_begin_user_action (buffer);
+ if (ide_completion_context_get_bounds (context, &begin, &end))
+ gtk_text_buffer_delete (buffer, &begin, &end);
+ ide_source_view_push_snippet (IDE_SOURCE_VIEW (view), IDE_SNIPPET (proposal), &begin);
+ gtk_text_buffer_end_user_action (buffer);
+}
+
+static void
+provider_iface_init (IdeCompletionProviderInterface *iface)
+{
+ iface->load = ide_snippet_completion_provider_load;
+ iface->get_priority = ide_snippet_completion_provider_get_priority;
+ iface->get_title = ide_snippet_completion_provider_get_title;
+ iface->populate_async = ide_snippet_completion_provider_populate_async;
+ iface->populate_finish = ide_snippet_completion_provider_populate_finish;
+ iface->refilter = ide_snippet_completion_provider_refilter;
+ iface->display_proposal = ide_snippet_completion_provider_display_proposal;
+ iface->activate_proposal = ide_snippet_completion_provider_activate_proposal;
+}
diff --git a/src/libide/snippets/ide-snippet-completion-provider.h
b/src/plugins/snippets/ide-snippet-completion-provider.h
similarity index 68%
rename from src/libide/snippets/ide-snippet-completion-provider.h
rename to src/plugins/snippets/ide-snippet-completion-provider.h
index 08ba84bf2..77ead4081 100644
--- a/src/libide/snippets/ide-snippet-completion-provider.h
+++ b/src/plugins/snippets/ide-snippet-completion-provider.h
@@ -18,20 +18,12 @@
#pragma once
-#include "completion/ide-completion-provider.h"
-#include "snippets/ide-snippet.h"
+#include <ide.h>
G_BEGIN_DECLS
#define IDE_TYPE_SNIPPET_COMPLETION_PROVIDER (ide_snippet_completion_provider_get_type())
-IDE_AVAILABLE_IN_3_30
G_DECLARE_FINAL_TYPE (IdeSnippetCompletionProvider, ide_snippet_completion_provider, IDE,
SNIPPET_COMPLETION_PROVIDER, IdeObject)
-IDE_AVAILABLE_IN_3_30
-IdeSnippetCompletionProvider *ide_snippet_completion_provider_new (void);
-IDE_AVAILABLE_IN_3_30
-void ide_snippet_completion_provider_set_language (IdeSnippetCompletionProvider
*self,
- const gchar
*lang_id);
-
G_END_DECLS
diff --git a/src/plugins/snippets/meson.build b/src/plugins/snippets/meson.build
new file mode 100644
index 000000000..486c9349b
--- /dev/null
+++ b/src/plugins/snippets/meson.build
@@ -0,0 +1,17 @@
+if get_option('with_snippets')
+
+snippets_resources = gnome.compile_resources(
+ 'snippets-resources',
+ 'snippets.gresource.xml',
+ c_name: 'gbp_snippets',
+)
+
+snippets_sources = [
+ 'snippets-plugin.c',
+ 'ide-snippet-completion-provider.c',
+]
+
+gnome_builder_plugins_sources += files(snippets_sources)
+gnome_builder_plugins_sources += snippets_resources[0]
+
+endif
diff --git a/src/plugins/snippets/snippets-plugin.c b/src/plugins/snippets/snippets-plugin.c
new file mode 100644
index 000000000..e37e63773
--- /dev/null
+++ b/src/plugins/snippets/snippets-plugin.c
@@ -0,0 +1,30 @@
+/* snippets-plugin.c
+ *
+ * Copyright 2018 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/>.
+ */
+
+#include <ide.h>
+#include <libpeas/peas.h>
+
+#include "ide-snippet-completion-provider.h"
+
+void
+gbp_snippets_register_types (PeasObjectModule *module)
+{
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_COMPLETION_PROVIDER,
+ IDE_TYPE_SNIPPET_COMPLETION_PROVIDER);
+}
diff --git a/src/plugins/snippets/snippets.gresource.xml b/src/plugins/snippets/snippets.gresource.xml
new file mode 100644
index 000000000..560b08dac
--- /dev/null
+++ b/src/plugins/snippets/snippets.gresource.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/builder/plugins">
+ <file>snippets.plugin</file>
+ </gresource>
+ <gresource prefix="/org/gnome/builder/plugins/snippets-plugin">
+ </gresource>
+</gresources>
diff --git a/src/plugins/snippets/snippets.plugin b/src/plugins/snippets/snippets.plugin
new file mode 100644
index 000000000..037dcec7f
--- /dev/null
+++ b/src/plugins/snippets/snippets.plugin
@@ -0,0 +1,11 @@
+[Plugin]
+Module=snippets-plugin
+Name=Snippets
+Description=Support for snippets in a variety of languages
+Authors=Christian Hergert <christian hergert me>
+Copyright=Copyright © 2018 Christian Hergert
+Depends=editor;
+Builtin=true
+Hidden=true
+Embedded=gbp_snippets_register_types
+X-Completion-Provider-Languages=*
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]