[gnome-builder/auto-indent] auto-indenter: lots of incremental work here.
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/auto-indent] auto-indenter: lots of incremental work here.
- Date: Thu, 18 Sep 2014 05:20:46 +0000 (UTC)
commit 81710b88f82dcab7fd10b2f473e487b3e578f2fb
Author: Christian Hergert <christian hergert me>
Date: Wed Sep 17 22:20:41 2014 -0700
auto-indenter: lots of incremental work here.
* move "auto-indenter" to GbSourceView.
* Start plumbing API so we can do more than just indentation.
for example, we need to be able to remove text so we can adjust
indent for } and end comments and such.
* stub } and / triggers.
src/editor/gb-editor-tab-private.h | 5 -
src/editor/gb-editor-tab.c | 44 +++--------
src/editor/gb-source-auto-indenter-c.c | 80 ++++++++++++++++++--
src/editor/gb-source-auto-indenter.c | 54 ++++++++++++++
src/editor/gb-source-auto-indenter.h | 30 ++++++--
src/editor/gb-source-view.c | 126 +++++++++++++++++++++++++++++++-
src/editor/gb-source-view.h | 5 +
7 files changed, 291 insertions(+), 53 deletions(-)
---
diff --git a/src/editor/gb-editor-tab-private.h b/src/editor/gb-editor-tab-private.h
index ad8b9ef..0122ad2 100644
--- a/src/editor/gb-editor-tab-private.h
+++ b/src/editor/gb-editor-tab-private.h
@@ -65,11 +65,6 @@ struct _GbEditorTabPrivate
GtkSourceGutterRenderer *change_renderer;
/*
- * Auto-indentation support for a given language.
- */
- GbSourceAutoIndenter *auto_indenter;
-
- /*
* Tab related settings.
*/
GbEditorSettings *settings;
diff --git a/src/editor/gb-editor-tab.c b/src/editor/gb-editor-tab.c
index 1ee6282..8351e6d 100644
--- a/src/editor/gb-editor-tab.c
+++ b/src/editor/gb-editor-tab.c
@@ -378,13 +378,26 @@ gb_editor_tab_language_changed (GbEditorTab *tab,
GbEditorDocument *document)
{
GtkSourceLanguage *language;
+ GbSourceAutoIndenter *indenter = NULL;
g_return_if_fail (GB_IS_EDITOR_TAB (tab));
g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (document));
+ if (language)
+ {
+ const gchar *lang_id = gtk_source_language_get_id (language);
+
+ if (lang_id)
+ indenter = gb_source_auto_indenter_c_new ();
+ }
+
+ gb_source_view_set_auto_indenter (tab->priv->source_view, indenter);
+ g_clear_object (&indenter);
+
gb_editor_tab_reload_snippets (tab, language);
+
}
@@ -861,29 +874,6 @@ on_source_view_push_snippet (GbSourceView *source_view,
}
}
-static gchar *
-on_source_view_query_auto_indent (GbSourceView *source_view,
- GtkTextIter *iter,
- GbEditorTab *tab)
-{
- GtkTextBuffer *buffer;
- GtkTextView *text_view = (GtkTextView *)source_view;
- gchar *ret = NULL;
-
- g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
- g_return_val_if_fail (GB_IS_EDITOR_TAB (tab), NULL);
- g_return_val_if_fail (iter, NULL);
-
- if (tab->priv->auto_indenter)
- {
- buffer = gtk_text_view_get_buffer (text_view);
- ret = gb_source_auto_indenter_query (tab->priv->auto_indenter, text_view,
- buffer, iter);
- }
-
- return ret;
-}
-
static gboolean
transform_file_to_language (GBinding *binding,
const GValue *src_value,
@@ -991,11 +981,6 @@ gb_editor_tab_constructed (GObject *object)
"push-snippet",
G_CALLBACK (on_source_view_push_snippet),
tab);
- g_signal_connect (priv->source_view,
- "query-auto-indent",
- G_CALLBACK (on_source_view_query_auto_indent),
- tab);
- g_print ("Connected\n");
g_signal_connect_swapped (priv->go_down_button,
"clicked",
@@ -1071,8 +1056,6 @@ gb_editor_tab_constructed (GObject *object)
gtk_source_gutter_insert (gutter, priv->change_renderer, 0);
}
- priv->auto_indenter = gb_source_auto_indenter_c_new ();
-
gb_editor_tab_cursor_moved (tab, priv->document);
EXIT;
@@ -1133,7 +1116,6 @@ gb_editor_tab_dispose (GObject *object)
g_clear_object (&tab->priv->search_highlighter);
g_clear_object (&tab->priv->search_settings);
g_clear_object (&tab->priv->search_context);
- g_clear_object (&tab->priv->auto_indenter);
g_clear_object (&tab->priv->settings);
EXIT;
diff --git a/src/editor/gb-source-auto-indenter-c.c b/src/editor/gb-source-auto-indenter-c.c
index 2125a55..bc69096 100644
--- a/src/editor/gb-source-auto-indenter-c.c
+++ b/src/editor/gb-source-auto-indenter-c.c
@@ -269,17 +269,16 @@ in_c89_comment (GtkTextIter *iter)
}
static gchar *
-gb_source_auto_indenter_c_query (GbSourceAutoIndenter *indenter,
- GtkTextView *view,
- GtkTextBuffer *buffer,
- GtkTextIter *iter)
+gb_source_auto_indenter_c_indent (GbSourceAutoIndenterC *c,
+ GtkTextView *view,
+ GtkTextBuffer *buffer,
+ GtkTextIter *iter)
{
GbSourceAutoIndenterCPrivate *priv;
- GbSourceAutoIndenterC *c = (GbSourceAutoIndenterC *)indenter;
GtkTextIter cur;
gunichar ch;
GString *str;
- gchar *ret;
+ gchar *ret = NULL;
ENTRY;
@@ -302,8 +301,9 @@ gb_source_auto_indenter_c_query (GbSourceAutoIndenter *indenter,
* start by moving back one character to get to the pre-newline insertion
* point.
*/
- if (!gtk_text_iter_backward_find_char (iter, non_space_predicate, NULL, NULL))
- GOTO (cleanup);
+ if (!g_unichar_isspace (gtk_text_iter_get_char (iter)))
+ if (!gtk_text_iter_backward_find_char (iter, non_space_predicate, NULL, NULL))
+ GOTO (cleanup);
/*
* Get our last non \n character entered.
@@ -420,6 +420,67 @@ cleanup:
RETURN (ret);
}
+static gboolean
+gb_source_auto_indenter_c_is_trigger (GbSourceAutoIndenter *indenter,
+ GdkEventKey *event)
+{
+ switch (event->keyval) {
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ case GDK_KEY_slash:
+ case GDK_KEY_braceright:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static gchar *
+gb_source_auto_indenter_c_format (GbSourceAutoIndenter *indenter,
+ GtkTextView *view,
+ GtkTextBuffer *buffer,
+ GtkTextIter *begin,
+ GtkTextIter *end,
+ GdkEventKey *event)
+{
+ GbSourceAutoIndenterC *c = (GbSourceAutoIndenterC *)indenter;
+ GtkTextIter begin_copy;
+ gchar *ret = NULL;
+
+ g_return_val_if_fail (GB_IS_SOURCE_AUTO_INDENTER_C (c), NULL);
+
+ switch (event->keyval) {
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ gtk_text_iter_assign (&begin_copy, begin);
+ ret = gb_source_auto_indenter_c_indent (c, view, buffer, begin);
+ gtk_text_iter_assign (begin, &begin_copy);
+ break;
+
+ case GDK_KEY_braceright:
+ /*
+ * Probably need to unindent this line.
+ */
+ g_debug ("TODO: unindent the curly brace if needed.");
+ break;
+
+ case GDK_KEY_slash:
+ /*
+ * TODO:
+ *
+ * If we are at the " * " beginning of a multi-line comment, let's just
+ * close the comment.
+ */
+ g_debug ("TODO: close current multi-line comment.");
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
static void
gb_source_auto_indenter_c_get_property (GObject *object,
guint prop_id,
@@ -465,7 +526,8 @@ gb_source_auto_indenter_c_class_init (GbSourceAutoIndenterCClass *klass)
object_class->get_property = gb_source_auto_indenter_c_get_property;
object_class->set_property = gb_source_auto_indenter_c_set_property;
- indenter_class->query = gb_source_auto_indenter_c_query;
+ indenter_class->is_trigger = gb_source_auto_indenter_c_is_trigger;
+ indenter_class->format = gb_source_auto_indenter_c_format;
gParamSpecs [PROP_SCOPE_INDENT] =
g_param_spec_int ("scope-indent",
diff --git a/src/editor/gb-source-auto-indenter.c b/src/editor/gb-source-auto-indenter.c
index 45bfeed..58ace44 100644
--- a/src/editor/gb-source-auto-indenter.c
+++ b/src/editor/gb-source-auto-indenter.c
@@ -47,10 +47,64 @@ gb_source_auto_indenter_query (GbSourceAutoIndenter *indenter,
buffer, iter);
}
+static gboolean
+gb_source_auto_indenter_real_is_trigger (GbSourceAutoIndenter *indenter,
+ GdkEventKey *event)
+{
+ return FALSE;
+}
+
+gboolean
+gb_source_auto_indenter_is_trigger (GbSourceAutoIndenter *indenter,
+ GdkEventKey *event)
+{
+ g_return_val_if_fail (GB_IS_SOURCE_AUTO_INDENTER (indenter), FALSE);
+ g_return_val_if_fail (event, FALSE);
+
+ return GB_SOURCE_AUTO_INDENTER_GET_CLASS (indenter)->is_trigger (indenter,
+ event);
+}
+
+gchar *
+gb_source_auto_indenter_format (GbSourceAutoIndenter *indenter,
+ GtkTextView *view,
+ GtkTextBuffer *buffer,
+ GtkTextIter *begin,
+ GtkTextIter *end,
+ GdkEventKey *event)
+{
+ g_return_val_if_fail (GB_IS_SOURCE_AUTO_INDENTER (indenter), NULL);
+ g_return_val_if_fail (GTK_IS_TEXT_VIEW (view), NULL);
+ g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+ g_return_val_if_fail (begin, NULL);
+ g_return_val_if_fail (end, NULL);
+ g_return_val_if_fail (event, NULL);
+
+ return GB_SOURCE_AUTO_INDENTER_GET_CLASS (indenter)->format (indenter,
+ view,
+ buffer,
+ begin,
+ end,
+ event);
+}
+
+gchar *
+gb_source_auto_indenter_real_format (GbSourceAutoIndenter *indenter,
+ GtkTextView *view,
+ GtkTextBuffer *buffer,
+ GtkTextIter *begin,
+ GtkTextIter *end,
+ GdkEventKey *event)
+{
+ return NULL;
+}
+
static void
gb_source_auto_indenter_class_init (GbSourceAutoIndenterClass *klass)
{
klass->query = gb_source_auto_indenter_real_query;
+ klass->is_trigger = gb_source_auto_indenter_real_is_trigger;
+ klass->format = gb_source_auto_indenter_real_format;
}
static void
diff --git a/src/editor/gb-source-auto-indenter.h b/src/editor/gb-source-auto-indenter.h
index 9270ac2..7d4bebd 100644
--- a/src/editor/gb-source-auto-indenter.h
+++ b/src/editor/gb-source-auto-indenter.h
@@ -53,14 +53,32 @@ struct _GbSourceAutoIndenterClass
GtkTextBuffer *buffer,
GtkTextIter *iter);
- gpointer padding[7];
+ gchar *(*format) (GbSourceAutoIndenter *indenter,
+ GtkTextView *view,
+ GtkTextBuffer *buffer,
+ GtkTextIter *begin,
+ GtkTextIter *end,
+ GdkEventKey *trigger);
+
+ gboolean (*is_trigger) (GbSourceAutoIndenter *indenter,
+ GdkEventKey *event);
+
+ gpointer padding[6];
};
-GType gb_source_auto_indenter_get_type (void) G_GNUC_CONST;
-gchar *gb_source_auto_indenter_query (GbSourceAutoIndenter *indenter,
- GtkTextView *view,
- GtkTextBuffer *buffer,
- GtkTextIter *iter);
+GType gb_source_auto_indenter_get_type (void) G_GNUC_CONST;
+gchar *gb_source_auto_indenter_query (GbSourceAutoIndenter *indenter,
+ GtkTextView *view,
+ GtkTextBuffer *buffer,
+ GtkTextIter *iter);
+gboolean gb_source_auto_indenter_is_trigger (GbSourceAutoIndenter *indenter,
+ GdkEventKey *event);
+gchar *gb_source_auto_indenter_format (GbSourceAutoIndenter *indenter,
+ GtkTextView *view,
+ GtkTextBuffer *buffer,
+ GtkTextIter *begin,
+ GtkTextIter *end,
+ GdkEventKey *event);
G_END_DECLS
diff --git a/src/editor/gb-source-view.c b/src/editor/gb-source-view.c
index f5061e2..d1f2fdc 100644
--- a/src/editor/gb-source-view.c
+++ b/src/editor/gb-source-view.c
@@ -26,6 +26,7 @@
#include "gb-cairo.h"
#include "gb-editor-document.h"
#include "gb-log.h"
+#include "gb-source-auto-indenter.h"
#include "gb-source-search-highlighter.h"
#include "gb-source-snippet-context.h"
#include "gb-source-snippet-private.h"
@@ -37,11 +38,14 @@ struct _GbSourceViewPrivate
GQueue *snippets;
GbSourceSearchHighlighter *search_highlighter;
GtkTextBuffer *buffer;
+ GbSourceAutoIndenter *auto_indenter;
+
guint buffer_insert_text_handler;
guint buffer_insert_text_after_handler;
guint buffer_delete_range_handler;
guint buffer_delete_range_after_handler;
guint buffer_mark_set_handler;
+
guint show_shadow : 1;
};
@@ -54,6 +58,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (GbSourceView, gb_source_view, GTK_SOURCE_TYPE_VIEW)
enum {
PROP_0,
+ PROP_AUTO_INDENTER,
PROP_SEARCH_HIGHLIGHTER,
PROP_SHOW_SHADOW,
LAST_PROP
@@ -77,8 +82,6 @@ on_search_highlighter_changed (GbSourceSearchHighlighter *highlighter,
g_return_if_fail (GB_IS_SOURCE_VIEW (view));
g_return_if_fail (GB_IS_SOURCE_SEARCH_HIGHLIGHTER (highlighter));
- g_print ("%s()\n", G_STRFUNC);
-
EXIT;
}
@@ -714,6 +717,9 @@ gb_source_view_key_press_event (GtkWidget *widget,
priv = view->priv;
+ /*
+ * Handle movement through the tab stops of the current snippet if needed.
+ */
if ((snippet = g_queue_peek_head (priv->snippets)))
{
switch ((gint) event->keyval)
@@ -745,6 +751,59 @@ gb_source_view_key_press_event (GtkWidget *widget,
}
}
+ if (priv->auto_indenter &&
+ gb_source_auto_indenter_is_trigger (priv->auto_indenter, event))
+ {
+ GtkTextMark *insert;
+ GtkTextIter begin;
+ GtkTextIter end;
+ gunichar ch;
+ GString *str;
+ gchar *indent;
+
+ if ((event->keyval == GDK_KEY_Return) || (event->keyval == GDK_KEY_KP_Enter))
+ if (gtk_text_view_im_context_filter_keypress (GTK_TEXT_VIEW (view), event))
+ return TRUE;
+
+ gtk_text_buffer_begin_user_action (priv->buffer);
+
+ /*
+ * Insert the current keypress into the buffer.
+ */
+ str = g_string_new (NULL);
+ ch = gdk_keyval_to_unicode (event->keyval);
+ g_string_append_unichar (str, ch);
+ gtk_text_buffer_insert_at_cursor (priv->buffer, str->str, str->len);
+ g_string_free (str, TRUE);
+
+ /*
+ * Set begin and end to the position of the new insertion point.
+ */
+ insert = gtk_text_buffer_get_insert (priv->buffer);
+ gtk_text_buffer_get_iter_at_mark (priv->buffer, &begin, insert);
+ gtk_text_buffer_get_iter_at_mark (priv->buffer, &end, insert);
+
+ /*
+ * Let the formatter potentially set the replacement text.
+ */
+ indent = gb_source_auto_indenter_format (priv->auto_indenter,
+ GTK_TEXT_VIEW (view),
+ priv->buffer, &begin, &end,
+ event);
+
+ if (indent)
+ {
+ if (!gtk_text_iter_equal (&begin, &end))
+ gtk_text_buffer_delete (priv->buffer, &begin, &end);
+ gtk_text_buffer_insert (priv->buffer, &begin, indent, -1);
+ g_free (indent);
+ }
+
+ gtk_text_buffer_end_user_action (priv->buffer);
+
+ return TRUE;
+ }
+
return GTK_WIDGET_CLASS (gb_source_view_parent_class)->key_press_event (widget, event);
}
@@ -994,12 +1053,51 @@ gb_source_view_finalize (GObject *object)
priv = GB_SOURCE_VIEW (object)->priv;
+ if (priv->buffer)
+ {
+ g_object_remove_weak_pointer (G_OBJECT (priv->buffer),
+ (gpointer *)&priv->buffer);
+ priv->buffer = NULL;
+ }
+
g_clear_pointer (&priv->snippets, g_queue_free);
g_clear_object (&priv->search_highlighter);
+ g_clear_object (&priv->auto_indenter);
G_OBJECT_CLASS (gb_source_view_parent_class)->finalize (object);
}
+GbSourceAutoIndenter *
+gb_source_view_get_auto_indenter (GbSourceView *view)
+{
+ g_return_val_if_fail (GB_IS_SOURCE_VIEW (view), NULL);
+
+ return view->priv->auto_indenter;
+}
+
+void
+gb_source_view_set_auto_indenter (GbSourceView *view,
+ GbSourceAutoIndenter *auto_indenter)
+{
+ GbSourceViewPrivate *priv;
+
+ g_return_if_fail (GB_IS_SOURCE_VIEW (view));
+ g_return_if_fail (!auto_indenter ||
+ GB_IS_SOURCE_AUTO_INDENTER (auto_indenter));
+
+ priv = view->priv;
+
+ if (priv->auto_indenter != auto_indenter)
+ {
+ g_clear_object (&priv->auto_indenter);
+ priv->auto_indenter = auto_indenter
+ ? g_object_ref (auto_indenter)
+ : NULL;
+ g_object_notify_by_pspec (G_OBJECT (view),
+ gParamSpecs [PROP_AUTO_INDENTER]);
+ }
+}
+
static void
gb_source_view_get_property (GObject *object,
guint prop_id,
@@ -1010,6 +1108,10 @@ gb_source_view_get_property (GObject *object,
switch (prop_id)
{
+ case PROP_AUTO_INDENTER:
+ g_value_set_object (value, gb_source_view_get_auto_indenter (view));
+ break;
+
case PROP_SEARCH_HIGHLIGHTER:
g_value_set_object (value, gb_source_view_get_search_highlighter (view));
break;
@@ -1033,6 +1135,10 @@ gb_source_view_set_property (GObject *object,
switch (prop_id)
{
+ case PROP_AUTO_INDENTER:
+ gb_source_view_set_auto_indenter (view, g_value_get_object (value));
+ break;
+
case PROP_SEARCH_HIGHLIGHTER:
gb_source_view_set_search_highlighter (view, g_value_get_object (value));
break;
@@ -1062,6 +1168,22 @@ gb_source_view_class_init (GbSourceViewClass *klass)
text_view_class->draw_layer = gb_source_view_draw_layer;
+ /**
+ * GbSourceView:auto-indenter:
+ *
+ * Sets the #GbSourceAutoIndenter to use while typing in the source view.
+ *
+ * %NULL to unset the auto-indenter.
+ */
+ gParamSpecs [PROP_AUTO_INDENTER] =
+ g_param_spec_object ("auto-indenter",
+ _("Auto Indenter"),
+ _("The indenter to use when auto_indent is set."),
+ GB_TYPE_SOURCE_AUTO_INDENTER,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_AUTO_INDENTER,
+ gParamSpecs [PROP_AUTO_INDENTER]);
+
gParamSpecs[PROP_SHOW_SHADOW] =
g_param_spec_boolean ("show-shadow",
_ ("Show Shadow"),
diff --git a/src/editor/gb-source-view.h b/src/editor/gb-source-view.h
index 301bb9f..c9cc9db 100644
--- a/src/editor/gb-source-view.h
+++ b/src/editor/gb-source-view.h
@@ -21,6 +21,7 @@
#include <gtksourceview/gtksourceview.h>
+#include "gb-source-auto-indenter.h"
#include "gb-source-snippet.h"
G_BEGIN_DECLS
@@ -66,6 +67,10 @@ gboolean gb_source_view_get_show_shadow (GbSourceView *view); /* XXX: Remove thi
void gb_source_view_set_show_shadow (GbSourceView *view, /* XXX: Remove this */
gboolean show_shadow);
+GbSourceAutoIndenter *gb_source_view_get_auto_indenter (GbSourceView *view);
+void gb_source_view_set_auto_indenter (GbSourceView *view,
+ GbSourceAutoIndenter *auto_indenter);
+
G_END_DECLS
#endif /* GB_SOURCE_VIEW_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]