[gtksourceview/wip/chergert/fix-custom-indenters] sourceview: improve input-method detection for indenters




commit 089b25c237ba73548f8ae1ec5e0116a143bb5b1f
Author: Christian Hergert <chergert redhat com>
Date:   Sun Jul 24 13:28:30 2022 -0700

    sourceview: improve input-method detection for indenters
    
    This attempts to improve the situation where we need to detect if an input
    method filtered our keypress but really inserted what we expected it to.
    This can happen with ibus over wayland stealing input like > or / and
    marking it filtered (but going through "commit-text").
    
    To make this work, we have to introspect a bit more by trying to convert
    our keyval to a unicode character, and then checking equality with what
    was just inserted at the previous character.

 gtksourceview/gtksourceview.c | 56 ++++++++++++++++++++++++++++++-------------
 1 file changed, 40 insertions(+), 16 deletions(-)
---
diff --git a/gtksourceview/gtksourceview.c b/gtksourceview/gtksourceview.c
index 19cb4d94..80c3a279 100644
--- a/gtksourceview/gtksourceview.c
+++ b/gtksourceview/gtksourceview.c
@@ -4035,6 +4035,9 @@ gtk_source_view_key_pressed (GtkSourceView         *view,
        {
                GdkEvent *event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (controller));
                gint64 insertion_count = _gtk_source_buffer_get_insertion_count (priv->source_buffer);
+               gunichar expected;
+               gboolean filtered;
+               gboolean did_insert;
 
                g_assert (gdk_event_get_event_type (event) == GDK_KEY_PRESS);
 
@@ -4054,17 +4057,23 @@ gtk_source_view_key_pressed (GtkSourceView         *view,
                 * indent the line (starting from the location directly after the
                 * inserted character).
                 */
+               expected = gdk_keyval_to_unicode (key);
 
-               /* 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.
+               /* We need to query the input-method first as we might be using
+                * ibus or similar with pinyin, etc.
+                */
+               filtered = gtk_text_view_im_context_filter_keypress (GTK_TEXT_VIEW (view), event);
+
+               /* If our change count incremented, then something was inserted.
+                * The change count is not incremented if only pre-edit changed.
+                */
+               did_insert = insertion_count != _gtk_source_buffer_get_insertion_count (priv->source_buffer);
+
+               /* If we didn't filter, then GTK would have inserted a \n for
+                * Return/KP_Enter if it's key-press handler would have fired.
+                * We need to emulate that.
                 */
-               if (!gtk_text_view_im_context_filter_keypress (GTK_TEXT_VIEW (view), event))
+               if (!filtered)
                {
                        gtk_text_buffer_begin_user_action (buf);
 
@@ -4072,20 +4081,35 @@ gtk_source_view_key_pressed (GtkSourceView         *view,
                        {
                                gtk_text_buffer_get_iter_at_mark (buf, &cur, mark);
                                gtk_text_buffer_insert (buf, &cur, "\n", 1);
+                               did_insert = TRUE;
+                               expected = '\n';
                        }
 
-                       /* 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_end_user_action (buf);
+               }
+
+               /* If we inserted something, then we are free to query the
+                * indenter, so long as what was entered is what we expected
+                * to insert based on the keyval. Some input-methods may not
+                * do that, such as < getting inserted as 《.
+                */
+               if (did_insert)
+               {
+                       GtkTextIter prev;
+                       gunichar ch;
+
+                       gtk_text_buffer_get_iter_at_mark (buf, &prev, mark);
+                       gtk_text_iter_backward_char (&prev);
+                       ch = gtk_text_iter_get_char (&prev);
+
+                       if (ch == expected)
                        {
+                               gtk_text_buffer_begin_user_action (buf);
                                gtk_text_buffer_get_iter_at_mark (buf, &cur, mark);
                                gtk_source_indenter_indent (priv->indenter, view, &cur);
                                gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (view), mark);
+                               gtk_text_buffer_end_user_action (buf);
                        }
-
-                       gtk_text_buffer_end_user_action (buf);
                }
 
                return GDK_EVENT_STOP;


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