[gnome-builder] libide: use CSS gtkwidget property for controlling sourceviewmode



commit c0811283a9dd754009458c2093f3b1a410645553
Author: Christian Hergert <christian hergert me>
Date:   Sat Mar 7 02:11:36 2015 -0800

    libide: use CSS gtkwidget property for controlling sourceviewmode
    
      -IdeSourceViewMode-suppress-unbound: true;
       This will block key presses that are not bound to accelerators.
    
      -IdeSourceViewMode-coalesce-undo: true;
       This will try to merge undo for all events in the mode.

 data/keybindings/emacs.css    |    2 +-
 data/keybindings/vim.css      |  200 ++++++++++++++++++++++++++--------------
 libide/ide-internal.h         |    3 +-
 libide/ide-source-view-mode.c |   74 ++++++++++++++--
 libide/ide-source-view-mode.h |    5 +-
 libide/ide-source-view.c      |   79 ++++++++++++----
 libide/ide-source-view.h      |    3 +-
 7 files changed, 262 insertions(+), 104 deletions(-)
---
diff --git a/data/keybindings/emacs.css b/data/keybindings/emacs.css
index 4999336..907fe49 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, 0) };
+  bind "<ctrl>x" { "set-mode" ("emacs-x", transient) };
   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 2c57c42..e595980 100644
--- a/data/keybindings/vim.css
+++ b/data/keybindings/vim.css
@@ -79,70 +79,70 @@
   bind "Escape" { "set-overwrite" (0)
                   "clear-count" ()
                   "clear-selection" ()
-                  "set-mode" ("vim-normal", permanent, 0) };
+                  "set-mode" ("vim-normal", permanent) };
   bind "<ctrl>bracketleft" { "set-overwrite" (0)
                              "clear-count" ()
                              "clear-selection" ()
-                             "set-mode" ("vim-normal", permanent, 0) };
+                             "set-mode" ("vim-normal", permanent) };
 }
 
 @binding-set builder-vim-source-view-normal-with-count
 {
   bind "0" { "append-to-count" (0)
-             "set-mode" ("vim-normal-with-count", transient, 0) };
+             "set-mode" ("vim-normal-with-count", transient) };
   bind "percent" { "movement" (line-percentage, 0, 1, 1)
-                   "set-mode" ("vim-normal-with-count", transient, 0) };
+                   "set-mode" ("vim-normal-with-count", transient) };
 }
 
 @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, 0) };
+             "set-mode" ("vim-normal-with-count", transient) };
   bind "2" { "append-to-count" (2)
-             "set-mode" ("vim-normal-with-count", transient, 0) };
+             "set-mode" ("vim-normal-with-count", transient) };
   bind "3" { "append-to-count" (3)
-             "set-mode" ("vim-normal-with-count", transient, 0) };
+             "set-mode" ("vim-normal-with-count", transient) };
   bind "4" { "append-to-count" (4)
-             "set-mode" ("vim-normal-with-count", transient, 0) };
+             "set-mode" ("vim-normal-with-count", transient) };
   bind "5" { "append-to-count" (5)
-             "set-mode" ("vim-normal-with-count", transient, 0) };
+             "set-mode" ("vim-normal-with-count", transient) };
   bind "6" { "append-to-count" (6)
-             "set-mode" ("vim-normal-with-count", transient, 0) };
+             "set-mode" ("vim-normal-with-count", transient) };
   bind "7" { "append-to-count" (7)
-             "set-mode" ("vim-normal-with-count", transient, 0) };
+             "set-mode" ("vim-normal-with-count", transient) };
   bind "8" { "append-to-count" (8)
-             "set-mode" ("vim-normal-with-count", transient, 0) };
+             "set-mode" ("vim-normal-with-count", transient) };
   bind "9" { "append-to-count" (9)
-             "set-mode" ("vim-normal-with-count", transient, 0) };
+             "set-mode" ("vim-normal-with-count", transient) };
 
   /* insert at cursor */
-  bind "i" { "set-mode" ("vim-insert", permanent, 1) };
+  bind "i" { "set-mode" ("vim-insert", permanent) };
 
   /* insert after cursor */
-  bind "a" { "set-mode" ("vim-insert", permanent, 1)
+  bind "a" { "set-mode" ("vim-insert", permanent)
              "movement" (next-char, 0, 0, 0) };
-  bind "<shift>a" { "set-mode" ("vim-insert", permanent, 1)
+  bind "<shift>a" { "set-mode" ("vim-insert", permanent)
                     "movement" (last-char, 0, 0, 0) };
 
   /* insert at first non-whitespace character */
-  bind "<shift>i" { "set-mode" ("vim-insert", permanent, 1)
+  bind "<shift>i" { "set-mode" ("vim-insert", permanent)
                     "movement" (first-nonspace-char, 0, 1, 0) };
 
   /* insert line after current, insert mode */
-  bind "o" { "set-mode" ("vim-insert", permanent, 1)
+  bind "o" { "set-mode" ("vim-insert", permanent)
              "movement" (line-end, 0, 1, 0)
              "insert-at-cursor-and-indent" ("\n") };
 
   /* insert line before current */
-  bind "<shift>o" { "set-mode" ("vim-insert", permanent, 1)
+  bind "<shift>o" { "set-mode" ("vim-insert", permanent)
                     "movement" (first-char, 0, 0, 0)
                     "insert-at-cursor" ("\n")
                     "move-cursor" (display-lines, -1, 0)
                     "auto-indent" () };
 
   /* swallow the current character and go to insert */
-  bind "s" { "set-mode" ("vim-insert", permanent, 1)
+  bind "s" { "set-mode" ("vim-insert", permanent)
              "movement" (next-char, 1, 1, 1)
              "copy-clipboard" ()
              "delete-selection" () };
@@ -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, 0) };
+  bind "z" { "set-mode" ("vim-normal-z", transient) };
 
   /* move by paragraph */
   bind "braceleft" { "movement" (paragraph-start, 0, 0, 1)
@@ -256,12 +256,12 @@
                     "clear-count" () };
 
   /* overwrite */
-  bind "<shift>r" { "set-mode" ("vim-insert", permanent, 1)
+  bind "<shift>r" { "set-mode" ("vim-insert", permanent)
                     "set-overwrite" (1) };
 
  /* jump to sub-mode */
-  bind "c" { "set-mode" ("vim-normal-c", transient, 0) };
-  bind "d" { "set-mode" ("vim-normal-d", transient, 0) };
+  bind "c" { "set-mode" ("vim-normal-c", transient) };
+  bind "d" { "set-mode" ("vim-normal-d", transient) };
 
   /* delete to end of line */
   bind "<shift>d" { "movement" (last-char, 1, 0, 0)
@@ -281,8 +281,8 @@
                     "delete-selection" ()
                     "clear-count" () };
 
-  bind "greater" { "set-mode" ("vim-normal-indent", transient, 0) };
-  bind "less" { "set-mode" ("vim-normal-indent", transient, 0) };
+  bind "greater" { "set-mode" ("vim-normal-indent", transient) };
+  bind "less" { "set-mode" ("vim-normal-indent", transient) };
 
   /* join selected lines */
   bind "<shift>j" { "movement" (first-char, 0, 1, 0)
@@ -316,7 +316,7 @@
                          "clear-count" () };
 
   /* copy */
-  bind "y" { "set-mode" ("vim-normal-y", transient, 0) };
+  bind "y" { "set-mode" ("vim-normal-y", transient) };
   bind "<shift>y" { "save-insert-mark" ()
                     "movement" (first-char, 0, 0, 0)
                     "movement" (next-line, 1, 1, 1)
@@ -328,22 +328,22 @@
 
   /* visual mode transition */
   bind "v" { "movement" (next-char, 1, 1, 1)
-             "set-mode" ("vim-visual", permanent, 0) };
+             "set-mode" ("vim-visual", permanent) };
   bind "<shift>v" { "movement" (first-char, 0, 1, 0)
                     "movement" (next-line, 1, 0, 1)
-                    "set-mode" ("vim-visual-line", permanent, 1) };
-  bind "<ctrl>v" { "set-mode" ("vim-visual-block", permanent, 0) };
+                    "set-mode" ("vim-visual-line", permanent) };
+  bind "<ctrl>v" { "set-mode" ("vim-visual-block", permanent) };
 }
 
 @binding-set builder-vim-source-view-normal-c
 {
-  bind "i" { "set-mode" ("vim-normal-c-i", transient, 0) };
+  bind "i" { "set-mode" ("vim-normal-c-i", transient) };
 
-  bind "e" { "set-mode" ("vim-insert", permanent, 1)
+  bind "e" { "set-mode" ("vim-insert", permanent)
              "movement" (next-word-end, 1, 0, 1)
              "copy-clipboard" ()
              "delete-selection" () };
-  bind "w" { "set-mode" ("vim-insert", permanent, 1)
+  bind "w" { "set-mode" ("vim-insert", permanent)
              "movement" (next-word-end, 1, 0, 1)
              "copy-clipboard" ()
              "delete-selection" () };
@@ -352,7 +352,7 @@
 @binding-set builder-vim-source-view-normal-c-i
 {
   /* cip */
-  bind "p" { "set-mode" ("vim-insert", permanent, 1)
+  bind "p" { "set-mode" ("vim-insert", permanent)
              "movement" (paragraph-start, 1, 1, 1)
              "swap-selection-bounds" ()
              "movement" (paragraph-end, 1, 1, 1)
@@ -400,8 +400,8 @@
                  "copy-clipboard" ()
                  "delete-selection" () };
 
-  bind "i" { "set-mode" ("vim-normal-d-i", transient, 0) };
-  bind "g" { "set-mode" ("vim-normal-d-g", transient, 0) };
+  bind "i" { "set-mode" ("vim-normal-d-i", transient) };
+  bind "g" { "set-mode" ("vim-normal-d-g", transient) };
 
   bind "d" { "save-insert-mark" ()
              "movement" (first-char, 0, 1, 0)
@@ -457,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, 0) };
+             "set-mode" ("vim-visual", permanent) };
   bind "t" { "movement" (scroll-screen-top, 1, 0, 0)
-             "set-mode" ("vim-visual", permanent, 0) };
+             "set-mode" ("vim-visual", permanent) };
   bind "b" { "movement" (scroll-screen-bottom, 1, 0, 0)
-             "set-mode" ("vim-visual", permanent, 0) };
+             "set-mode" ("vim-visual", permanent) };
 }
 
 @binding-set builder-vim-source-view-visual-line-z
 {
   bind "z" { "movement" (scroll-screen-center, 1, 0, 0)
-             "set-mode" ("vim-visual-line", permanent, 1) };
+             "set-mode" ("vim-visual-line", permanent) };
   bind "t" { "movement" (scroll-screen-top, 1, 0, 0)
-             "set-mode" ("vim-visual-line", permanent, 1) };
+             "set-mode" ("vim-visual-line", permanent) };
   bind "b" { "movement" (scroll-screen-bottom, 1, 0, 0)
-             "set-mode" ("vim-visual-line", permanent, 1) };
+             "set-mode" ("vim-visual-line", permanent) };
 }
 
 @binding-set builder-vim-source-view-normal-y
@@ -505,7 +505,7 @@
 
 @binding-set builder-vim-source-view-normal-g
 {
-  bind "<shift>i" { "set-mode" ("vim-insert", permanent, 1)
+  bind "<shift>i" { "set-mode" ("vim-insert", permanent)
                     "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) };
@@ -515,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, 0) };
-  bind "<shift>u" { "set-mode" ("vim-normal-g-u", transient, 0) };
+  bind "u"        { "set-mode" ("vim-normal-g-u", transient) };
+  bind "<shift>u" { "set-mode" ("vim-normal-g-u", transient) };
 }
 
 @binding-set builder-vim-source-view-normal-g-u
@@ -567,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, 0) };
+             "set-mode" ("vim-visual", permanent) };
   bind "<shift>e" { "movement" (previous-full-word-end, 1, 1, 0)
-                    "set-mode" ("vim-visual", permanent, 0) };
+                    "set-mode" ("vim-visual", permanent) };
   bind "g" { "movement" (first-line, 1, 1, 0)
-             "set-mode" ("vim-visual", permanent, 0) };
+             "set-mode" ("vim-visual", permanent) };
   bind "j" { "movement" (next-line, 1, 1, 0)
-             "set-mode" ("vim-visual", permanent, 0) };
+             "set-mode" ("vim-visual", permanent) };
   bind "m" { "movement" (middle-char, 1, 1, 0)
-             "set-mode" ("vim-visual", permanent, 0) };
+             "set-mode" ("vim-visual", permanent) };
 }
 
 @binding-set builder-vim-source-view-visual-line-g
 {
   bind "g" { "movement" (first-line, 1, 1, 0)
-             "set-mode" ("vim-visual-line", permanent, 1) };
+             "set-mode" ("vim-visual-line", permanent) };
   bind "j" { "movement" (next-line, 1, 1, 0)
-             "set-mode" ("vim-visual-line", permanent, 1) };
+             "set-mode" ("vim-visual-line", permanent) };
 }
 
 @binding-set builder-vim-source-view-insert
@@ -631,10 +631,10 @@
 
   bind "greater" { "indent-selection" (1)
                    "movement" (first-nonspace-char, 0, 1, 0)
-                   "set-mode" ("vim-normal", permanent, 0) };
+                   "set-mode" ("vim-normal", permanent) };
   bind "less" { "indent-selection" (-1)
                 "movement" (first-nonspace-char, 0, 1, 0)
-                "set-mode" ("vim-normal", permanent, 0) };
+                "set-mode" ("vim-normal", permanent) };
 
   bind "0" { "movement" (first-char, 1, 1, 0) };
   bind "<shift>asciicircum" { "movement" (first-nonspace-char, 1, 0, 0) };
@@ -658,10 +658,10 @@
                     "selection-theatric" (expand)
                     "clear-selection" ()
                     "movement" (last-char, 0, 1, 0)
-                    "set-mode" ("vim-normal", permanent, 0) };
+                    "set-mode" ("vim-normal", permanent) };
 
-  bind "g" { "set-mode" ("vim-visual-g", transient, 0) };
-  bind "z" { "set-mode" ("vim-visual-z", transient, 0) };
+  bind "g" { "set-mode" ("vim-visual-g", transient) };
+  bind "z" { "set-mode" ("vim-visual-z", transient) };
 }
 
 @binding-set builder-vim-source-view-visual-line
@@ -671,54 +671,54 @@
 
   /* just to be nice */
   bind "h" { "clear-selection" ()
-             "set-mode" ("vim-normal", permanent, 0) };
+             "set-mode" ("vim-normal", permanent) };
   bind "l" { "clear-selection" ()
-             "set-mode" ("vim-normal", permanent, 0) };
+             "set-mode" ("vim-normal", permanent) };
 
   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, 0) };
+  bind "z" { "set-mode" ("vim-visual-line-z", transient) };
 
   bind "x"        { "copy-clipboard" ()
                     "delete-selection" ()
                     "delete-from-cursor" (chars, 1)
-                    "set-mode" ("vim-normal", permanent, 0) };
+                    "set-mode" ("vim-normal", permanent) };
 
   bind "<shift>x" { "copy-clipboard" ()
                     "delete-selection" ()
                     "delete-from-cursor" (chars, 1)
-                    "set-mode" ("vim-normal", permanent, 0) };
+                    "set-mode" ("vim-normal", permanent) };
 
   bind "y"        { "copy-clipboard" ()
                     "selection-theatric" (expand)
                     "clear-selection" ()
-                    "set-mode" ("vim-normal", permanent, 0) };
+                    "set-mode" ("vim-normal", permanent) };
 
   bind "<shift>y" { "copy-clipboard" ()
                     "selection-theatric" (expand)
                     "clear-selection" ()
-                    "set-mode" ("vim-normal", permanent, 0) };
+                    "set-mode" ("vim-normal", permanent) };
 
   bind "<shift>j" { "join-lines" ()
                     "selection-theatric" (expand)
                     "clear-selection" ()
                     "movement" (last-char, 0, 1, 0)
-                    "set-mode" ("vim-normal", permanent, 0) };
+                    "set-mode" ("vim-normal", permanent) };
 
   bind "asciitilde" { "selection-theatric" (expand)
                       "change-case" (toggle)
                       "clear-selection" ()
-                      "set-mode" ("vim-normal", permanent, 0) };
+                      "set-mode" ("vim-normal", permanent) };
 
   bind "<shift>u" { "selection-theatric" (expand)
                     "change-case" (upper)
                     "clear-selection" ()
-                    "set-mode" ("vim-normal", permanent, 0) };
+                    "set-mode" ("vim-normal", permanent) };
   bind "u" { "selection-theatric" (expand)
              "change-case" (lower)
              "clear-selection" ()
-             "set-mode" ("vim-normal", permanent, 0) };
+             "set-mode" ("vim-normal", permanent) };
 
   bind "braceleft" { "movement" (paragraph-start, 1, 1, 1)
                      "movement" (last-char, 1, 1, 0) };
@@ -733,11 +733,11 @@
   bind "greater" { "indent-selection" (1)
                    "clear-selection" ()
                    "movement" (first-nonspace-char, 0, 1, 0)
-                   "set-mode" ("vim-normal", permanent, 0) };
+                   "set-mode" ("vim-normal", permanent) };
   bind "less" { "indent-selection" (-1)
                 "clear-selection" ()
                 "movement" (first-nonspace-char, 0, 1, 0)
-                "set-mode" ("vim-normal", permanent, 0) };
+                "set-mode" ("vim-normal", permanent) };
 
   bind "<ctrl>e" { "movement" (screen-up, 1, 0, 1) };
   bind "<ctrl>y" { "movement" (screen-down, 1, 0, 1) };
@@ -774,102 +774,162 @@
 
 IdeSourceViewMode.default,
 IdeSourceViewMode.vim-normal {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal;
 }
 
 IdeSourceViewMode.vim-normal-with-count {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal-with-count,
                     builder-vim-source-view-normal;
 }
 
 IdeSourceViewMode.vim-normal-c {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal-c;
 }
 
 IdeSourceViewMode.vim-normal-c-i {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal-c-i;
 }
 
 IdeSourceViewMode.vim-normal-d {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal-d;
 }
 
 IdeSourceViewMode.vim-normal-d-g {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal-d-g;
 }
 
 IdeSourceViewMode.vim-normal-d-i {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal-d-i;
 }
 
 IdeSourceViewMode.vim-normal-g {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal-g;
 }
 
 IdeSourceViewMode.vim-normal-g-u {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal-g-u;
 }
 
 IdeSourceViewMode.vim-normal-indent {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal-indent;
 }
 
 IdeSourceViewMode.vim-normal-y {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal-y;
 }
 
 IdeSourceViewMode.vim-normal-z {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-normal-z;
 }
 
 IdeSourceViewMode.vim-insert {
+  -IdeSourceViewMode-suppress-unbound: false;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-insert;
 }
 
 IdeSourceViewMode.vim-visual {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-visual;
 }
 
 IdeSourceViewMode.vim-visual-g {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-visual-g;
 }
 
 IdeSourceViewMode.vim-visual-z {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-visual-z;
 }
 
 IdeSourceViewMode.vim-visual-line {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-visual-line;
 }
 
 IdeSourceViewMode.vim-visual-line-g {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-visual-line-g;
 }
 
 IdeSourceViewMode.vim-visual-line-z {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view,
                     builder-vim-source-view-visual-line-z;
 }
 
 IdeSourceViewMode.vim-visual-block {
+  -IdeSourceViewMode-suppress-unbound: true;
+  -IdeSourceViewMode-coalesce-undo: true;
+
   gtk-key-bindings: builder-vim-source-view, builder-vim-source-view-visual-block;
 }
 
diff --git a/libide/ide-internal.h b/libide/ide-internal.h
index 5c282fb..3c9c849 100644
--- a/libide/ide-internal.h
+++ b/libide/ide-internal.h
@@ -67,8 +67,7 @@ gboolean           _ide_source_view_mode_do_event (IdeSourceViewMode     *mode,
                                                    gboolean              *remove);
 IdeSourceViewMode *_ide_source_view_mode_new      (GtkWidget             *view,
                                                    const char            *mode,
-                                                   IdeSourceViewModeType  type,
-                                                   gboolean               coalesce_undo);
+                                                   IdeSourceViewModeType  type);
 
 
 G_END_DECLS
diff --git a/libide/ide-source-view-mode.c b/libide/ide-source-view-mode.c
index bb571c3..f1d0099 100644
--- a/libide/ide-source-view-mode.c
+++ b/libide/ide-source-view-mode.c
@@ -20,6 +20,7 @@
 
 #include <glib/gi18n.h>
 
+#include "ide-debug.h"
 #include "ide-source-view.h"
 #include "ide-source-view-mode.h"
 
@@ -28,7 +29,6 @@ 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)
@@ -41,14 +41,47 @@ enum {
 
 static GParamSpec *gParamSpecs [LAST_PROP];
 
-gboolean
-ide_source_view_mode_get_coalesce_undo (IdeSourceViewMode *self)
+static void
+get_param (IdeSourceViewMode *self,
+           const gchar       *param,
+           GValue            *value)
 {
   IdeSourceViewModePrivate *priv = ide_source_view_mode_get_instance_private (self);
+  GtkStyleContext *context;
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self));
+
+  gtk_style_context_save (context);
+  gtk_style_context_add_class (context, priv->name);
+  gtk_style_context_get_style_property (context, param, value);
+  gtk_style_context_restore (context);
+}
 
-  g_return_val_if_fail (IDE_IS_SOURCE_VIEW_MODE (self), NULL);
+gboolean
+get_boolean_param (IdeSourceViewMode *self,
+                   const gchar       *param)
+{
+  GValue value = { 0 };
+  gboolean ret;
+
+  g_value_init (&value, G_TYPE_BOOLEAN);
+  get_param (self, param, &value);
+  ret = g_value_get_boolean (&value);
+  g_value_unset (&value);
 
-  return priv->coalesce_undo;
+  return ret;
+}
+
+gboolean
+ide_source_view_mode_get_coalesce_undo (IdeSourceViewMode *self)
+{
+  return get_boolean_param (self, "coalesce-undo");
+}
+
+gboolean
+ide_source_view_mode_get_suppress_unbound (IdeSourceViewMode *self)
+{
+  return get_boolean_param (self, "suppress-unbound");
 }
 
 static void
@@ -165,6 +198,23 @@ ide_source_view_mode_class_init (IdeSourceViewModeClass *klass)
                           (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_NAME, gParamSpecs [PROP_NAME]);
 
+  gtk_widget_class_install_style_property (GTK_WIDGET_CLASS (klass),
+                                           g_param_spec_boolean ("coalesce-undo",
+                                                                 _("Coalesce Undo"),
+                                                                 _("Coalesce Undo Items"),
+                                                                 FALSE,
+                                                                 (G_PARAM_READABLE |
+                                                                  G_PARAM_STATIC_STRINGS)));
+
+  gtk_widget_class_install_style_property (GTK_WIDGET_CLASS (klass),
+                                           g_param_spec_boolean ("suppress-unbound",
+                                                                 _("Supress Unbound"),
+                                                                 _("Suppress Unbound Keypresses"),
+                                                                 FALSE,
+                                                                 (G_PARAM_READABLE |
+                                                                  G_PARAM_STATIC_STRINGS)));
+
+
   /* Proxy all action signals from source view */
   type = IDE_TYPE_SOURCE_VIEW;
   while (type != G_TYPE_INVALID && type != GTK_TYPE_WIDGET)
@@ -237,6 +287,7 @@ _ide_source_view_mode_do_event (IdeSourceViewMode *mode,
 {
   IdeSourceViewModePrivate *priv = ide_source_view_mode_get_instance_private (mode);
   GtkStyleContext *context;
+  gboolean suppress_unbound;
   gboolean handled;
 
   g_return_val_if_fail (IDE_IS_SOURCE_VIEW_MODE (mode), FALSE);
@@ -245,6 +296,8 @@ _ide_source_view_mode_do_event (IdeSourceViewMode *mode,
 
   context = gtk_widget_get_style_context (GTK_WIDGET (mode));
 
+  suppress_unbound = ide_source_view_mode_get_suppress_unbound (mode);
+
   g_object_ref (context);
   gtk_style_context_save (context);
   gtk_style_context_add_class (context, priv->name);
@@ -272,6 +325,10 @@ _ide_source_view_mode_do_event (IdeSourceViewMode *mode,
       break;
 
     case IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT:
+      {
+        if (suppress_unbound)
+          handled = TRUE;
+      }
       break;
 
     case IDE_SOURCE_VIEW_MODE_TYPE_MODAL:
@@ -288,8 +345,7 @@ _ide_source_view_mode_do_event (IdeSourceViewMode *mode,
 IdeSourceViewMode *
 _ide_source_view_mode_new (GtkWidget             *view,
                            const char            *name,
-                           IdeSourceViewModeType  type,
-                           gboolean               coalesce_undo)
+                           IdeSourceViewModeType  type)
 {
   IdeSourceViewModePrivate *priv;
   IdeSourceViewMode *mode;
@@ -300,7 +356,9 @@ _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;
+
+  IDE_TRACE_MSG ("coalesce_undo = %d", ide_source_view_mode_get_coalesce_undo (mode));
+  IDE_TRACE_MSG ("supress_unbound = %d", ide_source_view_mode_get_suppress_unbound (mode));
 
   return g_object_ref_sink (mode);
 }
diff --git a/libide/ide-source-view-mode.h b/libide/ide-source-view-mode.h
index 52360dd..6a59746 100644
--- a/libide/ide-source-view-mode.h
+++ b/libide/ide-source-view-mode.h
@@ -46,8 +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);
+gboolean     ide_source_view_mode_get_suppress_unbound (IdeSourceViewMode *self);
+gboolean     ide_source_view_mode_get_coalesce_undo    (IdeSourceViewMode *self);
+const gchar *ide_source_view_mode_get_name             (IdeSourceViewMode *self);
 
 G_END_DECLS
 
diff --git a/libide/ide-source-view.c b/libide/ide-source-view.c
index bc1113a..7dc0097 100644
--- a/libide/ide-source-view.c
+++ b/libide/ide-source-view.c
@@ -157,8 +157,7 @@ static guint       gSignals [LAST_SIGNAL];
 
 static void ide_source_view_real_set_mode (IdeSourceView         *self,
                                            const gchar           *name,
-                                           IdeSourceViewModeType  type,
-                                           gboolean               coalesce_undo);
+                                           IdeSourceViewModeType  type);
 
 static void
 activate_action (GtkWidget   *widget,
@@ -941,6 +940,9 @@ ide_source_view_connect_buffer (IdeSourceView *self,
   ide_source_view__buffer_notify_language_cb (self, NULL, buffer);
   ide_source_view__buffer_notify_file_cb (self, NULL, buffer);
   ide_source_view__buffer_notify_highlight_diagnostics_cb (self, NULL, buffer);
+
+  if (priv->mode && ide_source_view_mode_get_coalesce_undo (priv->mode))
+    BEGIN_USER_ACTION (self);
 }
 
 static void
@@ -1428,7 +1430,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, FALSE);
+    ide_source_view_real_set_mode (self, NULL,  IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT);
 
   return ret;
 }
@@ -2113,38 +2115,48 @@ ide_source_view_real_selection_theatric (IdeSourceView         *self,
 static void
 ide_source_view_real_set_mode (IdeSourceView         *self,
                                const gchar           *mode,
-                               IdeSourceViewModeType  type,
-                               gboolean               coalesce_undo)
+                               IdeSourceViewModeType  type)
 {
   IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
 
   IDE_ENTRY;
-  IDE_TRACE_MSG ("mode (%s)", mode ?: "<default>");
 
   g_assert (IDE_IS_SOURCE_VIEW (self));
 
+#ifndef IDE_DISABLE_TRACE
+  {
+    const gchar *old_mode = "null";
+
+    if (priv->mode)
+      old_mode = ide_source_view_mode_get_name (priv->mode);
+    IDE_TRACE_MSG ("transition from mode (%s) to (%s)", old_mode, mode ?: "<default>");
+  }
+#endif
+
   if (priv->mode)
     {
-      if (ide_source_view_mode_get_coalesce_undo (priv->mode))
-        END_USER_ACTION (self);
+      IdeSourceViewMode *old_mode = g_object_ref (priv->mode);
+
       g_clear_object (&priv->mode);
+      if (ide_source_view_mode_get_coalesce_undo (old_mode))
+        END_USER_ACTION (self);
+      g_object_unref (old_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;
 
-  if (coalesce_undo)
-    BEGIN_USER_ACTION (self);
+  priv->mode = _ide_source_view_mode_new (GTK_WIDGET (self), mode, type);
 
-  priv->mode = _ide_source_view_mode_new (GTK_WIDGET (self), mode, type, coalesce_undo);
+  if (ide_source_view_mode_get_coalesce_undo (priv->mode))
+    BEGIN_USER_ACTION (self);
 
   IDE_EXIT;
 }
@@ -2377,8 +2389,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, NULL, IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT, FALSE);
+  ide_source_view_real_set_mode (self, NULL, IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT);
 
   /*
    * Completion does not have a way to retrieve visibility, so we need to track that ourselves
@@ -2417,6 +2428,34 @@ ide_source_view_constructed (GObject *object)
 }
 
 static void
+ide_source_view_real_undo (GtkSourceView *source_view)
+{
+  IdeSourceView *self = (IdeSourceView *)source_view;
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+  gboolean needs_unlock = !!priv->mode;
+
+  if (needs_unlock)
+    END_USER_ACTION (self);
+  GTK_SOURCE_VIEW_CLASS (ide_source_view_parent_class)->undo (source_view);
+  if (needs_unlock)
+    BEGIN_USER_ACTION (self);
+}
+
+static void
+ide_source_view_real_redo (GtkSourceView *source_view)
+{
+  IdeSourceView *self = (IdeSourceView *)source_view;
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+  gboolean needs_unlock = !!priv->mode;
+
+  if (needs_unlock)
+    END_USER_ACTION (self);
+  GTK_SOURCE_VIEW_CLASS (ide_source_view_parent_class)->redo (source_view);
+  if (needs_unlock)
+    BEGIN_USER_ACTION (self);
+}
+
+static void
 ide_source_view_dispose (GObject *object)
 {
   IdeSourceView *self = (IdeSourceView *)object;
@@ -2559,6 +2598,7 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkSourceViewClass *source_view_class = GTK_SOURCE_VIEW_CLASS (klass);
 
   object_class->constructed = ide_source_view_constructed;
   object_class->dispose = ide_source_view_dispose;
@@ -2569,6 +2609,9 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
   widget_class->key_press_event = ide_source_view_key_press_event;
   widget_class->query_tooltip = ide_source_view_query_tooltip;
 
+  source_view_class->undo = ide_source_view_real_undo;
+  source_view_class->redo = ide_source_view_real_redo;
+
   klass->action = ide_source_view_real_action;
   klass->append_to_count = ide_source_view_real_append_to_count;
   klass->auto_indent = ide_source_view_real_auto_indent;
@@ -2926,13 +2969,11 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
                   G_TYPE_FROM_CLASS (klass),
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (IdeSourceViewClass, set_mode),
-                  NULL, NULL,
-                  g_cclosure_marshal_generic,
+                  NULL, NULL, NULL,
                   G_TYPE_NONE,
-                  3,
+                  2,
                   G_TYPE_STRING,
-                  IDE_TYPE_SOURCE_VIEW_MODE_TYPE,
-                  G_TYPE_BOOLEAN);
+                  IDE_TYPE_SOURCE_VIEW_MODE_TYPE);
 
   gSignals [SET_OVERWRITE] =
     g_signal_new ("set-overwrite",
diff --git a/libide/ide-source-view.h b/libide/ide-source-view.h
index 280d3e5..5b1e4c2 100644
--- a/libide/ide-source-view.h
+++ b/libide/ide-source-view.h
@@ -237,8 +237,7 @@ struct _IdeSourceViewClass
                                        IdeSourceViewTheatric    theatric);
   void (*set_mode)                    (IdeSourceView           *self,
                                        const gchar             *mode,
-                                       IdeSourceViewModeType    type,
-                                       gboolean                 coalesce_undo);
+                                       IdeSourceViewModeType    type);
   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]