[gtksourceview/wip/chergert/indenter: 6/6] view: use GtkSourceIndenter interface




commit 04227943981179c1aff269355e8cedb768ed3f95
Author: Christian Hergert <chergert redhat com>
Date:   Thu Mar 11 09:45:24 2021 -0800

    view: use GtkSourceIndenter interface
    
    This uses the indenter interface instead of the compute_indentation()
    implementation from previous. Doing so allows for applications to provide
    custom indentation providers that may differ from what GtkSourceView
    provides internally.
    
    Fixes #166

 gtksourceview/gtksourceview.c | 121 ++++++++++++++++++------------------------
 1 file changed, 53 insertions(+), 68 deletions(-)
---
diff --git a/gtksourceview/gtksourceview.c b/gtksourceview/gtksourceview.c
index e4d5dd6b..1892f0b5 100644
--- a/gtksourceview/gtksourceview.c
+++ b/gtksourceview/gtksourceview.c
@@ -3106,42 +3106,6 @@ gtk_source_view_get_indent_width (GtkSourceView *view)
        return priv->indent_width;
 }
 
-static gchar *
-compute_indentation (GtkSourceView *view,
-                     GtkTextIter   *cur)
-{
-       GtkTextIter start;
-       GtkTextIter end;
-       gunichar ch;
-
-       start = *cur;
-       gtk_text_iter_set_line_offset (&start, 0);
-
-       end = start;
-
-       ch = gtk_text_iter_get_char (&end);
-
-       while (g_unichar_isspace (ch) &&
-              (ch != '\n') &&
-              (ch != '\r') &&
-              (gtk_text_iter_compare (&end, cur) < 0))
-       {
-               if (!gtk_text_iter_forward_char (&end))
-               {
-                       break;
-               }
-
-               ch = gtk_text_iter_get_char (&end);
-       }
-
-       if (gtk_text_iter_equal (&start, &end))
-       {
-               return NULL;
-       }
-
-       return gtk_text_iter_get_slice (&start, &end);
-}
-
 static guint
 get_real_indent_width (GtkSourceView *view)
 {
@@ -3992,11 +3956,6 @@ gtk_source_view_key_pressed (GtkSourceView         *view,
        guint modifiers;
        gboolean editable;
 
-       if (_gtk_source_view_assistants_handle_key (&priv->assistants, key, state))
-       {
-               return TRUE;
-       }
-
        buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
 
        editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (view));
@@ -4008,41 +3967,67 @@ gtk_source_view_key_pressed (GtkSourceView         *view,
        mark = gtk_text_buffer_get_insert (buf);
        gtk_text_buffer_get_iter_at_mark (buf, &cur, mark);
 
-       if ((key == GDK_KEY_Return || key == GDK_KEY_KP_Enter) &&
-           !(state & GDK_SHIFT_MASK) &&
-           priv->auto_indent)
-       {
-               /* Auto-indent means that when you press ENTER at the end of a
-                * line, the new line is automatically indented at the same
-                * level as the previous line.
-                * SHIFT+ENTER allows to avoid autoindentation.
+       if (editable &&
+           priv->auto_indent &&
+           priv->indenter != NULL &&
+           gtk_source_indenter_is_trigger (priv->indenter, view, &cur, state, key))
+       {
+               GdkEvent *event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (controller));
+               gint64 insertion_count = _gtk_source_buffer_get_insertion_count (priv->source_buffer);
+
+               g_assert (gdk_event_get_event_type (event) == GDK_KEY_PRESS);
+
+               /* To make this work as close to how GTK will commit text to the
+                * buffer as possible, we deliver the event information to the input
+                * method who then might commit the text to the GtkSourceBuffer. To
+                * do anything else would put some difficult work on the indenter to
+                * translate GDK keyvals into text which is incredibly complicated
+                * when input methods are in play.
+                *
+                * Since we don't have direct access to the input method, we check
+                * the location of the input and see if it changed after filtering
+                * the key press event.
+                *
+                * If we detect that something was actually inserted (and not filtered
+                * into a compose sequence or similar) then we ask the indenter to
+                * indent the line (starting from the location directly after the
+                * inserted character).
                 */
-               gchar *indent = NULL;
 
-               /* Calculate line indentation and create indent string. */
-               indent = compute_indentation (view, &cur);
+               gtk_text_buffer_begin_user_action (buf);
 
-               if (indent != NULL)
+               /* We can ignore the return value from filter_keypress because we
+                * already know this is a key we care about. Either we inserted
+                * text and will indent, or we didn't insert text and we should
+                * stop processing anyway.
+                *
+                * However, if key is Enter/Return, we will need to insert that
+                * newline manually instead of relying on the input method as it
+                * will not be doing it for us.
+                */
+               if (!gtk_text_view_im_context_filter_keypress (GTK_TEXT_VIEW (view), event))
                {
-                       /* Delete any selected text to preserve behavior without auto-indent */
-                       gtk_text_buffer_delete_selection (buf,
-                                                         TRUE,
-                                                         gtk_text_view_get_editable (GTK_TEXT_VIEW (view)));
+                       if (key == GDK_KEY_Return || key == GDK_KEY_KP_Enter)
+                       {
+                               gtk_text_buffer_get_iter_at_mark (buf, &cur, mark);
+                               gtk_text_buffer_insert (buf, &cur, "\n", 1);
+                       }
+               }
 
-                       /* If an input method or deletion has inserted some text while handling the
-                        * key press event, the cur iter may be invalid, so get the iter again
-                        */
+               /* Changing the preedit should not change our insertion count,
+                * so if our insertion count changed it was because soemthing
+                * was committed to the underlying source buffer.
+                */
+               if (insertion_count != _gtk_source_buffer_get_insertion_count (priv->source_buffer))
+               {
                        gtk_text_buffer_get_iter_at_mark (buf, &cur, mark);
-
-                       /* Insert new line and auto-indent. */
-                       gtk_text_buffer_begin_user_action (buf);
-                       gtk_text_buffer_insert (buf, &cur, "\n", 1);
-                       gtk_text_buffer_insert (buf, &cur, indent, strlen (indent));
-                       g_free (indent);
-                       gtk_text_buffer_end_user_action (buf);
+                       gtk_source_indenter_indent (priv->indenter, view, &cur);
                        gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (view), mark);
-                       return GDK_EVENT_STOP;
                }
+
+               gtk_text_buffer_end_user_action (buf);
+
+               return GDK_EVENT_STOP;
        }
 
        if (priv->enable_snippets &&


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]