[gnome-builder] libide: coalesce undo actions in various vim modes



commit 24e45f0970b39509541966090dcaadc8dbadfcf0
Author: Christian Hergert <christian hergert me>
Date:   Fri Mar 6 23:11:23 2015 -0800

    libide: coalesce undo actions in various vim modes

 data/keybindings/emacs.css    |    2 +-
 data/keybindings/vim.css      |  175 +++++++++++++++++++++--------------------
 libide/ide-internal.h         |    3 +-
 libide/ide-source-view-mode.c |   15 +++-
 libide/ide-source-view-mode.h |    3 +
 libide/ide-source-view.c      |   47 +++++++++--
 libide/ide-source-view.h      |    3 +-
 7 files changed, 148 insertions(+), 100 deletions(-)
---
diff --git a/data/keybindings/emacs.css b/data/keybindings/emacs.css
index 907fe49..4999336 100644
--- a/data/keybindings/emacs.css
+++ b/data/keybindings/emacs.css
@@ -46,7 +46,7 @@
 
 @binding-set builder-emacs-source-view
 {
-  bind "<ctrl>x" { "set-mode" ("emacs-x", transient) };
+  bind "<ctrl>x" { "set-mode" ("emacs-x", transient, 0) };
   bind "<ctrl>underscore" { "undo" () };
   bind "<alt>x" { "action" ("win", "show-command-bar", "") };
   bind "<ctrl>s" { "action" ("editor-frame", "find", "") };
diff --git a/data/keybindings/vim.css b/data/keybindings/vim.css
index e023266..2c57c42 100644
--- a/data/keybindings/vim.css
+++ b/data/keybindings/vim.css
@@ -79,73 +79,73 @@
   bind "Escape" { "set-overwrite" (0)
                   "clear-count" ()
                   "clear-selection" ()
-                  "set-mode" ("vim-normal", permanent) };
+                  "set-mode" ("vim-normal", permanent, 0) };
   bind "<ctrl>bracketleft" { "set-overwrite" (0)
                              "clear-count" ()
                              "clear-selection" ()
-                             "set-mode" ("vim-normal", permanent) };
+                             "set-mode" ("vim-normal", permanent, 0) };
 }
 
 @binding-set builder-vim-source-view-normal-with-count
 {
   bind "0" { "append-to-count" (0)
-             "set-mode" ("vim-normal-with-count", transient) };
+             "set-mode" ("vim-normal-with-count", transient, 0) };
   bind "percent" { "movement" (line-percentage, 0, 1, 1)
-                   "set-mode" ("vim-normal-with-count", transient) };
+                   "set-mode" ("vim-normal-with-count", transient, 0) };
 }
 
 @binding-set builder-vim-source-view-normal
 {
   /* todo: need a submode that will allow 0 to be used. */
   bind "1" { "append-to-count" (1)
-             "set-mode" ("vim-normal-with-count", transient) };
+             "set-mode" ("vim-normal-with-count", transient, 0) };
   bind "2" { "append-to-count" (2)
-             "set-mode" ("vim-normal-with-count", transient) };
+             "set-mode" ("vim-normal-with-count", transient, 0) };
   bind "3" { "append-to-count" (3)
-             "set-mode" ("vim-normal-with-count", transient) };
+             "set-mode" ("vim-normal-with-count", transient, 0) };
   bind "4" { "append-to-count" (4)
-             "set-mode" ("vim-normal-with-count", transient) };
+             "set-mode" ("vim-normal-with-count", transient, 0) };
   bind "5" { "append-to-count" (5)
-             "set-mode" ("vim-normal-with-count", transient) };
+             "set-mode" ("vim-normal-with-count", transient, 0) };
   bind "6" { "append-to-count" (6)
-             "set-mode" ("vim-normal-with-count", transient) };
+             "set-mode" ("vim-normal-with-count", transient, 0) };
   bind "7" { "append-to-count" (7)
-             "set-mode" ("vim-normal-with-count", transient) };
+             "set-mode" ("vim-normal-with-count", transient, 0) };
   bind "8" { "append-to-count" (8)
-             "set-mode" ("vim-normal-with-count", transient) };
+             "set-mode" ("vim-normal-with-count", transient, 0) };
   bind "9" { "append-to-count" (9)
-             "set-mode" ("vim-normal-with-count", transient) };
+             "set-mode" ("vim-normal-with-count", transient, 0) };
 
   /* insert at cursor */
-  bind "i" { "set-mode" ("vim-insert", permanent) };
+  bind "i" { "set-mode" ("vim-insert", permanent, 1) };
 
   /* insert after cursor */
-  bind "a" { "movement" (next-char, 0, 0, 0)
-             "set-mode" ("vim-insert", permanent) };
-  bind "<shift>a" { "movement" (last-char, 0, 0, 0)
-                    "set-mode" ("vim-insert", permanent) };
+  bind "a" { "set-mode" ("vim-insert", permanent, 1)
+             "movement" (next-char, 0, 0, 0) };
+  bind "<shift>a" { "set-mode" ("vim-insert", permanent, 1)
+                    "movement" (last-char, 0, 0, 0) };
 
   /* insert at first non-whitespace character */
-  bind "<shift>i" { "movement" (first-nonspace-char, 0, 1, 0)
-                    "set-mode" ("vim-insert", permanent) };
+  bind "<shift>i" { "set-mode" ("vim-insert", permanent, 1)
+                    "movement" (first-nonspace-char, 0, 1, 0) };
 
   /* insert line after current, insert mode */
-  bind "o" { "movement" (line-end, 0, 1, 0)
-             "insert-at-cursor-and-indent" ("\n")
-             "set-mode" ("vim-insert", permanent) };
+  bind "o" { "set-mode" ("vim-insert", permanent, 1)
+             "movement" (line-end, 0, 1, 0)
+             "insert-at-cursor-and-indent" ("\n") };
 
   /* insert line before current */
-  bind "<shift>o" { "movement" (first-char, 0, 0, 0)
+  bind "<shift>o" { "set-mode" ("vim-insert", permanent, 1)
+                    "movement" (first-char, 0, 0, 0)
                     "insert-at-cursor" ("\n")
                     "move-cursor" (display-lines, -1, 0)
-                    "auto-indent" ()
-                    "set-mode" ("vim-insert", permanent) };
+                    "auto-indent" () };
 
   /* swallow the current character and go to insert */
-  bind "s" { "movement" (next-char, 1, 1, 1)
+  bind "s" { "set-mode" ("vim-insert", permanent, 1)
+             "movement" (next-char, 1, 1, 1)
              "copy-clipboard" ()
-             "delete-selection" ()
-             "set-mode" ("vim-insert", permanent) };
+             "delete-selection" () };
 
   bind "Left"  { "movement" (previous-char, 0, 1, 1)
                  "clear-count" () };
@@ -199,7 +199,7 @@
                    "clear-count" () };
   bind "<ctrl>y" { "movement" (screen-down, 0, 0, 1)
                    "clear-count" () };
-  bind "z" { "set-mode" ("vim-normal-z", transient) };
+  bind "z" { "set-mode" ("vim-normal-z", transient, 0) };
 
   /* move by paragraph */
   bind "braceleft" { "movement" (paragraph-start, 0, 0, 1)
@@ -247,7 +247,8 @@
 
   /* redo */
   bind "<ctrl>r" { "redo" ()
-                   "clear-count" () };
+                   "clear-count" ()
+                  "clear-selection" () };
 
   bind "p" { "paste-clipboard-extended" (1, 1, 1)
              "clear-count" () };
@@ -255,12 +256,12 @@
                     "clear-count" () };
 
   /* overwrite */
-  bind "<shift>r" { "set-mode" ("vim-insert", permanent)
+  bind "<shift>r" { "set-mode" ("vim-insert", permanent, 1)
                     "set-overwrite" (1) };
 
  /* jump to sub-mode */
-  bind "c" { "set-mode" ("vim-normal-c", transient) };
-  bind "d" { "set-mode" ("vim-normal-d", transient) };
+  bind "c" { "set-mode" ("vim-normal-c", transient, 0) };
+  bind "d" { "set-mode" ("vim-normal-d", transient, 0) };
 
   /* delete to end of line */
   bind "<shift>d" { "movement" (last-char, 1, 0, 0)
@@ -280,8 +281,8 @@
                     "delete-selection" ()
                     "clear-count" () };
 
-  bind "greater" { "set-mode" ("vim-normal-indent", transient) };
-  bind "less" { "set-mode" ("vim-normal-indent", transient) };
+  bind "greater" { "set-mode" ("vim-normal-indent", transient, 0) };
+  bind "less" { "set-mode" ("vim-normal-indent", transient, 0) };
 
   /* join selected lines */
   bind "<shift>j" { "movement" (first-char, 0, 1, 0)
@@ -315,7 +316,7 @@
                          "clear-count" () };
 
   /* copy */
-  bind "y" { "set-mode" ("vim-normal-y", transient) };
+  bind "y" { "set-mode" ("vim-normal-y", transient, 0) };
   bind "<shift>y" { "save-insert-mark" ()
                     "movement" (first-char, 0, 0, 0)
                     "movement" (next-line, 1, 1, 1)
@@ -327,38 +328,38 @@
 
   /* visual mode transition */
   bind "v" { "movement" (next-char, 1, 1, 1)
-             "set-mode" ("vim-visual", permanent) };
+             "set-mode" ("vim-visual", permanent, 0) };
   bind "<shift>v" { "movement" (first-char, 0, 1, 0)
                     "movement" (next-line, 1, 0, 1)
-                    "set-mode" ("vim-visual-line", permanent) };
-  bind "<ctrl>v" { "set-mode" ("vim-visual-block", permanent) };
+                    "set-mode" ("vim-visual-line", permanent, 1) };
+  bind "<ctrl>v" { "set-mode" ("vim-visual-block", permanent, 0) };
 }
 
 @binding-set builder-vim-source-view-normal-c
 {
-  bind "i" { "set-mode" ("vim-normal-c-i", transient) };
+  bind "i" { "set-mode" ("vim-normal-c-i", transient, 0) };
 
-  bind "e" { "movement" (next-word-end, 1, 0, 1)
+  bind "e" { "set-mode" ("vim-insert", permanent, 1)
+             "movement" (next-word-end, 1, 0, 1)
              "copy-clipboard" ()
-             "delete-selection" ()
-             "set-mode" ("vim-insert", permanent) };
-  bind "w" { "movement" (next-word-end, 1, 0, 1)
+             "delete-selection" () };
+  bind "w" { "set-mode" ("vim-insert", permanent, 1)
+             "movement" (next-word-end, 1, 0, 1)
              "copy-clipboard" ()
-             "delete-selection" ()
-             "set-mode" ("vim-insert", permanent) };
+             "delete-selection" () };
 }
 
 @binding-set builder-vim-source-view-normal-c-i
 {
   /* cip */
-  bind "p" { "movement" (paragraph-start, 1, 1, 1)
+  bind "p" { "set-mode" ("vim-insert", permanent, 1)
+             "movement" (paragraph-start, 1, 1, 1)
              "swap-selection-bounds" ()
              "movement" (paragraph-end, 1, 1, 1)
              "copy-clipboard" ()
              "selection-theatric" (shrink)
              "delete-selection" ()
-             "clear-count" ()
-             "set-mode" ("vim-insert", permanent) };
+             "clear-count" () };
 }
 
 @binding-set builder-vim-source-view-normal-d
@@ -399,8 +400,8 @@
                  "copy-clipboard" ()
                  "delete-selection" () };
 
-  bind "i" { "set-mode" ("vim-normal-d-i", transient) };
-  bind "g" { "set-mode" ("vim-normal-d-g", transient) };
+  bind "i" { "set-mode" ("vim-normal-d-i", transient, 0) };
+  bind "g" { "set-mode" ("vim-normal-d-g", transient, 0) };
 
   bind "d" { "save-insert-mark" ()
              "movement" (first-char, 0, 1, 0)
@@ -456,21 +457,21 @@
 @binding-set builder-vim-source-view-visual-z
 {
   bind "z" { "movement" (scroll-screen-center, 1, 0, 0)
-             "set-mode" ("vim-visual", permanent) };
+             "set-mode" ("vim-visual", permanent, 0) };
   bind "t" { "movement" (scroll-screen-top, 1, 0, 0)
-             "set-mode" ("vim-visual", permanent) };
+             "set-mode" ("vim-visual", permanent, 0) };
   bind "b" { "movement" (scroll-screen-bottom, 1, 0, 0)
-             "set-mode" ("vim-visual", permanent) };
+             "set-mode" ("vim-visual", permanent, 0) };
 }
 
 @binding-set builder-vim-source-view-visual-line-z
 {
   bind "z" { "movement" (scroll-screen-center, 1, 0, 0)
-             "set-mode" ("vim-visual-line", permanent) };
+             "set-mode" ("vim-visual-line", permanent, 1) };
   bind "t" { "movement" (scroll-screen-top, 1, 0, 0)
-             "set-mode" ("vim-visual-line", permanent) };
+             "set-mode" ("vim-visual-line", permanent, 1) };
   bind "b" { "movement" (scroll-screen-bottom, 1, 0, 0)
-             "set-mode" ("vim-visual-line", permanent) };
+             "set-mode" ("vim-visual-line", permanent, 1) };
 }
 
 @binding-set builder-vim-source-view-normal-y
@@ -504,8 +505,8 @@
 
 @binding-set builder-vim-source-view-normal-g
 {
-  bind "<shift>i" { "movement" (first-char, 0, 1, 0)
-                    "set-mode" ("vim-insert", permanent) };
+  bind "<shift>i" { "set-mode" ("vim-insert", permanent, 1)
+                    "movement" (first-char, 0, 1, 0) };
   bind "e" { "movement" (previous-word-end, 0, 1, 1) };
   bind "<shift>e" { "movement" (previous-full-word-end, 0, 1, 1) };
   bind "g" { "movement" (first-line, 0, 1, 0 ) };
@@ -514,8 +515,8 @@
   /* todo: this should actually be screen middle. this does middle of the text width */
   bind "m" { "movement" (middle-char, 0, 1, 0) };
 
-  bind "u"        { "set-mode" ("vim-normal-g-u", transient) };
-  bind "<shift>u" { "set-mode" ("vim-normal-g-u", transient) };
+  bind "u"        { "set-mode" ("vim-normal-g-u", transient, 0) };
+  bind "<shift>u" { "set-mode" ("vim-normal-g-u", transient, 0) };
 }
 
 @binding-set builder-vim-source-view-normal-g-u
@@ -566,23 +567,23 @@
 @binding-set builder-vim-source-view-visual-g
 {
   bind "e" { "movement" (previous-word-end, 1, 1, 0)
-             "set-mode" ("vim-visual", permanent) };
+             "set-mode" ("vim-visual", permanent, 0) };
   bind "<shift>e" { "movement" (previous-full-word-end, 1, 1, 0)
-                    "set-mode" ("vim-visual", permanent) };
+                    "set-mode" ("vim-visual", permanent, 0) };
   bind "g" { "movement" (first-line, 1, 1, 0)
-             "set-mode" ("vim-visual", permanent) };
+             "set-mode" ("vim-visual", permanent, 0) };
   bind "j" { "movement" (next-line, 1, 1, 0)
-             "set-mode" ("vim-visual", permanent) };
+             "set-mode" ("vim-visual", permanent, 0) };
   bind "m" { "movement" (middle-char, 1, 1, 0)
-             "set-mode" ("vim-visual", permanent) };
+             "set-mode" ("vim-visual", permanent, 0) };
 }
 
 @binding-set builder-vim-source-view-visual-line-g
 {
   bind "g" { "movement" (first-line, 1, 1, 0)
-             "set-mode" ("vim-visual-line", permanent) };
+             "set-mode" ("vim-visual-line", permanent, 1) };
   bind "j" { "movement" (next-line, 1, 1, 0)
-             "set-mode" ("vim-visual-line", permanent) };
+             "set-mode" ("vim-visual-line", permanent, 1) };
 }
 
 @binding-set builder-vim-source-view-insert
@@ -630,10 +631,10 @@
 
   bind "greater" { "indent-selection" (1)
                    "movement" (first-nonspace-char, 0, 1, 0)
-                   "set-mode" ("vim-normal", permanent) };
+                   "set-mode" ("vim-normal", permanent, 0) };
   bind "less" { "indent-selection" (-1)
                 "movement" (first-nonspace-char, 0, 1, 0)
-                "set-mode" ("vim-normal", permanent) };
+                "set-mode" ("vim-normal", permanent, 0) };
 
   bind "0" { "movement" (first-char, 1, 1, 0) };
   bind "<shift>asciicircum" { "movement" (first-nonspace-char, 1, 0, 0) };
@@ -657,10 +658,10 @@
                     "selection-theatric" (expand)
                     "clear-selection" ()
                     "movement" (last-char, 0, 1, 0)
-                    "set-mode" ("vim-normal", permanent) };
+                    "set-mode" ("vim-normal", permanent, 0) };
 
-  bind "g" { "set-mode" ("vim-visual-g", transient) };
-  bind "z" { "set-mode" ("vim-visual-z", transient) };
+  bind "g" { "set-mode" ("vim-visual-g", transient, 0) };
+  bind "z" { "set-mode" ("vim-visual-z", transient, 0) };
 }
 
 @binding-set builder-vim-source-view-visual-line
@@ -670,54 +671,54 @@
 
   /* just to be nice */
   bind "h" { "clear-selection" ()
-             "set-mode" ("vim-normal", permanent) };
+             "set-mode" ("vim-normal", permanent, 0) };
   bind "l" { "clear-selection" ()
-             "set-mode" ("vim-normal", permanent) };
+             "set-mode" ("vim-normal", permanent, 0) };
 
   bind "Up" { "movement" (previous-line, 1, 0, 1) };
   bind "Down" { "movement" (next-line, 1, 0, 1) };
 
-  bind "z" { "set-mode" ("vim-visual-line-z", transient) };
+  bind "z" { "set-mode" ("vim-visual-line-z", transient, 0) };
 
   bind "x"        { "copy-clipboard" ()
                     "delete-selection" ()
                     "delete-from-cursor" (chars, 1)
-                    "set-mode" ("vim-normal", permanent) };
+                    "set-mode" ("vim-normal", permanent, 0) };
 
   bind "<shift>x" { "copy-clipboard" ()
                     "delete-selection" ()
                     "delete-from-cursor" (chars, 1)
-                    "set-mode" ("vim-normal", permanent) };
+                    "set-mode" ("vim-normal", permanent, 0) };
 
   bind "y"        { "copy-clipboard" ()
                     "selection-theatric" (expand)
                     "clear-selection" ()
-                    "set-mode" ("vim-normal", permanent) };
+                    "set-mode" ("vim-normal", permanent, 0) };
 
   bind "<shift>y" { "copy-clipboard" ()
                     "selection-theatric" (expand)
                     "clear-selection" ()
-                    "set-mode" ("vim-normal", permanent) };
+                    "set-mode" ("vim-normal", permanent, 0) };
 
   bind "<shift>j" { "join-lines" ()
                     "selection-theatric" (expand)
                     "clear-selection" ()
                     "movement" (last-char, 0, 1, 0)
-                    "set-mode" ("vim-normal", permanent) };
+                    "set-mode" ("vim-normal", permanent, 0) };
 
   bind "asciitilde" { "selection-theatric" (expand)
                       "change-case" (toggle)
                       "clear-selection" ()
-                      "set-mode" ("vim-normal", permanent) };
+                      "set-mode" ("vim-normal", permanent, 0) };
 
   bind "<shift>u" { "selection-theatric" (expand)
                     "change-case" (upper)
                     "clear-selection" ()
-                    "set-mode" ("vim-normal", permanent) };
+                    "set-mode" ("vim-normal", permanent, 0) };
   bind "u" { "selection-theatric" (expand)
              "change-case" (lower)
              "clear-selection" ()
-             "set-mode" ("vim-normal", permanent) };
+             "set-mode" ("vim-normal", permanent, 0) };
 
   bind "braceleft" { "movement" (paragraph-start, 1, 1, 1)
                      "movement" (last-char, 1, 1, 0) };
@@ -732,11 +733,11 @@
   bind "greater" { "indent-selection" (1)
                    "clear-selection" ()
                    "movement" (first-nonspace-char, 0, 1, 0)
-                   "set-mode" ("vim-normal", permanent) };
+                   "set-mode" ("vim-normal", permanent, 0) };
   bind "less" { "indent-selection" (-1)
                 "clear-selection" ()
                 "movement" (first-nonspace-char, 0, 1, 0)
-                "set-mode" ("vim-normal", permanent) };
+                "set-mode" ("vim-normal", permanent, 0) };
 
   bind "<ctrl>e" { "movement" (screen-up, 1, 0, 1) };
   bind "<ctrl>y" { "movement" (screen-down, 1, 0, 1) };
diff --git a/libide/ide-internal.h b/libide/ide-internal.h
index 3c9c849..5c282fb 100644
--- a/libide/ide-internal.h
+++ b/libide/ide-internal.h
@@ -67,7 +67,8 @@ gboolean           _ide_source_view_mode_do_event (IdeSourceViewMode     *mode,
                                                    gboolean              *remove);
 IdeSourceViewMode *_ide_source_view_mode_new      (GtkWidget             *view,
                                                    const char            *mode,
-                                                   IdeSourceViewModeType  type);
+                                                   IdeSourceViewModeType  type,
+                                                   gboolean               coalesce_undo);
 
 
 G_END_DECLS
diff --git a/libide/ide-source-view-mode.c b/libide/ide-source-view-mode.c
index fb66443..bb571c3 100644
--- a/libide/ide-source-view-mode.c
+++ b/libide/ide-source-view-mode.c
@@ -28,6 +28,7 @@ typedef struct
   GtkWidget             *view;
   char                  *name;
   IdeSourceViewModeType  type;
+  guint                  coalesce_undo : 1;
 } IdeSourceViewModePrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (IdeSourceViewMode, ide_source_view_mode, GTK_TYPE_WIDGET)
@@ -40,6 +41,16 @@ enum {
 
 static GParamSpec *gParamSpecs [LAST_PROP];
 
+gboolean
+ide_source_view_mode_get_coalesce_undo (IdeSourceViewMode *self)
+{
+  IdeSourceViewModePrivate *priv = ide_source_view_mode_get_instance_private (self);
+
+  g_return_val_if_fail (IDE_IS_SOURCE_VIEW_MODE (self), NULL);
+
+  return priv->coalesce_undo;
+}
+
 static void
 ide_source_view_mode_finalize (GObject *object)
 {
@@ -277,7 +288,8 @@ _ide_source_view_mode_do_event (IdeSourceViewMode *mode,
 IdeSourceViewMode *
 _ide_source_view_mode_new (GtkWidget             *view,
                            const char            *name,
-                           IdeSourceViewModeType  type)
+                           IdeSourceViewModeType  type,
+                           gboolean               coalesce_undo)
 {
   IdeSourceViewModePrivate *priv;
   IdeSourceViewMode *mode;
@@ -288,6 +300,7 @@ _ide_source_view_mode_new (GtkWidget             *view,
   priv->view = g_object_ref (view);
   priv->name = g_strdup (name);
   priv->type = type;
+  priv->coalesce_undo = coalesce_undo;
 
   return g_object_ref_sink (mode);
 }
diff --git a/libide/ide-source-view-mode.h b/libide/ide-source-view-mode.h
index 7f72b3c..52360dd 100644
--- a/libide/ide-source-view-mode.h
+++ b/libide/ide-source-view-mode.h
@@ -46,6 +46,9 @@ struct _IdeSourceViewModeClass
   GtkWidgetClass parent_class;
 };
 
+gboolean     ide_source_view_mode_get_coalesce_undo (IdeSourceViewMode *self);
+const gchar *ide_source_view_mode_get_name          (IdeSourceViewMode *self);
+
 G_END_DECLS
 
 #endif /* IDE_SOURCE_VIEW_MODE_H */
diff --git a/libide/ide-source-view.c b/libide/ide-source-view.c
index bd08444..bc1113a 100644
--- a/libide/ide-source-view.c
+++ b/libide/ide-source-view.c
@@ -53,6 +53,19 @@
 #define ANIMATION_X_GROW  50
 #define ANIMATION_Y_GROW  30
 
+#define BEGIN_USER_ACTION(self) \
+  G_STMT_START { \
+    GtkTextBuffer *b = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); \
+    IDE_TRACE_MSG ("begin_user_action()"); \
+    gtk_text_buffer_begin_user_action(b); \
+  } G_STMT_END
+#define END_USER_ACTION(self) \
+  G_STMT_START { \
+    GtkTextBuffer *b = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); \
+    IDE_TRACE_MSG ("end_user_action()"); \
+    gtk_text_buffer_end_user_action(b); \
+  } G_STMT_END
+
 typedef struct
 {
   IdeBackForwardList          *back_forward_list;
@@ -144,7 +157,8 @@ static guint       gSignals [LAST_SIGNAL];
 
 static void ide_source_view_real_set_mode (IdeSourceView         *self,
                                            const gchar           *name,
-                                           IdeSourceViewModeType  type);
+                                           IdeSourceViewModeType  type,
+                                           gboolean               coalesce_undo);
 
 static void
 activate_action (GtkWidget   *widget,
@@ -1400,7 +1414,11 @@ ide_source_view_do_mode (IdeSourceView *self,
         {
           /* only remove mode if it is still active */
           if (priv->mode == mode)
-            g_clear_object (&priv->mode);
+            {
+              if (ide_source_view_mode_get_coalesce_undo (mode))
+                END_USER_ACTION (self);
+              g_clear_object (&priv->mode);
+            }
         }
 
       g_object_unref (mode);
@@ -1410,7 +1428,7 @@ ide_source_view_do_mode (IdeSourceView *self,
     }
 
   if (!priv->mode)
-    ide_source_view_real_set_mode (self, NULL,  IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT);
+    ide_source_view_real_set_mode (self, NULL,  IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT, FALSE);
 
   return ret;
 }
@@ -2095,7 +2113,8 @@ ide_source_view_real_selection_theatric (IdeSourceView         *self,
 static void
 ide_source_view_real_set_mode (IdeSourceView         *self,
                                const gchar           *mode,
-                               IdeSourceViewModeType  type)
+                               IdeSourceViewModeType  type,
+                               gboolean               coalesce_undo)
 {
   IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
 
@@ -2104,19 +2123,28 @@ ide_source_view_real_set_mode (IdeSourceView         *self,
 
   g_assert (IDE_IS_SOURCE_VIEW (self));
 
-  g_clear_object (&priv->mode);
+  if (priv->mode)
+    {
+      if (ide_source_view_mode_get_coalesce_undo (priv->mode))
+        END_USER_ACTION (self);
+      g_clear_object (&priv->mode);
+    }
 
   if (mode == NULL)
     {
       mode = "default";
       type = IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT;
+      coalesce_undo = FALSE;
     }
 
   /* reset the count when switching to permanent mode */
   if (type == IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT)
     priv->count = 0;
 
-  priv->mode = _ide_source_view_mode_new (GTK_WIDGET (self), mode, type);
+  if (coalesce_undo)
+    BEGIN_USER_ACTION (self);
+
+  priv->mode = _ide_source_view_mode_new (GTK_WIDGET (self), mode, type, coalesce_undo);
 
   IDE_EXIT;
 }
@@ -2350,7 +2378,7 @@ ide_source_view_constructed (GObject *object)
   G_OBJECT_CLASS (ide_source_view_parent_class)->constructed (object);
 
   if (!priv->mode)
-    ide_source_view_real_set_mode (self, "default", IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT);
+    ide_source_view_real_set_mode (self, NULL, IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT, FALSE);
 
   /*
    * Completion does not have a way to retrieve visibility, so we need to track that ourselves
@@ -2901,9 +2929,10 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
                   NULL, NULL,
                   g_cclosure_marshal_generic,
                   G_TYPE_NONE,
-                  2,
+                  3,
                   G_TYPE_STRING,
-                  IDE_TYPE_SOURCE_VIEW_MODE_TYPE);
+                  IDE_TYPE_SOURCE_VIEW_MODE_TYPE,
+                  G_TYPE_BOOLEAN);
 
   gSignals [SET_OVERWRITE] =
     g_signal_new ("set-overwrite",
diff --git a/libide/ide-source-view.h b/libide/ide-source-view.h
index 5b1e4c2..280d3e5 100644
--- a/libide/ide-source-view.h
+++ b/libide/ide-source-view.h
@@ -237,7 +237,8 @@ struct _IdeSourceViewClass
                                        IdeSourceViewTheatric    theatric);
   void (*set_mode)                    (IdeSourceView           *self,
                                        const gchar             *mode,
-                                       IdeSourceViewModeType    type);
+                                       IdeSourceViewModeType    type,
+                                       gboolean                 coalesce_undo);
   void (*set_overwrite)               (IdeSourceView           *self,
                                        gboolean                 overwrite);
   void (*swap_selection_bounds)       (IdeSourceView           *self);


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