[gtksourceview/wip/chergert/snippets] start moving snippets mechanics outside of gtksourceview.c
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/chergert/snippets] start moving snippets mechanics outside of gtksourceview.c
- Date: Wed, 22 Jan 2020 03:33:13 +0000 (UTC)
commit 3ee35a04c0fa3e485119ff0444997fe164c53e10
Author: Christian Hergert <chergert redhat com>
Date: Tue Jan 21 19:33:10 2020 -0800
start moving snippets mechanics outside of gtksourceview.c
gtksourceview/gtksourcesnippet-private.h | 4 +-
gtksourceview/gtksourcesnippet.c | 4 +-
gtksourceview/gtksourceview-private.h | 50 ++++
gtksourceview/gtksourceview-snippets.c | 477 +++++++++++++++++++++++++++++++
gtksourceview/gtksourceview.c | 340 +---------------------
gtksourceview/gtksourceview.h | 2 -
gtksourceview/meson.build | 1 +
7 files changed, 545 insertions(+), 333 deletions(-)
---
diff --git a/gtksourceview/gtksourcesnippet-private.h b/gtksourceview/gtksourcesnippet-private.h
index 19f3981e..6338514a 100644
--- a/gtksourceview/gtksourcesnippet-private.h
+++ b/gtksourceview/gtksourcesnippet-private.h
@@ -46,13 +46,13 @@ G_GNUC_INTERNAL
void _gtk_source_snippet_before_insert_text (GtkSourceSnippet *self,
GtkTextBuffer *buffer,
GtkTextIter *iter,
- gchar *text,
+ const gchar *text,
gint len);
G_GNUC_INTERNAL
void _gtk_source_snippet_after_insert_text (GtkSourceSnippet *self,
GtkTextBuffer *buffer,
GtkTextIter *iter,
- gchar *text,
+ const gchar *text,
gint len);
G_GNUC_INTERNAL
void _gtk_source_snippet_before_delete_range (GtkSourceSnippet *self,
diff --git a/gtksourceview/gtksourcesnippet.c b/gtksourceview/gtksourcesnippet.c
index 14edd854..3f87235d 100644
--- a/gtksourceview/gtksourcesnippet.c
+++ b/gtksourceview/gtksourcesnippet.c
@@ -863,7 +863,7 @@ void
_gtk_source_snippet_before_insert_text (GtkSourceSnippet *self,
GtkTextBuffer *buffer,
GtkTextIter *iter,
- gchar *text,
+ const gchar *text,
gint len)
{
gint utf8_len;
@@ -890,7 +890,7 @@ void
_gtk_source_snippet_after_insert_text (GtkSourceSnippet *self,
GtkTextBuffer *buffer,
GtkTextIter *iter,
- gchar *text,
+ const gchar *text,
gint len)
{
GtkSourceSnippetChunk *chunk;
diff --git a/gtksourceview/gtksourceview-private.h b/gtksourceview/gtksourceview-private.h
new file mode 100644
index 00000000..920ea02e
--- /dev/null
+++ b/gtksourceview/gtksourceview-private.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * GtkSourceView is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "gtksourceview.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkSourceViewSnippets
+{
+ GtkSourceView *view;
+ GtkTextBuffer *buffer;
+ GQueue queue;
+ gulong view_notify_buffer_handler;
+ gulong buffer_insert_text_handler;
+ gulong buffer_insert_text_after_handler;
+ gulong buffer_delete_range_handler;
+ gulong buffer_delete_range_after_handler;
+} GtkSourceViewSnippets;
+
+void _gtk_source_view_snippets_init (GtkSourceViewSnippets *snippets,
+ GtkSourceView *view);
+void _gtk_source_view_snippets_shutdown (GtkSourceViewSnippets *snippets);
+void _gtk_source_view_snippets_push (GtkSourceViewSnippets *snippets,
+ GtkSourceSnippet *snippet,
+ GtkTextIter *iter);
+void _gtk_source_view_snippets_pop (GtkSourceViewSnippets *snippets);
+gboolean _gtk_source_view_snippets_key_pressed (GtkSourceViewSnippets *snippets,
+ guint key,
+ guint keycode,
+ GdkModifierType state);
+
+G_END_DECLS
diff --git a/gtksourceview/gtksourceview-snippets.c b/gtksourceview/gtksourceview-snippets.c
new file mode 100644
index 00000000..e2dd6975
--- /dev/null
+++ b/gtksourceview/gtksourceview-snippets.c
@@ -0,0 +1,477 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * GtkSourceView is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "gtksourceiter-private.h"
+#include "gtksourcesnippet-private.h"
+#include "gtksourcesnippetchunk.h"
+#include "gtksourceview-private.h"
+
+static void
+gtk_source_view_snippets_block (GtkSourceViewSnippets *snippets)
+{
+ g_assert (snippets != NULL);
+
+ g_signal_handler_block (snippets->buffer,
+ snippets->buffer_insert_text_handler);
+ g_signal_handler_block (snippets->buffer,
+ snippets->buffer_insert_text_after_handler);
+ g_signal_handler_block (snippets->buffer,
+ snippets->buffer_delete_range_handler);
+ g_signal_handler_block (snippets->buffer,
+ snippets->buffer_delete_range_after_handler);
+}
+
+static void
+gtk_source_view_snippets_unblock (GtkSourceViewSnippets *snippets)
+{
+ g_assert (snippets != NULL);
+
+ g_signal_handler_unblock (snippets->buffer,
+ snippets->buffer_insert_text_handler);
+ g_signal_handler_unblock (snippets->buffer,
+ snippets->buffer_insert_text_after_handler);
+ g_signal_handler_unblock (snippets->buffer,
+ snippets->buffer_delete_range_handler);
+ g_signal_handler_unblock (snippets->buffer,
+ snippets->buffer_delete_range_after_handler);
+}
+
+static void
+buffer_insert_text_cb (GtkTextBuffer *buffer,
+ GtkTextIter *location,
+ const gchar *text,
+ gint len,
+ GtkSourceViewSnippets *snippets)
+{
+ GtkSourceSnippet *snippet;
+
+ g_assert (GTK_IS_TEXT_BUFFER (buffer));
+ g_assert (location != NULL);
+ g_assert (text != NULL);
+ g_assert (snippets != NULL);
+
+ snippet = g_queue_peek_head (&snippets->queue);
+
+ if (snippet != NULL)
+ {
+ /* We'll complete the user action in the after phase */
+ gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (buffer));
+
+ gtk_source_view_snippets_block (snippets);
+ _gtk_source_snippet_before_insert_text (snippet,
+ GTK_TEXT_BUFFER (buffer),
+ location,
+ text,
+ len);
+ gtk_source_view_snippets_unblock (snippets);
+ }
+}
+
+static void
+buffer_insert_text_after_cb (GtkTextBuffer *buffer,
+ GtkTextIter *location,
+ const gchar *text,
+ gint len,
+ GtkSourceViewSnippets *snippets)
+{
+ GtkSourceSnippet *snippet;
+
+ g_assert (GTK_IS_TEXT_BUFFER (buffer));
+ g_assert (location != NULL);
+ g_assert (text != NULL);
+ g_assert (snippets != NULL);
+
+ snippet = g_queue_peek_head (&snippets->queue);
+
+ if (snippet != NULL)
+ {
+ gtk_source_view_snippets_block (snippets);
+ _gtk_source_snippet_after_insert_text (snippet,
+ GTK_TEXT_BUFFER (buffer),
+ location,
+ text,
+ len);
+ gtk_source_view_snippets_unblock (snippets);
+
+ /* Copmlete our action from the before phase */
+ gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (buffer));
+ }
+}
+
+static void
+buffer_delete_range_cb (GtkTextBuffer *buffer,
+ GtkTextIter *begin,
+ GtkTextIter *end,
+ GtkSourceViewSnippets *snippets)
+{
+ GtkSourceSnippet *snippet;
+
+ g_assert (GTK_IS_TEXT_BUFFER (buffer));
+ g_assert (begin != NULL);
+ g_assert (end != NULL);
+
+ snippet = g_queue_peek_head (&snippets->queue);
+
+ if (snippet != NULL)
+ {
+ /* We'll complete the user action in the after phase */
+ gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (buffer));
+
+ gtk_source_view_snippets_block (snippets);
+ _gtk_source_snippet_before_delete_range (snippet,
+ GTK_TEXT_BUFFER (buffer),
+ begin,
+ end);
+ gtk_source_view_snippets_unblock (snippets);
+ }
+}
+
+static void
+buffer_delete_range_after_cb (GtkTextBuffer *buffer,
+ GtkTextIter *begin,
+ GtkTextIter *end,
+ GtkSourceViewSnippets *snippets)
+{
+ GtkSourceSnippet *snippet;
+
+ g_assert (GTK_IS_TEXT_BUFFER (buffer));
+ g_assert (begin != NULL);
+ g_assert (end != NULL);
+
+ snippet = g_queue_peek_head (&snippets->queue);
+
+ if (snippet != NULL)
+ {
+ gtk_source_view_snippets_block (snippets);
+ _gtk_source_snippet_after_delete_range (snippet,
+ GTK_TEXT_BUFFER (buffer),
+ begin,
+ end);
+ gtk_source_view_snippets_unblock (snippets);
+
+ /* Copmlete our action from the before phase */
+ gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (buffer));
+ }
+}
+
+static void
+view_notify_buffer_cb (GtkSourceView *view,
+ GParamSpec *pspec,
+ GtkSourceViewSnippets *snippets)
+{
+ g_assert (view != NULL);
+ g_assert (snippets != NULL);
+ g_assert (snippets->view == view);
+
+ g_queue_clear_full (&snippets->queue, g_object_unref);
+
+ g_clear_signal_handler (&snippets->buffer_insert_text_handler,
+ snippets->buffer);
+ g_clear_signal_handler (&snippets->buffer_insert_text_after_handler,
+ snippets->buffer);
+ g_clear_signal_handler (&snippets->buffer_delete_range_handler,
+ snippets->buffer);
+ g_clear_signal_handler (&snippets->buffer_delete_range_after_handler,
+ snippets->buffer);
+
+ snippets->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ if (snippets->buffer != NULL)
+ {
+ snippets->buffer_insert_text_handler =
+ g_signal_connect (snippets->buffer,
+ "insert-text",
+ G_CALLBACK (buffer_insert_text_cb),
+ snippets);
+ snippets->buffer_insert_text_after_handler =
+ g_signal_connect_after (snippets->buffer,
+ "insert-text",
+ G_CALLBACK (buffer_insert_text_after_cb),
+ snippets);
+ snippets->buffer_delete_range_handler =
+ g_signal_connect (snippets->buffer,
+ "delete-range",
+ G_CALLBACK (buffer_delete_range_cb),
+ snippets);
+ snippets->buffer_delete_range_after_handler =
+ g_signal_connect_after (snippets->buffer,
+ "delete-range",
+ G_CALLBACK (buffer_delete_range_after_cb),
+ snippets);
+ }
+}
+
+void
+_gtk_source_view_snippets_init (GtkSourceViewSnippets *snippets,
+ GtkSourceView *view)
+{
+ g_return_if_fail (snippets != NULL);
+ g_return_if_fail (GTK_SOURCE_IS_VIEW (view));
+
+ memset (snippets, 0, sizeof *snippets);
+
+ snippets->view = view;
+ snippets->view_notify_buffer_handler =
+ g_signal_connect (view,
+ "notify::buffer",
+ G_CALLBACK (view_notify_buffer_cb),
+ snippets);
+
+ view_notify_buffer_cb (view, NULL, snippets);
+}
+
+void
+_gtk_source_view_snippets_shutdown (GtkSourceViewSnippets *snippets)
+{
+ g_return_if_fail (snippets != NULL);
+
+ g_queue_clear_full (&snippets->queue, g_object_unref);
+
+ g_clear_signal_handler (&snippets->view_notify_buffer_handler,
+ snippets->view);
+ g_clear_signal_handler (&snippets->buffer_insert_text_handler,
+ snippets->buffer);
+ g_clear_signal_handler (&snippets->buffer_insert_text_after_handler,
+ snippets->buffer);
+ g_clear_signal_handler (&snippets->buffer_delete_range_handler,
+ snippets->buffer);
+ g_clear_signal_handler (&snippets->buffer_delete_range_after_handler,
+ snippets->buffer);
+
+ snippets->buffer = NULL;
+ snippets->view = NULL;
+}
+
+static GtkSourceSnippet *
+lookup_snippet_by_trigger (GtkSourceViewSnippets *snippets,
+ const gchar *word)
+{
+ GtkSourceSnippetChunk *chunk;
+ GtkSourceSnippet *snippet;
+
+ g_assert (snippets != NULL);
+ g_assert (word != NULL);
+
+ snippet = gtk_source_snippet_new (word, NULL);
+
+ for (guint i = 0; i < 3; i++)
+ {
+ chunk = gtk_source_snippet_chunk_new ();
+ if (i == 0)
+ gtk_source_snippet_chunk_set_spec (chunk, word);
+ else
+ gtk_source_snippet_chunk_set_spec (chunk, "$1");
+ gtk_source_snippet_chunk_set_focus_position (chunk, i+1);
+ gtk_source_snippet_add_chunk (snippet, chunk);
+ g_object_unref (chunk);
+ }
+
+ chunk = gtk_source_snippet_chunk_new ();
+ gtk_source_snippet_chunk_set_focus_position (chunk, 0);
+ gtk_source_snippet_add_chunk (snippet, chunk);
+ g_object_unref (chunk);
+
+ return snippet;
+}
+
+static gboolean
+gtk_source_view_snippets_try_expand (GtkSourceViewSnippets *snippets,
+ GtkTextIter *iter)
+{
+ GtkSourceSnippet *snippet;
+ GtkTextIter begin;
+ gchar *word;
+
+ g_assert (snippets != NULL);
+ g_assert (iter != NULL);
+
+ if (gtk_text_iter_starts_line (iter) ||
+ !_gtk_source_iter_ends_full_word (iter))
+ {
+ return FALSE;
+ }
+
+ begin = *iter;
+
+ _gtk_source_iter_backward_full_word_start (&begin);
+
+ if (gtk_text_iter_compare (&begin, iter) >= 0)
+ {
+ return FALSE;
+ }
+
+ word = gtk_text_iter_get_slice (&begin, iter);
+
+ if (word == NULL || *word == 0)
+ {
+ return FALSE;
+ }
+
+ snippet = lookup_snippet_by_trigger (snippets, word);
+
+ g_free (word);
+
+ if (snippet != NULL)
+ {
+ _gtk_source_view_snippets_push (snippets, snippet, iter);
+ g_object_unref (snippet);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+_gtk_source_view_snippets_key_pressed (GtkSourceViewSnippets *snippets,
+ guint key,
+ guint keycode,
+ GdkModifierType state)
+{
+ GdkModifierType modifiers;
+ gboolean editable;
+
+ g_return_val_if_fail (snippets != NULL, FALSE);
+ g_return_val_if_fail (snippets->view != NULL, FALSE);
+
+ /* Be careful when testing for modifier state equality:
+ * caps lock, num lock,etc need to be taken into account */
+ modifiers = gtk_accelerator_get_default_mod_mask ();
+ editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (snippets->view));
+
+ if ((key == GDK_KEY_Tab || key == GDK_KEY_KP_Tab || key == GDK_KEY_ISO_Left_Tab) &&
+ ((state & modifiers) == 0 ||
+ (state & modifiers) == GDK_SHIFT_MASK) &&
+ editable &&
+ gtk_text_view_get_accepts_tab (GTK_TEXT_VIEW (snippets->view)))
+ {
+ GtkSourceSnippet *snippet = g_queue_peek_head (&snippets->queue);
+ GtkTextIter begin, end;
+ gboolean has_selection;
+
+ /* If we already have a snippet expanded, then we might need
+ * to move forward or backward between snippet positions.
+ */
+ if (snippet != NULL)
+ {
+ if ((state & modifiers) == 0)
+ {
+ if (!_gtk_source_snippet_move_next (snippet))
+ {
+ _gtk_source_view_snippets_pop (snippets);
+ }
+
+ return GDK_EVENT_STOP;
+ }
+ else if (state & GDK_SHIFT_MASK)
+ {
+ if (!_gtk_source_snippet_move_previous (snippet))
+ {
+ _gtk_source_view_snippets_pop (snippets);
+ }
+
+ return GDK_EVENT_STOP;
+ }
+ }
+
+ has_selection = gtk_text_buffer_get_selection_bounds (snippets->buffer,
+ &begin, &end);
+
+ /* tab: if there is no selection and the current word is a
+ * snippet trigger, then we should expand that snippet.
+ */
+ if ((state & modifiers) == 0 &&
+ !has_selection &&
+ gtk_source_view_snippets_try_expand (snippets, &end))
+ {
+ return GDK_EVENT_STOP;
+ }
+ }
+
+ return GDK_EVENT_PROPAGATE;
+}
+
+void
+_gtk_source_view_snippets_push (GtkSourceViewSnippets *snippets,
+ GtkSourceSnippet *snippet,
+ GtkTextIter *iter)
+{
+ GtkSourceSnippet *previous_snippet;
+ gboolean more_to_focus;
+
+ g_assert (snippets != NULL);
+ g_assert (GTK_SOURCE_IS_SNIPPET (snippet));
+ g_assert (iter != NULL);
+
+ previous_snippet = g_queue_peek_head (&snippets->queue);
+
+ if (previous_snippet != NULL)
+ {
+ _gtk_source_snippet_pause (previous_snippet);
+ }
+
+ g_queue_push_head (&snippets->queue, g_object_ref (snippet));
+
+ gtk_text_buffer_begin_user_action (snippets->buffer);
+ gtk_source_view_snippets_block (snippets);
+ more_to_focus = _gtk_source_snippet_begin (snippet, snippets->buffer, iter);
+ gtk_source_view_snippets_unblock (snippets);
+ gtk_text_buffer_end_user_action (snippets->buffer);
+
+ gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (snippets->view),
+ gtk_text_buffer_get_insert (snippets->buffer));
+
+ if (!more_to_focus)
+ {
+ _gtk_source_view_snippets_pop (snippets);
+ }
+}
+
+void
+_gtk_source_view_snippets_pop (GtkSourceViewSnippets *snippets)
+{
+ GtkSourceSnippet *next_snippet;
+ GtkSourceSnippet *snippet;
+
+ g_assert (snippets != NULL);
+
+ snippet = g_queue_pop_head (&snippets->queue);
+
+ if (snippet != NULL)
+ {
+ next_snippet = g_queue_peek_head (&snippets->queue);
+
+ if (next_snippet != NULL)
+ {
+ gchar *new_text;
+
+ new_text = _gtk_source_snippet_get_edited_text (snippet);
+ _gtk_source_snippet_replace_current_chunk_text (next_snippet, new_text);
+ _gtk_source_snippet_unpause (next_snippet);
+ _gtk_source_snippet_move_next (next_snippet);
+
+ g_free (new_text);
+ }
+
+ g_object_unref (snippet);
+ }
+}
diff --git a/gtksourceview/gtksourceview.c b/gtksourceview/gtksourceview.c
index fb0018ab..2f5bd29f 100644
--- a/gtksourceview/gtksourceview.c
+++ b/gtksourceview/gtksourceview.c
@@ -22,8 +22,6 @@
#include "config.h"
-#include "gtksourceview.h"
-
#include <string.h>
#include <fribidi.h>
#include <gtk/gtk.h>
@@ -54,6 +52,7 @@
#include "gtksourcespacedrawer-private.h"
#include "gtksourcespacedrawer.h"
#include "gtksourcestylescheme-private.h"
+#include "gtksourceview-private.h"
/**
* SECTION:view
@@ -161,7 +160,6 @@ enum
MOVE_TO_MATCHING_BRACKET,
MOVE_WORDS,
PUSH_SNIPPET,
- POP_SNIPPET,
SHOW_COMPLETION,
SMART_HOME_END,
N_SIGNALS
@@ -209,7 +207,7 @@ typedef struct
GtkSourceCompletion *completion;
- GQueue snippets;
+ GtkSourceViewSnippets snippets;
guint right_margin_pos;
gint cached_right_margin_pos;
@@ -322,7 +320,6 @@ static void gtk_source_view_populate_extra_menu (GtkSourceView
static void gtk_source_view_real_push_snippet (GtkSourceView *view,
GtkSourceSnippet *snippet,
GtkTextIter *location);
-static void gtk_source_view_pop_snippet (GtkSourceView *view);
static void
gtk_source_view_constructed (GObject *object)
@@ -861,27 +858,6 @@ gtk_source_view_class_init (GtkSourceViewClass *klass)
G_TYPE_FROM_CLASS (klass),
_gtk_source_marshal_VOID__OBJECT_BOXEDv);
- /**
- * GtkSourceView::pop-snippet:
- * @view: a #GtkSourceView
- * @snippet: a #GtkSourceSnippet
- *
- * The ::pop-snippet signal is emitted when a snippet's focus positions
- * have been exhausted.
- *
- * Since: 5.0
- */
- signals[POP_SNIPPET] =
- g_signal_new ("pop-snippet",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkSourceViewClass, pop_snippet),
- NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 1,
- GTK_SOURCE_TYPE_SNIPPET);
-
/**
* GtkSourceView::smart-home-end:
* @view: the #GtkSourceView
@@ -1404,6 +1380,8 @@ gtk_source_view_init (GtkSourceView *view)
gtk_style_context_add_class (context, "sourceview");
gtk_source_view_populate_extra_menu (view);
+
+ _gtk_source_view_snippets_init (&priv->snippets, view);
}
static void
@@ -1418,6 +1396,9 @@ gtk_source_view_dispose (GObject *object)
remove_source_buffer (view);
+ /* Release our snippet state. This is safe to call multiple times. */
+ _gtk_source_view_snippets_shutdown (&priv->snippets);
+
/* Disconnect notify buffer because the destroy of the textview will set
* the buffer to NULL, and we call get_buffer in the notify which would
* reinstate a buffer which we don't want.
@@ -1611,116 +1592,6 @@ implicit_trailing_newline_changed_cb (GtkSourceBuffer *buffer,
gtk_source_view_queue_draw (view);
}
-static void
-buffer_insert_text_cb (GtkSourceBuffer *buffer,
- GtkTextIter *location,
- gchar *text,
- gint len,
- GtkSourceView *view)
-{
- GtkSourceViewPrivate *priv = gtk_source_view_get_instance_private (view);
- GtkSourceSnippet *snippet;
-
- g_assert (GTK_SOURCE_IS_BUFFER (buffer));
- g_assert (location != NULL);
- g_assert (text != NULL);
- g_assert (GTK_SOURCE_IS_VIEW (view));
-
- snippet = g_queue_peek_head (&priv->snippets);
-
- if (snippet != NULL)
- {
- gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (buffer));
- _gtk_source_snippet_before_insert_text (snippet,
- GTK_TEXT_BUFFER (buffer),
- location,
- text,
- len);
- }
-}
-
-static void
-buffer_after_insert_text_cb (GtkSourceBuffer *buffer,
- GtkTextIter *location,
- gchar *text,
- gint len,
- GtkSourceView *view)
-{
- GtkSourceViewPrivate *priv = gtk_source_view_get_instance_private (view);
- GtkSourceSnippet *snippet;
-
- g_assert (GTK_SOURCE_IS_BUFFER (buffer));
- g_assert (location != NULL);
- g_assert (text != NULL);
- g_assert (GTK_SOURCE_IS_VIEW (view));
-
- snippet = g_queue_peek_head (&priv->snippets);
-
- if (snippet != NULL)
- {
- _gtk_source_snippet_after_insert_text (snippet,
- GTK_TEXT_BUFFER (buffer),
- location,
- text,
- len);
- gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (buffer));
- }
-}
-
-static void
-buffer_delete_range_cb (GtkSourceBuffer *buffer,
- GtkTextIter *begin,
- GtkTextIter *end,
- GtkSourceView *view)
-{
- GtkSourceViewPrivate *priv = gtk_source_view_get_instance_private (view);
- GtkSourceSnippet *snippet;
-
- g_assert (GTK_SOURCE_IS_BUFFER (buffer));
- g_assert (begin != NULL);
- g_assert (end != NULL);
- g_assert (GTK_SOURCE_IS_VIEW (view));
-
- snippet = g_queue_peek_head (&priv->snippets);
-
- if (snippet != NULL)
- {
- //ide_source_view_block_handlers (self);
- _gtk_source_snippet_before_delete_range (snippet,
- GTK_TEXT_BUFFER (buffer),
- begin,
- end);
- //ide_source_view_unblock_handlers (self);
- }
-}
-
-static void
-buffer_delete_range_after_cb (GtkSourceBuffer *buffer,
- GtkTextIter *begin,
- GtkTextIter *end,
- GtkSourceView *view)
-{
- GtkSourceViewPrivate *priv = gtk_source_view_get_instance_private (view);
- GtkSourceSnippet *snippet;
-
- g_assert (GTK_SOURCE_IS_BUFFER (buffer));
- g_assert (begin != NULL);
- g_assert (end != NULL);
- g_assert (GTK_SOURCE_IS_VIEW (view));
-
- snippet = g_queue_peek_head (&priv->snippets);
-
- if (snippet != NULL)
- {
- //ide_source_view_block_handlers (self);
- _gtk_source_snippet_after_delete_range (snippet,
- GTK_TEXT_BUFFER (buffer),
- begin,
- end);
- //ide_source_view_unblock_handlers (self);
- }
-}
-
static void
remove_source_buffer (GtkSourceView *view)
{
@@ -1750,14 +1621,6 @@ remove_source_buffer (GtkSourceView *view)
implicit_trailing_newline_changed_cb,
view);
- g_signal_handlers_disconnect_by_func (priv->source_buffer,
- buffer_insert_text_cb,
- view);
-
- g_signal_handlers_disconnect_by_func (priv->source_buffer,
- buffer_after_insert_text_cb,
- view);
-
buffer_internal = _gtk_source_buffer_internal_get_from_buffer (priv->source_buffer);
g_signal_handlers_disconnect_by_func (buffer_internal,
@@ -1813,16 +1676,6 @@ set_source_buffer (GtkSourceView *view,
G_CALLBACK (buffer_has_selection_changed_cb),
view);
- g_signal_connect (buffer,
- "insert-text",
- G_CALLBACK (buffer_insert_text_cb),
- view);
-
- g_signal_connect_after (buffer,
- "insert-text",
- G_CALLBACK (buffer_after_insert_text_cb),
- view);
-
buffer_internal = _gtk_source_buffer_internal_get_from_buffer (priv->source_buffer);
g_signal_connect (buffer_internal,
@@ -4028,82 +3881,6 @@ do_ctrl_backspace (GtkSourceView *view)
return FALSE;
}
-static GtkSourceSnippet *
-lookup_snippet_by_trigger (GtkSourceView *view,
- const gchar *word)
-{
- GtkSourceSnippet *snippet;
- GtkSourceSnippetChunk *chunk;
-
- g_assert (GTK_SOURCE_IS_VIEW (view));
- g_assert (word != NULL);
-
- snippet = gtk_source_snippet_new (word, NULL);
-
- for (guint i = 0; i < 3; i++)
- {
- chunk = gtk_source_snippet_chunk_new ();
- gtk_source_snippet_chunk_set_spec (chunk, word);
- gtk_source_snippet_chunk_set_focus_position (chunk, i+1);
- gtk_source_snippet_add_chunk (snippet, chunk);
- g_object_unref (chunk);
- }
-
- chunk = gtk_source_snippet_chunk_new ();
- gtk_source_snippet_chunk_set_focus_position (chunk, 0);
- gtk_source_snippet_add_chunk (snippet, chunk);
- g_object_unref (chunk);
-
- return snippet;
-}
-
-static gboolean
-gtk_source_view_try_expand_snippet (GtkSourceView *view,
- GtkTextIter *iter)
-{
- GtkSourceSnippet *snippet;
- GtkTextIter begin;
- gchar *word;
-
- g_assert (GTK_SOURCE_IS_VIEW (view));
- g_assert (iter != NULL);
-
- if (gtk_text_iter_starts_line (iter) ||
- !_gtk_source_iter_ends_full_word (iter))
- {
- return FALSE;
- }
-
- begin = *iter;
-
- _gtk_source_iter_backward_full_word_start (&begin);
-
- if (gtk_text_iter_compare (&begin, iter) >= 0)
- {
- return FALSE;
- }
-
- word = gtk_text_iter_get_slice (&begin, iter);
-
- if (word == NULL || *word == 0)
- {
- return FALSE;
- }
-
- snippet = lookup_snippet_by_trigger (view, word);
-
- g_free (word);
-
- if (snippet != NULL)
- {
- gtk_source_view_push_snippet (view, snippet, iter);
- g_object_unref (snippet);
- return TRUE;
- }
-
- return FALSE;
-}
-
static gboolean
gtk_source_view_key_pressed (GtkSourceView *view,
guint key,
@@ -4166,6 +3943,11 @@ gtk_source_view_key_pressed (GtkSourceView *view,
}
}
+ if (_gtk_source_view_snippets_key_pressed (&priv->snippets, key, keycode, state))
+ {
+ return GDK_EVENT_STOP;
+ }
+
/* if tab or shift+tab:
* with shift+tab key is GDK_ISO_Left_Tab (yay! on win32 and mac too!)
*/
@@ -4175,47 +3957,11 @@ gtk_source_view_key_pressed (GtkSourceView *view,
editable &&
gtk_text_view_get_accepts_tab (GTK_TEXT_VIEW (view)))
{
- GtkSourceSnippet *snippet = g_queue_peek_head (&priv->snippets);
GtkTextIter s, e;
gboolean has_selection;
has_selection = gtk_text_buffer_get_selection_bounds (buf, &s, &e);
- /* If we already have a snippet expanded, then we might need
- * to move forward or backward between snippet positions.
- */
- if (snippet != NULL)
- {
- if (state == 0)
- {
- if (!_gtk_source_snippet_move_next (snippet))
- {
- gtk_source_view_pop_snippet (view);
- }
-
- return GDK_EVENT_STOP;
- }
- else if (state & GDK_SHIFT_MASK)
- {
- if (!_gtk_source_snippet_move_previous (snippet))
- {
- gtk_source_view_pop_snippet (view);
- }
-
- return GDK_EVENT_STOP;
- }
- }
-
- /* tab: if there is no selection and the current word is a
- * snippet trigger, then we should expand that snippet.
- */
- if (state == 0 &&
- !has_selection &&
- gtk_source_view_try_expand_snippet (view, &e))
- {
- return GDK_EVENT_STOP;
- }
-
if (priv->indent_on_tab)
{
/* shift+tab: always unindent */
@@ -5281,28 +5027,12 @@ gtk_source_view_real_push_snippet (GtkSourceView *view,
GtkTextIter *location)
{
GtkSourceViewPrivate *priv = gtk_source_view_get_instance_private (view);
- GtkTextBuffer *buffer;
- gboolean more_to_focus;
g_assert (GTK_SOURCE_IS_VIEW (view));
g_assert (GTK_SOURCE_IS_SNIPPET (snippet));
g_assert (location != NULL);
- buffer = gtk_text_iter_get_buffer (location);
-
- g_queue_push_head (&priv->snippets, g_object_ref (snippet));
-
- gtk_text_buffer_begin_user_action (buffer);
- more_to_focus = _gtk_source_snippet_begin (snippet, buffer, location);
- gtk_text_buffer_end_user_action (buffer);
-
- gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (view),
- gtk_text_buffer_get_insert (buffer));
-
- if (!more_to_focus)
- {
- gtk_source_view_pop_snippet (view);
- }
+ _gtk_source_view_snippets_push (&priv->snippets, snippet, location);
}
/**
@@ -5324,9 +5054,7 @@ gtk_source_view_push_snippet (GtkSourceView *view,
GtkSourceSnippet *snippet,
GtkTextIter *location)
{
- GtkSourceViewPrivate *priv = gtk_source_view_get_instance_private (view);
GtkSourceSnippetContext *context;
- GtkSourceSnippet *previous_snippet;
GtkTextBuffer *buffer;
GtkTextIter iter;
gboolean use_spaces;
@@ -5336,13 +5064,6 @@ gtk_source_view_push_snippet (GtkSourceView *view,
g_return_if_fail (GTK_SOURCE_IS_VIEW (view));
g_return_if_fail (GTK_SOURCE_IS_SNIPPET (snippet));
- previous_snippet = g_queue_peek_head (&priv->snippets);
-
- if (previous_snippet != NULL)
- {
- _gtk_source_snippet_pause (previous_snippet);
- }
-
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
if (location == NULL)
@@ -5369,38 +5090,3 @@ gtk_source_view_push_snippet (GtkSourceView *view,
g_signal_emit (view, signals [PUSH_SNIPPET], 0, snippet, location);
}
-
-static void
-gtk_source_view_pop_snippet (GtkSourceView *view)
-{
- GtkSourceViewPrivate *priv = gtk_source_view_get_instance_private (view);
- GtkSourceSnippet *next_snippet;
- GtkSourceSnippet *snippet;
-
- g_return_if_fail (GTK_SOURCE_IS_VIEW (view));
-
- snippet = g_queue_pop_head (&priv->snippets);
-
- if (snippet == NULL)
- {
- return;
- }
-
- next_snippet = g_queue_peek_head (&priv->snippets);
-
- if (next_snippet != NULL)
- {
- gchar *new_text;
-
- new_text = _gtk_source_snippet_get_edited_text (snippet);
- _gtk_source_snippet_replace_current_chunk_text (next_snippet, new_text);
- _gtk_source_snippet_unpause (next_snippet);
- _gtk_source_snippet_move_next (next_snippet);
-
- g_free (new_text);
- }
-
- g_signal_emit (view, signals[POP_SNIPPET], 0, snippet);
-
- g_object_unref (snippet);
-}
diff --git a/gtksourceview/gtksourceview.h b/gtksourceview/gtksourceview.h
index a7a719c2..367e8b2c 100644
--- a/gtksourceview/gtksourceview.h
+++ b/gtksourceview/gtksourceview.h
@@ -99,8 +99,6 @@ struct _GtkSourceViewClass
void (*push_snippet) (GtkSourceView *view,
GtkSourceSnippet *snippet,
GtkTextIter *location);
- void (*pop_snippet) (GtkSourceView *view,
- GtkSourceSnippet *snippet);
/*< private >*/
gpointer _reserved[20];
diff --git a/gtksourceview/meson.build b/gtksourceview/meson.build
index 7aca6f1b..5073577a 100644
--- a/gtksourceview/meson.build
+++ b/gtksourceview/meson.build
@@ -106,6 +106,7 @@ core_private_c = files([
'gtksourcemarkssequence.c',
'gtksourcepixbufhelper.c',
'gtksourceregex.c',
+ 'gtksourceview-snippets.c',
])
core_c_args = [
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]