[gnome-builder] wip



commit 8be3f3b44a8d7b50e499941ed3d890fba3b1c1bc
Author: Christian Hergert <christian hergert me>
Date:   Wed Mar 18 15:20:55 2015 -0700

    wip

 configure.ac                                       |    6 +-
 {libide/trie => cut-n-paste}/trie.c                |    0
 {libide/trie => cut-n-paste}/trie.h                |    0
 data/data.mk                                       |    5 +-
 data/gsettings.mk                                  |    6 +-
 .../org.gnome.builder.editor.gschema.xml.in        |   23 +-
 ...rg.gnome.builder.editor.language.gschema.xml.in |    0
 .../org.gnome.builder.editor.vim.gschema.xml.in    |    0
 data/keybindings/default.css                       |   13 +
 data/keybindings/emacs.css                         |    4 +-
 data/keybindings/vim.css                           |   13 +-
 data/{styles => style-schemes}/builder-dark.xml    |    0
 data/{styles => style-schemes}/builder.xml         |    0
 {src/resources => data}/ui/gb-command-bar.ui       |    0
 data/ui/gb-editor-frame.ui                         |  112 +
 .../ui/gb-editor-settings-widget.ui                |    0
 .../ui/gb-editor-tweak-widget.ui                   |    8 +
 data/ui/gb-editor-view.ui                          |   56 +
 data/ui/gb-editor-workspace.ui                     |   12 +
 data/ui/gb-view-stack.ui                           |  301 +
 data/ui/gb-workbench.ui                            |   63 +
 libide/Makefile.am                                 |    5 +-
 libide/devhelp/ide-devhelp-search-provider.c       |  141 +-
 libide/git/ide-git-search-index.c                  |    8 +-
 libide/git/ide-git-search-provider.c               |    7 +
 libide/gsettings/ide-language-defaults.c           |   34 +-
 libide/ide-back-forward-item.c                     |   71 +-
 libide/ide-back-forward-list.c                     |    5 +-
 libide/ide-buffer-manager.c                        |   72 +-
 libide/ide-file.c                                  |    5 +
 libide/ide-log.c                                   |    2 +-
 libide/ide-search-context.c                        |   18 +-
 libide/ide-search-context.h                        |    3 +-
 libide/ide-search-reducer.c                        |    3 +-
 libide/ide.h                                       |    1 +
 src/animation/gb-animation.c                       | 1133 ----
 src/animation/gb-animation.h                       |   89 -
 src/animation/gb-frame-source.c                    |  134 -
 src/animation/gb-frame-source.h                    |   32 -
 src/app/gb-application-actions.c                   |  230 +
 .../gb-application-actions.h}                      |   25 +-
 .../gb-application-private.h}                      |   33 +-
 src/app/gb-application.c                           |  675 +--
 src/app/gb-application.h                           |   27 +-
 src/auto-indent/c-parse-helper.c                   |  255 -
 src/auto-indent/gb-source-auto-indenter-c.c        | 1486 -----
 src/auto-indent/gb-source-auto-indenter-c.h        |   56 -
 src/auto-indent/gb-source-auto-indenter-python.c   |  727 ---
 src/auto-indent/gb-source-auto-indenter-python.h   |   56 -
 src/auto-indent/gb-source-auto-indenter-xml.c      |  430 --
 src/auto-indent/gb-source-auto-indenter-xml.h      |   56 -
 src/auto-indent/gb-source-auto-indenter.c          |   98 -
 src/auto-indent/gb-source-auto-indenter.h          |   78 -
 .../gb-source-code-assistant-renderer.c            |  332 --
 .../gb-source-code-assistant-renderer.h            |   55 -
 src/code-assistant/gb-source-code-assistant.c      |  829 ---
 src/code-assistant/gb-source-code-assistant.h      |   60 -
 src/commands/gb-command-bar.c                      |   14 +-
 src/commands/gb-command-gaction-provider.c         |   12 +-
 src/commands/gb-command-provider.c                 |   34 +-
 src/commands/gb-command-provider.h                 |    4 +-
 src/commands/gb-command-vim-provider.c             |    4 +
 src/commands/gb-command-vim.c                      |   18 +-
 src/commands/gb-command.c                          |    2 +-
 src/credits/gb-credits-widget.c                    |  315 -
 src/credits/gb-credits-widget.h                    |   65 -
 src/dialogs/gb-close-confirmation-dialog.c         |  688 ---
 src/dialogs/gb-close-confirmation-dialog.h         |   64 -
 src/documents/gb-document-grid.c                   | 1001 ----
 src/documents/gb-document-grid.h                   |   77 -
 src/documents/gb-document-manager.c                |  352 --
 src/documents/gb-document-manager.h                |   76 -
 src/documents/gb-document-menu-button.c            |  698 ---
 src/documents/gb-document-menu-button.h            |   68 -
 src/documents/gb-document-stack.c                  | 1127 ----
 src/documents/gb-document-stack.h                  |   83 -
 src/documents/gb-document-view.c                   |  303 -
 src/documents/gb-document-view.h                   |   72 -
 src/documents/gb-document.c                        |   14 +-
 src/documents/gb-document.h                        |   14 +-
 src/editor/gb-editor-document.c                    | 1477 +-----
 src/editor/gb-editor-document.h                    |   62 +-
 src/editor/gb-editor-file-mark.c                   |  239 -
 src/editor/gb-editor-file-mark.h                   |   67 -
 src/editor/gb-editor-file-marks.c                  |  388 --
 src/editor/gb-editor-file-marks.h                  |   71 -
 src/editor/gb-editor-frame-actions.c               |   52 +
 .../gb-editor-frame-actions.h}                     |   25 +-
 src/editor/gb-editor-frame-private.h               |   44 +-
 src/editor/gb-editor-frame.c                       | 1627 +-----
 src/editor/gb-editor-frame.h                       |   36 +-
 src/editor/gb-editor-navigation-item.c             |  257 -
 src/editor/gb-editor-navigation-item.h             |   63 -
 src/editor/gb-editor-settings-widget.c             |   16 +-
 src/editor/gb-editor-tweak-widget.c                |   57 +-
 src/editor/gb-editor-tweak-widget.h                |   29 +-
 src/editor/gb-editor-view-actions.c                |  271 +
 .../gb-editor-view-actions.h}                      |   25 +-
 .../gb-editor-view-private.h}                      |   37 +-
 src/editor/gb-editor-view.c                        | 1120 +----
 src/editor/gb-editor-view.h                        |   47 +-
 .../gb-editor-workspace-actions.c}                 |   29 +-
 .../gb-editor-workspace-actions.h}                 |   25 +-
 .../gb-editor-workspace-private.h}                 |   27 +-
 src/editor/gb-editor-workspace.c                   |  470 +--
 src/editor/gb-editor-workspace.h                   |   32 +-
 src/editor/gb-source-change-gutter-renderer.c      |  210 -
 src/editor/gb-source-change-gutter-renderer.h      |   55 -
 src/editor/gb-source-change-monitor.c              |  905 ---
 src/editor/gb-source-change-monitor.h              |   71 -
 src/editor/gb-source-formatter.c                   |    8 +-
 src/editor/gb-source-search-highlighter.c          |  369 --
 src/editor/gb-source-search-highlighter.h          |   64 -
 src/editor/gb-source-view.c                        | 2496 --------
 src/editor/gb-source-view.h                        |   99 -
 src/emacs/gb-source-emacs.c                        | 1365 -----
 src/emacs/gb-source-emacs.h                        |   65 -
 src/fuzzy/fuzzy.c                                  |  548 --
 src/fuzzy/fuzzy.h                                  |   55 -
 src/gca/gca-diagnostics.c                          | 1039 ----
 src/gca/gca-diagnostics.h                          |  170 -
 src/gca/gca-diagnostics.xml                        |    9 -
 src/gca/gca-service.c                              | 1291 ----
 src/gca/gca-service.h                              |  209 -
 src/gca/gca-service.xml                            |   16 -
 src/gca/gca-structs.c                              |  107 -
 src/gca/gca-structs.h                              |   67 -
 src/git/gb-git-search-provider.c                   |  539 --
 src/git/gb-git-search-provider.h                   |   61 -
 src/gnome-builder.mk                               |  222 +-
 src/html/gb-html-view.c                            |    6 +-
 src/keybindings/gb-keybindings.c                   |  311 +-
 src/keybindings/gb-keybindings.h                   |   45 +-
 src/log/gb-log.c                                   |  206 -
 src/log/gb-log.h                                   |   77 -
 src/main.c                                         |    5 +-
 src/navigation/gb-navigation-item.c                |  236 -
 src/navigation/gb-navigation-item.h                |   65 -
 src/navigation/gb-navigation-list.c                |  315 -
 src/navigation/gb-navigation-list.h                |   68 -
 src/preferences/gb-preferences-page-editor.c       |   53 +-
 src/preferences/gb-preferences-page-emacs.c        |   11 +-
 src/preferences/gb-preferences-page-vim.c          |   20 +-
 src/preferences/gb-preferences-page.c              |    2 +-
 src/preferences/gb-preferences-window.c            |    8 +-
 src/resources/css/builder.Adwaita.css              |   13 +-
 src/resources/gnome-builder.gresource.xml          |   25 +-
 src/resources/gtk/menus.ui                         |    6 +-
 src/resources/keybindings/default.ini              |   42 -
 src/resources/keybindings/vim.ini                  |   41 -
 src/resources/language/defaults.ini                |   74 -
 src/resources/ui/gb-editor-frame.ui                |  112 -
 src/resources/ui/gb-editor-view.ui                 |  224 -
 src/resources/ui/gb-editor-workspace.ui            |   55 -
 src/resources/ui/gb-preferences-page-editor.ui     |   59 +-
 src/resources/ui/gb-preferences-page-emacs.ui      |    2 +
 src/resources/ui/gb-preferences-page-vim.ui        |    2 +
 src/search/gb-search-box.c                         |  258 +-
 src/search/gb-search-box.h                         |   35 +-
 src/search/gb-search-context.c                     |  207 -
 src/search/gb-search-context.h                     |   75 -
 src/search/gb-search-display-group.c               |  193 +-
 src/search/gb-search-display-group.h               |   51 +-
 src/search/gb-search-display-row.c                 |   64 +-
 src/search/gb-search-display-row.h                 |   33 +-
 src/search/gb-search-display.c                     |  369 +-
 src/search/gb-search-display.h                     |   39 +-
 src/search/gb-search-manager.c                     |  130 -
 src/search/gb-search-manager.h                     |   59 -
 src/search/gb-search-provider.c                    |   93 -
 src/search/gb-search-provider.h                    |   68 -
 src/search/gb-search-reducer.c                     |   98 -
 src/search/gb-search-reducer.h                     |   49 -
 src/search/gb-search-result.c                      |  266 -
 src/search/gb-search-result.h                      |   62 -
 src/search/gb-search-types.h                       |   72 -
 src/snippets/gb-source-snippet-chunk.c             |  355 --
 src/snippets/gb-source-snippet-chunk.h             |   74 -
 src/snippets/gb-source-snippet-completion-item.c   |  182 -
 src/snippets/gb-source-snippet-completion-item.h   |   61 -
 .../gb-source-snippet-completion-provider.c        |  377 --
 .../gb-source-snippet-completion-provider.h        |   60 -
 src/snippets/gb-source-snippet-context.c           |  725 ---
 src/snippets/gb-source-snippet-context.h           |   72 -
 src/snippets/gb-source-snippet-parser.c            |  618 --
 src/snippets/gb-source-snippet-parser.h            |   60 -
 src/snippets/gb-source-snippet-private.h           |   57 -
 src/snippets/gb-source-snippet.c                   | 1099 ----
 src/snippets/gb-source-snippet.h                   |   83 -
 src/snippets/gb-source-snippets-manager.c          |  231 -
 src/snippets/gb-source-snippets-manager.h          |   62 -
 src/snippets/gb-source-snippets.c                  |  171 -
 src/snippets/gb-source-snippets.h                  |   67 -
 src/theatrics/gb-box-theatric.c                    |  336 --
 src/theatrics/gb-box-theatric.h                    |   55 -
 src/tree/gb-tree.c                                 |   34 +-
 src/trie/trie.c                                    |  812 ---
 src/trie/trie.h                                    |   52 -
 src/util/gb-widget.c                               |  104 +-
 src/util/gb-widget.h                               |   43 +-
 src/views/gb-view-grid.c                           |  631 ++
 src/views/gb-view-grid.h                           |   48 +
 src/views/gb-view-stack-actions.c                  |  125 +
 src/views/gb-view-stack-actions.h                  |   30 +
 src/views/gb-view-stack-private.h                  |   49 +
 src/views/gb-view-stack.c                          |  409 ++
 src/views/gb-view-stack.h                          |   43 +
 src/views/gb-view.c                                |  240 +
 src/views/gb-view.h                                |   50 +
 src/vim/gb-source-vim.c                            | 6152 --------------------
 src/vim/gb-source-vim.h                            |  116 -
 src/workbench/gb-workbench-actions.c               |   81 +
 .../gb-workbench-actions.h}                        |   25 +-
 src/workbench/gb-workbench-private.h               |   60 +
 src/workbench/gb-workbench-types.h                 |    9 +-
 src/workbench/gb-workbench.c                       | 1100 +---
 src/workbench/gb-workbench.h                       |   43 +-
 src/workbench/gb-workspace.c                       |   76 +-
 src/workbench/gb-workspace.h                       |   25 +-
 tests/test-navigation-list.c                       |   58 -
 tests/tests.mk                                     |   13 +-
 tools/ide-search.c                                 |    2 +-
 222 files changed, 4978 insertions(+), 44132 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index bf364b1..d7d22cb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -71,9 +71,9 @@ AC_CONFIG_FILES([
        src/util/gb-version.h
        data/icons/Makefile
        data/libide-1.0.pc
-       data/org.gnome.builder.editor.gschema.xml
-       data/org.gnome.builder.editor.language.gschema.xml
-       data/org.gnome.builder.editor.vim.gschema.xml
+       data/gsettings/org.gnome.builder.editor.gschema.xml
+       data/gsettings/org.gnome.builder.editor.language.gschema.xml
+       data/gsettings/org.gnome.builder.editor.vim.gschema.xml
        po/Makefile.in
 ])
 
diff --git a/libide/trie/trie.c b/cut-n-paste/trie.c
similarity index 100%
rename from libide/trie/trie.c
rename to cut-n-paste/trie.c
diff --git a/libide/trie/trie.h b/cut-n-paste/trie.h
similarity index 100%
rename from libide/trie/trie.h
rename to cut-n-paste/trie.h
diff --git a/data/data.mk b/data/data.mk
index ac6d9ee..5c0816f 100644
--- a/data/data.mk
+++ b/data/data.mk
@@ -16,7 +16,10 @@ CLEANFILES += $(service_DATA)
 
 # GtkSourceView Style Scheme
 styledir = $(datadir)/gtksourceview-3.0/styles/
-style_DATA = data/styles/builder.xml data/styles/builder-dark.xml
+style_DATA = \
+       data/style-schemes/builder.xml \
+       data/style-schemes/builder-dark.xml \
+       $(NULL)
 EXTRA_DIST += $(style_DATA)
 
 data/org.gnome.Builder.service: data/org.gnome.Builder.service.in
diff --git a/data/gsettings.mk b/data/gsettings.mk
index fbd3e0b..f8c7dda 100644
--- a/data/gsettings.mk
+++ b/data/gsettings.mk
@@ -1,7 +1,7 @@
 gsettingsschema_in_files = \
-       data/org.gnome.builder.editor.gschema.xml.in \
-       data/org.gnome.builder.editor.vim.gschema.xml.in \
-       data/org.gnome.builder.editor.language.gschema.xml.in
+       data/gsettings/org.gnome.builder.editor.gschema.xml.in \
+       data/gsettings/org.gnome.builder.editor.vim.gschema.xml.in \
+       data/gsettings/org.gnome.builder.editor.language.gschema.xml.in
 
 gsettings_SCHEMAS = $(gsettingsschema_in_files:.xml.in=.xml)
 .PRECIOUS: $(gsettings_SCHEMAS)
diff --git a/data/org.gnome.builder.editor.gschema.xml.in 
b/data/gsettings/org.gnome.builder.editor.gschema.xml.in
similarity index 82%
rename from data/org.gnome.builder.editor.gschema.xml.in
rename to data/gsettings/org.gnome.builder.editor.gschema.xml.in
index 55cdcbc..2730295 100644
--- a/data/org.gnome.builder.editor.gschema.xml.in
+++ b/data/gsettings/org.gnome.builder.editor.gschema.xml.in
@@ -1,14 +1,12 @@
 <schemalist>
   <schema id="org.gnome.builder.editor" path="/org/gnome/builder/editor/" gettext-domain="gnome-builder">
-    <key name="vim-mode" type="b">
-      <default>false</default>
-      <summary>Enable VIM keybindings</summary>
-      <description>Whether or not VIM style keybindings should be used in the source code 
editor.</description>
-    </key>
-    <key name="emacs-mode" type="b">
-      <default>false</default>
-      <summary>Enable EMACS keybindings</summary>
-      <description>Whether or not EMACS style keybindings should be used in the source code 
editor.</description>
+    <key name="keybindings" type="s">
+      <choices>
+        <choice value="default"/>
+        <choice value="emacs"/>
+        <choice value="vim"/>
+      </choices>
+      <default>'default'</default>
     </key>
     <key name="restore-insert-mark" type="b">
       <default>true</default>
@@ -21,7 +19,7 @@
       <summary>Enable auto-completion of words in document.</summary>
       <description>If enabled, words within the current document will be available for 
auto-completion.</description>
     </key>
-    <key name="show-diff" type="b">
+    <key name="show-line-changes" type="b">
       <default>true</default>
       <summary>Show modified lines.</summary>
       <description>If enabled, the editor will show line additions and changes next to the source 
code.</description>
@@ -41,6 +39,11 @@
       <summary>Show line numbers.</summary>
       <description>If enabled, the editor will show line numbers.</description>
     </key>
+    <key name="smart-backspace" type="b">
+      <default>true</default>
+      <summary>Smart backspace.</summary>
+      <description>Backspace will remove additional spaces to keep you aligned to the indentation 
size.</description>
+    </key>
     <key name="smart-home-end" type="b">
       <default>true</default>
       <summary>Smart home end.</summary>
diff --git a/data/org.gnome.builder.editor.language.gschema.xml.in 
b/data/gsettings/org.gnome.builder.editor.language.gschema.xml.in
similarity index 100%
rename from data/org.gnome.builder.editor.language.gschema.xml.in
rename to data/gsettings/org.gnome.builder.editor.language.gschema.xml.in
diff --git a/data/org.gnome.builder.editor.vim.gschema.xml.in 
b/data/gsettings/org.gnome.builder.editor.vim.gschema.xml.in
similarity index 100%
rename from data/org.gnome.builder.editor.vim.gschema.xml.in
rename to data/gsettings/org.gnome.builder.editor.vim.gschema.xml.in
diff --git a/data/keybindings/default.css b/data/keybindings/default.css
new file mode 100644
index 0000000..ad33511
--- /dev/null
+++ b/data/keybindings/default.css
@@ -0,0 +1,13 @@
+
+ binding-set default-ide-source-view
+{
+  bind "<ctrl>comma" { "action" ("app", "preferences", "") };
+  bind "<ctrl>f" { "action" ("frame", "find", "") };
+  bind "<ctrl>period" { "action" ("workbench", "global-search", "") };
+  bind "<ctrl>s" { "action" ("editor-view", "save", "") };
+}
+
+IdeSourceViewMode.default {
+  gtk-key-bindings: default-ide-source-view;
+}
+
diff --git a/data/keybindings/emacs.css b/data/keybindings/emacs.css
index 27cb9ef..6c8b0e4 100644
--- a/data/keybindings/emacs.css
+++ b/data/keybindings/emacs.css
@@ -50,7 +50,7 @@
   bind "<ctrl>underscore" { "undo" () };
   bind "<alt>x" { "action" ("win", "show-command-bar", "") };
   bind "<ctrl>s" { "action" ("editor-frame", "find", "") };
-  bind "<ctrl>period" { "action" ("win", "global-search", "") };
+  bind "<ctrl>period" { "action" ("workbench", "global-search", "") };
   bind "<ctrl>comma" { "action" ("app", "preferences", "") };
   bind "<alt>n" { "move-error" (down) };
   bind "<alt>p" { "move-error" (up) };
@@ -77,7 +77,7 @@
   bind "0" { "action" ("stack", "close", "") };
   bind "k" { "action" ("stack", "close", "") };
   bind "<ctrl>f" { "action" ("workspace", "open", "") };
-  bind "<ctrl>s" { "action" ("stack", "save", "") };
+  bind "<ctrl>s" { "action" ("editor-view", "save", "") };
   bind "s" { "action" ("win", "save-all", "") };
   bind "b" { "action" ("workspace", "new-document", "") };
   bind "<ctrl>w" { "action" ("stack", "save-as", "") };
diff --git a/data/keybindings/vim.css b/data/keybindings/vim.css
index 5cbaf93..a40dcf7 100644
--- a/data/keybindings/vim.css
+++ b/data/keybindings/vim.css
@@ -88,6 +88,10 @@
                              "clear-selection" ()
                              "clear-snippets" ()
                              "set-mode" ("vim-normal", permanent) };
+
+  bind "<ctrl>comma" { "action" ("app", "preferences", "") };
+  bind "<ctrl>period" { "action" ("workbench", "global-search", "") };
+  bind "<ctrl>s" { "action" ("editor-view", "save", "") };
 }
 
 @binding-set builder-vim-source-view-normal-with-count
@@ -124,6 +128,9 @@
   /* replay the last recording */
   bind "period" { "replay-macro" (1) };
 
+  /* start search */
+  bind "slash" { "action" ("frame", "find", "") };
+
   /* insert at cursor */
   bind "i" { "begin-macro" ()
              "set-mode" ("vim-insert", permanent) };
@@ -323,9 +330,13 @@
                    "clear-selection" () };
 
   bind "p" { "begin-macro" ()
+             "save-insert-mark" ()
              "paste-clipboard-extended" (1, 1, 1)
              "clear-count" ()
-             "end-macro" () };
+             "restore-insert-mark" ()
+             "end-macro" ()
+             "movement" (next-line, 0, 0, 0)
+             "movement" (first-nonspace-char, 0, 1, 0) };
   bind "<shift>p" { "begin-macro" ()
                     "paste-clipboard-extended" (1, 0, 1)
                     "clear-count" ()
diff --git a/data/styles/builder-dark.xml b/data/style-schemes/builder-dark.xml
similarity index 100%
rename from data/styles/builder-dark.xml
rename to data/style-schemes/builder-dark.xml
diff --git a/data/styles/builder.xml b/data/style-schemes/builder.xml
similarity index 100%
rename from data/styles/builder.xml
rename to data/style-schemes/builder.xml
diff --git a/src/resources/ui/gb-command-bar.ui b/data/ui/gb-command-bar.ui
similarity index 100%
rename from src/resources/ui/gb-command-bar.ui
rename to data/ui/gb-command-bar.ui
diff --git a/data/ui/gb-editor-frame.ui b/data/ui/gb-editor-frame.ui
new file mode 100644
index 0000000..288a0ff
--- /dev/null
+++ b/data/ui/gb-editor-frame.ui
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.15 -->
+  <template class="GbEditorFrame" parent="GtkBin">
+    <child>
+      <object class="GtkOverlay">
+        <property name="expand">true</property>
+        <property name="visible">true</property>
+        <child type="overlay">
+          <object class="NautilusFloatingBar" id="floating_bar">
+            <property name="halign">end</property>
+            <property name="primary_label"></property>
+            <property name="valign">end</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+        <child type="overlay">
+          <object class="GtkRevealer" id="search_revealer">
+            <property name="halign">end</property>
+            <property name="valign">start</property>
+            <property name="visible">true</property>
+            <property name="width-request">300</property>
+            <child>
+              <object class="GtkFrame">
+                <property name="visible">true</property>
+                <property name="margin-end">12</property>
+                <style>
+                  <class name="gb-search-slider"/>
+                </style>
+                <child>
+                  <object class="GtkBox">
+                    <property name="orientation">horizontal</property>
+                    <property name="visible">true</property>
+                    <style>
+                      <class name="linked"/>
+                    </style>
+                    <child>
+                      <object class="GdTaggedEntry" id="search_entry">
+                        <property name="visible">true</property>
+                        <property name="tag-close-visible">false</property>
+                        <property name="can-focus">true</property>
+                        <property name="width-request">260</property>
+                        <property name="primary-icon-activatable">true</property>
+                        <property name="primary-icon-sensitive">true</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkButton">
+                        <property name="visible">true</property>
+                        <property name="can-focus">false</property>
+                        <style>
+                          <class name="image-button"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="icon-name">go-up-symbolic</property>
+                            <property name="icon-size">1</property>
+                            <property name="visible">true</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkButton">
+                        <property name="visible">true</property>
+                        <property name="can-focus">false</property>
+                        <style>
+                          <class name="image-button"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="icon-name">go-down-symbolic</property>
+                            <property name="icon-size">1</property>
+                            <property name="visible">true</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow" id="scrolled_window">
+            <property name="visible">true</property>
+            <child>
+              <object class="IdeSourceView" id="source_view">
+                <property name="auto-indent">true</property>
+                <property name="enable-word-completion">true</property>
+                <property name="highlight-current-line">true</property>
+                <property name="insert-matching-brace">true</property>
+                <property name="overwrite-braces">true</property>
+                <property name="scroll-offset">0</property>
+                <property name="show-grid-lines">true</property>
+                <property name="show-line-changes">true</property>
+                <property name="show-line-numbers">true</property>
+                <property name="show-right-margin">true</property>
+                <property name="show-search-bubbles">true</property>
+                <property name="show-search-shadow">true</property>
+                <property name="smart-backspace">true</property>
+                <property name="snippet-completion">true</property>
+                <property name="visible">true</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/resources/ui/gb-editor-settings-widget.ui b/data/ui/gb-editor-settings-widget.ui
similarity index 100%
rename from src/resources/ui/gb-editor-settings-widget.ui
rename to data/ui/gb-editor-settings-widget.ui
diff --git a/src/resources/ui/gb-editor-tweak-widget.ui b/data/ui/gb-editor-tweak-widget.ui
similarity index 95%
rename from src/resources/ui/gb-editor-tweak-widget.ui
rename to data/ui/gb-editor-tweak-widget.ui
index f08e201..0e5ee49 100644
--- a/src/resources/ui/gb-editor-tweak-widget.ui
+++ b/data/ui/gb-editor-tweak-widget.ui
@@ -84,6 +84,14 @@
               </object>
             </child>
             <child>
+              <object class="GtkModelButton">
+                <property name="visible">true</property>
+                <property name="text" translatable="yes">Smart Backspace</property>
+                <property name="halign">fill</property>
+                <property name="action-name">editor-view.smart-backspace</property>
+              </object>
+            </child>
+            <child>
               <object class="GtkLabel">
                 <property name="visible">true</property>
                 <property name="label" translatable="yes">Indentation</property>
diff --git a/data/ui/gb-editor-view.ui b/data/ui/gb-editor-view.ui
new file mode 100644
index 0000000..d62ab1b
--- /dev/null
+++ b/data/ui/gb-editor-view.ui
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.15 -->
+  <template class="GbEditorView" parent="GbView">
+    <child>
+      <object class="GtkOverlay">
+        <property name="visible">true</property>
+        <child type="overlay">
+          <object class="GtkProgressBar" id="progress_bar">
+            <property name="halign">fill</property>
+            <property name="orientation">horizontal</property>
+            <property name="valign">start</property>
+            <property name="visible">false</property>
+            <style>
+              <class name="osd"/>
+            </style>
+          </object>
+        </child>
+        <child>
+          <object class="GtkPaned" id="paned">
+            <property name="expand">true</property>
+            <property name="visible">true</property>
+            <child>
+              <object class="GbEditorFrame" id="frame1">
+                <property name="visible">true</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child internal-child="controls">
+      <object class="GtkBox">
+        <child>
+          <object class="GtkMenuButton" id="tweak_button">
+            <property name="popover">popover</property>
+            <property name="visible">true</property>
+            <style>
+              <class name="dim-label"/>
+              <class name="text-button"/>
+              <class name="flat"/>
+            </style>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+  <object class="GtkPopover" id="popover">
+    <child>
+      <object class="GbEditorTweakWidget" id="tweak_widget">
+        <property name="border-width">12</property>
+        <property name="visible">true</property>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/data/ui/gb-editor-workspace.ui b/data/ui/gb-editor-workspace.ui
new file mode 100644
index 0000000..2fa83b4
--- /dev/null
+++ b/data/ui/gb-editor-workspace.ui
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.15 -->
+  <template class="GbEditorWorkspace" parent="GbWorkspace">
+    <child>
+      <object class="GbViewGrid" id="view_grid">
+        <property name="expand">true</property>
+        <property name="visible">true</property>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/data/ui/gb-view-stack.ui b/data/ui/gb-view-stack.ui
new file mode 100644
index 0000000..f78ee10
--- /dev/null
+++ b/data/ui/gb-view-stack.ui
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.15 -->
+  <template class="GbViewStack" parent="GtkBin">
+    <child>
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
+        <property name="visible">true</property>
+        <child>
+          <object class="GtkBox">
+            <property name="orientation">horizontal</property>
+            <property name="visible">true</property>
+            <style>
+              <class name="notebook"/>
+              <class name="header"/>
+            </style>
+            <child>
+              <object class="GtkBox">
+                <property name="orientation">horizontal</property>
+                <property name="visible">true</property>
+                <property name="margin-bottom">3</property>
+                <property name="margin-end">6</property>
+                <property name="margin-start">6</property>
+                <property name="margin-top">3</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="orientation">horizontal</property>
+                    <property name="visible">true</property>
+                    <style>
+                      <class name="linked"/>
+                    </style>
+                    <child>
+                      <object class="GtkButton" id="go_backward">
+                        <property name="visible">true</property>
+                        <property name="action-name">navigation.go-backward</property>
+                        <style>
+                          <class name="flat"/>
+                          <class name="image-button"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="icon-name">go-previous-symbolic</property>
+                            <property name="visible">true</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="go_forward">
+                        <property name="visible">true</property>
+                        <property name="action-name">navigation.go-forkward</property>
+                        <style>
+                          <class name="flat"/>
+                          <class name="image-button"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="icon-name">go-next-symbolic</property>
+                            <property name="visible">true</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="center">
+                  <object class="GtkMenuButton">
+                    <property name="hexpand">true</property>
+                    <property name="popover">popover</property>
+                    <property name="visible">true</property>
+                    <style>
+                      <class name="dim-label"/>
+                      <class name="flat"/>
+                      <class name="text-button"/>
+                    </style>
+                    <child>
+                      <object class="GtkLabel" id="title_label">
+                        <property name="visible">true</property>
+                        <property name="width-chars">40</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkButton">
+                    <property name="visible">true</property>
+                    <style>
+                      <class name="dim-label"/>
+                      <class name="image-button"/>
+                      <class name="flat"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">true</property>
+                        <property name="icon-name">window-close-symbolic</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="pack-type">end</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkStack" id="controls_stack">
+                    <property name="visible">true</property>
+                  </object>
+                  <packing>
+                    <property name="pack-type">end</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkStack" id="stack">
+            <property name="hexpand">true</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+  <object class="GtkPopover" id="popover">
+    <child>
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
+        <property name="spacing">12</property>
+        <property name="visible">true</property>
+        <property name="margin-start">6</property>
+        <property name="margin-end">6</property>
+        <property name="margin-top">12</property>
+        <property name="margin-bottom">12</property>
+        <child>
+          <object class="GtkBox">
+            <property name="margin-end">12</property>
+            <property name="margin-start">12</property>
+            <property name="spacing">6</property>
+            <property name="visible">true</property>
+            <child>
+              <object class="GtkLabel" id="split_label">
+                <property name="label" translatable="yes">Split</property>
+                <property name="visible">true</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">true</property>
+                <property name="margin-start">6</property>
+                <style>
+                  <class name="linked"/>
+                </style>
+                <child>
+                  <object class="GtkButton">
+                    <property name="visible">true</property>
+                    <property name="action-name">view.split-left</property>
+                    <style>
+                      <class name="image-button"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">true</property>
+                        <property name="icon-name">builder-split-left-symbolic</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkButton">
+                    <property name="visible">true</property>
+                    <property name="action-name">view.split-right</property>
+                    <style>
+                      <class name="image-button"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">true</property>
+                        <property name="icon-name">builder-split-right-symbolic</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkButton">
+                <property name="visible">true</property>
+                <property name="action-name">view.split-down</property>
+                <style>
+                  <class name="image-button"/>
+                </style>
+                <child>
+                  <object class="GtkImage">
+                    <property name="visible">true</property>
+                    <property name="icon-name">builder-split-tab-symbolic</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="margin-end">12</property>
+            <property name="margin-start">12</property>
+            <property name="spacing">6</property>
+            <property name="visible">true</property>
+            <child>
+              <object class="GtkLabel" id="move_label">
+                <property name="visible">true</property>
+                <property name="label" translatable="yes">Move</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkBox">
+                <property name="hexpand">true</property>
+                <property name="margin-start">6</property>
+                <property name="visible">true</property>
+                <style>
+                  <class name="linked"/>
+                </style>
+                <child>
+                  <object class="GtkButton">
+                    <property name="action-name">view.move-left</property>
+                    <property name="hexpand">true</property>
+                    <property name="visible">true</property>
+                    <style>
+                      <class name="image-button"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">true</property>
+                        <property name="icon-name">builder-move-left-symbolic</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkButton">
+                    <property name="action-name">view.move-right</property>
+                    <property name="hexpand">true</property>
+                    <property name="visible">true</property>
+                    <style>
+                      <class name="image-button"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">true</property>
+                        <property name="icon-name">builder-move-right-symbolic</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="orientation">vertical</property>
+            <property name="visible">true</property>
+            <child>
+              <object class="GtkModelButton">
+                <property name="action-name">view.save</property>
+                <property name="halign">fill</property>
+                <property name="hexpand">true</property>
+                <property name="text" translatable="yes">Save</property>
+                <property name="visible">true</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkModelButton">
+                <property name="action-name">view.save-as</property>
+                <property name="halign">fill</property>
+                <property name="hexpand">true</property>
+                <property name="text" translatable="yes">Save As</property>
+                <property name="visible">true</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkModelButton">
+            <property name="halign">fill</property>
+            <property name="hexpand">true</property>
+            <property name="action-name">view.close</property>
+            <property name="text" translatable="yes">Close</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkSizeGroup">
+    <property name="mode">horizontal</property>
+    <widgets>
+      <widget name="split_label"/>
+      <widget name="move_label"/>
+    </widgets>
+  </object>
+</interface>
diff --git a/data/ui/gb-workbench.ui b/data/ui/gb-workbench.ui
new file mode 100644
index 0000000..fe76192
--- /dev/null
+++ b/data/ui/gb-workbench.ui
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.15 -->
+  <template class="GbWorkbench" parent="GtkApplicationWindow">
+    <property name="icon-name">builder</property>
+    <child type="titlebar">
+      <object class="GtkHeaderBar">
+        <property name="visible">true</property>
+        <property name="show_close_button">true</property>
+        <child type="title">
+          <object class="GbSearchBox" id="search_box">
+            <property name="margin-end">6</property>
+            <property name="margin-start">6</property>
+            <property name="visible">true</property>
+            <property name="width_request">540</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkMenuButton" id="gear_menu_button">
+            <property name="visible">true</property>
+            <style>
+              <class name="image-button"/>
+            </style>
+            <child>
+              <object class="GtkImage">
+                <property name="icon_name">open-menu-symbolic</property>
+                <property name="valign">baseline</property>
+                <property name="visible">true</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="pack_type">end</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
+        <property name="visible">true</property>
+        <child>
+          <object class="GtkStack" id="stack">
+            <property name="expand">true</property>
+            <property name="transition_type">slide-up-down</property>
+            <property name="visible">true</property>
+            <child>
+              <object class="GbEditorWorkspace" id="editor_workspace">
+                <property name="visible">true</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GbCommandBar" id="command_bar">
+            <property name="transition-type">slide-up</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 7e4fcce..fb95204 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -180,6 +180,8 @@ libide_1_0_la_public_sources = \
 
 libide_1_0_la_SOURCES = \
        $(libide_1_0_la_public_sources) \
+       cut-n-paste/trie.c \
+       cut-n-paste/trie.h \
        libide/autotools/ide-makecache.c \
        libide/autotools/ide-makecache.h \
        libide/c/c-parse-helper.c \
@@ -249,8 +251,6 @@ libide_1_0_la_SOURCES = \
        libide/theatrics/ide-box-theatric.h \
        libide/theatrics/ide-frame-source.c \
        libide/theatrics/ide-frame-source.h \
-       libide/trie/trie.c \
-       libide/trie/trie.h \
        libide/util/ide-cairo.c \
        libide/util/ide-cairo.h \
        libide/util/ide-pango.c \
@@ -260,6 +260,7 @@ libide_1_0_la_SOURCES = \
        $(NULL)
 
 libide_1_0_la_includes = \
+       -I$(top_srcdir)/cut-n-paste \
        -I$(top_srcdir)/libide \
        -I$(top_srcdir)/libide/autotools \
        -I$(top_srcdir)/libide/c \
diff --git a/libide/devhelp/ide-devhelp-search-provider.c b/libide/devhelp/ide-devhelp-search-provider.c
index 084213c..af9ec9d 100644
--- a/libide/devhelp/ide-devhelp-search-provider.c
+++ b/libide/devhelp/ide-devhelp-search-provider.c
@@ -28,93 +28,72 @@
 #include "ide-search-result.h"
 #include "ide-search-context.h"
 
-typedef struct
-{
-  DhBookManager  *book_manager;
-  DhKeywordModel *keywords_model;
-} IdeDevhelpSearchProviderPrivate;
-
 struct _IdeDevhelpSearchProvider
 {
-  IdeSearchProvider                parent;
+  IdeSearchProvider  parent;
 
-  /*< private >*/
-  IdeDevhelpSearchProviderPrivate *priv;
+  DhBookManager     *book_manager;
+  DhKeywordModel    *keywords_model;
 };
 
-typedef struct
-{
-  IdeSearchContext *context;
-  gchar            *search_terms;
-  gsize             max_results;
-} PopulateState;
-
-G_DEFINE_TYPE_WITH_PRIVATE (IdeDevhelpSearchProvider,
-                            ide_devhelp_search_provider,
-                            IDE_TYPE_SEARCH_PROVIDER)
+G_DEFINE_TYPE (IdeDevhelpSearchProvider, ide_devhelp_search_provider, IDE_TYPE_SEARCH_PROVIDER)
 
-static GQuark      gQuarkLink;
+static GQuark gQuarkLink;
 
 static void
-populate_get_matches_cb (GObject      *source_object,
-                         GAsyncResult *res,
-                         gpointer      user_data)
+ide_devhelp_search_provider_populate (IdeSearchProvider *provider,
+                                      IdeSearchContext  *context,
+                                      const gchar       *search_terms,
+                                      gsize              max_results,
+                                      GCancellable      *cancellable)
 {
-  IdeDevhelpSearchProviderPrivate *priv;
-  IdeContext* context;
-  PopulateState *state;
+  IdeDevhelpSearchProvider *self = (IdeDevhelpSearchProvider *)provider;
   g_auto(IdeSearchReducer) reducer = { 0 };
+  IdeContext *idecontext;
   GtkTreeIter iter;
   gboolean valid;
-  gint count = 0;
+  gint count = 0;;
   gint total;
 
-  priv = IDE_DEVHELP_SEARCH_PROVIDER (source_object)->priv;
-  state = (PopulateState*) user_data;
-  context = ide_object_get_context (IDE_OBJECT (state->context));
+  g_assert (IDE_IS_DEVHELP_SEARCH_PROVIDER (self));
+  g_assert (IDE_IS_SEARCH_CONTEXT (context));
+  g_assert (search_terms);
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  dh_keyword_model_filter (priv->keywords_model, state->search_terms, NULL, NULL);
+  if (search_terms [0] == '\0')
+    {
+      ide_search_context_provider_completed (context, provider);
+      return;
+    }
 
-  total = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (priv->keywords_model),
-                                          NULL);
-  if (state->max_results != 0)
-    total = MIN (total, state->max_results);
+  idecontext = ide_object_get_context (IDE_OBJECT (provider));
 
-  /* initialize our reducer, which helps us prevent creating unnecessary
-   * objects that will simply be discarded */
-  ide_search_reducer_init (&reducer,
-                           state->context,
-                           IDE_SEARCH_PROVIDER (source_object),
-                           state->max_results);
+  dh_keyword_model_filter (self->keywords_model, search_terms, NULL, NULL);
+
+  ide_search_reducer_init (&reducer, context, provider, max_results);
+
+  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->keywords_model), &iter);
+  total = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (self->keywords_model), NULL);
 
-  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->keywords_model),
-                                         &iter);
   while (valid)
     {
       g_autoptr(IdeSearchResult) result = NULL;
-      DhLink *link = NULL;
       g_autofree gchar *name = NULL;
-      gfloat score = .0;
+      DhLink *link = NULL;
+      gfloat score = (total - count) / (gfloat)total;
 
-      gtk_tree_model_get (GTK_TREE_MODEL (priv->keywords_model), &iter,
+      gtk_tree_model_get (GTK_TREE_MODEL (self->keywords_model), &iter,
                           DH_KEYWORD_MODEL_COL_NAME, &name,
                           DH_KEYWORD_MODEL_COL_LINK, &link,
                           -1);
 
-      valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->keywords_model),
-                                        &iter);
+      valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->keywords_model), &iter);
 
-      count++;
-      score = (total - count) / (gfloat) (total + 1);
+      /* we traverse from best to worst, so just break */
       if (!ide_search_reducer_accepts (&reducer, score))
-        continue;
+        break;
 
-      if (!g_str_is_ascii (name))
-        {
-          gchar *ascii_name = g_str_to_ascii (name, NULL);
-          g_free (name);
-          name = ascii_name;
-        }
+      count++;
 
       if ((dh_link_get_flags (link) & DH_LINK_FLAGS_DEPRECATED) != 0)
         {
@@ -123,44 +102,20 @@ populate_get_matches_cb (GObject      *source_object,
           name = italic_name;
         }
 
-      result = ide_search_result_new (context,
-                                      name,
-                                      dh_link_get_book_name (link),
-                                      score);
-      g_object_set_qdata_full (G_OBJECT (result),
-                               gQuarkLink,
-                               dh_link_get_uri (link),
-                               g_free);
+      result = ide_search_result_new (idecontext, name, dh_link_get_book_name (link), score);
+      g_object_set_qdata_full (G_OBJECT (result), gQuarkLink, dh_link_get_uri (link), g_free);
 
       /* push the result through the search reducer */
       ide_search_reducer_push (&reducer, result);
     }
 
-  ide_search_context_provider_completed (state->context,
-                                         IDE_SEARCH_PROVIDER (source_object));
-
-  g_free (state->search_terms);
-  g_object_unref (state->context);
-  g_slice_free (PopulateState, state);
+  ide_search_context_provider_completed (context, provider);
 }
 
-void
-ide_devhelp_search_provider_populate (IdeSearchProvider *provider,
-                                      IdeSearchContext  *context,
-                                      const gchar       *search_terms,
-                                      gsize              max_results,
-                                      GCancellable      *cancellable)
+static const gchar *
+ide_devhelp_search_provider_get_verb (IdeSearchProvider *provider)
 {
-  PopulateState *state;
-  g_autoptr(GTask) task = NULL;
-
-  state = g_new0 (PopulateState, 1);
-  state->context = g_object_ref (context);
-  state->search_terms = g_strdup (search_terms);
-  state->max_results = max_results;
-
-  task = g_task_new (provider, cancellable, populate_get_matches_cb, state);
-  g_task_return_pointer (task, NULL, NULL);
+  return _("Documentation");
 }
 
 static void
@@ -168,8 +123,8 @@ ide_devhelp_search_provider_constructed (GObject *object)
 {
   IdeDevhelpSearchProvider *self = IDE_DEVHELP_SEARCH_PROVIDER (object);
 
-  dh_book_manager_populate (self->priv->book_manager);
-  dh_keyword_model_set_words (self->priv->keywords_model, self->priv->book_manager);
+  dh_book_manager_populate (self->book_manager);
+  dh_keyword_model_set_words (self->keywords_model, self->book_manager);
 }
 
 static void
@@ -177,7 +132,7 @@ ide_devhelp_search_provider_finalize (GObject *object)
 {
   IdeDevhelpSearchProvider *self = IDE_DEVHELP_SEARCH_PROVIDER (object);
 
-  g_clear_object (&self->priv->book_manager);
+  g_clear_object (&self->book_manager);
 
   G_OBJECT_CLASS (ide_devhelp_search_provider_parent_class)->finalize (object);
 }
@@ -191,6 +146,7 @@ ide_devhelp_search_provider_class_init (IdeDevhelpSearchProviderClass *klass)
   object_class->constructed = ide_devhelp_search_provider_constructed;
   object_class->finalize = ide_devhelp_search_provider_finalize;
 
+  provider_class->get_verb = ide_devhelp_search_provider_get_verb;
   provider_class->populate = ide_devhelp_search_provider_populate;
 
   gQuarkLink = g_quark_from_static_string ("LINK");
@@ -199,7 +155,6 @@ ide_devhelp_search_provider_class_init (IdeDevhelpSearchProviderClass *klass)
 static void
 ide_devhelp_search_provider_init (IdeDevhelpSearchProvider *self)
 {
-  self->priv = ide_devhelp_search_provider_get_instance_private (self);
-  self->priv->book_manager = dh_book_manager_new ();
-  self->priv->keywords_model = dh_keyword_model_new ();
+  self->book_manager = dh_book_manager_new ();
+  self->keywords_model = dh_keyword_model_new ();
 }
diff --git a/libide/git/ide-git-search-index.c b/libide/git/ide-git-search-index.c
index 01f98d7..76a50c5 100644
--- a/libide/git/ide-git-search-index.c
+++ b/libide/git/ide-git-search-index.c
@@ -227,12 +227,8 @@ ide_git_search_index_populate (IdeGitSearchIndex *self,
           markup = str_highlight (shortname, search_terms);
 
           /* create our search result and connect to signals */
-          result = ide_search_result_new (context,
-                                          markup,
-                                          str->str,
-                                          match->score);
-          g_object_set_qdata_full (G_OBJECT (result), gPathQuark,
-                                   g_strdup (match->value), g_free);
+          result = ide_search_result_new (context, markup, str->str, match->score);
+          g_object_set_qdata_full (G_OBJECT (result), gPathQuark, g_strdup (match->value), g_free);
 #if 0
           /* I think we might want to leave this signal on the provider */
           g_signal_connect (result, "activate", G_CALLBACK (activate_cb), NULL);
diff --git a/libide/git/ide-git-search-provider.c b/libide/git/ide-git-search-provider.c
index 634f37c..9e7a4c4 100644
--- a/libide/git/ide-git-search-provider.c
+++ b/libide/git/ide-git-search-provider.c
@@ -190,6 +190,12 @@ ide_git_search_provider_populate (IdeSearchProvider *provider,
                                            state);
 }
 
+static const gchar *
+ide_git_search_provider_get_verb (IdeSearchProvider *provider)
+{
+  return _("Switch To");
+}
+
 static void
 ide_git_search_provider_finalize (GObject *object)
 {
@@ -208,6 +214,7 @@ ide_git_search_provider_class_init (IdeGitSearchProviderClass *klass)
 
   object_class->finalize = ide_git_search_provider_finalize;
 
+  provider_class->get_verb = ide_git_search_provider_get_verb;
   provider_class->populate = ide_git_search_provider_populate;
 }
 
diff --git a/libide/gsettings/ide-language-defaults.c b/libide/gsettings/ide-language-defaults.c
index 3d0bde2..7797295 100644
--- a/libide/gsettings/ide-language-defaults.c
+++ b/libide/gsettings/ide-language-defaults.c
@@ -286,30 +286,30 @@ ide_language_defaults_init_worker (GTask        *task,
           g_task_return_error (task, error);
           goto failure;
         }
-    }
 
-  version_contents = g_strdup_printf ("%d", global_version);
+      version_contents = g_strdup_printf ("%d", global_version);
 
-  version_dir = g_path_get_dirname (version_path);
+      version_dir = g_path_get_dirname (version_path);
 
-  if (!g_file_test (version_dir, G_FILE_TEST_IS_DIR))
-    {
-      if (g_mkdir_with_parents (version_dir, 0750) == -1)
+      if (!g_file_test (version_dir, G_FILE_TEST_IS_DIR))
         {
-          g_task_return_new_error (task,
-                                   G_IO_ERROR,
-                                   g_io_error_from_errno (errno),
-                                   "%s", g_strerror (errno));
-          goto failure;
+          if (g_mkdir_with_parents (version_dir, 0750) == -1)
+            {
+              g_task_return_new_error (task,
+                                       G_IO_ERROR,
+                                       g_io_error_from_errno (errno),
+                                       "%s", g_strerror (errno));
+              goto failure;
+            }
         }
-    }
 
-  IDE_TRACE_MSG ("Writing new language defaults version to \"%s\"", version_path);
+      IDE_TRACE_MSG ("Writing new language defaults version to \"%s\"", version_path);
 
-  if (!g_file_set_contents (version_path, version_contents, -1, &error))
-    {
-      g_task_return_error (task, error);
-      goto failure;
+      if (!g_file_set_contents (version_path, version_contents, -1, &error))
+        {
+          g_task_return_error (task, error);
+          goto failure;
+        }
     }
 
   g_task_return_boolean (task, TRUE);
diff --git a/libide/ide-back-forward-item.c b/libide/ide-back-forward-item.c
index 9524e91..44ed77c 100644
--- a/libide/ide-back-forward-item.c
+++ b/libide/ide-back-forward-item.c
@@ -50,42 +50,6 @@ ide_back_forward_item_new (IdeContext        *context,
                        NULL);
 }
 
-gboolean
-ide_back_forward_item_chain (IdeBackForwardItem *self,
-                             IdeBackForwardItem *other)
-{
-  IdeSourceLocation *loc1;
-  IdeSourceLocation *loc2;
-  IdeFile *file1;
-  IdeFile *file2;
-  gint line1;
-  gint line2;
-
-  g_return_val_if_fail (IDE_IS_BACK_FORWARD_ITEM (self), FALSE);
-  g_return_val_if_fail (IDE_IS_BACK_FORWARD_ITEM (other), FALSE);
-
-  loc1 = ide_back_forward_item_get_location (self);
-  loc2 = ide_back_forward_item_get_location (other);
-
-  file1 = ide_source_location_get_file (loc1);
-  file2 = ide_source_location_get_file (loc2);
-
-  if (!ide_file_equal (file1, file2))
-    return FALSE;
-
-  line1 = ide_source_location_get_line (loc1);
-  line2 = ide_source_location_get_line (loc2);
-
-  if (ABS (line1 - line2) <= NUM_LINES_CHAIN_MAX)
-    {
-      self->location = ide_source_location_ref (loc2);
-      ide_source_location_unref (loc1);
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
 IdeSourceLocation *
 ide_back_forward_item_get_location (IdeBackForwardItem *self)
 {
@@ -186,3 +150,38 @@ static void
 ide_back_forward_item_init (IdeBackForwardItem *self)
 {
 }
+
+gboolean
+ide_back_forward_item_chain (IdeBackForwardItem *self,
+                             IdeBackForwardItem *other)
+{
+  IdeSourceLocation *loc1;
+  IdeSourceLocation *loc2;
+  IdeFile *file1;
+  IdeFile *file2;
+  gint line1;
+  gint line2;
+
+  g_return_val_if_fail (IDE_IS_BACK_FORWARD_ITEM (self), FALSE);
+  g_return_val_if_fail (IDE_IS_BACK_FORWARD_ITEM (other), FALSE);
+
+  loc1 = ide_back_forward_item_get_location (self);
+  loc2 = ide_back_forward_item_get_location (other);
+
+  file1 = ide_source_location_get_file (loc1);
+  file2 = ide_source_location_get_file (loc2);
+
+  if (!ide_file_equal (file1, file2))
+    return FALSE;
+
+  line1 = ide_source_location_get_line (loc1);
+  line2 = ide_source_location_get_line (loc2);
+
+  if (ABS (line1 - line2) <= NUM_LINES_CHAIN_MAX)
+    {
+      ide_back_forward_item_set_location (self, other->location);
+      return TRUE;
+    }
+
+  return FALSE;
+}
diff --git a/libide/ide-back-forward-list.c b/libide/ide-back-forward-list.c
index f4aa566..8cf7a50 100644
--- a/libide/ide-back-forward-list.c
+++ b/libide/ide-back-forward-list.c
@@ -640,6 +640,7 @@ create_source_location (IdeBackForwardList *self,
   IdeContext *context;
   IdeProject *project;
   g_autoptr(IdeFile) file = NULL;
+  IdeSourceLocation *ret;
 
   g_assert (IDE_IS_BACK_FORWARD_LIST (self));
   g_assert (G_IS_FILE (gfile));
@@ -648,7 +649,9 @@ create_source_location (IdeBackForwardList *self,
   project = ide_context_get_project (context);
   file = ide_project_get_project_file (project, gfile);
 
-  return ide_source_location_new (file, line, line_offset, 0);
+  ret = ide_source_location_new (file, line, line_offset, 0);
+
+  return ret;
 }
 
 static void
diff --git a/libide/ide-buffer-manager.c b/libide/ide-buffer-manager.c
index 2c932d3..39bdbcf 100644
--- a/libide/ide-buffer-manager.c
+++ b/libide/ide-buffer-manager.c
@@ -86,6 +86,8 @@ enum {
 };
 
 enum {
+  CREATE_BUFFER,
+
   SAVE_BUFFER,
   BUFFER_SAVED,
 
@@ -661,12 +663,29 @@ ide_buffer_manager_load_file_async (IdeBufferManager     *self,
                                   "context", context,
                                   NULL);
   if (buffer)
-    state->buffer = g_object_ref (buffer);
+    {
+      state->buffer = g_object_ref (buffer);
+    }
   else
-    state->buffer = g_object_new (IDE_TYPE_BUFFER,
-                                  "context", context,
-                                  "file", file,
-                                  NULL);
+    {
+      /*
+       * Allow application to specify the buffer instance which may be a
+       * decendent of IdeBuffer.
+       */
+      g_signal_emit (self, gSignals [CREATE_BUFFER], 0, file, &state->buffer);
+
+      if ((state->buffer != NULL) && !IDE_IS_BUFFER (state->buffer))
+        {
+          g_warning ("Invalid buffer type retrieved from create-buffer signal.");
+          state->buffer = NULL;
+        }
+
+      if (state->buffer == NULL)
+        state->buffer = g_object_new (IDE_TYPE_BUFFER,
+                                      "context", context,
+                                      "file", file,
+                                      NULL);
+    }
 
   _ide_buffer_set_loading (state->buffer, TRUE);
 
@@ -717,6 +736,7 @@ ide_buffer_manager_save_file__save_cb (GObject      *object,
   g_autoptr(GTask) task = user_data;
   GtkSourceFileSaver *saver = (GtkSourceFileSaver *)object;
   IdeBufferManager *self;
+  IdeFile *file;
   SaveState *state;
   GError *error = NULL;
 
@@ -739,6 +759,11 @@ ide_buffer_manager_save_file__save_cb (GObject      *object,
       return;
     }
 
+  /* Make the buffer as not modified if we saved it to the backing file */
+  file = ide_buffer_get_file (state->buffer);
+  if (ide_file_equal (file, state->file))
+    gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (state->buffer), FALSE);
+
   /* Notify signal handlers that the file is saved */
   g_signal_emit (self, gSignals [BUFFER_SAVED], 0, state->buffer);
 
@@ -1034,6 +1059,31 @@ ide_buffer_manager_class_init (IdeBufferManagerClass *klass)
                                    gParamSpecs [PROP_AUTO_SAVE_TIMEOUT]);
 
   /**
+   * IdeBufferManager::create-buffer:
+   * @self: An #IdeBufferManager
+   * @file: An #IdeFile
+   *
+   * This signal is emitted when there is a request to create a new buffer
+   * object. This allows subclasses of #IdeBuffer to be instantiated by the
+   * buffer manager.
+   *
+   * The first handler of this signal is responsible for returning an
+   * #IdeBuffer or %NULL, for which one will be created.
+   *
+   * Returns: (transfer full) (nullable): An #IdeBuffer or %NULL.
+   */
+  gSignals [CREATE_BUFFER] = g_signal_new ("create-buffer",
+                                           G_TYPE_FROM_CLASS (klass),
+                                           G_SIGNAL_RUN_LAST,
+                                           0,
+                                           g_signal_accumulator_first_wins,
+                                           NULL,
+                                           g_cclosure_marshal_generic,
+                                           IDE_TYPE_BUFFER,
+                                           1,
+                                           IDE_TYPE_FILE);
+
+  /**
    * IdeBufferManager::save-buffer:
    * @self: An #IdeBufferManager.
    * @buffer: an #IdeBuffer.
@@ -1042,7 +1092,7 @@ ide_buffer_manager_class_init (IdeBufferManagerClass *klass)
    * if you'd like to perform mutation of the buffer before it is persisted to storage.
    */
   gSignals [SAVE_BUFFER] = g_signal_new ("save-buffer",
-                                         G_TYPE_FROM_CLASS (object_class),
+                                         G_TYPE_FROM_CLASS (klass),
                                          G_SIGNAL_RUN_LAST,
                                          0,
                                          NULL, NULL,
@@ -1061,7 +1111,7 @@ ide_buffer_manager_class_init (IdeBufferManagerClass *klass)
    * storage.
    */
   gSignals [BUFFER_SAVED] = g_signal_new ("buffer-saved",
-                                          G_TYPE_FROM_CLASS (object_class),
+                                          G_TYPE_FROM_CLASS (klass),
                                           G_SIGNAL_RUN_LAST,
                                           0,
                                           NULL, NULL,
@@ -1079,7 +1129,7 @@ ide_buffer_manager_class_init (IdeBufferManagerClass *klass)
    * connect to this signal to be notified when loading of a buffer has begun.
    */
   gSignals [LOAD_BUFFER] = g_signal_new ("load-buffer",
-                                         G_TYPE_FROM_CLASS (object_class),
+                                         G_TYPE_FROM_CLASS (klass),
                                          G_SIGNAL_RUN_LAST,
                                          0,
                                          NULL, NULL,
@@ -1097,7 +1147,7 @@ ide_buffer_manager_class_init (IdeBufferManagerClass *klass)
    * signal to be notified when a buffer has completed loading.
    */
   gSignals [BUFFER_LOADED] = g_signal_new ("buffer-loaded",
-                                           G_TYPE_FROM_CLASS (object_class),
+                                           G_TYPE_FROM_CLASS (klass),
                                            G_SIGNAL_RUN_LAST,
                                            0,
                                            NULL, NULL,
@@ -1115,7 +1165,7 @@ ide_buffer_manager_class_init (IdeBufferManagerClass *klass)
    * signal when you want to perform an operation while a buffer is in focus.
    */
   gSignals [BUFFER_FOCUS_ENTER] = g_signal_new ("buffer-focus-enter",
-                                                G_TYPE_FROM_CLASS (object_class),
+                                                G_TYPE_FROM_CLASS (klass),
                                                 G_SIGNAL_RUN_LAST,
                                                 0,
                                                 NULL, NULL,
@@ -1133,7 +1183,7 @@ ide_buffer_manager_class_init (IdeBufferManagerClass *klass)
    * to this signal to stop any work you were performing while the buffer was focused.
    */
   gSignals [BUFFER_FOCUS_LEAVE] = g_signal_new ("buffer-focus-leave",
-                                                G_TYPE_FROM_CLASS (object_class),
+                                                G_TYPE_FROM_CLASS (klass),
                                                 G_SIGNAL_RUN_LAST,
                                                 0,
                                                 NULL, NULL,
diff --git a/libide/ide-file.c b/libide/ide-file.c
index c9df629..ff62de4 100644
--- a/libide/ide-file.c
+++ b/libide/ide-file.c
@@ -19,6 +19,7 @@
 #include <glib/gi18n.h>
 #include <gtksourceview/gtksource.h>
 
+#include "ide-debug.h"
 #include "ide-file.h"
 #include "ide-file-settings.h"
 #include "ide-language.h"
@@ -333,6 +334,8 @@ ide_file_finalize (GObject *object)
 {
   IdeFile *self = (IdeFile *)object;
 
+  IDE_ENTRY;
+
   g_clear_object (&self->file);
   g_clear_object (&self->source_file);
   g_clear_object (&self->language);
@@ -340,6 +343,8 @@ ide_file_finalize (GObject *object)
   g_clear_pointer (&self->content_type, g_free);
 
   G_OBJECT_CLASS (ide_file_parent_class)->finalize (object);
+
+  IDE_EXIT;
 }
 
 static void
diff --git a/libide/ide-log.c b/libide/ide-log.c
index ae9abc8..f172f13 100644
--- a/libide/ide-log.c
+++ b/libide/ide-log.c
@@ -99,7 +99,7 @@ ide_log_level_str (GLogLevelFlags log_level)
  */
 static void
 ide_log_write_to_channel (GIOChannel  *channel,
-                         const gchar *message)
+                          const gchar *message)
 {
   g_io_channel_write_chars (channel, message, -1, NULL, NULL);
   g_io_channel_flush (channel, NULL);
diff --git a/libide/ide-search-context.c b/libide/ide-search-context.c
index d7c2172..80798db 100644
--- a/libide/ide-search-context.c
+++ b/libide/ide-search-context.c
@@ -16,6 +16,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define G_LOG_DOMAIN "ide-search-context"
+
+#include "ide-debug.h"
 #include "ide-search-context.h"
 #include "ide-search-provider.h"
 #include "ide-search-result.h"
@@ -26,6 +29,7 @@ struct _IdeSearchContext
 
   GCancellable *cancellable;
   GList        *providers;
+  gsize         max_results;
   guint         in_progress;
   guint         executed : 1;
 };
@@ -115,35 +119,37 @@ ide_search_context_set_provider_count (IdeSearchContext  *self,
 
 void
 ide_search_context_execute (IdeSearchContext *self,
-                            const gchar      *search_terms)
+                            const gchar      *search_terms,
+                            gsize             max_results)
 {
   GList *iter;
 
+  IDE_ENTRY;
+
   g_return_if_fail (IDE_IS_SEARCH_CONTEXT (self));
   g_return_if_fail (!self->executed);
   g_return_if_fail (search_terms);
 
   self->executed = TRUE;
   self->in_progress = g_list_length (self->providers);
+  self->max_results = max_results;
 
   if (!self->in_progress)
     {
       g_signal_emit (self, gSignals [COMPLETED], 0);
-      return;
+      IDE_EXIT;
     }
 
   for (iter = self->providers; iter; iter = iter->next)
     {
-      gsize max_results = 0;
-
-      /* TODO: Get the max results for this provider */
-
       ide_search_provider_populate (iter->data,
                                     self,
                                     search_terms,
                                     max_results,
                                     self->cancellable);
     }
+
+  IDE_EXIT;
 }
 
 void
diff --git a/libide/ide-search-context.h b/libide/ide-search-context.h
index 55fec02..5de1ea4 100644
--- a/libide/ide-search-context.h
+++ b/libide/ide-search-context.h
@@ -38,7 +38,8 @@ void         ide_search_context_remove_result      (IdeSearchContext  *self,
                                                     IdeSearchResult   *result);
 void         ide_search_context_cancel             (IdeSearchContext  *self);
 void         ide_search_context_execute            (IdeSearchContext  *self,
-                                                    const gchar       *search_terms);
+                                                    const gchar       *search_terms,
+                                                    gsize              max_results);
 void         ide_search_context_set_provider_count (IdeSearchContext  *self,
                                                     IdeSearchProvider *provider,
                                                     guint64            count);
diff --git a/libide/ide-search-reducer.c b/libide/ide-search-reducer.c
index 4753b7c..5d765de 100644
--- a/libide/ide-search-reducer.c
+++ b/libide/ide-search-reducer.c
@@ -62,8 +62,7 @@ ide_search_reducer_push (IdeSearchReducer *reducer,
       /* Remove lowest score */
       iter = g_sequence_get_begin_iter (reducer->sequence);
       lowest = g_sequence_get (iter);
-      ide_search_context_remove_result (reducer->context, reducer->provider,
-                                       lowest);
+      ide_search_context_remove_result (reducer->context, reducer->provider, lowest);
       g_sequence_remove (iter);
     }
 
diff --git a/libide/ide.h b/libide/ide.h
index e637050..c5080a9 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -33,6 +33,7 @@ G_BEGIN_DECLS
 #include "ide-buffer.h"
 #include "ide-buffer-manager.h"
 #include "ide-context.h"
+#include "ide-debug.h"
 #include "ide-debugger.h"
 #include "ide-deployer.h"
 #include "ide-device.h"
diff --git a/src/app/gb-application-actions.c b/src/app/gb-application-actions.c
new file mode 100644
index 0000000..edb69a0
--- /dev/null
+++ b/src/app/gb-application-actions.c
@@ -0,0 +1,230 @@
+/* gb-application-actions.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gb-application"
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib/gi18n.h>
+
+#include "gb-application-actions.h"
+#include "gb-application-private.h"
+#include "gb-support.h"
+#include "gb-workbench.h"
+
+static void
+gb_application_actions_preferences (GSimpleAction *action,
+                                    GVariant      *parameter,
+                                    gpointer       user_data)
+{
+  GbApplication *self = user_data;
+  GbPreferencesWindow *window;
+  GbWorkbench *workbench = NULL;
+  GList *list;
+
+  IDE_ENTRY;
+
+  g_assert (GB_IS_APPLICATION (self));
+
+  if (self->preferences_window)
+    {
+      gtk_window_present (GTK_WINDOW (self->preferences_window));
+      return;
+    }
+
+  list = gtk_application_get_windows (GTK_APPLICATION (self));
+
+  for (; list; list = list->next)
+    if (GB_IS_WORKBENCH (list->data))
+      workbench = GB_WORKBENCH (list->data);
+
+  window = g_object_new (GB_TYPE_PREFERENCES_WINDOW,
+                         "transient-for", workbench,
+                         NULL);
+  ide_set_weak_pointer (&self->preferences_window, window);
+
+  gtk_window_present (GTK_WINDOW (window));
+
+  IDE_EXIT;
+}
+
+static void
+gb_application_actions_support (GSimpleAction *action,
+                                GVariant      *parameter,
+                                gpointer       user_data)
+{
+  GbApplication *self = user_data;
+  GtkWidget *dialog;
+  gchar *text = NULL;
+  GList *windows;
+  GError *error = NULL;
+  gchar *str = NULL;
+  gchar *log_path = NULL;
+  gchar *name = NULL;
+
+  name = g_strdup_printf ("gnome-builder-%u.log", (int)getpid ());
+  log_path = g_build_filename (g_get_home_dir (), name, NULL);
+  g_free (name);
+
+  windows = gtk_application_get_windows (GTK_APPLICATION (self));
+
+  str = gb_get_support_log ();
+
+  if (!g_file_set_contents (log_path, str, -1, &error))
+    {
+      g_printerr ("%s\n", error->message);
+      goto cleanup;
+    }
+
+  text = g_strdup_printf (_("The support log file has been written to '%s'. "
+                            "Please provide this file as an attachment on "
+                            "your bug report or support request."),
+                            log_path);
+
+  g_message ("%s", text);
+
+  dialog = gtk_message_dialog_new (windows ? windows->data : NULL,
+                                   GTK_DIALOG_DESTROY_WITH_PARENT,
+                                   GTK_MESSAGE_INFO,
+                                   GTK_BUTTONS_CLOSE,
+                                   "%s", text);
+  gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+  g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+  gtk_window_present (GTK_WINDOW (dialog));
+
+cleanup:
+  g_free (text);
+  g_clear_error (&error);
+  g_free (str);
+  g_free (log_path);
+}
+
+static void
+gb_application_actions_quit (GSimpleAction *action,
+                             GVariant      *param,
+                             gpointer       user_data)
+{
+  GbApplication *self = user_data;
+
+  IDE_ENTRY;
+
+  g_assert (GB_IS_APPLICATION (self));
+
+  g_application_quit (G_APPLICATION (self));
+
+  IDE_EXIT;
+}
+
+static void
+gb_application_actions_about (GSimpleAction *action,
+                              GVariant      *param,
+                              gpointer       user_data)
+{
+  GbApplication *self = user_data;
+  const gchar *artists[] = {
+    "Allan Day",
+    "Hylke Bons",
+    "Jakub Steiner",
+    NULL };
+  const gchar *authors[] = {
+    "Alexander Larsson",
+    "Alexandre Franke",
+    "Carlos Soriano",
+    "Christian Hergert",
+    "Cosimo Cecchi",
+    "Dimitris Zenios",
+    "Fabiano Fidêncio",
+    "Florian Bäuerle",
+    "Florian Müllner",
+    "Hashem Nasarat",
+    "Hylke Bons",
+    "Igor Gnatenko",
+    "Jakub Steiner",
+    "Jasper St. Pierre",
+    "Jonathon Jongsma",
+    "Mathieu Bridon",
+    "Megh Parikh",
+    "Michael Catanzaro",
+    "Pete Travis",
+    "Ray Strode",
+    "Roberto Majadas",
+    "Ting-Wei Lan",
+    "Trinh Anh Ngoc",
+    "Yosef Or Boczko",
+    NULL };
+  const gchar *funders[] = {
+    "Aaron Hergert",
+    "Christian Hergert",
+    /* todo: load from crowdfunding */
+    NULL };
+  const gchar *documenters[] = {
+   NULL };
+  GtkDialog *dialog;
+  GtkWindow *parent = NULL;
+  GList *iter;
+  GList *windows;
+
+  g_assert (GB_IS_APPLICATION (self));
+
+  windows = gtk_application_get_windows (GTK_APPLICATION (self));
+
+  for (iter = windows; iter; iter = iter->next)
+    {
+      if (GB_IS_WORKBENCH (iter->data))
+        {
+          parent = iter->data;
+          break;
+        }
+    }
+
+  dialog = g_object_new (GTK_TYPE_ABOUT_DIALOG,
+                         "artists", artists,
+                         "authors", authors,
+                         "comments", _("An IDE for GNOME"),
+                         "documenters", documenters,
+                         "license-type", GTK_LICENSE_GPL_3_0,
+                         "logo-icon-name", "builder",
+                         "modal", FALSE,
+                         "program-name", _("GNOME Builder"),
+                         "transient-for", parent,
+                         "translator-credits", _("translator-credits"),
+                         "version", PACKAGE_VERSION,
+                         "website", "https://wiki.gnome.org/Apps/Builder";,
+                         "website-label", _("Learn more about GNOME Builder"),
+                         NULL);
+  gtk_about_dialog_add_credit_section (GTK_ABOUT_DIALOG (dialog), _("Funded By"), funders);
+
+  g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+  gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static const GActionEntry GbApplicationActions[] = {
+  { "about",       gb_application_actions_about },
+  { "preferences", gb_application_actions_preferences },
+  { "quit",        gb_application_actions_quit },
+  { "support",     gb_application_actions_support },
+};
+
+void
+gb_application_actions_init (GbApplication *self)
+{
+  g_action_map_add_action_entries (G_ACTION_MAP (self), GbApplicationActions,
+                                   G_N_ELEMENTS (GbApplicationActions), self);
+}
diff --git a/src/auto-indent/c-parse-helper.h b/src/app/gb-application-actions.h
similarity index 57%
copy from src/auto-indent/c-parse-helper.h
copy to src/app/gb-application-actions.h
index 418f518..c4e660e 100644
--- a/src/auto-indent/c-parse-helper.h
+++ b/src/app/gb-application-actions.h
@@ -1,6 +1,6 @@
-/* c-parse-helper.h
+/* gb-application-actions.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,26 +16,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef C_PARSE_HELPER_H
-#define C_PARSE_HELPER_H
+#ifndef GB_APPLICATION_ACTIONS_H
+#define GB_APPLICATION_ACTIONS_H
 
-#include <glib.h>
+#include "gb-application.h"
 
 G_BEGIN_DECLS
 
-typedef struct
-{
-  gchar *type;
-  gchar *name;
-  guint  ellipsis : 1;
-  guint  n_star   : 4;
-} Parameter;
-
-gboolean   parameter_validate (Parameter       *param);
-void       parameter_free     (Parameter       *p);
-Parameter *parameter_copy     (const Parameter *src);
-GSList    *parse_parameters   (const gchar     *text);
+void gb_application_actions_init (GbApplication *self);
 
 G_END_DECLS
 
-#endif /* C_PARSE_HELPER_H */
+#endif /* GB_APPLICATION_ACTIONS_H */
diff --git a/src/auto-indent/c-parse-helper.h b/src/app/gb-application-private.h
similarity index 57%
copy from src/auto-indent/c-parse-helper.h
copy to src/app/gb-application-private.h
index 418f518..24c01f6 100644
--- a/src/auto-indent/c-parse-helper.h
+++ b/src/app/gb-application-private.h
@@ -1,6 +1,6 @@
-/* c-parse-helper.h
+/* gb-application-private.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,26 +16,27 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef C_PARSE_HELPER_H
-#define C_PARSE_HELPER_H
+#ifndef GB_APPLICATION_PRIVATE_H
+#define GB_APPLICATION_PRIVATE_H
 
-#include <glib.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+#include "gb-keybindings.h"
+#include "gb-preferences-window.h"
 
 G_BEGIN_DECLS
 
-typedef struct
+struct _GbApplication
 {
-  gchar *type;
-  gchar *name;
-  guint  ellipsis : 1;
-  guint  n_star   : 4;
-} Parameter;
+  GtkApplication       parent_instance;
+
+  GSettings           *editor_settings;
+  GbKeybindings       *keybindings;
+  GbPreferencesWindow *preferences_window;
+};
 
-gboolean   parameter_validate (Parameter       *param);
-void       parameter_free     (Parameter       *p);
-Parameter *parameter_copy     (const Parameter *src);
-GSList    *parse_parameters   (const gchar     *text);
 
 G_END_DECLS
 
-#endif /* C_PARSE_HELPER_H */
+#endif /* GB_APPLICATION_PRIVATE_H */
diff --git a/src/app/gb-application.c b/src/app/gb-application.c
index d1ce037..fc19763 100644
--- a/src/app/gb-application.c
+++ b/src/app/gb-application.c
@@ -16,7 +16,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define G_LOG_DOMAIN "app"
+#define G_LOG_DOMAIN "gb-application"
 
 #ifdef HAVE_CONFIG_H
 # include "config.h"
@@ -27,128 +27,56 @@
 #include <ide.h>
 
 #include "gb-application.h"
-#include "gb-editor-file-marks.h"
+#include "gb-application-actions.h"
+#include "gb-application-private.h"
+#include "gb-editor-document.h"
 #include "gb-editor-workspace.h"
 #include "gb-glib.h"
-#include "gb-log.h"
-#include "gb-keybindings.h"
-#include "gb-preferences-window.h"
-#include "gb-support.h"
 #include "gb-resources.h"
 #include "gb-workbench.h"
 
-#define ADWAITA_CSS  "resource:///org/gnome/builder/css/builder.Adwaita.css"
-#define LANGUAGE_SCHEMA "org.gnome.builder.editor.language"
-#define LANGUAGE_PATH "/org/gnome/builder/editor/language/"
-#define GSV_PATH "resource:///org/gnome/builder/styles/"
+#define ADWAITA_CSS "resource:///org/gnome/builder/css/builder.Adwaita.css"
+#define GSV_PATH    "resource:///org/gnome/builder/styles/"
 
-struct _GbApplicationPrivate
-{
-  GbKeybindings       *keybindings;
-  GSettings           *editor_settings;
-  GbPreferencesWindow *preferences_window;
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (GbApplication, gb_application, GTK_TYPE_APPLICATION)
+G_DEFINE_TYPE (GbApplication, gb_application, GTK_TYPE_APPLICATION)
 
 static void
-gb_application_setup_search_paths (void)
+get_default_size (GtkRequisition *req)
 {
-  GtkSourceStyleSchemeManager *mgr;
+  GdkScreen *screen;
+  GdkRectangle rect;
+  gint primary;
+
+  screen = gdk_screen_get_default ();
+  primary = gdk_screen_get_primary_monitor (screen);
+  gdk_screen_get_monitor_geometry (screen, primary, &rect);
 
-  mgr = gtk_source_style_scheme_manager_get_default ();
-  gtk_source_style_scheme_manager_append_search_path (
-      mgr, PACKAGE_DATADIR"/gtksourceview-3.0/styles/");
+  req->width = rect.width * 0.75;
+  req->height = rect.height * 0.75;
 }
 
 static void
-gb_application_install_language_defaults (GbApplication *self)
+gb_application_setup_search_paths (void)
 {
-  gchar *defaults_installed_path;
-  gboolean exists;
-
-  g_return_if_fail (GB_IS_APPLICATION (self));
-
-  defaults_installed_path = g_build_filename (g_get_user_data_dir (),
-                                              "gnome-builder",
-                                              ".defaults-installed",
-                                              NULL);
-  exists = g_file_test (defaults_installed_path, G_FILE_TEST_EXISTS);
+  GtkSourceStyleSchemeManager *style_scheme_manager;
+  static gboolean initialized;
 
-  if (!exists)
-    {
-      GKeyFile *key_file;
-      GBytes *bytes;
-
-      key_file = g_key_file_new ();
-
-      bytes =
-        g_resources_lookup_data ("/org/gnome/builder/language/defaults.ini",
-                                 0, NULL);
-
-      if (bytes)
-        {
-          if (g_key_file_load_from_data (key_file,
-                                         g_bytes_get_data (bytes, NULL),
-                                         g_bytes_get_size (bytes),
-                                         0, NULL))
-            {
-              gchar **groups;
-              guint i;
-
-              groups = g_key_file_get_groups (key_file, NULL);
-
-              for (i = 0; groups [i]; i++)
-                {
-                  GSettings *settings;
-                  gchar *settings_path;
-                  gchar **keys;
-                  guint j;
-
-                  settings_path = g_strdup_printf (
-                      "/org/gnome/builder/editor/language/%s/", groups [i]);
-                  settings = g_settings_new_with_path (
-                      "org.gnome.builder.editor.language",
-                      settings_path);
-                  g_free (settings_path);
-
-                  keys = g_key_file_get_keys (key_file, groups [i], NULL, NULL);
-
-                  for (j = 0; keys [j]; j++)
-                    {
-                      GVariant *param;
-                      gchar *value;
-
-                      value = g_key_file_get_value (key_file, groups [i],
-                                                    keys [j], NULL);
-                      param = g_variant_parse (NULL, value, NULL, NULL, NULL);
-
-                      if (param)
-                        {
-                          g_settings_set_value (settings, keys [j], param);
-                          g_variant_unref (param);
-                        }
-
-                      g_free (value);
-                    }
-
-                  g_object_unref (settings);
-                  g_strfreev (keys);
-                }
-
-              g_strfreev (groups);
-            }
-
-          g_bytes_unref (bytes);
-        }
+  if (initialized)
+    return;
 
-      g_key_file_free (key_file);
-      g_file_set_contents (defaults_installed_path, "", 0, NULL);
-    }
-
-  g_free (defaults_installed_path);
+  style_scheme_manager = gtk_source_style_scheme_manager_get_default ();
+  gtk_source_style_scheme_manager_append_search_path (style_scheme_manager,
+                                                      PACKAGE_DATADIR"/gtksourceview-3.0/styles/");
+  initialized = TRUE;
 }
 
+/**
+ * gb_application_make_skeleton_dirs:
+ * @self: A #GbApplication.
+ *
+ * Creates all the directories we might need later. Simpler to just ensure they
+ * are created during startup.
+ */
 static void
 gb_application_make_skeleton_dirs (GbApplication *self)
 {
@@ -177,39 +105,36 @@ gb_application_make_skeleton_dirs (GbApplication *self)
 
   path = g_build_filename (g_get_user_config_dir (),
                            "gnome-builder",
-                           "uncrustify",
+                           "syntax",
                            NULL);
   g_mkdir_with_parents (path, 0750);
   g_free (path);
-}
 
-static void
-gb_application_load_file_marks (GbApplication *application)
-{
-  GbEditorFileMarks *marks;
-  GError *error = NULL;
-
-  g_return_if_fail (GB_IS_APPLICATION (application));
-
-  marks = gb_editor_file_marks_get_default ();
-
-  if (!gb_editor_file_marks_load (marks, &error))
-    {
-      g_warning ("%s", error->message);
-      g_clear_error (&error);
-    }
+  path = g_build_filename (g_get_user_config_dir (),
+                           "gnome-builder",
+                           "uncrustify",
+                           NULL);
+  g_mkdir_with_parents (path, 0750);
+  g_free (path);
 }
 
+/**
+ * gb_application_on_theme_changed:
+ * @self: A #GbApplication.
+ *
+ * Update the theme overrides when the theme changes. This includes our custom
+ * CSS for Adwaita, etc.
+ */
 static void
 gb_application_on_theme_changed (GbApplication *self,
                                  GParamSpec    *pspec,
                                  GtkSettings   *settings)
 {
-  static GtkCssProvider *provider = NULL;
+  static GtkCssProvider *provider;
   GdkScreen *screen;
   gchar *theme;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_assert (GB_IS_APPLICATION (self));
   g_assert (GTK_IS_SETTINGS (settings));
@@ -242,7 +167,7 @@ gb_application_on_theme_changed (GbApplication *self,
 
   g_free (theme);
 
-  EXIT;
+  IDE_EXIT;
 }
 
 static void
@@ -250,7 +175,7 @@ gb_application_register_theme_overrides (GbApplication *application)
 {
   GtkSettings *settings;
 
-  ENTRY;
+  IDE_ENTRY;
 
   gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (),
                                     "/org/gnome/builder/icons/");
@@ -267,190 +192,149 @@ gb_application_register_theme_overrides (GbApplication *application)
                            G_CONNECT_SWAPPED);
   gb_application_on_theme_changed (application, NULL, settings);
 
-  EXIT;
+  IDE_EXIT;
 }
 
 static void
-gb_application_load_keybindings (GbApplication *application,
-                                 const gchar   *name)
+gb_application_load_keybindings (GbApplication *self)
 {
-  GbKeybindings *keybindings = NULL;
-  GError *error = NULL;
-  GBytes *bytes = NULL;
-  gchar *path;
+  g_autoptr(GSettings) settings = NULL;
+  g_autofree gchar *name = NULL;
 
-  g_return_if_fail (GB_IS_APPLICATION (application));
+  g_assert (GB_IS_APPLICATION (self));
 
-  if (application->priv->keybindings)
-    {
-      gb_keybindings_unregister (application->priv->keybindings,
-                                 GTK_APPLICATION (application));
-      g_clear_object (&application->priv->keybindings);
-    }
+  settings = g_settings_new ("org.gnome.builder.editor");
+  name = g_settings_get_string (settings, "keybindings");
+  self->keybindings = gb_keybindings_new (GTK_APPLICATION (self), name);
+  g_settings_bind (settings, "keybindings", self->keybindings, "mode", G_SETTINGS_BIND_GET);
+}
 
-  path = g_strdup_printf ("/org/gnome/builder/keybindings/%s.ini", name);
-  bytes = g_resources_lookup_data (path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
-  g_free (path);
+static GbWorkbench *
+gb_application_find_workbench_for_file (GbApplication *self,
+                                        GFile         *file)
+{
+  GList *iter;
+  GList *workbenches;
 
-  if (!bytes)
-    {
-      g_warning (_("Failed to load keybindings."));
-      return;
-    }
+  g_assert (GB_IS_APPLICATION (self));
+  g_assert (G_IS_FILE (file));
 
-  keybindings = gb_keybindings_new ();
+  workbenches = gtk_application_get_windows (GTK_APPLICATION (self));
 
-  if (!gb_keybindings_load_bytes (keybindings, bytes, &error))
+  /*
+   * Find the a project that contains this file in its working directory.
+   */
+  for (iter = workbenches; iter; iter = iter->next)
     {
-      g_warning (_("Failed to load keybindings: %s"), error->message);
-      goto cleanup;
-    }
-
-  path = g_build_filename (g_get_user_config_dir (),
-                           "gnome-builder",
-                           "keybindings.ini",
-                           NULL);
+      if (GB_IS_WORKBENCH (iter->data))
+        {
+          GbWorkbench *workbench = iter->data;
+          g_autofree gchar *relpath = NULL;
+          IdeContext *context;
+          IdeVcs *vcs;
+          GFile *workdir;
 
-  if (g_file_test (path, G_FILE_TEST_EXISTS) &&
-      !gb_keybindings_load_path (keybindings, path, &error))
-    {
-      g_warning (_("Failed to load local keybindings: %s"), error->message);
-      goto cleanup;
-    }
+          context = gb_workbench_get_context (workbench);
+          vcs = ide_context_get_vcs (context);
+          workdir = ide_vcs_get_working_directory (vcs);
 
-  g_free (path);
+          relpath = g_file_get_relative_path (workdir, file);
 
-  gb_keybindings_register (keybindings, GTK_APPLICATION (application));
+          if (relpath != NULL)
+            return workbench;
+        }
+    }
 
-  application->priv->keybindings = g_object_ref (keybindings);
+  /*
+   * No matches found, take the first workbench we find.
+   */
+  for (iter = workbenches; iter; iter = iter->next)
+    if (GB_IS_WORKBENCH (iter->data))
+      return iter->data;
 
-cleanup:
-  g_clear_object (&keybindings);
-  g_clear_error (&error);
-  g_clear_pointer (&bytes, g_bytes_unref);
+  return NULL;
 }
 
 static void
-gb_application_vim_mode_changed (GbApplication *self,
-                                 const gchar   *key,
-                                 GSettings     *settings)
+gb_application_activate (GApplication *application)
 {
-  g_return_if_fail (GB_IS_APPLICATION (self));
-  g_return_if_fail (G_IS_SETTINGS (settings));
-
-  if (g_settings_get_boolean (settings, "vim-mode"))
-    {
-      g_settings_set_boolean (settings, "emacs-mode", FALSE);
-      gb_application_load_keybindings (self, "vim");
-    }
-  else
-    gb_application_load_keybindings (self, "default");
+  g_warning ("TODO: Show project selection window");
 }
 
-static void
-gb_application_emacs_mode_changed (GbApplication *self,
-                                 const gchar   *key,
-                                 GSettings     *settings)
+static IdeBuffer *
+on_create_buffer (IdeBufferManager *buffer_manager,
+                  IdeFile          *file,
+                  gpointer          user_data)
 {
-  g_return_if_fail (GB_IS_APPLICATION (self));
-  g_return_if_fail (G_IS_SETTINGS (settings));
-
-  if (g_settings_get_boolean (settings, "emacs-mode"))
-    {
-      g_settings_set_boolean (settings, "vim-mode", FALSE);
-      gb_application_load_keybindings (self, "emacs");
-    }
-  else
-    gb_application_load_keybindings (self, "default");
+  return g_object_new (GB_TYPE_EDITOR_DOCUMENT,
+                       "context", ide_object_get_context (IDE_OBJECT (buffer_manager)),
+                       "file", file,
+                       "highlight-diagnostics", TRUE,
+                       NULL);
 }
 
 static void
-gb_application_register_keybindings (GbApplication *self)
+gb_application__context_new_cb (GObject      *object,
+                                GAsyncResult *result,
+                                gpointer      user_data)
 {
-  g_return_if_fail (GB_IS_APPLICATION (self));
-  g_return_if_fail (!self->priv->editor_settings);
-
-  self->priv->editor_settings = g_settings_new ("org.gnome.builder.editor");
-  g_signal_connect_object (self->priv->editor_settings,
-                           "changed::vim-mode",
-                           G_CALLBACK (gb_application_vim_mode_changed),
-                           self,
-                           G_CONNECT_SWAPPED);
-  g_signal_connect_object (self->priv->editor_settings,
-                           "changed::emacs-mode",
-                           G_CALLBACK (gb_application_emacs_mode_changed),
-                           self,
-                           G_CONNECT_SWAPPED);
-  if (g_settings_get_boolean(self->priv->editor_settings, "vim-mode") == TRUE)
-    gb_application_vim_mode_changed (self, NULL, self->priv->editor_settings);
-  else if (g_settings_get_boolean(self->priv->editor_settings, "emacs-mode") == TRUE)
-    gb_application_emacs_mode_changed (self, NULL, self->priv->editor_settings);
-  else
-    gb_application_vim_mode_changed (self, NULL, self->priv->editor_settings);
-
-}
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(IdeContext) context = NULL;
+  IdeBufferManager *bufmgr;
+  GbApplication *self;
+  GbWorkbench *workbench;
+  GtkRequisition req;
+  GPtrArray *ar;
+  GError *error = NULL;
+  gsize i;
 
-static GbWorkbench *
-gb_application_create_workbench (GApplication *application)
-{
-  GtkWindow *window;
-  GdkScreen *screen;
-  GdkRectangle geom;
-  gint primary;
-  gint default_width;
-  gint default_height;
+  g_assert (G_IS_TASK (task));
 
-  ENTRY;
+  self = g_task_get_source_object (task);
+  ar = g_task_get_task_data (task);
 
-  /*
-   * Determine 3/4's the screen width for the default size. We will maximize
-   * the window anyway, but handy when unmaximizing.
-   */
-  screen = gdk_screen_get_default ();
-  primary = gdk_screen_get_primary_monitor (screen);
-  gdk_screen_get_monitor_geometry (screen, primary, &geom);
-  default_width = (geom.width / 4) * 3;
-  default_height = (geom.height / 4) * 3;
+  g_assert (GB_IS_APPLICATION (self));
+  g_assert (ar);
+  g_assert (ar->len);
 
-  window = g_object_new (GB_TYPE_WORKBENCH,
-                         "title", _ ("Builder"),
-                         "default-width", default_width,
-                         "default-height", default_height,
-                         "window-position", GTK_WIN_POS_CENTER,
-                         NULL);
+  context = ide_context_new_finish (result, &error);
 
-  gtk_window_maximize (window);
+  if (!context)
+    {
+      g_warning ("%s", error->message);
+      g_clear_error (&error);
+      goto cleanup;
+    }
 
-  gtk_application_add_window (GTK_APPLICATION (application), window);
+  bufmgr = ide_context_get_buffer_manager (context);
+  g_signal_connect (bufmgr, "create-buffer", G_CALLBACK (on_create_buffer), NULL);
 
-  RETURN (GB_WORKBENCH (window));
-}
+  get_default_size (&req);
 
-static void
-gb_application_activate (GApplication *application)
-{
-  GbWorkbench *workbench;
-  GbWorkspace *workspace;
-  GList *list;
+  workbench = g_object_new (GB_TYPE_WORKBENCH,
+                            "application", self,
+                            "context", context,
+                            "default-width", req.width,
+                            "default-height", req.height,
+                            "title", _("Builder"),
+                            NULL);
 
-  g_return_if_fail (GB_IS_APPLICATION (application));
+  for (i = 0; i < ar->len; i++)
+    {
+      GFile *file;
 
-  list = gtk_application_get_windows (GTK_APPLICATION (application));
+      file = g_ptr_array_index (ar, i);
+      g_assert (G_IS_FILE (file));
 
-  for (; list; list = list->next)
-    {
-      if (GB_IS_WORKBENCH (list->data))
-        {
-          gtk_window_present (GTK_WINDOW (list->data));
-          return;
-        }
+      gb_workbench_open (workbench, file);
     }
 
-  workbench = gb_application_create_workbench (application);
-  workspace = gb_workbench_get_workspace (workbench, GB_TYPE_EDITOR_WORKSPACE);
-  gb_editor_workspace_new_document (GB_EDITOR_WORKSPACE (workspace));
-
+  gtk_window_maximize (GTK_WINDOW (workbench));
   gtk_window_present (GTK_WINDOW (workbench));
+
+cleanup:
+  g_task_return_boolean (task, FALSE);
+  g_application_release (G_APPLICATION (self));
 }
 
 static void
@@ -459,153 +343,65 @@ gb_application_open (GApplication   *application,
                      gint            n_files,
                      const gchar    *hint)
 {
-  GbWorkbench *workbench = NULL;
-  GbWorkspace *workspace;
-  GList *list;
+  GbApplication *self = (GbApplication *)application;
+  GbWorkbench *workbench;
+  g_autoptr(GPtrArray) ar = NULL;
   guint i;
 
-  ENTRY;
-
-  g_assert (GB_IS_APPLICATION (application));
-
-  list = gtk_application_get_windows (GTK_APPLICATION (application));
-
-  for (; list; list = list->next)
-    {
-      if (GB_IS_WORKBENCH (list->data))
-        {
-          workbench = GB_WORKBENCH (list->data);
-          break;
-        }
-    }
-
-  if (!workbench)
-    workbench = GB_WORKBENCH (gb_application_create_workbench (application));
-
-  gtk_window_present (GTK_WINDOW (workbench));
-
-  workspace = gb_workbench_get_workspace (workbench,
-                                          GB_TYPE_EDITOR_WORKSPACE);
+  IDE_ENTRY;
 
-  g_assert (GB_IS_EDITOR_WORKSPACE (workspace));
+  g_assert (GB_IS_APPLICATION (self));
 
+  /*
+   * Try to open the files using an existing workbench.
+   */
   for (i = 0; i < n_files; i++)
     {
-      g_return_if_fail (G_IS_FILE (files [i]));
-      gb_editor_workspace_open (GB_EDITOR_WORKSPACE (workspace), files [i]);
-    }
+      GFile *file = files [i];
 
-  EXIT;
-}
-
-static void
-gb_application_activate_quit_action (GSimpleAction *action,
-                                     GVariant      *parameter,
-                                     gpointer       user_data)
-{
-  g_return_if_fail (GB_IS_APPLICATION (user_data));
-
-  g_application_quit (G_APPLICATION (user_data));
-}
+      g_assert (G_IS_FILE (file));
 
-static void
-gb_application_activate_preferences_action (GSimpleAction *action,
-                                            GVariant      *parameter,
-                                            gpointer       user_data)
-{
-  GbApplication *application = user_data;
-  GbPreferencesWindow *window;
-  GbWorkbench *workbench = NULL;
-  GList *list;
+      workbench = gb_application_find_workbench_for_file (self, file);
 
-  g_return_if_fail (GB_IS_APPLICATION (application));
+      if (workbench != NULL)
+        {
+          gb_workbench_open (workbench, file);
+          gtk_window_present (GTK_WINDOW (workbench));
+          continue;
+        }
 
-  if (application->priv->preferences_window)
-    {
-      gtk_window_present (GTK_WINDOW (application->priv->preferences_window));
-      return;
+      if (!ar)
+        ar = g_ptr_array_new_with_free_func (g_object_unref);
+      g_ptr_array_add (ar, g_object_ref (file));
     }
 
-  list = gtk_application_get_windows (GTK_APPLICATION (application));
-
-  for (; list; list = list->next)
-    if (GB_IS_WORKBENCH (list->data))
-      workbench = GB_WORKBENCH (list->data);
-
-  window = g_object_new (GB_TYPE_PREFERENCES_WINDOW,
-                         "transient-for", workbench,
-                         NULL);
-  gb_set_weak_pointer (window, &application->priv->preferences_window);
-
-  gtk_window_present (GTK_WINDOW (window));
-}
-
-static void
-gb_application_activate_support_action (GSimpleAction *action,
-                                        GVariant      *parameter,
-                                        gpointer       user_data)
-{
-  GbApplication *application = user_data;
-  GtkWidget *dialog;
-  gchar *text = NULL;
-  GList *windows;
-  GError *error = NULL;
-  gchar *str = NULL;
-  gchar *log_path = NULL;
-  gchar *name = NULL;
-
-  name = g_strdup_printf ("gnome-builder-%u.log", (int)getpid ());
-  log_path = g_build_filename (g_get_home_dir (), name, NULL);
-  g_free (name);
-
-  windows = gtk_application_get_windows (GTK_APPLICATION (application));
-
-  str = gb_get_support_log ();
-
-  if (!g_file_set_contents (log_path, str, -1, &error))
+  /*
+   * No workbench found for these files, let's create one!
+   */
+  if (ar && ar->len)
     {
-      g_printerr ("%s\n", error->message);
-      goto cleanup;
-    }
+      g_autoptr(GFile) directory = NULL;
+      g_autoptr(GTask) task = NULL;
+      GFile *file;
 
-  text = g_strdup_printf (_("The support log file has been written to '%s'. "
-                            "Please provide this file as an attachment on "
-                            "your bug report or support request."),
-                            log_path);
+      task = g_task_new (self, NULL, NULL, NULL);
+      g_task_set_task_data (task, g_ptr_array_ref (ar), (GDestroyNotify)g_ptr_array_unref);
 
-  g_message ("%s", text);
-
-  dialog = gtk_message_dialog_new (windows ? windows->data : NULL,
-                                   GTK_DIALOG_DESTROY_WITH_PARENT,
-                                   GTK_MESSAGE_INFO,
-                                   GTK_BUTTONS_CLOSE,
-                                   "%s", text);
-  gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
-  g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
-  gtk_window_present (GTK_WINDOW (dialog));
-
-cleanup:
-  g_free (text);
-  g_clear_error (&error);
-  g_free (str);
-  g_free (log_path);
-}
+      file = g_ptr_array_index (ar, 0);
 
-static void
-gb_application_register_actions (GbApplication *self)
-{
-  static const GActionEntry action_entries[] = {
-    { "preferences", gb_application_activate_preferences_action },
-    { "support", gb_application_activate_support_action },
-    { "quit", gb_application_activate_quit_action },
-  };
+      if (g_file_query_file_type (file, 0, NULL) == G_FILE_TYPE_DIRECTORY)
+        directory = g_object_ref (file);
+      else
+        directory = g_file_get_parent (file);
 
-  g_return_if_fail (GB_IS_APPLICATION (self));
+      ide_context_new_async (directory,
+                             NULL,
+                             gb_application__context_new_cb,
+                             g_object_ref (task));
+      g_application_hold (G_APPLICATION (self));
+    }
 
-  g_action_map_add_action_entries (G_ACTION_MAP (self),
-                                   action_entries,
-                                   G_N_ELEMENTS (action_entries),
-                                   self);
+  IDE_EXIT;
 }
 
 static void
@@ -613,7 +409,7 @@ gb_application_startup (GApplication *app)
 {
   GbApplication *self = (GbApplication *)app;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_assert (GB_IS_APPLICATION (self));
 
@@ -623,42 +419,16 @@ gb_application_startup (GApplication *app)
   G_APPLICATION_CLASS (gb_application_parent_class)->startup (app);
 
   gb_application_make_skeleton_dirs (self);
-  gb_application_install_language_defaults (self);
-  gb_application_register_actions (self);
-  gb_application_register_keybindings (self);
+  gb_application_actions_init (self);
   gb_application_register_theme_overrides (self);
-  gb_application_load_file_marks (self);
   gb_application_setup_search_paths ();
+  gb_application_load_keybindings (self);
 
-  EXIT;
-}
-
-static void
-gb_application_shutdown (GApplication *app)
-{
-  GbApplication *self = (GbApplication *)app;
-  GbEditorFileMarks *marks;
-  GError *error = NULL;
-
-  ENTRY;
-
-  g_assert (GB_IS_APPLICATION (self));
-
-  marks = gb_editor_file_marks_get_default ();
-
-  if (!gb_editor_file_marks_save (marks, NULL, &error))
-    {
-      g_warning ("%s", error->message);
-      g_clear_error (&error);
-    }
-
-  G_APPLICATION_CLASS (gb_application_parent_class)->shutdown (app);
-
-  EXIT;
+  IDE_EXIT;
 }
 
 static gboolean
-verbose_cb (void)
+gb_application_increase_verbosity (void)
 {
   ide_log_increase_verbosity ();
   return TRUE;
@@ -671,8 +441,12 @@ gb_application_local_command_line (GApplication   *app,
 {
   g_autoptr(GOptionContext) context = NULL;
   GOptionEntry entries[] = {
-    { "verbose", 'v', G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK,
-      verbose_cb, N_("Increase verbosity. May be specified multiple times.") },
+    { "verbose",
+      'v',
+      G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_IN_MAIN,
+      G_OPTION_ARG_CALLBACK,
+      gb_application_increase_verbosity,
+      N_("Increase verbosity. May be specified multiple times.") },
     { NULL }
   };
 
@@ -682,36 +456,24 @@ gb_application_local_command_line (GApplication   *app,
   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
   g_option_context_parse_strv (context, argv, NULL);
 
-  return G_APPLICATION_CLASS (gb_application_parent_class)->
-    local_command_line (app, argv, exit_status);
-}
-
-static void
-gb_application_constructed (GObject *object)
-{
-  ENTRY;
-
-  if (G_OBJECT_CLASS (gb_application_parent_class)->constructed)
-    G_OBJECT_CLASS (gb_application_parent_class)->constructed (object);
-
-  EXIT;
+  return G_APPLICATION_CLASS (gb_application_parent_class)->local_command_line (app,
+                                                                                argv,
+                                                                                exit_status);
 }
 
 static void
 gb_application_finalize (GObject *object)
 {
-  GbApplicationPrivate *priv;
-
-  ENTRY;
+  GbApplication *self = (GbApplication *)object;
 
-  priv = GB_APPLICATION (object)->priv;
+  IDE_ENTRY;
 
-  g_clear_object (&priv->editor_settings);
-  g_clear_object (&priv->keybindings);
+  g_clear_object (&self->keybindings);
+  g_clear_object (&self->editor_settings);
 
   G_OBJECT_CLASS (gb_application_parent_class)->finalize (object);
 
-  EXIT;
+  IDE_EXIT;
 }
 
 static void
@@ -720,24 +482,21 @@ gb_application_class_init (GbApplicationClass *klass)
   GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  ENTRY;
+  IDE_ENTRY;
 
-  object_class->constructed = gb_application_constructed;
   object_class->finalize = gb_application_finalize;
 
   app_class->activate = gb_application_activate;
   app_class->startup = gb_application_startup;
-  app_class->shutdown = gb_application_shutdown;
   app_class->open = gb_application_open;
   app_class->local_command_line = gb_application_local_command_line;
 
-  EXIT;
+  IDE_EXIT;
 }
 
 static void
 gb_application_init (GbApplication *application)
 {
-  ENTRY;
-  application->priv = gb_application_get_instance_private (application);
-  EXIT;
+  IDE_ENTRY;
+  IDE_EXIT;
 }
diff --git a/src/app/gb-application.h b/src/app/gb-application.h
index 24adbed..43d2666 100644
--- a/src/app/gb-application.h
+++ b/src/app/gb-application.h
@@ -23,32 +23,9 @@
 
 G_BEGIN_DECLS
 
-#define GB_TYPE_APPLICATION            (gb_application_get_type())
-#define GB_APPLICATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_APPLICATION, 
GbApplication))
-#define GB_APPLICATION_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_APPLICATION, 
GbApplication const))
-#define GB_APPLICATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_APPLICATION, 
GbApplicationClass))
-#define GB_IS_APPLICATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_APPLICATION))
-#define GB_IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_APPLICATION))
-#define GB_APPLICATION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_APPLICATION, 
GbApplicationClass))
+#define GB_TYPE_APPLICATION (gb_application_get_type())
 
-typedef struct _GbApplication        GbApplication;
-typedef struct _GbApplicationClass   GbApplicationClass;
-typedef struct _GbApplicationPrivate GbApplicationPrivate;
-
-struct _GbApplication
-{
-  GtkApplication parent;
-
-  /*< private >*/
-  GbApplicationPrivate *priv;
-};
-
-struct _GbApplicationClass
-{
-  GtkApplicationClass parent_class;
-};
-
-GType gb_application_get_type (void);
+G_DECLARE_FINAL_TYPE (GbApplication, gb_application, GB, APPLICATION, GtkApplication)
 
 G_END_DECLS
 
diff --git a/src/commands/gb-command-bar.c b/src/commands/gb-command-bar.c
index de21055..f2d3d5c 100644
--- a/src/commands/gb-command-bar.c
+++ b/src/commands/gb-command-bar.c
@@ -17,8 +17,8 @@
  */
 
 #include <glib/gi18n.h>
+#include <ide.h>
 
-#include "gb-animation.h"
 #include "gb-command.h"
 #include "gb-command-bar.h"
 #include "gb-command-bar-item.h"
@@ -165,12 +165,12 @@ gb_command_bar_push_result (GbCommandBar    *bar,
   upper = gtk_adjustment_get_upper (vadj);
   frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (bar->priv->list_box));
 
-  gb_object_animate (vadj,
-                     GB_ANIMATION_EASE_IN_CUBIC,
-                     250,
-                     frame_clock,
-                     "value", upper,
-                     NULL);
+  ide_object_animate (vadj,
+                      IDE_ANIMATION_EASE_IN_CUBIC,
+                      250,
+                      frame_clock,
+                      "value", upper,
+                      NULL);
 }
 
 static void
diff --git a/src/commands/gb-command-gaction-provider.c b/src/commands/gb-command-gaction-provider.c
index 50ce087..6a50102 100644
--- a/src/commands/gb-command-gaction-provider.c
+++ b/src/commands/gb-command-gaction-provider.c
@@ -18,11 +18,11 @@
 
 #define G_LOG_DOMAIN "gaction-commands"
 
+#include <ide.h>
 #include <string.h>
 
 #include "gb-command-gaction-provider.h"
 #include "gb-command-gaction.h"
-#include "gb-log.h"
 
 G_DEFINE_TYPE (GbCommandGactionProvider, gb_command_gaction_provider,
                GB_TYPE_COMMAND_PROVIDER)
@@ -152,13 +152,13 @@ gb_command_gaction_provider_lookup (GbCommandProvider *provider,
   GList *iter;
   gchar *action_name = NULL;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_return_val_if_fail (GB_IS_COMMAND_GACTION_PROVIDER (self), NULL);
   g_return_val_if_fail (command_text, NULL);
 
   if (!parse_command_text (command_text, &action_name, &params))
-    RETURN (NULL);
+    IDE_RETURN (NULL);
 
   groups = discover_groups (self);
 
@@ -181,7 +181,7 @@ gb_command_gaction_provider_lookup (GbCommandProvider *provider,
   g_list_free (groups);
   g_free (action_name);
 
-  RETURN (command);
+  IDE_RETURN (command);
 }
 
 static void
@@ -193,7 +193,7 @@ gb_command_gaction_provider_complete (GbCommandProvider *provider,
   GList *groups;
   GList *iter;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_return_if_fail (GB_IS_COMMAND_GACTION_PROVIDER (self));
   g_return_if_fail (initial_command_text);
@@ -221,7 +221,7 @@ gb_command_gaction_provider_complete (GbCommandProvider *provider,
 
   g_list_free (groups);
 
-  EXIT;
+  IDE_EXIT;
 }
 
 static void
diff --git a/src/commands/gb-command-provider.c b/src/commands/gb-command-provider.c
index 6b05ed2..6602a64 100644
--- a/src/commands/gb-command-provider.c
+++ b/src/commands/gb-command-provider.c
@@ -24,12 +24,11 @@
 struct _GbCommandProviderPrivate
 {
   GbWorkbench    *workbench;
-  GbDocumentView *active_view;
+  GbView *active_view;
   gint            priority;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GbCommandProvider, gb_command_provider,
-                            G_TYPE_OBJECT)
+G_DEFINE_TYPE_WITH_PRIVATE (GbCommandProvider, gb_command_provider, G_TYPE_OBJECT)
 
 enum {
   PROP_0,
@@ -62,9 +61,9 @@ gb_command_provider_new (GbWorkbench *workbench)
  * Returns the "active-tab" property. The active-tab is the last tab that
  * was focused in the workbench.
  *
- * Returns: (transfer none): A #GbDocumentView or %NULL.
+ * Returns: (transfer none): A #GbView or %NULL.
  */
-GbDocumentView *
+GbView *
 gb_command_provider_get_active_view (GbCommandProvider *provider)
 {
   g_return_val_if_fail (GB_IS_COMMAND_PROVIDER (provider), NULL);
@@ -74,12 +73,12 @@ gb_command_provider_get_active_view (GbCommandProvider *provider)
 
 static void
 gb_command_provider_set_active_view (GbCommandProvider *provider,
-                                    GbDocumentView             *tab)
+                                    GbView             *tab)
 {
   GbCommandProviderPrivate *priv;
 
   g_return_if_fail (GB_IS_COMMAND_PROVIDER (provider));
-  g_return_if_fail (!tab || GB_IS_DOCUMENT_VIEW (tab));
+  g_return_if_fail (!tab || GB_IS_VIEW (tab));
 
   priv = provider->priv;
 
@@ -112,13 +111,13 @@ on_workbench_set_focus (GbCommandProvider *provider,
 
   /* walk the hierarchy to find a tab */
   if (widget)
-    while (!GB_IS_DOCUMENT_VIEW (widget))
+    while (!GB_IS_VIEW (widget))
       if (!(widget = gtk_widget_get_parent (widget)))
         break;
 
-  if (GB_IS_DOCUMENT_VIEW (widget))
+  if (GB_IS_VIEW (widget))
     gb_command_provider_set_active_view (provider,
-                                         GB_DOCUMENT_VIEW (widget));
+                                         GB_VIEW (widget));
 }
 
 static void
@@ -313,13 +312,11 @@ gb_command_provider_class_init (GbCommandProviderClass *klass)
 
   gParamSpecs [PROP_ACTIVE_VIEW] =
     g_param_spec_object ("active-tab",
-                         _("Active DocumentView"),
-                         _("The last focused GbDocumentView widget."),
-                         GB_TYPE_DOCUMENT_VIEW,
-                         (G_PARAM_READABLE |
-                          G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_ACTIVE_VIEW,
-                                   gParamSpecs [PROP_ACTIVE_VIEW]);
+                         _("Active View"),
+                         _("The last focused GbView widget."),
+                         GB_TYPE_VIEW,
+                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_ACTIVE_VIEW, gParamSpecs [PROP_ACTIVE_VIEW]);
 
   /**
    * GbCommandProvider:priority:
@@ -341,8 +338,7 @@ gb_command_provider_class_init (GbCommandProviderClass *klass)
                       G_MAXINT,
                       0,
                       (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_PRIORITY,
-                                   gParamSpecs [PROP_PRIORITY]);
+  g_object_class_install_property (object_class, PROP_PRIORITY, gParamSpecs [PROP_PRIORITY]);
 
   /**
    * GbCommandProvider:workbench:
diff --git a/src/commands/gb-command-provider.h b/src/commands/gb-command-provider.h
index fd0ad91..5cce3ac 100644
--- a/src/commands/gb-command-provider.h
+++ b/src/commands/gb-command-provider.h
@@ -22,7 +22,7 @@
 #include <gio/gio.h>
 
 #include "gb-command.h"
-#include "gb-document-view.h"
+#include "gb-view.h"
 #include "gb-workbench-types.h"
 
 G_BEGIN_DECLS
@@ -61,7 +61,7 @@ struct _GbCommandProviderClass
 GType              gb_command_provider_get_type        (void);
 GbCommandProvider *gb_command_provider_new             (GbWorkbench       *workbench);
 GbWorkbench       *gb_command_provider_get_workbench   (GbCommandProvider *provider);
-GbDocumentView    *gb_command_provider_get_active_view (GbCommandProvider *provider);
+GbView            *gb_command_provider_get_active_view (GbCommandProvider *provider);
 gint               gb_command_provider_get_priority    (GbCommandProvider *provider);
 void               gb_command_provider_set_priority    (GbCommandProvider *provider,
                                                         gint               priority);
diff --git a/src/commands/gb-command-vim-provider.c b/src/commands/gb-command-vim-provider.c
index d6ecbbf..67d0a4f 100644
--- a/src/commands/gb-command-vim-provider.c
+++ b/src/commands/gb-command-vim-provider.c
@@ -18,6 +18,8 @@
 
 #define G_LOG_DOMAIN "vim-command-provider"
 
+#if 0
+
 #include "gb-editor-view.h"
 #include "gb-editor-frame-private.h"
 #include "gb-command-vim.h"
@@ -170,3 +172,5 @@ gb_command_vim_provider_init (GbCommandVimProvider *self)
   g_object_set_data_full (G_OBJECT (self), "editor-settings", settings,
                           g_object_unref);
 }
+
+#endif
diff --git a/src/commands/gb-command-vim.c b/src/commands/gb-command-vim.c
index daee4a5..11c8d36 100644
--- a/src/commands/gb-command-vim.c
+++ b/src/commands/gb-command-vim.c
@@ -17,14 +17,14 @@
  */
 
 #include <glib/gi18n.h>
+#include <ide.h>
 
 #include "gb-command-vim.h"
-#include "gb-source-view.h"
 
 struct _GbCommandVimPrivate
 {
-  GbSourceView *source_view;
-  gchar        *command_text;
+  IdeSourceView *source_view;
+  gchar         *command_text;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (GbCommandVim, gb_command_vim, GB_TYPE_COMMAND)
@@ -38,7 +38,7 @@ enum {
 
 static GParamSpec *gParamSpecs [LAST_PROP];
 
-GbSourceView *
+IdeSourceView *
 gb_command_vim_get_source_view (GbCommandVim *vim)
 {
   g_return_val_if_fail (GB_IS_COMMAND_VIM (vim), NULL);
@@ -47,11 +47,11 @@ gb_command_vim_get_source_view (GbCommandVim *vim)
 }
 
 static void
-gb_command_vim_set_source_view (GbCommandVim *vim,
-                                GbSourceView *source_view)
+gb_command_vim_set_source_view (GbCommandVim  *vim,
+                                IdeSourceView *source_view)
 {
   g_return_if_fail (GB_IS_COMMAND_VIM (vim));
-  g_return_if_fail (!source_view || GB_IS_SOURCE_VIEW (source_view));
+  g_return_if_fail (!source_view || IDE_IS_SOURCE_VIEW (source_view));
 
   if (source_view != vim->priv->source_view)
     {
@@ -106,10 +106,12 @@ gb_command_vim_execute (GbCommand *command)
 
   if (self->priv->source_view)
     {
+#if 0
       GbSourceVim *vim;
 
       vim = gb_source_view_get_vim (self->priv->source_view);
       gb_source_vim_execute_command (vim, self->priv->command_text);
+#endif
     }
 
   return NULL;
@@ -198,7 +200,7 @@ gb_command_vim_class_init (GbCommandVimClass *klass)
     g_param_spec_object ("source-view",
                          _("Source View"),
                          _("The source view to modify."),
-                         GB_TYPE_SOURCE_VIEW,
+                         IDE_TYPE_SOURCE_VIEW,
                          (G_PARAM_READWRITE |
                           G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_SOURCE_VIEW,
diff --git a/src/commands/gb-command.c b/src/commands/gb-command.c
index aaa8b45..c04ad30 100644
--- a/src/commands/gb-command.c
+++ b/src/commands/gb-command.c
@@ -60,7 +60,7 @@ gb_command_class_init (GbCommandClass *klass)
                   G_STRUCT_OFFSET (GbCommandClass, execute),
                   g_signal_accumulator_first_wins,
                   NULL,
-                  NULL,
+                  g_cclosure_marshal_generic,
                   GB_TYPE_COMMAND_RESULT,
                   0);
 }
diff --git a/src/documents/gb-document.c b/src/documents/gb-document.c
index 4bd74dd..4abccda 100644
--- a/src/documents/gb-document.c
+++ b/src/documents/gb-document.c
@@ -16,10 +16,12 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define G_LOG_DOMAIN "gb-document"
+
 #include <glib/gi18n.h>
 
 #include "gb-document.h"
-#include "gb-document-view.h"
+#include "gb-view.h"
 
 G_DEFINE_INTERFACE (GbDocument, gb_document, G_TYPE_OBJECT)
 
@@ -207,6 +209,14 @@ gb_document_default_init (GbDocumentInterface *iface)
                          (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
   g_object_interface_install_property (iface, gParamSpecs [PROP_READ_ONLY]);
 
+  /**
+   * GbDocument::create-view:
+   * @self: A #GbDocument.
+   *
+   * Creates a new view for the document.
+   *
+   * Returns: (ctype GbView*) (transfer full): A #GbView.
+   */
   gSignals [CREATE_VIEW] =
     g_signal_new ("create-view",
                   GB_TYPE_DOCUMENT,
@@ -215,6 +225,6 @@ gb_document_default_init (GbDocumentInterface *iface)
                   g_signal_accumulator_first_wins,
                   NULL,
                   g_cclosure_marshal_generic,
-                  GB_TYPE_DOCUMENT_VIEW,
+                  GTK_TYPE_WIDGET,
                   0);
 }
diff --git a/src/documents/gb-document.h b/src/documents/gb-document.h
index 590d345..d6b0294 100644
--- a/src/documents/gb-document.h
+++ b/src/documents/gb-document.h
@@ -35,13 +35,13 @@ struct _GbDocumentInterface
 {
   GTypeInterface parent;
 
-  GtkWidget   *(*create_view)           (GbDocument *document);
-  gboolean     (*get_modified)          (GbDocument *document);
-  gboolean     (*get_mtime)             (GbDocument *document,
-                                         GTimeVal   *mtime);
-  gboolean     (*get_read_only)         (GbDocument *document);
-  const gchar *(*get_title)             (GbDocument *document);
-  gboolean     (*is_untitled)           (GbDocument *document);
+  GtkWidget   *(*create_view)           (GbDocument           *document);
+  gboolean     (*get_modified)          (GbDocument           *document);
+  gboolean     (*get_mtime)             (GbDocument           *document,
+                                         GTimeVal             *mtime);
+  gboolean     (*get_read_only)         (GbDocument           *document);
+  const gchar *(*get_title)             (GbDocument           *document);
+  gboolean     (*is_untitled)           (GbDocument           *document);
   void         (*save_async)            (GbDocument           *document,
                                          GtkWidget            *toplevel,
                                          GCancellable         *cancellable,
diff --git a/src/editor/gb-editor-document.c b/src/editor/gb-editor-document.c
index e0653b0..180f0e7 100644
--- a/src/editor/gb-editor-document.c
+++ b/src/editor/gb-editor-document.c
@@ -1,6 +1,6 @@
 /* gb-editor-document.c
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2014-2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,1321 +16,94 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define G_LOG_DOMAIN "editor-document"
+#define G_LOG_DOMAIN "gb-editor-document"
 
 #include <glib/gi18n.h>
-#include <gtksourceview/gtksource.h>
+#include <ide.h>
 
 #include "gb-document.h"
-#include "gb-doc-seq.h"
 #include "gb-editor-document.h"
-#include "gb-editor-file-marks.h"
 #include "gb-editor-view.h"
-#include "gb-log.h"
-#include "gb-gtk.h"
-#include "gca-structs.h"
 
-struct _GbEditorDocumentPrivate
+struct _GbEditorDocument
 {
-  GtkSourceFile         *file;
-  GbSourceChangeMonitor *change_monitor;
-  GbSourceCodeAssistant *code_assistant;
-  gchar                 *title;
-  GCancellable          *cancellable;
-  GError                *error;
-
-  gdouble                progress;
-  guint                  doc_seq_id;
-  GTimeVal               mtime;
-  GTimeVal               unsaved_ctime;
-
-  guint                  file_changed_on_volume : 1;
-  guint                  mtime_set : 1;
-  guint                  read_only : 1;
-  guint                  trim_trailing_whitespace : 1;
+  IdeBuffer parent_instance;
 };
 
 enum {
   PROP_0,
-  PROP_CHANGE_MONITOR,
-  PROP_ERROR,
-  PROP_FILE,
-  PROP_FILE_CHANGED_ON_VOLUME,
   PROP_MODIFIED,
-  PROP_PROGRESS,
   PROP_READ_ONLY,
-  PROP_STYLE_SCHEME_NAME,
-  PROP_TITLE,
-  PROP_TRIM_TRAILING_WHITESPACE,
   LAST_PROP
 };
 
 enum {
-  CURSOR_MOVED,
-  FILE_MARK_SET,
-  SAVED,
   LAST_SIGNAL
 };
 
-static void gb_editor_document_init_document (GbDocumentInterface *iface);
-static void gb_editor_document_update_title  (GbEditorDocument *document);
-
-G_DEFINE_TYPE_EXTENDED (GbEditorDocument,
-                        gb_editor_document,
-                        GTK_SOURCE_TYPE_BUFFER,
-                        0,
-                        G_ADD_PRIVATE (GbEditorDocument)
-                        G_IMPLEMENT_INTERFACE (GB_TYPE_DOCUMENT,
-                                               gb_editor_document_init_document))
-
-static GParamSpec *gParamSpecs [LAST_PROP];
-static guint gSignals [LAST_SIGNAL];
-
-GbEditorDocument *
-gb_editor_document_new (void)
-{
-  return g_object_new (GB_TYPE_EDITOR_DOCUMENT, NULL);
-}
-
-static gboolean
-gb_editor_document_is_untitled (GbDocument *document)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), FALSE);
-
-  return (GB_EDITOR_DOCUMENT (document)->priv->doc_seq_id > 0);
-}
-
-/**
- * gb_editor_document_get_error:
- *
- * Fetches the most recent error for the #GbEditorDocument instance. If no
- * error has been registered, %NULL is returned.
- *
- * Returns: (transfer none): A #GError or %NULL.
- */
-const GError *
-gb_editor_document_get_error (GbEditorDocument *document)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), NULL);
-
-  return document->priv->error;
-}
-
-static void
-gb_editor_document_set_error (GbEditorDocument *document,
-                              const GError     *error)
-{
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  if (error != document->priv->error)
-    {
-      g_clear_error (&document->priv->error);
-      document->priv->error = g_error_copy (error);
-      g_object_notify_by_pspec (G_OBJECT (document), gParamSpecs [PROP_ERROR]);
-    }
-}
-
-static gboolean
-gb_editor_document_get_read_only (GbDocument *document)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), FALSE);
-
-  return GB_EDITOR_DOCUMENT (document)->priv->read_only;
-}
-
-static void
-gb_editor_document_set_read_only (GbEditorDocument *document,
-                                  gboolean          read_only)
-{
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  if (document->priv->read_only != read_only)
-    {
-      document->priv->read_only = !!read_only;
-      g_object_notify (G_OBJECT (document), "read-only");
-      gb_editor_document_update_title (document);
-    }
-
-  EXIT;
-}
-
-gboolean
-gb_editor_document_get_file_changed_on_volume (GbEditorDocument *document)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), FALSE);
-
-  return document->priv->file_changed_on_volume;
-}
-
-static void
-gb_editor_document_set_file_changed_on_volume (GbEditorDocument *document,
-                                               gboolean          file_changed_on_volume)
-{
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  if (file_changed_on_volume != document->priv->file_changed_on_volume)
-    {
-      document->priv->file_changed_on_volume = !!file_changed_on_volume;
-      g_object_notify_by_pspec (G_OBJECT (document),
-                                gParamSpecs [PROP_FILE_CHANGED_ON_VOLUME]);
-    }
-}
-
-static void
-gb_editor_document_check_modified_cb (GObject      *object,
-                                      GAsyncResult *result,
-                                      gpointer      user_data)
-{
-  GbEditorDocument *document = user_data;
-  GFileInfo *info;
-  GError *error = NULL;
-  GFile *file = (GFile *)object;
-
-  g_return_if_fail (G_IS_FILE (file));
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  info = g_file_query_info_finish (file, result, &error);
-
-  if (info)
-    {
-      if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
-        {
-          gboolean read_only;
-
-          read_only = !g_file_info_get_attribute_boolean (info,
-                                                          G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
-          if (gb_editor_document_get_read_only (GB_DOCUMENT (document)) != read_only)
-            gb_editor_document_set_read_only (document, read_only);
-        }
-
-      if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED) && document->priv->mtime_set)
-        {
-          GTimeVal tv;
-
-          g_file_info_get_modification_time (info, &tv);
-
-          if (memcmp (&tv, &document->priv->mtime, sizeof tv) != 0)
-            gb_editor_document_set_file_changed_on_volume (document, TRUE);
-        }
-    }
-
-  g_clear_object (&document);
-  g_clear_object (&info);
-}
-
-void
-gb_editor_document_check_externally_modified (GbEditorDocument *document)
-{
-  GFile *location;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  if (document->priv->file_changed_on_volume)
-    return;
-
-  location = gtk_source_file_get_location (document->priv->file);
-  if (!location)
-    return;
-
-  g_file_query_info_async (location,
-                           G_FILE_ATTRIBUTE_TIME_MODIFIED ","
-                           G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
-                           G_FILE_QUERY_INFO_NONE,
-                           G_PRIORITY_DEFAULT,
-                           document->priv->cancellable,
-                           gb_editor_document_check_modified_cb,
-                           g_object_ref (document));
-}
-
-gdouble
-gb_editor_document_get_progress (GbEditorDocument *document)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), 0.0);
-
-  return document->priv->progress;
-}
-
-static void
-gb_editor_document_set_progress (GbEditorDocument *document,
-                                 gdouble           progress)
-{
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-  g_return_if_fail (progress >= 0.0);
-  g_return_if_fail (progress <= 1.0);
-
-  document->priv->progress = progress;
-  g_object_notify_by_pspec (G_OBJECT (document), gParamSpecs [PROP_PROGRESS]);
-}
-
-gboolean
-gb_editor_document_get_trim_trailing_whitespace (GbEditorDocument *document)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), FALSE);
-
-  return document->priv->trim_trailing_whitespace;
-}
-
-void
-gb_editor_document_set_trim_trailing_whitespace (GbEditorDocument *document,
-                                                 gboolean          trim_trailing_whitespace)
-{
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  if (trim_trailing_whitespace != document->priv->trim_trailing_whitespace)
-    {
-      document->priv->trim_trailing_whitespace = !!trim_trailing_whitespace;
-      g_object_notify_by_pspec (G_OBJECT (document),
-                                gParamSpecs [PROP_TRIM_TRAILING_WHITESPACE]);
-    }
-}
-
-GbSourceChangeMonitor *
-gb_editor_document_get_change_monitor (GbEditorDocument *document)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), NULL);
-
-  return document->priv->change_monitor;
-}
-
-GbSourceCodeAssistant *
-gb_editor_document_get_code_assistant (GbEditorDocument *document)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), NULL);
-
-  return document->priv->code_assistant;
-}
-
-GtkSourceFile *
-gb_editor_document_get_file (GbEditorDocument *document)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), NULL);
-
-  return document->priv->file;
-}
-
-static void
-gb_editor_document_set_style_scheme_name (GbEditorDocument *document,
-                                          const gchar      *style_scheme_name)
-{
-  GtkSourceStyleSchemeManager *manager;
-  GtkSourceStyleScheme *scheme;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  manager = gtk_source_style_scheme_manager_get_default ();
-  scheme = gtk_source_style_scheme_manager_get_scheme (manager,
-                                                       style_scheme_name);
-  gtk_source_buffer_set_style_scheme (GTK_SOURCE_BUFFER (document), scheme);
-}
-
-static void
-gb_editor_document_mark_set (GtkTextBuffer     *buffer,
-                             const GtkTextIter *iter,
-                             GtkTextMark       *mark)
-{
-  if (GTK_TEXT_BUFFER_CLASS (gb_editor_document_parent_class)->mark_set)
-    GTK_TEXT_BUFFER_CLASS (gb_editor_document_parent_class)->mark_set (buffer, iter, mark);
-
-  if (mark == gtk_text_buffer_get_insert (buffer))
-    g_signal_emit (buffer, gSignals [CURSOR_MOVED], 0);
-}
-
-static void
-gb_editor_document_changed (GtkTextBuffer *buffer)
-{
-  g_assert (GB_IS_EDITOR_DOCUMENT (buffer));
-
-  g_signal_emit (buffer, gSignals [CURSOR_MOVED], 0);
-
-  GTK_TEXT_BUFFER_CLASS (gb_editor_document_parent_class)->changed (buffer);
-}
-
-static void
-gb_editor_document_add_diagnostic (GbEditorDocument *document,
-                                   GcaDiagnostic    *diag,
-                                   GcaSourceRange   *range)
-{
-  GtkTextBuffer *buffer;
-  GtkTextIter begin;
-  GtkTextIter end;
-  guint column;
-
-  g_assert (GB_IS_EDITOR_DOCUMENT (document));
-  g_assert (diag);
-  g_assert (range);
-
-  if (range->begin.line == -1 || range->end.line == -1)
-    return;
-
-  buffer = GTK_TEXT_BUFFER (document);
-
-  gtk_text_buffer_get_iter_at_line (buffer, &begin, range->begin.line);
-  for (column = range->begin.column; column; column--)
-    if (gtk_text_iter_ends_line (&begin) || !gtk_text_iter_forward_char (&begin))
-      break;
-
-  gtk_text_buffer_get_iter_at_line (buffer, &end, range->end.line);
-  for (column = range->end.column; column; column--)
-    if (gtk_text_iter_ends_line (&end) || !gtk_text_iter_forward_char (&end))
-      break;
-
-  if (gtk_text_iter_equal (&begin, &end))
-    gtk_text_iter_forward_to_line_end (&end);
-
-  gtk_text_buffer_apply_tag_by_name (buffer, "ErrorTag", &begin, &end);
-}
-
-static void
-apply_tag_style (GbEditorDocument *document,
-                 GtkTextTag       *tag,
-                 const gchar      *style_id)
-{
-  GtkSourceStyleScheme *scheme;
-  GtkSourceStyle *style;
-  gboolean background_set;
-  gboolean bold_set;
-  gboolean foreground_set;
-  gboolean line_background_set;
-  gchar *str;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (document));
-  if (!scheme)
-    return;
-
-  style = gtk_source_style_scheme_get_style (scheme, style_id);
-  if (!style)
-    return;
-
-  g_object_get (style,
-                "background-set", &background_set,
-                "bold-set", &bold_set,
-                "foreground-set", &foreground_set,
-                "line-background-set", &line_background_set,
-                NULL);
-
-  if (background_set)
-    {
-      g_object_get (style, "background", &str, NULL);
-      g_object_set (tag, "background", str, NULL);
-      g_free (str);
-    }
-  else
-    g_object_set (tag, "background-set", FALSE, NULL);
-
-  if (bold_set)
-    {
-      PangoWeight weight;
-      gboolean bold;
-
-      g_object_get (style, "bold", &bold, NULL);
-      weight = bold ? PANGO_WEIGHT_NORMAL : PANGO_WEIGHT_BOLD;
-      g_object_set (tag, "weight", weight, NULL);
-    }
-  else
-    g_object_set (tag, "weight-set", FALSE, NULL);
-
-  if (foreground_set)
-    {
-      g_object_get (style, "foreground", &str, NULL);
-      g_object_set (tag, "foreground", str, NULL);
-      g_free (str);
-    }
-  else
-    g_object_set (tag, "foreground-set", FALSE, NULL);
-
-  if (line_background_set)
-    {
-      g_object_get (style, "line-background", &str, NULL);
-      g_object_set (tag, "paragraph-background", str, NULL);
-      g_free (str);
-    }
-  else
-    g_object_set (tag, "paragraph-background-set", FALSE, NULL);
-}
-
-static GtkTextTag *
-gb_editor_document_get_error_tag (GbEditorDocument *document)
-{
-  GtkTextBuffer *buffer;
-  GtkTextTagTable *tag_table;
-  GtkTextTag *tag;
-
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), NULL);
-
-  buffer = GTK_TEXT_BUFFER (document);
-  tag_table = gtk_text_buffer_get_tag_table (buffer);
-  tag = gtk_text_tag_table_lookup (tag_table, "ErrorTag");
-
-  if (!tag)
-    {
-      tag = gtk_text_buffer_create_tag (buffer, "ErrorTag",
-                                        "underline", PANGO_UNDERLINE_ERROR,
-                                        NULL);
-      apply_tag_style (document, tag, "def:error");
-    }
-
-  return tag;
-}
-
-static void
-gb_editor_document_notify_style_scheme (GbEditorDocument *document,
-                                        GParamSpec       *pspec,
-                                        gpointer          unused)
-{
-  GtkTextTag *tag;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  tag = gb_editor_document_get_error_tag (document);
-  apply_tag_style (document, tag, "def:error");
-}
-
-static void
-gb_editor_document_code_assistant_changed (GbEditorDocument      *document,
-                                           GbSourceCodeAssistant *code_assistant)
-{
-  GtkTextIter begin;
-  GtkTextIter end;
-  GtkTextTag *tag;
-  GArray *ar;
-  guint i;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-  g_return_if_fail (GB_IS_SOURCE_CODE_ASSISTANT (code_assistant));
-
-  /*
-   * Update all of the error tags in the buffer based on the diagnostics
-   * returned from code assistance. We might want to find a way to do this
-   * iteratively in the background based interactivity.
-   */
-
-  tag = gb_editor_document_get_error_tag (document);
-
-  gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (document), &begin, &end);
-  gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (document), tag, &begin, &end);
-
-  ar = gb_source_code_assistant_get_diagnostics (code_assistant);
-
-  for (i = 0; i < ar->len; i++)
-    {
-      GcaDiagnostic *diag;
-      guint j;
-
-      diag = &g_array_index (ar, GcaDiagnostic, i);
-
-      for (j = 0; j < diag->locations->len; j++)
-        {
-          GcaSourceRange *range;
-
-          range = &g_array_index (diag->locations, GcaSourceRange, j);
-          gb_editor_document_add_diagnostic (document, diag, range);
-        }
-    }
-
-  g_array_unref (ar);
-}
-
-static gboolean
-gb_editor_document_should_trim_line (GbEditorDocument *document,
-                                     guint             line)
-{
-  GbSourceChangeFlags flags;
-
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), FALSE);
-
-  flags = gb_source_change_monitor_get_line (document->priv->change_monitor,
-                                             line);
-
-  return !!flags;
-}
-
-static gboolean
-text_iter_is_space (const GtkTextIter *iter)
-{
-  return g_unichar_isspace (gtk_text_iter_get_char (iter));
-}
-
-static void
-gb_editor_document_trim (GbEditorDocument *document)
-{
-  GtkTextBuffer *buffer;
-  GtkTextIter iter;
-  gint line;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  buffer = GTK_TEXT_BUFFER (document);
-
-  gtk_text_buffer_get_end_iter (buffer, &iter);
-
-  for (line = gtk_text_iter_get_line (&iter); line >= 0; line--)
-    {
-      if (gb_editor_document_should_trim_line (document, line))
-        {
-          gtk_text_buffer_get_iter_at_line (buffer, &iter, line);
-
-          if (gtk_text_iter_forward_to_line_end (&iter) &&
-              text_iter_is_space (&iter))
-            {
-              GtkTextIter begin = iter;
-
-              while (text_iter_is_space (&begin))
-                {
-                  if (gtk_text_iter_starts_line (&begin))
-                    break;
-
-                  if (!gtk_text_iter_backward_char (&begin))
-                    break;
-                }
-
-              if (!text_iter_is_space (&begin) &&
-                  !gtk_text_iter_ends_line (&begin))
-                gtk_text_iter_forward_char (&begin);
-
-              if (!gtk_text_iter_equal (&begin, &iter))
-                gtk_text_buffer_delete (buffer, &begin, &iter);
-            }
-        }
-    }
-
-  EXIT;
-}
-
-static void
-gb_editor_document_guess_language (GbEditorDocument *document)
-{
-  GtkSourceLanguageManager *manager;
-  GtkSourceLanguage *lang;
-  GtkTextIter begin;
-  GtkTextIter end;
-  gboolean result_uncertain = TRUE;
-  GFile *location;
-  gchar *name = NULL;
-  gchar *text = NULL;
-  gchar *content_type = NULL;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  location = gtk_source_file_get_location (document->priv->file);
-  if (location)
-    name = g_file_get_basename (location);
-
-  gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (document), &begin, &end);
-  text = gtk_text_iter_get_slice (&begin, &end);
-
-  content_type = g_content_type_guess (name,
-                                       (const guint8 *)text, strlen (text),
-                                       &result_uncertain);
-  if (result_uncertain)
-    g_clear_pointer (&content_type, g_free);
-
-  manager = gtk_source_language_manager_get_default ();
-  lang = gtk_source_language_manager_guess_language (manager, name, content_type);
-
-  gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (document), lang);
-
-  g_free (content_type);
-  g_free (name);
-  g_free (text);
-}
-
-static void
-gb_editor_document_update_title (GbEditorDocument *document)
-{
-  GbEditorDocumentPrivate *priv;
-  GFile *location;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  priv = document->priv;
-
-  g_clear_pointer (&priv->title, g_free);
-
-  location = gtk_source_file_get_location (priv->file);
-
-  if (location)
-    {
-      priv->title = g_file_get_basename (location);
-
-      if (document->priv->read_only)
-        {
-          gchar *tmp = priv->title;
-          priv->title = g_strdup_printf (_("%s (Read Only)"), tmp);
-          g_free (tmp);
-        }
-    }
-  else
-    priv->title = g_strdup_printf (_("untitled document %u"), priv->doc_seq_id);
-
-  g_object_notify (G_OBJECT (document), "title");
-}
-
-static void
-gb_editor_document_notify_file_location (GbEditorDocument *document,
-                                         GParamSpec       *pspec,
-                                         GtkSourceFile    *file)
-{
-  GbEditorDocumentPrivate *priv;
-  GFile *location;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-  g_return_if_fail (GTK_SOURCE_IS_FILE (file));
-
-  priv = document->priv;
-
-  location = gtk_source_file_get_location (file);
-
-  if (!location)
-    {
-      if (!priv->doc_seq_id)
-        {
-          priv->doc_seq_id = gb_doc_seq_acquire ();
-          g_get_current_time (&priv->unsaved_ctime);
-        }
-    }
-  else
-    {
-      if (priv->doc_seq_id)
-        {
-          gb_doc_seq_release (priv->doc_seq_id);
-          priv->doc_seq_id = 0;
-        }
-    }
+static void document_interface_init (GbDocumentInterface *iface);
 
-  gb_editor_document_update_title (document);
+G_DEFINE_TYPE_WITH_CODE (GbEditorDocument, gb_editor_document, IDE_TYPE_BUFFER,
+                         G_IMPLEMENT_INTERFACE (GB_TYPE_DOCUMENT,
+                                                document_interface_init))
 
-  gb_source_change_monitor_set_file (priv->change_monitor, location);
-
-  gb_editor_document_guess_language (document);
-}
-
-static void
-gb_editor_document_progress_cb (goffset  current_num_bytes,
-                                goffset  total_num_bytes,
-                                gpointer user_data)
-{
-  GbEditorDocument *document = user_data;
-  gdouble fraction;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  fraction = total_num_bytes
-           ? ((gdouble)current_num_bytes / (gdouble)total_num_bytes)
-           : 1.0;
-
-  gb_editor_document_set_progress (document, fraction);
-}
-
-static void
-gb_editor_document_load_info_cb (GObject      *object,
-                                 GAsyncResult *result,
-                                 gpointer      user_data)
-{
-  GbEditorDocument *document = user_data;
-  GFileInfo *info;
-  GError *error = NULL;
-  GFile *file = (GFile *)object;
-
-  g_return_if_fail (G_IS_FILE (file));
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  info = g_file_query_info_finish (file, result, &error);
-
-  if (info)
-    {
-      if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
-        {
-          gboolean read_only;
-
-          read_only = !g_file_info_get_attribute_boolean (info,
-                                                          G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
-          gb_editor_document_set_read_only (document, read_only);
-        }
-
-      if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
-        {
-          GTimeVal tv;
-
-          g_file_info_get_modification_time (info, &tv);
-
-          document->priv->mtime = tv;
-          document->priv->mtime_set = TRUE;
-        }
-    }
-
-  g_clear_object (&document);
-  g_clear_object (&info);
-}
-
-static GFile *
-gb_editor_document_prompt_save (GbEditorDocument *document,
-                                GtkWidget        *toplevel)
-{
-  const gchar *title;
-  GtkDialog *dialog;
-  GtkWidget *suggested;
-  gint response;
-  GFile *chosen_file = NULL;
-
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), NULL);
-  g_return_val_if_fail (!toplevel || GTK_IS_WIDGET (toplevel), NULL);
-
-  dialog = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
-                         "action", GTK_FILE_CHOOSER_ACTION_SAVE,
-                         "do-overwrite-confirmation", TRUE,
-                         "local-only", FALSE,
-                         "select-multiple", FALSE,
-                         "show-hidden", FALSE,
-                         "transient-for", toplevel,
-                         "title", _("Save Document As"),
-                         NULL);
-
-  title = gb_document_get_title (GB_DOCUMENT (document));
-  gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), title);
-
-  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
-                          _("Cancel"), GTK_RESPONSE_CANCEL,
-                          _("Save"), GTK_RESPONSE_OK,
-                          NULL);
-
-  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
-
-  suggested = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog),
-                                                  GTK_RESPONSE_OK);
-  gtk_style_context_add_class (gtk_widget_get_style_context (suggested),
-                               GTK_STYLE_CLASS_SUGGESTED_ACTION);
-
-  response = gtk_dialog_run (GTK_DIALOG (dialog));
-  gtk_widget_hide (GTK_WIDGET (dialog));
-
-  if (response == GTK_RESPONSE_OK)
-    {
-      chosen_file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
-      gtk_source_file_set_location (document->priv->file, chosen_file);
-    }
-
-  gtk_widget_destroy (GTK_WIDGET (dialog));
-
-  return chosen_file;
-}
-
-static void
-gb_editor_document_save_cb (GObject      *object,
-                            GAsyncResult *result,
-                            gpointer      user_data)
-{
-  GtkSourceFileSaver *saver = (GtkSourceFileSaver *)object;
-  GbSourceChangeMonitor *change_monitor;
-  GbEditorDocument *document;
-  GError *error = NULL;
-  GTask *task = user_data;
-  GFile *location;
-
-  ENTRY;
-
-  g_return_if_fail (GTK_SOURCE_IS_FILE_SAVER (saver));
-  g_return_if_fail (G_IS_ASYNC_RESULT (result));
-  g_return_if_fail (G_IS_TASK (task));
-
-  document = g_task_get_source_object (task);
-
-  if (!gtk_source_file_saver_save_finish (saver, result, &error))
-    {
-      gb_editor_document_set_error (document, error);
-      g_task_return_error (task, error);
-      GOTO (cleanup);
-    }
-
-  /*
-   * FIXME:
-   *
-   *   Technically this can race. We need to either disable the editing
-   *   for the buffer during the process or keep a sequence number to
-   *   ensure it hasn't changed since we started the request to save.
-   */
-  gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (document), FALSE);
-
-  location = gtk_source_file_saver_get_location (saver);
-  g_file_query_info_async (location,
-                           G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE","
-                           G_FILE_ATTRIBUTE_TIME_MODIFIED,
-                           G_FILE_QUERY_INFO_NONE,
-                           G_PRIORITY_DEFAULT,
-                           document->priv->cancellable,
-                           gb_editor_document_load_info_cb,
-                           g_object_ref (document));
-
-  change_monitor = gb_editor_document_get_change_monitor (document);
-  gb_source_change_monitor_reload (change_monitor);
-
-  g_task_return_boolean (task, TRUE);
-
-  g_signal_emit (document, gSignals [SAVED], 0);
-
-cleanup:
-  g_object_unref (task);
-
-  EXIT;
-}
-
-static void
-gb_editor_document_save_async (GbDocument          *doc,
-                               GtkWidget           *toplevel,
-                               GCancellable        *cancellable,
-                               GAsyncReadyCallback  callback,
-                               gpointer             user_data)
+static GtkWidget *
+gb_editor_document_create_view (GbDocument *self)
 {
-  GtkSourceFileSaver *saver;
-  GbEditorDocument *document = (GbEditorDocument *)doc;
-  GbEditorFileMarks *marks;
-  GbEditorFileMark *mark;
-  GFile *location;
-  GTask *task;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  if (!(location = gtk_source_file_get_location (document->priv->file)))
-    {
-      GFile *chosen_file;
+  GtkWidget *ret;
 
-      chosen_file = gb_editor_document_prompt_save (document, toplevel);
+  IDE_ENTRY;
 
-      if (!chosen_file)
-        {
-          g_task_report_new_error (document, callback, user_data,
-                                   gb_editor_document_save_async,
-                                   G_IO_ERROR,
-                                   G_IO_ERROR_NOT_FOUND,
-                                   _("No file was selected."));
-          EXIT;
-        }
+  g_assert (GB_IS_EDITOR_DOCUMENT (self));
 
-      location = gtk_source_file_get_location (document->priv->file);
-      g_assert (location == chosen_file);
+  ret = g_object_new (GB_TYPE_EDITOR_VIEW,
+                      "document", self,
+                      "visible", TRUE,
+                      NULL);
 
-      g_clear_object (&chosen_file);
-    }
-
-  task = g_task_new (document, cancellable, callback, user_data);
-
-  if (document->priv->trim_trailing_whitespace)
-    gb_editor_document_trim (document);
-
-  saver = gtk_source_file_saver_new (GTK_SOURCE_BUFFER (document),
-                                     document->priv->file);
-
-  location = gtk_source_file_get_location (document->priv->file);
-
-  if (location)
-    {
-      GtkTextMark *insert;
-      GtkTextIter iter;
-      guint line;
-      guint column;
-
-      marks = gb_editor_file_marks_get_default ();
-      mark = gb_editor_file_marks_get_for_file (marks, location);
-
-      insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (document));
-      gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (document), &iter,
-                                        insert);
-      line = gtk_text_iter_get_line (&iter);
-      column = gtk_text_iter_get_line_offset (&iter);
-
-      gb_editor_file_mark_set_line (mark, line);
-      gb_editor_file_mark_set_column (mark, column);
-    }
-
-  gb_editor_document_set_progress (document, 0.0);
-
-  document->priv->mtime_set = FALSE;
-
-  gtk_source_file_saver_save_async (saver,
-                                    G_PRIORITY_DEFAULT,
-                                    cancellable,
-                                    gb_editor_document_progress_cb,
-                                    g_object_ref (document),
-                                    g_object_unref,
-                                    gb_editor_document_save_cb,
-                                    task);
-
-  g_object_unref (saver);
-
-  EXIT;
+  IDE_RETURN (ret);
 }
 
 static gboolean
-gb_editor_document_save_finish (GbDocument    *document,
-                                GAsyncResult  *result,
-                                GError       **error)
-{
-  GTask *task = (GTask *)result;
-
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), FALSE);
-  g_return_val_if_fail (G_IS_TASK (task), FALSE);
-
-  return g_task_propagate_boolean (task, error);
-}
-
-static void
-gb_editor_document_save_as_cb (GObject      *object,
-                               GAsyncResult *result,
-                               gpointer      user_data)
-{
-  GbDocument *document;
-  GTask *task = user_data;
-  GError *error = NULL;
-
-  g_return_if_fail (G_IS_ASYNC_RESULT (result));
-  g_return_if_fail (G_IS_TASK (task));
-
-  document = g_task_get_source_object (task);
-
-  if (!gb_editor_document_save_finish (document, result, &error))
-    g_task_return_error (task, error);
-  else
-    g_task_return_boolean (task, TRUE);
-
-  g_object_unref (task);
-}
-
-static void
-gb_editor_document_save_as_async (GbDocument          *document,
-                                  GtkWidget           *toplevel,
-                                  GCancellable        *cancellable,
-                                  GAsyncReadyCallback  callback,
-                                  gpointer             user_data)
+gb_editor_document_get_modified (GbDocument *document)
 {
-  GbEditorDocument *self = (GbEditorDocument *)document;
-  GTask *task;
-  GFile *chosen_file;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (self));
-
-  task = g_task_new (self, cancellable, callback, user_data);
-
-  chosen_file = gb_editor_document_prompt_save (self, toplevel);
-
-  if (chosen_file)
-    {
-      gb_editor_document_save_async (GB_DOCUMENT (self),
-                                     toplevel,
-                                     cancellable,
-                                     gb_editor_document_save_as_cb,
-                                     task);
-      g_clear_object (&chosen_file);
-    }
-  else
-    {
-      g_task_return_new_error (task,
-                               G_IO_ERROR,
-                               G_IO_ERROR_NOT_FOUND,
-                               _("No file was selected for saving."));
-    }
-
-  EXIT;
+  return gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (document));
 }
 
 static gboolean
-gb_editor_document_save_as_finish (GbDocument    *document,
-                                   GAsyncResult  *result,
-                                   GError       **error)
-{
-  GTask *task = (GTask *)result;
-
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), FALSE);
-  g_return_val_if_fail (G_IS_TASK (task), FALSE);
-
-  return g_task_propagate_boolean (task, error);
-}
-
-static void
-gb_editor_document_restore_insert (GbEditorDocument *document)
-{
-  GbEditorFileMarks *marks;
-  GbEditorFileMark *mark;
-  GtkTextBuffer *buffer;
-  GtkTextIter iter;
-  GSettings *settings;
-  gboolean load_mark;
-  GFile *file;
-  guint line;
-  guint column;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  settings = g_settings_new ("org.gnome.builder.editor");
-  load_mark = g_settings_get_boolean (settings, "restore-insert-mark");
-  g_clear_object (&settings);
-
-  buffer = GTK_TEXT_BUFFER (document);
-
-  if (!load_mark)
-    {
-      gtk_text_buffer_get_start_iter (buffer, &iter);
-      gtk_text_buffer_select_range (buffer, &iter, &iter);
-      return;
-    }
-
-  file = gtk_source_file_get_location (document->priv->file);
-  if (!file)
-    return;
-
-  marks = gb_editor_file_marks_get_default ();
-  mark = gb_editor_file_marks_get_for_file (marks, file);
-
-  line = gb_editor_file_mark_get_line (mark);
-  column = gb_editor_file_mark_get_column (mark);
-
-  gb_gtk_text_buffer_get_iter_at_line_and_offset (buffer, &iter, line, column);
-  gtk_text_buffer_select_range (buffer, &iter, &iter);
-
-  g_signal_emit (document, gSignals [FILE_MARK_SET], 0, &iter);
-}
-
-static void
-gb_editor_document_load_cb (GObject      *object,
-                            GAsyncResult *result,
-                            gpointer      user_data)
-{
-  GtkSourceFileLoader *loader = (GtkSourceFileLoader *)object;
-  GbEditorDocument *document;
-  GFile *location;
-  GError *error = NULL;
-  GTask *task = user_data;
-
-  ENTRY;
-
-  g_return_if_fail (GTK_SOURCE_IS_FILE_LOADER (loader));
-  g_return_if_fail (G_IS_ASYNC_RESULT (result));
-  g_return_if_fail (G_IS_TASK (task));
-
-  document = g_task_get_source_object (task);
-
-  if (!gtk_source_file_loader_load_finish (loader, result, &error))
-    {
-      gb_editor_document_set_error (document, error);
-      g_task_return_error (task, error);
-      GOTO (cleanup);
-    }
-
-  document->priv->mtime_set = FALSE;
-  document->priv->file_changed_on_volume = FALSE;
-
-  location = gtk_source_file_loader_get_location (loader);
-  g_file_query_info_async (location,
-                           G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE","
-                           G_FILE_ATTRIBUTE_TIME_MODIFIED,
-                           G_FILE_QUERY_INFO_NONE,
-                           G_PRIORITY_DEFAULT,
-                           document->priv->cancellable,
-                           gb_editor_document_load_info_cb,
-                           g_object_ref (document));
-
-  gb_editor_document_restore_insert (document);
-  gb_editor_document_guess_language (document);
-
-  g_task_return_boolean (task, TRUE);
-
-cleanup:
-  g_object_unref (task);
-
-  EXIT;
-}
-
-void
-gb_editor_document_load_async (GbEditorDocument      *document,
-                               GFile                 *file,
-                               GCancellable          *cancellable,
-                               GAsyncReadyCallback    callback,
-                               gpointer               user_data)
-{
-  GtkSourceFileLoader *loader;
-  GTask *task;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  if (file)
-    gtk_source_file_set_location (document->priv->file, file);
-
-  task = g_task_new (document, cancellable, callback, user_data);
-
-  loader = gtk_source_file_loader_new (GTK_SOURCE_BUFFER (document),
-                                       document->priv->file);
-
-  gb_editor_document_set_file_changed_on_volume (document, FALSE);
-  gb_editor_document_set_progress (document, 0.0);
-
-  gtk_source_file_loader_load_async (loader,
-                                     G_PRIORITY_DEFAULT,
-                                     cancellable,
-                                     gb_editor_document_progress_cb,
-                                     g_object_ref (document),
-                                     g_object_unref,
-                                     gb_editor_document_load_cb,
-                                     task);
-
-  g_object_unref (loader);
-
-  EXIT;
-}
-
-gboolean
-gb_editor_document_load_finish (GbEditorDocument  *document,
-                                GAsyncResult      *result,
-                                GError           **error)
-{
-  GTask *task = (GTask *)result;
-
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), FALSE);
-  g_return_val_if_fail (G_IS_TASK (task), FALSE);
-
-  return g_task_propagate_boolean (task, error);
-}
-
-void
-gb_editor_document_reload (GbEditorDocument *document)
-{
-  GFile *location;
-
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  location = gtk_source_file_get_location (document->priv->file);
-
-  if (!location)
-    {
-      g_warning ("Cannot reload document as it has not been saved to disk.");
-      return;
-    }
-
-  gb_editor_document_load_async (document, location, NULL, NULL, NULL);
-}
-
-static void
-gb_editor_document_modified_changed (GtkTextBuffer *buffer)
-{
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (buffer));
-
-  if (GTK_TEXT_BUFFER_CLASS (gb_editor_document_parent_class)->modified_changed)
-    GTK_TEXT_BUFFER_CLASS (gb_editor_document_parent_class)->
-      modified_changed (buffer);
-
-  g_object_notify (G_OBJECT (buffer), "modified");
-}
-
-gboolean
-gb_editor_document_get_mtime (GbDocument *document,
-                              GTimeVal   *mtime)
+gb_editor_document_get_read_only (GbDocument *document)
 {
-  GbEditorDocument *self = (GbEditorDocument *)document;
-
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (self), FALSE);
-
-  if (self->priv->doc_seq_id)
-    {
-      memcpy (mtime, &self->priv->unsaved_ctime, sizeof *mtime);
-      return TRUE;
-    }
-
-  if (self->priv->mtime_set)
-    {
-      memcpy (mtime, &self->priv->mtime, sizeof *mtime);
-      return TRUE;
-    }
-
   return FALSE;
 }
 
-gboolean
-gb_editor_document_get_modified (GbDocument *document)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), FALSE);
-
-  return gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (document));
-}
-
-const gchar *
+static const gchar *
 gb_editor_document_get_title (GbDocument *document)
 {
-  GbEditorDocument *self = (GbEditorDocument *)document;
-
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (self), NULL);
-
-  return self->priv->title;
-}
-
-static GtkWidget *
-gb_editor_document_create_view (GbDocument *document)
-{
-  GbEditorView *view;
-
-  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), NULL);
-
-  view = g_object_new (GB_TYPE_EDITOR_VIEW,
-                       "document", document,
-                       "visible", TRUE,
-                       NULL);
-
-  return GTK_WIDGET (view);
+  return ide_buffer_get_title (IDE_BUFFER (document));
 }
 
 static void
 gb_editor_document_constructed (GObject *object)
 {
-  GbEditorDocument *self = (GbEditorDocument *)object;
-
+  IDE_ENTRY;
   G_OBJECT_CLASS (gb_editor_document_parent_class)->constructed (object);
-
-  gb_editor_document_notify_file_location (self, NULL, self->priv->file);
+  IDE_EXIT;
 }
 
 static void
 gb_editor_document_dispose (GObject *object)
 {
-  GbEditorDocument *document = (GbEditorDocument *)object;
-
-  if (!g_cancellable_is_cancelled (document->priv->cancellable))
-    g_cancellable_cancel (document->priv->cancellable);
-
+  IDE_ENTRY;
   G_OBJECT_CLASS (gb_editor_document_parent_class)->dispose (object);
+  IDE_EXIT;
 }
 
 static void
 gb_editor_document_finalize (GObject *object)
 {
-  GbEditorDocumentPrivate *priv = GB_EDITOR_DOCUMENT (object)->priv;
-
-  ENTRY;
-
-  if (priv->doc_seq_id)
-    {
-      gb_doc_seq_release (priv->doc_seq_id);
-      priv->doc_seq_id = 0;
-    }
-
-  g_clear_object (&priv->file);
-  g_clear_object (&priv->change_monitor);
-  g_clear_object (&priv->code_assistant);
-  g_clear_object (&priv->cancellable);
-  g_clear_pointer (&priv->title, g_free);
-
+  IDE_ENTRY;
   G_OBJECT_CLASS(gb_editor_document_parent_class)->finalize (object);
-
-  EXIT;
+  IDE_EXIT;
 }
 
 static void
@@ -1343,45 +116,12 @@ gb_editor_document_get_property (GObject    *object,
 
   switch (prop_id)
     {
-    case PROP_MODIFIED:
-      g_value_set_boolean (value,
-                           gb_editor_document_get_modified (GB_DOCUMENT (self)));
-      break;
-
-    case PROP_CHANGE_MONITOR:
-      g_value_set_object (value, gb_editor_document_get_change_monitor (self));
-      break;
-
-    case PROP_ERROR:
-      g_value_set_boxed (value, gb_editor_document_get_error (self));
-      break;
-
-    case PROP_FILE:
-      g_value_set_object (value, gb_editor_document_get_file (self));
-      break;
-
-    case PROP_FILE_CHANGED_ON_VOLUME:
-      g_value_set_boolean (value,
-                           gb_editor_document_get_file_changed_on_volume (self));
-      break;
-
     case PROP_READ_ONLY:
-      g_value_set_boolean (value,
-                           gb_editor_document_get_read_only (GB_DOCUMENT (self)));
-      break;
-
-    case PROP_PROGRESS:
-      g_value_set_double (value, gb_editor_document_get_progress (self));
+      g_value_set_boolean (value, gb_editor_document_get_read_only (GB_DOCUMENT (self)));
       break;
 
-    case PROP_TITLE:
-      g_value_set_string (value,
-                          gb_editor_document_get_title (GB_DOCUMENT (self)));
-      break;
-
-    case PROP_TRIM_TRAILING_WHITESPACE:
-      g_value_set_boolean (value,
-                           gb_editor_document_get_trim_trailing_whitespace (self));
+    case PROP_MODIFIED:
+      g_value_set_boolean (value, gb_editor_document_get_modified (GB_DOCUMENT (self)));
       break;
 
     default:
@@ -1395,20 +135,10 @@ gb_editor_document_set_property (GObject      *object,
                                  const GValue *value,
                                  GParamSpec   *pspec)
 {
-  GbEditorDocument *self = (GbEditorDocument *)object;
+  //GbEditorDocument *self = (GbEditorDocument *)object;
 
   switch (prop_id)
     {
-    case PROP_STYLE_SCHEME_NAME:
-      gb_editor_document_set_style_scheme_name (self,
-                                                g_value_get_string (value));
-      break;
-
-    case PROP_TRIM_TRAILING_WHITESPACE:
-      gb_editor_document_set_trim_trailing_whitespace (self,
-                                                       g_value_get_boolean (value));
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1419,7 +149,6 @@ static void
 gb_editor_document_class_init (GbEditorDocumentClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  GtkTextBufferClass *text_buffer_class = GTK_TEXT_BUFFER_CLASS (klass);
 
   object_class->constructed = gb_editor_document_constructed;
   object_class->dispose = gb_editor_document_dispose;
@@ -1427,152 +156,20 @@ gb_editor_document_class_init (GbEditorDocumentClass *klass)
   object_class->get_property = gb_editor_document_get_property;
   object_class->set_property = gb_editor_document_set_property;
 
-  text_buffer_class->mark_set = gb_editor_document_mark_set;
-  text_buffer_class->changed = gb_editor_document_changed;
-  text_buffer_class->modified_changed = gb_editor_document_modified_changed;
-
-  g_object_class_override_property (object_class, PROP_MODIFIED, "modified");
   g_object_class_override_property (object_class, PROP_READ_ONLY, "read-only");
-  g_object_class_override_property (object_class, PROP_TITLE, "title");
-
-  gParamSpecs [PROP_CHANGE_MONITOR] =
-    g_param_spec_object ("change-monitor",
-                         _("Change Monitor"),
-                         _("The change monitor for the backing file."),
-                         GB_TYPE_SOURCE_CHANGE_MONITOR,
-                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_CHANGE_MONITOR,
-                                   gParamSpecs [PROP_CHANGE_MONITOR]);
-
-  gParamSpecs [PROP_ERROR] =
-    g_param_spec_boxed ("error",
-                        _("Error"),
-                        _("An error that may have been loaded."),
-                        G_TYPE_ERROR,
-                        (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_ERROR,
-                                   gParamSpecs [PROP_ERROR]);
-
-  gParamSpecs [PROP_FILE] =
-    g_param_spec_object ("file",
-                         _("File"),
-                         _("The backing file for the document."),
-                         GTK_SOURCE_TYPE_FILE,
-                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_FILE,
-                                   gParamSpecs [PROP_FILE]);
-
-  gParamSpecs [PROP_FILE_CHANGED_ON_VOLUME] =
-    g_param_spec_boolean ("file-changed-on-volume",
-                          _("File Changed on Volume"),
-                          _("If the file has changed underneath the buffer."),
-                          FALSE,
-                          (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_FILE_CHANGED_ON_VOLUME,
-                                   gParamSpecs [PROP_FILE_CHANGED_ON_VOLUME]);
-
-  gParamSpecs [PROP_PROGRESS] =
-    g_param_spec_double ("progress",
-                         _("Progress"),
-                         _("Loading or saving progress."),
-                         0.0,
-                         1.0,
-                         0.0,
-                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_PROGRESS,
-                                   gParamSpecs [PROP_PROGRESS]);
-
-  gParamSpecs [PROP_STYLE_SCHEME_NAME] =
-    g_param_spec_string ("style-scheme-name",
-                         _("Style Scheme Name"),
-                         _("The style scheme name."),
-                         NULL,
-                         (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_STYLE_SCHEME_NAME,
-                                   gParamSpecs [PROP_STYLE_SCHEME_NAME]);
-
-  gParamSpecs [PROP_TRIM_TRAILING_WHITESPACE] =
-    g_param_spec_boolean ("trim-trailing-whitespace",
-                         _("Trim Trailing Whitespace"),
-                         _("If whitespace should be trimmed before saving."),
-                         TRUE,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_TRIM_TRAILING_WHITESPACE,
-                                   gParamSpecs [PROP_TRIM_TRAILING_WHITESPACE]);
-
-  gSignals [CURSOR_MOVED] =
-    g_signal_new ("cursor-moved",
-                  G_OBJECT_CLASS_TYPE (object_class),
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (GbEditorDocumentClass, cursor_moved),
-                  NULL,
-                  NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                  G_TYPE_NONE,
-                  0);
-
-  gSignals [FILE_MARK_SET] =
-    g_signal_new ("file-mark-set",
-                  G_OBJECT_CLASS_TYPE (object_class),
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (GbEditorDocumentClass, file_mark_set),
-                  NULL, NULL,
-                  g_cclosure_marshal_generic,
-                  G_TYPE_NONE,
-                  1,
-                  GTK_TYPE_TEXT_ITER);
-
-  gSignals [SAVED] =
-    g_signal_new ("saved",
-                  G_OBJECT_CLASS_TYPE (object_class),
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (GbEditorDocumentClass, saved),
-                  NULL, NULL,
-                  g_cclosure_marshal_generic,
-                  G_TYPE_NONE,
-                  0);
+  g_object_class_override_property (object_class, PROP_MODIFIED, "modified");
 }
 
 static void
 gb_editor_document_init (GbEditorDocument *document)
 {
-  document->priv = gb_editor_document_get_instance_private (document);
-
-  document->priv->cancellable = g_cancellable_new ();
-  document->priv->trim_trailing_whitespace = TRUE;
-  document->priv->file = gtk_source_file_new ();
-  document->priv->change_monitor = gb_source_change_monitor_new (GTK_TEXT_BUFFER (document));
-  document->priv->code_assistant = gb_source_code_assistant_new (GTK_TEXT_BUFFER (document));
-
-  g_signal_connect_object (document->priv->file,
-                           "notify::location",
-                           G_CALLBACK (gb_editor_document_notify_file_location),
-                           document,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (document->priv->code_assistant,
-                           "changed",
-                           G_CALLBACK (gb_editor_document_code_assistant_changed),
-                           document,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect (document,
-                    "notify::style-scheme",
-                    G_CALLBACK (gb_editor_document_notify_style_scheme),
-                    NULL);
 }
 
 static void
-gb_editor_document_init_document (GbDocumentInterface *iface)
+document_interface_init (GbDocumentInterface *iface)
 {
+  iface->create_view = gb_editor_document_create_view;
   iface->get_modified = gb_editor_document_get_modified;
-  iface->get_mtime = gb_editor_document_get_mtime;
   iface->get_read_only = gb_editor_document_get_read_only;
   iface->get_title = gb_editor_document_get_title;
-  iface->is_untitled = gb_editor_document_is_untitled;
-  iface->create_view = gb_editor_document_create_view;
-  iface->save_async = gb_editor_document_save_async;
-  iface->save_finish = gb_editor_document_save_finish;
-  iface->save_as_async = gb_editor_document_save_as_async;
-  iface->save_as_finish = gb_editor_document_save_as_finish;
 }
diff --git a/src/editor/gb-editor-document.h b/src/editor/gb-editor-document.h
index b86f3ac..ada3ea5 100644
--- a/src/editor/gb-editor-document.h
+++ b/src/editor/gb-editor-document.h
@@ -1,6 +1,6 @@
 /* gb-editor-document.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2014-2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,67 +19,13 @@
 #ifndef GB_EDITOR_DOCUMENT_H
 #define GB_EDITOR_DOCUMENT_H
 
-#include <gtksourceview/gtksourcebuffer.h>
-
-#include "gb-source-change-monitor.h"
-#include "gb-source-code-assistant.h"
+#include <ide.h>
 
 G_BEGIN_DECLS
 
-#define GB_TYPE_EDITOR_DOCUMENT            (gb_editor_document_get_type())
-#define GB_EDITOR_DOCUMENT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_EDITOR_DOCUMENT, 
GbEditorDocument))
-#define GB_EDITOR_DOCUMENT_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_EDITOR_DOCUMENT, 
GbEditorDocument const))
-#define GB_EDITOR_DOCUMENT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_EDITOR_DOCUMENT, 
GbEditorDocumentClass))
-#define GB_IS_EDITOR_DOCUMENT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_EDITOR_DOCUMENT))
-#define GB_IS_EDITOR_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_EDITOR_DOCUMENT))
-#define GB_EDITOR_DOCUMENT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_EDITOR_DOCUMENT, 
GbEditorDocumentClass))
-
-typedef struct _GbEditorDocument        GbEditorDocument;
-typedef struct _GbEditorDocumentClass   GbEditorDocumentClass;
-typedef struct _GbEditorDocumentPrivate GbEditorDocumentPrivate;
-
-struct _GbEditorDocument
-{
-  GtkSourceBuffer parent;
-
-  /*< private >*/
-  GbEditorDocumentPrivate *priv;
-};
-
-struct _GbEditorDocumentClass
-{
-  GtkSourceBufferClass parent_class;
-
-  void (*cursor_moved)  (GbEditorDocument *document);
-  void (*file_mark_set) (GbEditorDocument *document,
-                         GtkTextIter      *location);
-  void (*saved)         (GbEditorDocument *document);
-};
+#define GB_TYPE_EDITOR_DOCUMENT (gb_editor_document_get_type())
 
-GbEditorDocument      *gb_editor_document_new                          (void);
-GType                  gb_editor_document_get_type                     (void);
-GtkSourceFile         *gb_editor_document_get_file                     (GbEditorDocument       *document);
-void                   gb_editor_document_set_file                     (GbEditorDocument       *document,
-                                                                        GtkSourceFile          *file);
-gdouble                gb_editor_document_get_progress                 (GbEditorDocument       *document);
-GbSourceChangeMonitor *gb_editor_document_get_change_monitor           (GbEditorDocument       *document);
-GbSourceCodeAssistant *gb_editor_document_get_code_assistant           (GbEditorDocument       *document);
-gboolean               gb_editor_document_get_file_changed_on_volume   (GbEditorDocument       *document);
-gboolean               gb_editor_document_get_trim_trailing_whitespace (GbEditorDocument       *document);
-void                   gb_editor_document_set_trim_trailing_whitespace (GbEditorDocument       *document,
-                                                                        gboolean                
trim_trailing_whitespace);
-void                   gb_editor_document_load_async                   (GbEditorDocument       *document,
-                                                                        GFile                  *file,
-                                                                        GCancellable           *cancellable,
-                                                                        GAsyncReadyCallback     callback,
-                                                                        gpointer                user_data);
-gboolean               gb_editor_document_load_finish                  (GbEditorDocument       *document,
-                                                                        GAsyncResult           *result,
-                                                                        GError                **error);
-void                   gb_editor_document_reformat                     (GbEditorDocument       *document);
-void                   gb_editor_document_check_externally_modified    (GbEditorDocument       *document);
-void                   gb_editor_document_reload                       (GbEditorDocument       *document);
-const GError          *gb_editor_document_get_error                    (GbEditorDocument       *document);
+G_DECLARE_FINAL_TYPE (GbEditorDocument, gb_editor_document, GB, EDITOR_DOCUMENT, IdeBuffer)
 
 G_END_DECLS
 
diff --git a/src/editor/gb-editor-frame-actions.c b/src/editor/gb-editor-frame-actions.c
new file mode 100644
index 0000000..25cd256
--- /dev/null
+++ b/src/editor/gb-editor-frame-actions.c
@@ -0,0 +1,52 @@
+/* gb-editor-frame-actions.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtksourceview/gtksource.h>
+
+#include "gb-editor-frame-actions.h"
+#include "gb-editor-frame-private.h"
+
+static void
+gb_editor_frame_actions_find (GSimpleAction *action,
+                              GVariant      *variant,
+                              gpointer       user_data)
+{
+  GbEditorFrame *self = user_data;
+
+  g_assert (GB_IS_EDITOR_FRAME (self));
+
+  gtk_revealer_set_reveal_child (self->search_revealer, TRUE);
+  gtk_widget_grab_focus (GTK_WIDGET (self->search_entry));
+}
+
+static const GActionEntry GbEditorFrameActions[] = {
+  { "find",     gb_editor_frame_actions_find },
+};
+
+void
+gb_editor_frame_actions_init (GbEditorFrame *self)
+{
+  g_autoptr(GSimpleActionGroup) group = NULL;
+
+  g_assert (GB_IS_EDITOR_FRAME (self));
+
+  group = g_simple_action_group_new ();
+  g_action_map_add_action_entries (G_ACTION_MAP (group), GbEditorFrameActions,
+                                   G_N_ELEMENTS (GbEditorFrameActions), self);
+  gtk_widget_insert_action_group (GTK_WIDGET (self), "frame", G_ACTION_GROUP (group));
+}
diff --git a/src/auto-indent/c-parse-helper.h b/src/editor/gb-editor-frame-actions.h
similarity index 57%
copy from src/auto-indent/c-parse-helper.h
copy to src/editor/gb-editor-frame-actions.h
index 418f518..f841ebd 100644
--- a/src/auto-indent/c-parse-helper.h
+++ b/src/editor/gb-editor-frame-actions.h
@@ -1,6 +1,6 @@
-/* c-parse-helper.h
+/* gb-editor-frame-actions.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,26 +16,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef C_PARSE_HELPER_H
-#define C_PARSE_HELPER_H
+#ifndef GB_EDITOR_FRAME_ACTIONS_H
+#define GB_EDITOR_FRAME_ACTIONS_H
 
-#include <glib.h>
+#include "gb-editor-frame.h"
 
 G_BEGIN_DECLS
 
-typedef struct
-{
-  gchar *type;
-  gchar *name;
-  guint  ellipsis : 1;
-  guint  n_star   : 4;
-} Parameter;
-
-gboolean   parameter_validate (Parameter       *param);
-void       parameter_free     (Parameter       *p);
-Parameter *parameter_copy     (const Parameter *src);
-GSList    *parse_parameters   (const gchar     *text);
+void gb_editor_frame_actions_init (GbEditorFrame *self);
 
 G_END_DECLS
 
-#endif /* C_PARSE_HELPER_H */
+#endif /* GB_EDITOR_FRAME_ACTIONS_H */
diff --git a/src/editor/gb-editor-frame-private.h b/src/editor/gb-editor-frame-private.h
index 46e5bae..41957d6 100644
--- a/src/editor/gb-editor-frame-private.h
+++ b/src/editor/gb-editor-frame-private.h
@@ -1,6 +1,6 @@
 /* gb-editor-frame-private.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,45 +19,23 @@
 #ifndef GB_EDITOR_FRAME_PRIVATE_H
 #define GB_EDITOR_FRAME_PRIVATE_H
 
-#include "gb-editor-frame.h"
-#include "gb-source-change-gutter-renderer.h"
-#include "gb-source-code-assistant-renderer.h"
-#include "gb-source-search-highlighter.h"
-#include "gb-source-view.h"
+#include <gtk/gtk.h>
+#include <ide.h>
+
 #include "gd-tagged-entry.h"
-#include "gca-structs.h"
 #include "nautilus-floating-bar.h"
 
 G_BEGIN_DECLS
 
-struct _GbEditorFramePrivate
+struct _GbEditorFrame
 {
-  /* Widgets owned by GtkBuilder */
-  GtkSpinner                    *busy_spinner;
-  GbSourceChangeGutterRenderer  *diff_renderer;
-  GbSourceCodeAssistantRenderer *code_assistant_renderer;
-  NautilusFloatingBar           *floating_bar;
-  GtkButton                     *forward_search;
-  GtkButton                     *backward_search;
-  GtkScrolledWindow             *scrolled_window;
-  GtkRevealer                   *search_revealer;
-  GdTaggedEntry                 *search_entry;
-  GdTaggedEntryTag              *search_entry_tag;
-  GbSourceView                  *source_view;
-
-  /* Objects owned by GbEditorFrame */
-  GbEditorDocument              *document;
-  GtkSourceSearchContext        *search_context;
-  GtkSourceSearchSettings       *search_settings;
-  GbSourceSearchHighlighter     *search_highlighter;
-  GtkDirectionType               search_direction;
-
-  /* Signal handler identifiers */
-  gulong                         cursor_moved_handler;
+  GtkBin             parent_instance;
 
-  /* Tracking last cursor position when jumping */
-  guint                          saved_line;
-  guint                          saved_line_offset;
+  NautilusFloatingBar *floating_bar;
+  GtkScrolledWindow   *scrolled_window;
+  GtkRevealer         *search_revealer;
+  GdTaggedEntry       *search_entry;
+  IdeSourceView       *source_view;
 };
 
 G_END_DECLS
diff --git a/src/editor/gb-editor-frame.c b/src/editor/gb-editor-frame.c
index 13f7c3e..e8d2219 100644
--- a/src/editor/gb-editor-frame.c
+++ b/src/editor/gb-editor-frame.c
@@ -1,6 +1,6 @@
 /* gb-editor-frame.c
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,433 +16,31 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define G_LOG_DOMAIN "editor-frame"
-
 #include <glib/gi18n.h>
-#include <gio/gio.h>
+#include <ide.h>
 
+#include "gb-editor-document.h"
 #include "gb-editor-frame.h"
+#include "gb-editor-frame-actions.h"
 #include "gb-editor-frame-private.h"
-#include "gb-editor-workspace.h"
-#include "gb-gtk.h"
-#include "gb-log.h"
-#include "gb-source-formatter.h"
-#include "gb-string.h"
 #include "gb-widget.h"
-#include "gb-workbench.h"
 
-G_DEFINE_TYPE_WITH_PRIVATE (GbEditorFrame, gb_editor_frame, GTK_TYPE_OVERLAY)
+G_DEFINE_TYPE (GbEditorFrame, gb_editor_frame, GTK_TYPE_BIN)
 
 enum {
   PROP_0,
   PROP_DOCUMENT,
-  PROP_SEARCH_DIRECTION,
   LAST_PROP
 };
 
-enum {
-  FOCUSED,
-  LAST_SIGNAL
-};
-
 static GParamSpec *gParamSpecs [LAST_PROP];
-static guint       gSignals [LAST_SIGNAL];
-
-static void gb_editor_frame_set_search_direction (GbEditorFrame    *self,
-                                                  GtkDirectionType  search_direction);
-GtkWidget *
-gb_editor_frame_new (void)
-{
-  return g_object_new (GB_TYPE_EDITOR_FRAME, NULL);
-}
-
-/**
- * gb_editor_frame_link:
- * @src: (in): The source frame.
- * @dst: (in): The destination frame.
- *
- * This function is intended to link two #GbEditorFrame instances to use the
- * same backend buffer. This is useful when you want two separate views of the
- * same content.
- */
-void
-gb_editor_frame_link (GbEditorFrame *src,
-                      GbEditorFrame *dst)
-{
-  g_return_if_fail (GB_IS_EDITOR_FRAME (src));
-  g_return_if_fail (GB_IS_EDITOR_FRAME (dst));
-
-  g_object_bind_property (src, "document", dst, "document",
-                          G_BINDING_SYNC_CREATE);
-}
-
-static void
-gb_editor_frame_restore_position (GbEditorFrame *self)
-{
-  GtkTextView *text_view;
-  GtkTextIter iter;
-  GtkTextBuffer *buffer;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  text_view = GTK_TEXT_VIEW (self->priv->source_view);
-  buffer = gtk_text_view_get_buffer (text_view);
-
-  gb_gtk_text_buffer_get_iter_at_line_and_offset (buffer, &iter,
-                                                  self->priv->saved_line,
-                                                  self->priv->saved_line_offset);
-  gtk_text_buffer_select_range (buffer, &iter, &iter);
-  if (!gb_gtk_text_view_get_iter_visible (text_view, &iter))
-    gb_gtk_text_view_scroll_to_iter (text_view, &iter, 0.25, TRUE, 0.0, 0.5);
-}
-
-static void
-gb_editor_frame_save_position (GbEditorFrame *self)
-{
-  GtkTextBuffer *buffer;
-  GtkTextMark *insert;
-  GtkTextIter iter;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  buffer = GTK_TEXT_BUFFER (self->priv->document);
-  insert = gtk_text_buffer_get_insert (buffer);
-  gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
-
-  self->priv->saved_line = gtk_text_iter_get_line (&iter);
-  self->priv->saved_line_offset = gtk_text_iter_get_line_offset (&iter);
-}
-
-/**
- * gb_editor_frame_match:
- * @self: the #GbEditorFrame
- * @direction: the direction to search through the document
- * @rubberbanding: if %TRUE then use the match closest to the
- * position of cursor at the time gb_editor_frame_save_position()
- * was last called, if %FALSE then use the match closest to
- * the current cursor position.
- *
- * Move to a search match in the direction of @direction and/or
- * select the match.
- */
-static void
-gb_editor_frame_match (GbEditorFrame    *self,
-                       GtkDirectionType  direction,
-                       gboolean          rubberbanding)
-{
-  GbEditorFramePrivate *priv;
-  GtkTextBuffer *buffer;
-  GtkTextIter select_begin;
-  GtkTextIter select_end;
-  GtkTextIter match_begin;
-  GtkTextIter match_end;
-  gboolean has_selection;
-  gboolean search_backward;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN);
-
-  priv = self->priv;
-
-  if (direction == GTK_DIR_UP)
-    search_backward = TRUE;
-  else if (direction == GTK_DIR_DOWN)
-    search_backward = FALSE;
-  else
-    g_assert_not_reached ();
-
-  gb_editor_frame_set_search_direction (self, direction);
-
-  buffer = GTK_TEXT_BUFFER (priv->document);
-
-  /*
-   * Start by trying from our current location unless we are rubberbanding, then
-   * start from our saved position.
-   */
-  if (rubberbanding)
-    {
-      gb_gtk_text_buffer_get_iter_at_line_and_offset (buffer, &select_begin,
-                                                      priv->saved_line,
-                                                      priv->saved_line_offset);
-      select_end = select_begin;
-    }
-  else
-    {
-      has_selection = gtk_text_buffer_get_selection_bounds (buffer,
-                                                            &select_begin,
-                                                            &select_end);
-
-      if (!has_selection)
-        {
-          if (!search_backward)
-            {
-              if (!gtk_text_iter_forward_char (&select_end))
-                gtk_text_buffer_get_end_iter (buffer, &select_end);
-            }
-          else
-            {
-              if (!gtk_text_iter_backward_char (&select_begin))
-                gtk_text_buffer_get_start_iter (buffer, &select_begin);
-            }
-        }
-    }
-
-  if (!search_backward)
-    {
-      if (gtk_source_search_context_forward (priv->search_context, &select_end,
-                                             &match_begin, &match_end))
-        GOTO (found_match);
-    }
-  else
-    {
-      if (gtk_source_search_context_backward (priv->search_context, &select_begin,
-                                              &match_begin, &match_end))
-        GOTO (found_match);
-    }
-
-  gb_editor_frame_restore_position (self);
-
-  EXIT;
-
-found_match:
-  gb_source_view_jump_notify (priv->source_view);
-  gb_source_view_clear_saved_cursor (priv->source_view);
-  gtk_text_buffer_select_range (GTK_TEXT_BUFFER (priv->document),
-                                &match_begin, &match_end);
-
-  if (!gb_gtk_text_view_get_iter_visible (GTK_TEXT_VIEW (priv->source_view),
-                                          &match_end))
-    gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->source_view),
-                                  &match_end, 0.0, TRUE, 1.0, 0.5);
-
-  EXIT;
-}
-
-/**
- * gb_editor_frame_move_next_match:
- *
- * Move to the next search match after the cursor position.
- */
-static void
-gb_editor_frame_move_next_match (GbEditorFrame *self,
-                                 gboolean       rubberbanding)
-{
-  gb_editor_frame_match (self, GTK_DIR_DOWN, rubberbanding);
-}
-
-/**
- * gb_editor_frame_move_previous_match:
- *
- * Move to the first match before the cursor position.
- */
-static void
-gb_editor_frame_move_previous_match (GbEditorFrame *self,
-                                     gboolean       rubberbanding)
-{
-  gb_editor_frame_match (self, GTK_DIR_UP, rubberbanding);
-}
-
-static void
-gb_editor_frame_set_position_label (GbEditorFrame *self,
-                                    const gchar   *text)
-{
-  GbEditorFramePrivate *priv;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  priv = self->priv;
-
-  if (!text || !*text)
-    {
-      if (priv->search_entry_tag)
-        {
-          gd_tagged_entry_remove_tag (priv->search_entry,
-                                      priv->search_entry_tag);
-          g_clear_object (&priv->search_entry_tag);
-        }
-      return;
-    }
-
-  if (!priv->search_entry_tag)
-    {
-      priv->search_entry_tag = gd_tagged_entry_tag_new ("");
-      gd_tagged_entry_tag_set_style (priv->search_entry_tag,
-                                     "gb-search-entry-occurrences-tag");
-      gd_tagged_entry_add_tag (priv->search_entry,
-                               priv->search_entry_tag);
-    }
-
-  gd_tagged_entry_tag_set_label (priv->search_entry_tag, text);
-}
-
-static void
-gb_editor_frame_update_search_position_label (GbEditorFrame *self)
-{
-  GbEditorFramePrivate *priv;
-  GtkStyleContext *context;
-  GtkTextIter begin;
-  GtkTextIter end;
-  const gchar *search_text;
-  gchar *text;
-  gint count;
-  gint pos;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  priv = self->priv;
-
-  gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (priv->document),
-                                        &begin, &end);
-  pos = gtk_source_search_context_get_occurrence_position (
-    priv->search_context, &begin, &end);
-  count = gtk_source_search_context_get_occurrences_count (
-    priv->search_context);
-
-  if ((pos == -1) || (count == -1))
-    {
-      /*
-       * We are not yet done scanning the buffer.
-       * We will be updated when we know more, so just hide it for now.
-       */
-      gb_editor_frame_set_position_label (self, NULL);
-      return;
-    }
-
-  context = gtk_widget_get_style_context (GTK_WIDGET (priv->search_entry));
-  search_text = gtk_entry_get_text (GTK_ENTRY (priv->search_entry));
-
-  if ((count == 0) && !gb_str_empty0 (search_text))
-    gtk_style_context_add_class (context, GTK_STYLE_CLASS_ERROR);
-  else
-    gtk_style_context_remove_class (context, GTK_STYLE_CLASS_ERROR);
-
-  text = g_strdup_printf (_("%u of %u"), pos, count);
-  gb_editor_frame_set_position_label (self, text);
-  g_free (text);
-}
-
-static void
-gb_editor_frame_on_search_occurrences_notify (GbEditorFrame          *self,
-                                              GParamSpec             *pspec,
-                                              GtkSourceSearchContext *search_context)
-{
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GTK_SOURCE_IS_SEARCH_CONTEXT (search_context));
-
-  gb_editor_frame_update_search_position_label (self);
-}
-
-void
-gb_editor_frame_reformat (GbEditorFrame *self)
-{
-  GbEditorFramePrivate *priv;
-  GbSourceFormatter *formatter;
-  GtkSourceLanguage *language;
-  GtkTextBuffer *buffer;
-  GtkTextIter begin;
-  GtkTextIter end;
-  GtkTextIter iter;
-  GtkTextMark *insert;
-  gboolean fragment = TRUE;
-  GError *error = NULL;
-  gchar *input = NULL;
-  gchar *output = NULL;
-  guint line_number;
-  guint char_offset;
-
-  ENTRY;
-
-  /*
-   * TODO: Do this asynchronously, add tab state, propagate errors.
-   */
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  priv = self->priv;
-
-  buffer = GTK_TEXT_BUFFER (priv->document);
-
-  gtk_text_buffer_get_selection_bounds (buffer, &begin, &end);
-
-  if (gtk_text_iter_compare (&begin, &end) == 0)
-    {
-      gtk_text_buffer_get_bounds (buffer, &begin, &end);
-      fragment = FALSE;
-    }
-
-  input = gtk_text_buffer_get_text (buffer, &begin, &end, TRUE);
-
-  insert = gtk_text_buffer_get_insert (buffer);
-  gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
-  char_offset = gtk_text_iter_get_line_offset (&iter);
-  line_number = gtk_text_iter_get_line (&iter);
-
-  language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buffer));
-  formatter = gb_source_formatter_new_from_language (language);
-
-  if (!gb_source_formatter_format (formatter, input, fragment, NULL, &output,
-                                   &error))
-    {
-      g_warning ("%s", error->message);
-      g_clear_error (&error);
-      GOTO (cleanup);
-    }
-
-  gtk_text_buffer_begin_user_action (buffer);
 
-  /* TODO: Keep the cursor on same CXCursor from Clang instead of the
-   *       same character offset within the buffer. We probably want
-   *       to defer this to the formatter API since it will be language
-   *       specific.
-   */
-
-  gtk_text_buffer_delete (buffer, &begin, &end);
-  gtk_text_buffer_insert (buffer, &begin, output, -1);
-
-  if (line_number >= gtk_text_buffer_get_line_count (buffer))
-    {
-      gtk_text_buffer_get_bounds (buffer, &begin, &iter);
-      goto select_range;
-    }
-
-  gtk_text_buffer_get_iter_at_line (buffer, &iter, line_number);
-  gtk_text_iter_forward_to_line_end (&iter);
-
-  if (gtk_text_iter_get_line (&iter) != line_number)
-    gtk_text_iter_backward_char (&iter);
-  else if (gtk_text_iter_get_line_offset (&iter) > char_offset)
-    gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, line_number, char_offset);
-
-select_range:
-  gtk_text_buffer_select_range (buffer, &iter, &iter);
-  gtk_text_buffer_end_user_action (buffer);
-
-  gb_gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->source_view), &iter,
-                                   0.25, TRUE, 0.5, 0.5);
-
-cleanup:
-  g_free (input);
-  g_free (output);
-  g_clear_object (&formatter);
-
-  EXIT;
-}
-
-/**
- * gb_editor_frame_on_cursor_moved:
- *
- * Update cursor ruler in the floating bar upon changing of insert text mark.
- */
 static void
-gb_editor_frame_on_cursor_moved (GbEditorFrame    *self,
-                                 GbEditorDocument *document)
+on_cursor_moved (GbEditorDocument  *document,
+                 const GtkTextIter *location,
+                 GbEditorFrame     *self)
 {
   GtkSourceView *source_view;
-  GtkTextBuffer *buffer;
-  GtkTextIter iter;
-  GtkTextMark *mark;
   gchar *text;
   guint ln;
   guint col;
@@ -450,1149 +48,82 @@ gb_editor_frame_on_cursor_moved (GbEditorFrame    *self,
   g_return_if_fail (GB_IS_EDITOR_FRAME (self));
   g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
 
-  source_view = GTK_SOURCE_VIEW (self->priv->source_view);
-  buffer = GTK_TEXT_BUFFER (document);
-
-  mark = gtk_text_buffer_get_insert (buffer);
-  gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
-
-  ln = gtk_text_iter_get_line (&iter);
-  col = gtk_source_view_get_visual_column (source_view, &iter);
+  source_view = GTK_SOURCE_VIEW (self->source_view);
 
+  ln = gtk_text_iter_get_line (location);
+  col = gtk_source_view_get_visual_column (source_view, location);
   text = g_strdup_printf (_("Line %u, Column %u"), ln + 1, col + 1);
-  nautilus_floating_bar_set_primary_label (self->priv->floating_bar, text);
+  nautilus_floating_bar_set_primary_label (self->floating_bar, text);
   g_free (text);
 
-  gb_editor_frame_update_search_position_label (self);
-}
-
-static void
-gb_editor_frame_on_file_mark_set (GbEditorFrame *self,
-                                  GtkTextIter   *location,
-                                  GtkTextBuffer *buffer)
-{
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
-
-  if (!gtk_widget_has_focus (GTK_WIDGET (self->priv->source_view)))
-    return;
-
-  gb_gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (self->priv->source_view),
-                                   location, 0.0, TRUE, 0.5, 0.5);
-}
-
-static void
-gb_editor_frame_document_saved (GbEditorFrame    *self,
-                                GbEditorDocument *document)
-{
-  GdkWindow *window;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  window = gtk_text_view_get_window (GTK_TEXT_VIEW (self->priv->source_view),
-                                     GTK_TEXT_WINDOW_WIDGET);
-  gdk_window_invalidate_rect (window, NULL, TRUE);
-}
-
-/**
- * gb_editor_frame_connect:
- *
- * Attach to dynamic signals for the #GtkTextBuffer. Create any objects that
- * are dependent on the buffer.
- */
-static void
-gb_editor_frame_connect (GbEditorFrame    *self,
-                         GbEditorDocument *document)
-{
-  GbEditorFramePrivate *priv;
-  GbSourceChangeMonitor *monitor;
-  GbSourceCodeAssistant *code_assistant;
-  GtkTextIter iter;
-  GtkTextMark *insert;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-  g_return_if_fail (!self->priv->document);
-
-  priv = self->priv;
-
-  /*
-   * Save the document for later.
-   */
-  priv->document = g_object_ref (document);
-  gtk_text_view_set_buffer (GTK_TEXT_VIEW (priv->source_view),
-                            GTK_TEXT_BUFFER (priv->document));
-
-  /*
-   * Look the saved signal so that we can invalidate the window afterwards.
-   * This could happen since gutter content could change (like if it is a
-   * new file in a git repo).
-   */
-  g_signal_connect_object (priv->document,
-                           "saved",
-                           G_CALLBACK (gb_editor_frame_document_saved),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  /*
-   * Connect change monitor to gutter.
-   */
-  monitor = gb_editor_document_get_change_monitor (document);
-  g_object_set (priv->diff_renderer,
-                "change-monitor", monitor,
-                NULL);
-
-  /*
-   * Connect code assistance to gutter and spinner.
-   */
-  code_assistant = gb_editor_document_get_code_assistant (document);
-  g_object_set (priv->code_assistant_renderer,
-                "code-assistant", code_assistant,
-                NULL);
-  g_object_bind_property (code_assistant, "active",
-                          priv->busy_spinner, "active",
-                          G_BINDING_SYNC_CREATE);
-  g_object_bind_property (code_assistant, "active",
-                          priv->busy_spinner, "visible",
-                          G_BINDING_SYNC_CREATE);
-
-  /*
-   * Don't allow editing if the buffer is read-only.
-   */
-  g_object_bind_property (priv->document, "read-only",
-                          priv->source_view, "editable",
-                          G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
-
-  /*
-   * Create search defaults for this frame.
-   */
-  priv->search_context = g_object_new (GTK_SOURCE_TYPE_SEARCH_CONTEXT,
-                                       "buffer", priv->document,
-                                       "settings", priv->search_settings,
-                                       "highlight", TRUE,
-                                       NULL);
-  g_object_set (priv->search_highlighter,
-                "search-context", priv->search_context,
-                NULL);
-
-  g_signal_connect_object (priv->search_context,
-                           "notify::occurrences-count",
-                           G_CALLBACK (gb_editor_frame_on_search_occurrences_notify),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->document,
-                           "file-mark-set",
-                           G_CALLBACK (gb_editor_frame_on_file_mark_set),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  /*
-   * Connect to cursor-moved signal to update cursor position label.
-   */
-  if (GB_IS_EDITOR_DOCUMENT (priv->document))
-    {
-      priv->cursor_moved_handler =
-        g_signal_connect_swapped (priv->document,
-                                  "cursor-moved",
-                                  G_CALLBACK (gb_editor_frame_on_cursor_moved),
-                                  self);
-    }
-
-  insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (document));
-  gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (document), &iter, insert);
-  gb_gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (self->priv->source_view),
-                                   &iter, 0.0, TRUE, 0.5, 0.0);
-
-  EXIT;
-}
-
-/**
- * gb_editor_frame_disconnect:
- *
- * Cleanup any signals or objects that are related to the #GtkTextBuffer.
- */
-static void
-gb_editor_frame_disconnect (GbEditorFrame *self)
-{
-  GbEditorFramePrivate *priv;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  priv = self->priv;
-
-  if (priv->document)
-    {
-      g_signal_handler_disconnect (priv->document, priv->cursor_moved_handler);
-      priv->cursor_moved_handler = 0;
-    }
-
-  g_object_set (priv->diff_renderer,
-                "change-monitor", NULL,
-                NULL);
-
-  g_object_set (priv->code_assistant_renderer,
-                "code-assistant", NULL,
-                NULL);
-
-  g_object_set (priv->search_highlighter,
-                "search-context", NULL,
-                NULL);
-
-  g_clear_object (&priv->document);
-  g_clear_object (&priv->search_context);
-
-  EXIT;
+  //gb_editor_frame_update_search_position_label (self);
 }
 
 /**
  * gb_editor_frame_get_document:
  *
- * Gets the #GbEditorDocument associated with the #GbEditorFrame.
+ * Gets the #GbEditorFrame:document property.
  *
- * Returns: (transfer none): A #GbEditorDocument.
+ * Returns: (transfer none) (nullable): A #GbEditorDocument or %NULL.
  */
 GbEditorDocument *
 gb_editor_frame_get_document (GbEditorFrame *self)
 {
-  g_return_val_if_fail (GB_IS_EDITOR_FRAME (self), NULL);
-
-  return self->priv->document;
-}
-
-/**
- * gb_editor_frame_set_document:
- *
- * Set the #GbEditorDocument to be displayed by the #GbEditorFrame.
- */
-void
-gb_editor_frame_set_document (GbEditorFrame    *self,
-                              GbEditorDocument *document)
-{
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (!document || GB_IS_EDITOR_DOCUMENT (document));
-
-  if (document != self->priv->document)
-    {
-      gb_editor_frame_disconnect (self);
-      if (document)
-        gb_editor_frame_connect (self, document);
-      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_DOCUMENT]);
-    }
-}
-
-/**
- * gb_editor_frame_get_search_direction:
- * @self: a #GbEditorFrame
- *
- * Gets the #GtkDirectionType associated with the last search.
- * Will only be %GTK_DIR_DOWN or %GTK_DIR_UP
- *
- * Returns: A #GtkDirectionType.
- */
-GtkDirectionType
-gb_editor_frame_get_search_direction (GbEditorFrame *self)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_FRAME (self), GTK_DIR_DOWN);
-
-  return self->priv->search_direction;
-}
-
-static void
-gb_editor_frame_set_search_direction (GbEditorFrame    *self,
-                                      GtkDirectionType  search_direction)
-{
-  if (self->priv->search_direction == search_direction)
-    return;
-
-  self->priv->search_direction = search_direction;
-
-  g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_SEARCH_DIRECTION]);
-}
-
-/**
- * gb_editor_frame_on_focus_in_event:
- *
- * Handle the "focus-in-event" on the #GbSourceView. Ensure the search entry
- * is hidden and we are no longer highlighting search results.
- */
-static gboolean
-gb_editor_frame_on_focus_in_event (GbEditorFrame *self,
-                                   GdkEvent      *event,
-                                   GbSourceView  *source_view)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_FRAME (self), FALSE);
-  g_return_val_if_fail (GB_IS_SOURCE_VIEW (source_view), FALSE);
-
-  if (gtk_revealer_get_reveal_child (self->priv->search_revealer))
-    gtk_revealer_set_reveal_child (self->priv->search_revealer, FALSE);
-
-  if (gtk_source_search_context_get_highlight (self->priv->search_context))
-    gtk_source_search_context_set_highlight (self->priv->search_context, FALSE);
-
-  gb_editor_document_check_externally_modified (self->priv->document);
-
-  g_signal_emit (self, gSignals [FOCUSED], 0);
-
-  return GDK_EVENT_PROPAGATE;
-}
-
-/**
- * gb_editor_frame_on_populate_popup:
- *
- * Update the popup menu to include choices for language highlight.
- */
-static void
-gb_editor_frame_on_populate_popup (GbEditorFrame *self,
-                                   GtkWidget     *popup,
-                                   GtkTextView   *text_view)
-{
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
-  g_return_if_fail (GTK_IS_WIDGET (popup));
-
-  /* TODO: Highlight Language Widget */
-}
-
-/**
- * gb_editor_frame_on_push_snippet:
- *
- * Update snippet context with the filename of the current document.
- */
-static void
-gb_editor_frame_on_push_snippet (GbEditorFrame          *self,
-                                 GbSourceSnippet        *snippet,
-                                 GbSourceSnippetContext *context,
-                                 GtkTextIter            *iter,
-                                 GbSourceView           *source_view)
-{
-  GtkSourceFile *source_file;
-  GFile *file;
-
-  g_return_if_fail (GB_IS_SOURCE_VIEW (source_view));
-  g_return_if_fail (GB_IS_SOURCE_SNIPPET (snippet));
-  g_return_if_fail (GB_IS_SOURCE_SNIPPET_CONTEXT (context));
-  g_return_if_fail (iter);
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  source_file = gb_editor_document_get_file (self->priv->document);
-  file = gtk_source_file_get_location (source_file);
-  g_assert (!file || G_IS_FILE (file));
-
-  if (file)
-    {
-      gchar *name;
-
-      name = g_file_get_basename (file);
-      gb_source_snippet_context_add_variable (context, "filename", name);
-      g_free (name);
-    }
-}
-
-static gboolean
-gb_editor_frame_on_search_entry_key_press (GbEditorFrame *self,
-                                           GdkEventKey   *event,
-                                           GdTaggedEntry *entry)
-{
-  gint begin;
-  gint end;
-
-  ENTRY;
-
-  g_assert (GD_IS_TAGGED_ENTRY (entry));
-  g_assert (GB_IS_EDITOR_FRAME (self));
-
-  /*
-   * WORKAROUND:
-   *
-   * There is some weird stuff going on with key-press when we have a selection.
-   * We want to overwrite the text, but sometimes it doesn't. So we can just
-   * force it if the string field is set.
-   */
-  if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &begin, &end) &&
-      g_unichar_isprint (gdk_keyval_to_unicode (event->keyval)))
-    {
-      gtk_editable_delete_selection (GTK_EDITABLE (entry));
-    }
-
-  switch (event->keyval)
-    {
-    case GDK_KEY_Escape:
-      gtk_revealer_set_reveal_child (self->priv->search_revealer, FALSE);
-      gb_source_view_set_show_shadow (self->priv->source_view, FALSE);
-      gb_editor_frame_restore_position (self);
-      gtk_widget_grab_focus (GTK_WIDGET (self->priv->source_view));
-      RETURN (GDK_EVENT_STOP);
-
-    case GDK_KEY_Down:
-      gb_editor_frame_move_next_match (self, FALSE);
-      gb_editor_frame_save_position (self);
-      RETURN (GDK_EVENT_STOP);
-
-    case GDK_KEY_Up:
-      gb_editor_frame_move_previous_match (self, FALSE);
-      gb_editor_frame_save_position (self);
-      RETURN (GDK_EVENT_STOP);
-
-    default:
-      break;
-    }
-
-  RETURN (GDK_EVENT_PROPAGATE);
-}
-
-static void
-gb_editor_frame_on_search_entry_changed (GbEditorFrame *self,
-                                         GtkEntry      *entry)
-{
-  const gchar *search_text;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GD_IS_TAGGED_ENTRY (entry));
-
-  search_text = gtk_entry_get_text (entry);
-
-  if (!gb_str_empty0 (search_text))
-    {
-      if (self->priv->search_direction == GTK_DIR_DOWN)
-        gb_editor_frame_move_next_match (self, TRUE);
-      else if (self->priv->search_direction == GTK_DIR_UP)
-        gb_editor_frame_move_previous_match (self, TRUE);
-      else
-        g_assert_not_reached ();
-    }
-}
-
-static void
-gb_editor_frame_on_search_entry_activate (GbEditorFrame *self,
-                                          GdTaggedEntry *entry)
-{
   GtkTextBuffer *buffer;
-  GtkTextIter begin;
-  GtkTextIter end;
-  ENTRY;
-
-  g_assert (GD_IS_TAGGED_ENTRY (entry));
-  g_assert (GB_IS_EDITOR_FRAME (self));
-
-  if (self->priv->search_direction == GTK_DIR_DOWN)
-    gb_editor_frame_move_next_match (self, TRUE);
-  else if (self->priv->search_direction == GTK_DIR_UP)
-    gb_editor_frame_move_previous_match (self, TRUE);
-  else
-    g_assert_not_reached ();
-
-  buffer = GTK_TEXT_BUFFER (self->priv->document);
-
-  if (gtk_text_buffer_get_has_selection (buffer))
-    {
-      gtk_text_buffer_get_selection_bounds (buffer, &begin, &end);
-
-      if (gtk_text_iter_compare (&begin, &end) <= 0)
-        gtk_text_buffer_select_range (buffer, &begin, &begin);
-      else
-        gtk_text_buffer_select_range (buffer, &end, &end);
-    }
-
-  gtk_widget_grab_focus (GTK_WIDGET (self->priv->source_view));
-
-  EXIT;
-}
-
-static void
-gb_editor_frame_on_forward_search_clicked (GbEditorFrame *self,
-                                           GtkButton     *button)
-{
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GTK_IS_BUTTON (button));
-
-  gb_editor_frame_move_next_match (self, FALSE);
-}
-
-static void
-gb_editor_frame_on_backward_search_clicked (GbEditorFrame *self,
-                                            GtkButton     *button)
-{
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GTK_IS_BUTTON (button));
-
-  gb_editor_frame_move_previous_match (self, FALSE);
-}
-
-/**
- * gb_editor_frame_on_begin_search:
- *
- * Show the search machinery when a request to begin a search has occurred.
- */
-static void
-gb_editor_frame_on_begin_search (GbEditorFrame    *self,
-                                 GtkDirectionType  direction,
-                                 const gchar      *search_text,
-                                 GbSourceView     *source_view)
-{
-  GbEditorFramePrivate *priv;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GB_IS_SOURCE_VIEW (source_view));
-
-  priv = self->priv;
-
-  gb_editor_frame_save_position (self);
-
-  if (search_text)
-    gtk_entry_set_text (GTK_ENTRY (priv->search_entry), search_text);
-
-  gtk_revealer_set_reveal_child (priv->search_revealer, TRUE);
-  gtk_source_search_context_set_highlight (priv->search_context, TRUE);
-  gtk_widget_grab_focus (GTK_WIDGET (priv->search_entry));
 
-  if (search_text)
-    {
-      if (direction == GTK_DIR_DOWN)
-        gb_editor_frame_move_next_match (self, TRUE);
-      else if (direction == GTK_DIR_UP)
-        gb_editor_frame_move_previous_match (self, TRUE);
-    }
-  else
-    {
-      const gchar *text;
-      guint len;
+  g_return_val_if_fail (GB_IS_EDITOR_FRAME (self), NULL);
 
-      if (direction == GTK_DIR_DOWN)
-        gb_editor_frame_move_next_match (self, TRUE);
-      else if (direction == GTK_DIR_UP)
-        gb_editor_frame_move_previous_match (self, TRUE);
-      else
-        g_assert_not_reached ();
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view));
 
-      /*
-       * We manually get the string length instead of passing -1 for length
-       * because -1 doesn't seem to work as documented.
-       */
-      text = gtk_entry_get_text (GTK_ENTRY (priv->search_entry));
-      len = g_utf8_strlen (text, -1);
-      gtk_editable_select_region (GTK_EDITABLE (priv->search_entry), 0, len);
-    }
+  if (GB_IS_EDITOR_DOCUMENT (buffer))
+    return GB_EDITOR_DOCUMENT (buffer);
 
-  EXIT;
+  return NULL;
 }
 
 void
-gb_editor_frame_find (GbEditorFrame *self,
-                      const gchar   *search_text)
-{
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  gb_editor_frame_on_begin_search (self, GTK_DIR_DOWN, search_text,
-                                   self->priv->source_view);
-}
-
-static void
-gb_editor_frame_find_activate (GSimpleAction *action,
-                               GVariant      *parameter,
-                               gpointer       user_data)
+gb_editor_frame_set_document (GbEditorFrame    *self,
+                              GbEditorDocument *document)
 {
-  GbEditorFrame *self = user_data;
-
   g_return_if_fail (GB_IS_EDITOR_FRAME (self));
+  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
 
-  gb_editor_frame_find (self, NULL);
+  gtk_text_view_set_buffer (GTK_TEXT_VIEW (self->source_view), GTK_TEXT_BUFFER (document));
+  g_signal_connect (document, "cursor-moved", G_CALLBACK (on_cursor_moved), self);
+  g_object_bind_property (document, "busy", self->floating_bar, "show-spinner", G_BINDING_SYNC_CREATE);
 }
 
 static gboolean
-gb_editor_frame_on_query_tooltip (GbEditorFrame *self,
-                                  gint           x,
-                                  gint           y,
-                                  gboolean       keyboard_mode,
-                                  GtkTooltip    *tooltip,
-                                  GbSourceView  *source_view)
-{
-  GbEditorFramePrivate *priv;
-  GbSourceCodeAssistant *code_assistant;
-  GtkTextIter iter;
-  GArray *ar;
-  gboolean ret = FALSE;
-  guint line;
-  guint i;
-
-  g_assert (GB_IS_SOURCE_VIEW (source_view));
-  g_assert (GB_IS_EDITOR_FRAME (self));
-
-  priv = self->priv;
-
-  code_assistant = gb_editor_document_get_code_assistant (priv->document);
-  if (!code_assistant)
-    return FALSE;
-
-  ar = gb_source_code_assistant_get_diagnostics (code_assistant);
-  if (!ar)
-    return FALSE;
-
-  gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (source_view),
-                                         GTK_TEXT_WINDOW_WIDGET,
-                                         x, y, &x, &y);
-
-  gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (source_view),
-                                      &iter, x, y);
-
-  line = gtk_text_iter_get_line (&iter);
-
-  for (i = 0; i < ar->len; i++)
-    {
-      GcaDiagnostic *diag;
-      guint j;
-
-      diag = &g_array_index (ar, GcaDiagnostic, i);
-
-      for (j = 0; j < diag->locations->len; j++)
-        {
-          GcaSourceRange *loc;
-
-          loc = &g_array_index (diag->locations, GcaSourceRange, j);
-
-          if ((loc->begin.line <= line) && (loc->end.line >= line))
-            {
-              gtk_tooltip_set_text (tooltip, diag->message);
-              ret = TRUE;
-              goto cleanup;
-            }
-        }
-    }
-
-cleanup:
-  g_array_unref (ar);
-
-  return ret;
-}
-
-static void
-gb_editor_frame_on_switch_to_file (GbEditorFrame *self,
-                                   GFile         *file,
-                                   GbSourceVim   *vim)
-{
-  GbWorkspace *workspace;
-  GbWorkbench *workbench;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (G_IS_FILE (file));
-  g_return_if_fail (GB_IS_SOURCE_VIM (vim));
-
-  workbench = gb_widget_get_workbench (GTK_WIDGET (self));
-  workspace = gb_workbench_get_workspace (workbench, GB_TYPE_EDITOR_WORKSPACE);
-  gb_editor_workspace_open (GB_EDITOR_WORKSPACE (workspace), file);
-}
-
-static void
-gb_editor_frame_on_command_toggled (GbEditorFrame *self,
-                                    gboolean       visible,
-                                    GbSourceVim   *vim)
-{
-  GbWorkbench *workbench;
-  GAction *action;
-  GVariant *params;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GB_IS_SOURCE_VIM (vim));
-
-  workbench = gb_widget_get_workbench (GTK_WIDGET (self));
-  if (!workbench)
-    EXIT;
-
-  action = g_action_map_lookup_action (G_ACTION_MAP (workbench),
-                                       "toggle-command-bar");
-  if (!action)
-    EXIT;
-
-  params = g_variant_new_boolean (visible);
-  g_action_activate (action, params);
-
-  EXIT;
-}
-
-static void
-gb_editor_frame_on_jump_to_doc (GbEditorFrame *self,
-                                const gchar   *search_text,
-                                GbSourceView  *source_view)
-{
-  GActionGroup *action_group;
-  GbWorkbench *workbench;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GB_IS_SOURCE_VIEW (source_view));
-  g_return_if_fail (search_text);
-
-  workbench = gb_widget_get_workbench (GTK_WIDGET (self));
-  action_group = gtk_widget_get_action_group (GTK_WIDGET (workbench),
-                                              "workspace");
-  g_action_group_activate_action (action_group, "jump-to-doc",
-                                  g_variant_new_string (search_text));
-
-  EXIT;
-}
-
-static void
-gb_editor_frame_on_drop_uris (GbEditorFrame  *self,
-                              const gchar   **uri_list,
-                              GbSourceView   *source_view)
-{
-  GVariantBuilder *builder;
-  GVariant *variant;
-  guint i;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  g_return_if_fail (GB_IS_SOURCE_VIEW (source_view));
-  g_return_if_fail (uri_list);
-
-  builder = g_variant_builder_new (G_VARIANT_TYPE_STRING_ARRAY);
-  for (i = 0; uri_list [i]; i++)
-    g_variant_builder_add (builder, "s", uri_list[i]);
-  variant = g_variant_builder_end (builder);
-  g_variant_builder_unref (builder);
-
-  gb_widget_activate_action (GTK_WIDGET (self),
-                             "workspace", "open-uri-list",
-                             variant);
-
-  EXIT;
-}
-
-static void
-gb_editor_frame_grab_focus (GtkWidget *widget)
-{
-  GbEditorFrame *self = (GbEditorFrame *)widget;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  gtk_widget_grab_focus (GTK_WIDGET (self->priv->source_view));
-
-  EXIT;
-}
-
-static void
-gb_editor_frame_scroll_to_line (GbEditorFrame *self,
-                                guint          line,
-                                guint          offset)
-{
-  GtkTextBuffer *buffer;
-  GtkTextView *text_view;
-  GtkTextIter iter;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  buffer = GTK_TEXT_BUFFER (self->priv->document);
-  text_view = GTK_TEXT_VIEW (self->priv->source_view);
-
-  gb_gtk_text_buffer_get_iter_at_line_and_offset (buffer, &iter, line, offset);
-  gtk_text_buffer_select_range (buffer, &iter, &iter);
-  gb_gtk_text_view_scroll_to_iter (text_view, &iter, 0.0, TRUE, 0.0, 0.5);
-}
-
-static void
-gb_editor_frame_next_diagnostic (GbEditorFrame *self)
-{
-  GbSourceCodeAssistant *assistant;
-  GtkTextMark *mark;
-  GtkTextIter iter;
-  guint current_line;
-  GArray *ar;
-  guint i;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  assistant = gb_editor_document_get_code_assistant (self->priv->document);
-  ar = gb_source_code_assistant_get_diagnostics (assistant);
-  mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (self->priv->document));
-  gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (self->priv->document),
-                                    &iter, mark);
-  current_line = gtk_text_iter_get_line (&iter);
-
-  if (ar)
-    {
-      for (i = 0; i < ar->len; i++)
-        {
-          GcaDiagnostic *diag;
-          guint j;
-
-          diag = &g_array_index (ar, GcaDiagnostic, i);
-
-          for (j = 0; j < diag->locations->len; j++)
-            {
-              GcaSourceRange *range;
-
-              range = &g_array_index (diag->locations, GcaSourceRange, j);
-
-              if (range->begin.line > current_line)
-                {
-                  gb_editor_frame_scroll_to_line (self,
-                                                  range->begin.line,
-                                                  range->begin.column);
-                  goto cleanup;
-                }
-            }
-        }
-
-      /* wrap around to first diagnostic */
-      if (ar->len > 0)
-        {
-          GcaDiagnostic *diag;
-
-          diag = &g_array_index (ar, GcaDiagnostic, 0);
-
-          if (diag->locations->len > 0)
-            {
-              GcaSourceRange *range;
-
-              range = &g_array_index (diag->locations, GcaSourceRange, 0);
-              gb_editor_frame_scroll_to_line (self, range->begin.line,
-                                              range->begin.column);
-            }
-        }
-
-cleanup:
-      g_array_unref (ar);
-    }
-}
-
-static void
-gb_editor_frame_previous_diagnostic (GbEditorFrame *self)
+get_smart_home_end (GValue   *value,
+                    GVariant *variant,
+                    gpointer  user_data)
 {
-  GbSourceCodeAssistant *assistant;
-  GtkTextMark *mark;
-  GtkTextIter iter;
-  guint current_line;
-  GArray *ar;
-  gint i;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  assistant = gb_editor_document_get_code_assistant (self->priv->document);
-  ar = gb_source_code_assistant_get_diagnostics (assistant);
-  mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (self->priv->document));
-  gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (self->priv->document),
-                                    &iter, mark);
-  current_line = gtk_text_iter_get_line (&iter);
-
-  if (ar)
-    {
-      for (i = 0; i < ar->len; i++)
-        {
-          GcaDiagnostic *diag;
-          guint j;
-
-          diag = &g_array_index (ar, GcaDiagnostic, ar->len-i-1);
-
-          for (j = 0; j < diag->locations->len; j++)
-            {
-              GcaSourceRange *range;
-
-              range = &g_array_index (diag->locations, GcaSourceRange, j);
-
-              if (range->begin.line < current_line)
-                {
-                  gb_editor_frame_scroll_to_line (self,
-                                                  range->begin.line,
-                                                  range->begin.column);
-                  goto cleanup;
-                }
-            }
-        }
-
-      /* wrap around to last diagnostic */
-      if (ar->len > 0)
-        {
-          GcaDiagnostic *diag;
-
-          diag = &g_array_index (ar, GcaDiagnostic, ar->len-1);
-
-          if (diag->locations->len > 0)
-            {
-              GcaSourceRange *range;
-
-              range = &g_array_index (diag->locations, GcaSourceRange, 0);
-              gb_editor_frame_scroll_to_line (self, range->begin.line,
-                                              range->begin.column);
-            }
-        }
-    }
-
-cleanup:
-  g_clear_pointer (&ar, g_array_unref);
-}
-
-static void
-gb_editor_frame_reformat_activate (GSimpleAction *action,
-                                   GVariant      *parameter,
-                                   gpointer       user_data)
-{
-  GbEditorFrame *self = user_data;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  gb_editor_frame_reformat (self);
-}
-
-static void
-gb_editor_frame_next_diagnostic_activate (GSimpleAction *action,
-                                          GVariant      *parameter,
-                                          gpointer       user_data)
-{
-  GbEditorFrame *self = user_data;
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  gb_editor_frame_next_diagnostic (self);
-}
-
-static void
-gb_editor_frame_previous_diagnostic_activate (GSimpleAction *action,
-                                              GVariant      *parameter,
-                                              gpointer       user_data)
-{
-  GbEditorFrame *self = user_data;
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-  gb_editor_frame_previous_diagnostic (self);
-}
-
-static void
-gb_editor_frame_scroll (GbEditorFrame    *self,
-                        GtkDirectionType  dir)
-{
-  GtkAdjustment *vadj;
-  GtkScrolledWindow *scroller;
-  GtkTextMark *insert;
-  GtkTextView *view;
-  GtkTextBuffer *buffer;
-  GdkRectangle rect;
-  GtkTextIter iter;
-  gdouble amount;
-  gdouble value;
-  gdouble upper;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  scroller = self->priv->scrolled_window;
-  view = GTK_TEXT_VIEW (self->priv->source_view);
-  buffer = GTK_TEXT_BUFFER (self->priv->document);
-
-  insert = gtk_text_buffer_get_insert (buffer);
-  gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
-  gtk_text_view_get_iter_location (view, &iter, &rect);
-
-  amount = (dir == GTK_DIR_UP) ? -rect.height : rect.height;
-
-  vadj = gtk_scrolled_window_get_vadjustment (scroller);
-  value = gtk_adjustment_get_value (vadj);
-  upper = gtk_adjustment_get_upper (vadj);
-  gtk_adjustment_set_value (vadj, CLAMP (value + amount, 0, upper));
-}
-
-static void
-gb_editor_frame_scroll_down (GSimpleAction *action,
-                             GVariant      *parameter,
-                             gpointer       user_data)
-{
-  GbEditorFrame *self = user_data;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
+  if (g_variant_get_boolean (variant))
+    g_value_set_enum (value, GTK_SOURCE_SMART_HOME_END_BEFORE);
+  else
+    g_value_set_enum (value, GTK_SOURCE_SMART_HOME_END_DISABLED);
 
-  gb_editor_frame_scroll (self, GTK_DIR_DOWN);
-  gtk_text_view_place_cursor_onscreen (GTK_TEXT_VIEW (self->priv->source_view));
+  return TRUE;
 }
 
 static void
-gb_editor_frame_scroll_up (GSimpleAction *action,
-                           GVariant      *parameter,
-                           gpointer       user_data)
+keybindings_changed (GSettings     *settings,
+                     const gchar   *key,
+                     GbEditorFrame *self)
 {
-  GbEditorFrame *self = user_data;
-
-  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
-
-  gb_editor_frame_scroll (self, GTK_DIR_UP);
-  gtk_text_view_place_cursor_onscreen (GTK_TEXT_VIEW (self->priv->source_view));
+  g_signal_emit_by_name (self->source_view,
+                         "set-mode",
+                         NULL,
+                         IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT);
 }
 
 static void
 gb_editor_frame_finalize (GObject *object)
 {
-  GbEditorFrame *self = GB_EDITOR_FRAME (object);
-
-  gb_editor_frame_disconnect (self);
-
-  g_clear_object (&self->priv->code_assistant_renderer);
-  g_clear_object (&self->priv->diff_renderer);
-  g_clear_object (&self->priv->search_settings);
-  g_clear_object (&self->priv->search_highlighter);
-
   G_OBJECT_CLASS (gb_editor_frame_parent_class)->finalize (object);
 }
 
 static void
-gb_editor_frame_constructed (GObject *object)
-{
-  GbSourceChangeMonitor *monitor = NULL;
-  GbEditorFramePrivate *priv;
-  GtkSourceGutter *gutter;
-  GbEditorFrame *self = (GbEditorFrame *)object;
-  GbSourceVim *vim;
-  GSettings *settings;
-
-  G_OBJECT_CLASS (gb_editor_frame_parent_class)->constructed (object);
-
-  priv = self->priv;
-
-  settings = g_settings_new ("org.gnome.builder.editor");
-
-  if (priv->document)
-    monitor = gb_editor_document_get_change_monitor (priv->document);
-
-  gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (priv->source_view),
-                                       GTK_TEXT_WINDOW_LEFT);
-
-  priv->diff_renderer = g_object_new (GB_TYPE_SOURCE_CHANGE_GUTTER_RENDERER,
-                                      "change-monitor", monitor,
-                                      "size", 2,
-                                      "visible", TRUE,
-                                      "xpad", 1,
-                                      NULL);
-  priv->diff_renderer = g_object_ref (priv->diff_renderer);
-  gtk_source_gutter_insert (gutter,
-                            GTK_SOURCE_GUTTER_RENDERER (priv->diff_renderer),
-                            0);
-  g_settings_bind (settings, "show-diff",
-                   priv->diff_renderer, "visible",
-                   G_SETTINGS_BIND_GET);
-
-  priv->code_assistant_renderer =
-    g_object_new (GB_TYPE_SOURCE_CODE_ASSISTANT_RENDERER,
-                  "code-assistant", NULL,
-                  "size", 16,
-                  "visible", TRUE,
-                  NULL);
-  priv->code_assistant_renderer = g_object_ref (priv->code_assistant_renderer);
-  gtk_source_gutter_insert (gutter,
-                            GTK_SOURCE_GUTTER_RENDERER (priv->code_assistant_renderer),
-                            -50);
-
-  priv->search_settings = g_object_new (GTK_SOURCE_TYPE_SEARCH_SETTINGS,
-                                        "wrap-around", TRUE,
-                                        NULL);
-  g_object_bind_property (priv->search_entry, "text",
-                          priv->search_settings, "search-text",
-                          G_BINDING_SYNC_CREATE);
-
-  priv->search_highlighter =
-    g_object_new (GB_TYPE_SOURCE_SEARCH_HIGHLIGHTER,
-                  "search-settings", priv->search_settings,
-                  NULL);
-  g_object_set (priv->source_view,
-                "search-highlighter", priv->search_highlighter,
-                NULL);
-  g_object_bind_property (priv->search_revealer, "reveal-child",
-                          priv->source_view, "show-shadow",
-                          G_BINDING_SYNC_CREATE);
-
-  vim = gb_source_view_get_vim (priv->source_view);
-  g_signal_connect_object (vim,
-                           "command-visibility-toggled",
-                           G_CALLBACK (gb_editor_frame_on_command_toggled),
-                           self,
-                           G_CONNECT_SWAPPED);
-  g_signal_connect_object (vim,
-                           "switch-to-file",
-                           G_CALLBACK (gb_editor_frame_on_switch_to_file),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->source_view,
-                           "display-documentation",
-                           G_CALLBACK (gb_editor_frame_on_jump_to_doc),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->source_view,
-                           "drop-uris",
-                           G_CALLBACK (gb_editor_frame_on_drop_uris),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->source_view,
-                           "focus-in-event",
-                           G_CALLBACK (gb_editor_frame_on_focus_in_event),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->source_view,
-                           "populate-popup",
-                           G_CALLBACK (gb_editor_frame_on_populate_popup),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->source_view,
-                           "push-snippet",
-                           G_CALLBACK (gb_editor_frame_on_push_snippet),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->source_view,
-                           "begin-search",
-                           G_CALLBACK (gb_editor_frame_on_begin_search),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->source_view,
-                           "query-tooltip",
-                           G_CALLBACK (gb_editor_frame_on_query_tooltip),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->search_entry,
-                           "key-press-event",
-                           G_CALLBACK (gb_editor_frame_on_search_entry_key_press),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->search_entry,
-                           "changed",
-                           G_CALLBACK (gb_editor_frame_on_search_entry_changed),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->search_entry,
-                           "activate",
-                           G_CALLBACK (gb_editor_frame_on_search_entry_activate),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->forward_search,
-                           "clicked",
-                           G_CALLBACK (gb_editor_frame_on_forward_search_clicked),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (priv->backward_search,
-                           "clicked",
-                           G_CALLBACK (gb_editor_frame_on_backward_search_clicked),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  g_object_unref (settings);
-}
-
-static void
 gb_editor_frame_get_property (GObject    *object,
                               guint       prop_id,
                               GValue     *value,
@@ -1606,10 +137,6 @@ gb_editor_frame_get_property (GObject    *object,
       g_value_set_object (value, gb_editor_frame_get_document (self));
       break;
 
-    case PROP_SEARCH_DIRECTION:
-      g_value_set_enum (value, gb_editor_frame_get_search_direction (self));
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -1638,86 +165,48 @@ static void
 gb_editor_frame_class_init (GbEditorFrameClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
-  object_class->constructed = gb_editor_frame_constructed;
   object_class->finalize = gb_editor_frame_finalize;
   object_class->get_property = gb_editor_frame_get_property;
   object_class->set_property = gb_editor_frame_set_property;
 
-  widget_class->grab_focus = gb_editor_frame_grab_focus;
-
   gParamSpecs [PROP_DOCUMENT] =
     g_param_spec_object ("document",
                          _("Document"),
-                         _("The document for the editor."),
+                         _("The editor document."),
                          GB_TYPE_EDITOR_DOCUMENT,
                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_DOCUMENT,
-                                   gParamSpecs [PROP_DOCUMENT]);
-
-  gParamSpecs [PROP_SEARCH_DIRECTION] =
-    g_param_spec_enum ("search-direction",
-                       _("Search Direction"),
-                       _("The direction of the last text searched for."),
-                       GTK_TYPE_DIRECTION_TYPE,
-                       GTK_DIR_DOWN,
-                       (G_PARAM_READABLE |
-                        G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_SEARCH_DIRECTION,
-                                   gParamSpecs [PROP_SEARCH_DIRECTION]);
-
-
-  gSignals [FOCUSED] =
-    g_signal_new ("focused",
-                  GB_TYPE_EDITOR_FRAME,
-                  G_SIGNAL_RUN_LAST,
-                  0,
-                  NULL,
-                  NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                  G_TYPE_NONE,
-                  0);
+  g_object_class_install_property (object_class, PROP_DOCUMENT, gParamSpecs [PROP_DOCUMENT]);
 
   GB_WIDGET_CLASS_TEMPLATE (klass, "gb-editor-frame.ui");
-  GB_WIDGET_CLASS_BIND (klass, GbEditorFrame, busy_spinner);
+
   GB_WIDGET_CLASS_BIND (klass, GbEditorFrame, floating_bar);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorFrame, forward_search);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorFrame, backward_search);
   GB_WIDGET_CLASS_BIND (klass, GbEditorFrame, scrolled_window);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorFrame, search_revealer);
   GB_WIDGET_CLASS_BIND (klass, GbEditorFrame, search_entry);
+  GB_WIDGET_CLASS_BIND (klass, GbEditorFrame, search_revealer);
   GB_WIDGET_CLASS_BIND (klass, GbEditorFrame, source_view);
 
-  g_type_ensure (GB_TYPE_SOURCE_VIEW);
-  g_type_ensure (GD_TYPE_TAGGED_ENTRY);
   g_type_ensure (NAUTILUS_TYPE_FLOATING_BAR);
+  g_type_ensure (GD_TYPE_TAGGED_ENTRY);
 }
 
 static void
 gb_editor_frame_init (GbEditorFrame *self)
 {
-  const GActionEntry entries[] = {
-    { "find", gb_editor_frame_find_activate },
-    { "reformat", gb_editor_frame_reformat_activate },
-    { "scroll-up", gb_editor_frame_scroll_up },
-    { "scroll-down", gb_editor_frame_scroll_down },
-    { "next-diagnostic", gb_editor_frame_next_diagnostic_activate },
-    { "previous-diagnostic", gb_editor_frame_previous_diagnostic_activate },
-  };
-  GSimpleActionGroup *actions;
-
-  self->priv = gb_editor_frame_get_instance_private (self);
+  g_autoptr(GSettings) settings = NULL;
 
   gtk_widget_init_template (GTK_WIDGET (self));
 
-  actions = g_simple_action_group_new ();
-  g_action_map_add_action_entries (G_ACTION_MAP (actions),
-                                   entries, G_N_ELEMENTS (entries),
-                                   self);
-  gtk_widget_insert_action_group (GTK_WIDGET (self), "editor-frame",
-                                  G_ACTION_GROUP (actions));
-  g_object_unref (actions);
+  gb_editor_frame_actions_init (self);
 
-  self->priv->search_direction = GTK_DIR_DOWN;
+  settings = g_settings_new ("org.gnome.builder.editor");
+  g_settings_bind (settings, "font-name", self->source_view, "font-name", G_SETTINGS_BIND_GET);
+  g_settings_bind (settings, "highlight-current-line", self->source_view, "highlight-current-line", 
G_SETTINGS_BIND_GET);
+  g_settings_bind (settings, "show-grid-lines", self->source_view, "show-grid-lines", G_SETTINGS_BIND_GET);
+  g_settings_bind (settings, "show-line-changes", self->source_view, "show-line-changes", 
G_SETTINGS_BIND_GET);
+  g_settings_bind (settings, "show-line-numbers", self->source_view, "show-line-numbers", 
G_SETTINGS_BIND_GET);
+  g_settings_bind (settings, "smart-backspace", self->source_view, "smart-backspace", G_SETTINGS_BIND_GET);
+  g_settings_bind_with_mapping (settings, "smart-home-end", self->source_view, "smart-home-end", 
G_SETTINGS_BIND_GET, get_smart_home_end, NULL, NULL, NULL);
+  g_settings_bind (settings, "word-completion", self->source_view, "enable-word-completion", 
G_SETTINGS_BIND_GET);
+  g_signal_connect (settings, "changed::keybindings", G_CALLBACK (keybindings_changed), self);
 }
diff --git a/src/editor/gb-editor-frame.h b/src/editor/gb-editor-frame.h
index 7d10478..ed6b1fb 100644
--- a/src/editor/gb-editor-frame.h
+++ b/src/editor/gb-editor-frame.h
@@ -1,6 +1,6 @@
 /* gb-editor-frame.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,43 +25,13 @@
 
 G_BEGIN_DECLS
 
-#define GB_TYPE_EDITOR_FRAME            (gb_editor_frame_get_type())
-#define GB_EDITOR_FRAME(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_EDITOR_FRAME, 
GbEditorFrame))
-#define GB_EDITOR_FRAME_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_EDITOR_FRAME, 
GbEditorFrame const))
-#define GB_EDITOR_FRAME_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_EDITOR_FRAME, 
GbEditorFrameClass))
-#define GB_IS_EDITOR_FRAME(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_EDITOR_FRAME))
-#define GB_IS_EDITOR_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_EDITOR_FRAME))
-#define GB_EDITOR_FRAME_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_EDITOR_FRAME, 
GbEditorFrameClass))
+#define GB_TYPE_EDITOR_FRAME (gb_editor_frame_get_type())
 
-typedef struct _GbEditorFrame        GbEditorFrame;
-typedef struct _GbEditorFrameClass   GbEditorFrameClass;
-typedef struct _GbEditorFramePrivate GbEditorFramePrivate;
+G_DECLARE_FINAL_TYPE (GbEditorFrame, gb_editor_frame, GB, EDITOR_FRAME, GtkBin)
 
-struct _GbEditorFrame
-{
-  GtkOverlay parent;
-
-  /*< private >*/
-  GbEditorFramePrivate *priv;
-};
-
-struct _GbEditorFrameClass
-{
-  GtkOverlayClass parent;
-};
-
-GType             gb_editor_frame_get_type     (void);
-GtkWidget        *gb_editor_frame_new          (void);
-void              gb_editor_frame_link         (GbEditorFrame    *src,
-                                                GbEditorFrame    *dst);
 GbEditorDocument *gb_editor_frame_get_document (GbEditorFrame    *self);
 void              gb_editor_frame_set_document (GbEditorFrame    *self,
                                                 GbEditorDocument *document);
-void              gb_editor_frame_find         (GbEditorFrame    *self,
-                                                const gchar      *search_text);
-void              gb_editor_frame_reformat     (GbEditorFrame    *self);
-
-GtkDirectionType  gb_editor_frame_get_search_direction (GbEditorFrame *self);
 
 G_END_DECLS
 
diff --git a/src/editor/gb-editor-settings-widget.c b/src/editor/gb-editor-settings-widget.c
index e10ad02..26c2527 100644
--- a/src/editor/gb-editor-settings-widget.c
+++ b/src/editor/gb-editor-settings-widget.c
@@ -168,14 +168,14 @@ gb_editor_settings_widget_class_init (GbEditorSettingsWidgetClass *klass)
   object_class->set_property = gb_editor_settings_widget_set_property;
 
   GB_WIDGET_CLASS_TEMPLATE (klass, "gb-editor-settings-widget.ui");
-  GB_WIDGET_CLASS_BIND (klass, GbEditorSettingsWidget, auto_indent);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorSettingsWidget, insert_matching_brace);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorSettingsWidget, insert_spaces_instead_of_tabs);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorSettingsWidget, right_margin_position);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorSettingsWidget, overwrite_braces);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorSettingsWidget, show_right_margin);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorSettingsWidget, tab_width);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorSettingsWidget, trim_trailing_whitespace);
+  GB_WIDGET_CLASS_BIND_PRIVATE (klass, GbEditorSettingsWidget, auto_indent);
+  GB_WIDGET_CLASS_BIND_PRIVATE (klass, GbEditorSettingsWidget, insert_matching_brace);
+  GB_WIDGET_CLASS_BIND_PRIVATE (klass, GbEditorSettingsWidget, insert_spaces_instead_of_tabs);
+  GB_WIDGET_CLASS_BIND_PRIVATE (klass, GbEditorSettingsWidget, right_margin_position);
+  GB_WIDGET_CLASS_BIND_PRIVATE (klass, GbEditorSettingsWidget, overwrite_braces);
+  GB_WIDGET_CLASS_BIND_PRIVATE (klass, GbEditorSettingsWidget, show_right_margin);
+  GB_WIDGET_CLASS_BIND_PRIVATE (klass, GbEditorSettingsWidget, tab_width);
+  GB_WIDGET_CLASS_BIND_PRIVATE (klass, GbEditorSettingsWidget, trim_trailing_whitespace);
 
   gParamSpecs [PROP_LANGUAGE] =
     g_param_spec_string ("language",
diff --git a/src/editor/gb-editor-tweak-widget.c b/src/editor/gb-editor-tweak-widget.c
index 3cf3c69..b94a87d 100644
--- a/src/editor/gb-editor-tweak-widget.c
+++ b/src/editor/gb-editor-tweak-widget.c
@@ -25,14 +25,15 @@
 #include "gb-string.h"
 #include "gb-widget.h"
 
-struct _GbEditorTweakWidgetPrivate
+struct _GbEditorTweakWidget
 {
+  GtkBin          parent_instance;
+
   GtkSearchEntry *entry;
   GtkListBox     *list_box;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GbEditorTweakWidget, gb_editor_tweak_widget,
-                            GTK_TYPE_BIN)
+G_DEFINE_TYPE (GbEditorTweakWidget, gb_editor_tweak_widget, GTK_TYPE_BIN)
 
 static GQuark gLangQuark;
 
@@ -67,55 +68,36 @@ gb_editor_tweak_widget_filter_func (GtkListBoxRow *row,
 }
 
 static void
-gb_editor_tweak_widget_entry_changed (GbEditorTweakWidget *widget,
+gb_editor_tweak_widget_entry_changed (GbEditorTweakWidget *self,
                                       GtkEntry            *entry)
 {
   const gchar *text;
 
-  g_return_if_fail (GB_IS_EDITOR_TWEAK_WIDGET (widget));
+  g_return_if_fail (GB_IS_EDITOR_TWEAK_WIDGET (self));
   g_return_if_fail (GTK_IS_ENTRY (entry));
 
   text = gtk_entry_get_text (entry);
 
   if (gb_str_empty0 (text))
-    gtk_list_box_set_filter_func (widget->priv->list_box, NULL, NULL, NULL);
+    gtk_list_box_set_filter_func (self->list_box, NULL, NULL, NULL);
   else
-    gtk_list_box_set_filter_func (widget->priv->list_box,
+    gtk_list_box_set_filter_func (self->list_box,
                                   gb_editor_tweak_widget_filter_func,
                                   g_strdup (text),
                                   g_free);
 }
 
-static GActionGroup *
-find_action_group (GtkWidget   *widget,
-                   const gchar *name)
-{
-  GActionGroup *group = NULL;
-
-  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
-  g_return_val_if_fail (name, NULL);
-
-  while (!group && widget)
-    {
-      group = gtk_widget_get_action_group (widget, name);
-      widget = gtk_widget_get_parent (widget);
-    }
-
-  return group;
-}
-
 static void
-gb_editor_tweak_widget_row_activated (GbEditorTweakWidget *widget,
+gb_editor_tweak_widget_row_activated (GbEditorTweakWidget *self,
                                       GtkListBoxRow       *row,
                                       GtkListBox          *list_box)
 {
   GtkSourceLanguage *lang;
-  GActionGroup *group;
   const gchar *lang_id;
   GtkWidget *child;
   GVariant *param;
 
-  g_return_if_fail (GB_IS_EDITOR_TWEAK_WIDGET (widget));
+  g_return_if_fail (GB_IS_EDITOR_TWEAK_WIDGET (self));
   g_return_if_fail (GTK_IS_LIST_BOX_ROW (row));
   g_return_if_fail (GTK_IS_LIST_BOX (list_box));
 
@@ -124,23 +106,22 @@ gb_editor_tweak_widget_row_activated (GbEditorTweakWidget *widget,
 
   if (lang)
     {
-      group = find_action_group (GTK_WIDGET (widget), "editor-view");
       lang_id = gtk_source_language_get_id (lang);
       param = g_variant_new_string (lang_id);
-      g_action_group_activate_action (group, "language", param);
+      gb_widget_activate_action (GTK_WIDGET (self), "editor-view", "language", param);
     }
 }
 
 static void
 gb_editor_tweak_widget_constructed (GObject *object)
 {
-  GbEditorTweakWidget *widget = (GbEditorTweakWidget *)object;
+  GbEditorTweakWidget *self = (GbEditorTweakWidget *)object;
   GtkSourceLanguageManager *manager;
   GtkSourceLanguage *lang;
   const gchar * const *lang_ids;
   guint i;
 
-  g_return_if_fail (GB_IS_EDITOR_TWEAK_WIDGET (widget));
+  g_return_if_fail (GB_IS_EDITOR_TWEAK_WIDGET (self));
 
   G_OBJECT_CLASS (gb_editor_tweak_widget_parent_class)->constructed (object);
 
@@ -162,19 +143,19 @@ gb_editor_tweak_widget_constructed (GObject *object)
                           "margin-bottom", 3,
                           NULL);
       g_object_set_qdata (G_OBJECT (row), gLangQuark, lang);
-      gtk_list_box_insert (widget->priv->list_box, row, -1);
+      gtk_list_box_insert (self->list_box, row, -1);
     }
 
-  g_signal_connect_object (widget->priv->entry,
+  g_signal_connect_object (self->entry,
                            "changed",
                            G_CALLBACK (gb_editor_tweak_widget_entry_changed),
-                           widget,
+                           self,
                            G_CONNECT_SWAPPED);
 
-  g_signal_connect_object (widget->priv->list_box,
+  g_signal_connect_object (self->list_box,
                            "row-activated",
                            G_CALLBACK (gb_editor_tweak_widget_row_activated),
-                           widget,
+                           self,
                            G_CONNECT_SWAPPED);
 }
 
@@ -195,7 +176,5 @@ gb_editor_tweak_widget_class_init (GbEditorTweakWidgetClass *klass)
 static void
 gb_editor_tweak_widget_init (GbEditorTweakWidget *self)
 {
-  self->priv = gb_editor_tweak_widget_get_instance_private (self);
-
   gtk_widget_init_template (GTK_WIDGET (self));
 }
diff --git a/src/editor/gb-editor-tweak-widget.h b/src/editor/gb-editor-tweak-widget.h
index d1f1bf4..6394dfa 100644
--- a/src/editor/gb-editor-tweak-widget.h
+++ b/src/editor/gb-editor-tweak-widget.h
@@ -20,36 +20,13 @@
 #define GB_EDITOR_TWEAK_WIDGET_H
 
 #include <gtk/gtk.h>
+#include <ide.h>
 
 G_BEGIN_DECLS
 
-#define GB_TYPE_EDITOR_TWEAK_WIDGET            (gb_editor_tweak_widget_get_type())
-#define GB_EDITOR_TWEAK_WIDGET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_EDITOR_TWEAK_WIDGET, GbEditorTweakWidget))
-#define GB_EDITOR_TWEAK_WIDGET_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_EDITOR_TWEAK_WIDGET, GbEditorTweakWidget const))
-#define GB_EDITOR_TWEAK_WIDGET_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  
GB_TYPE_EDITOR_TWEAK_WIDGET, GbEditorTweakWidgetClass))
-#define GB_IS_EDITOR_TWEAK_WIDGET(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GB_TYPE_EDITOR_TWEAK_WIDGET))
-#define GB_IS_EDITOR_TWEAK_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  
GB_TYPE_EDITOR_TWEAK_WIDGET))
-#define GB_EDITOR_TWEAK_WIDGET_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  
GB_TYPE_EDITOR_TWEAK_WIDGET, GbEditorTweakWidgetClass))
+#define GB_TYPE_EDITOR_TWEAK_WIDGET (gb_editor_tweak_widget_get_type())
 
-typedef struct _GbEditorTweakWidget        GbEditorTweakWidget;
-typedef struct _GbEditorTweakWidgetClass   GbEditorTweakWidgetClass;
-typedef struct _GbEditorTweakWidgetPrivate GbEditorTweakWidgetPrivate;
-
-struct _GbEditorTweakWidget
-{
-  GtkBin parent;
-
-  /*< private >*/
-  GbEditorTweakWidgetPrivate *priv;
-};
-
-struct _GbEditorTweakWidgetClass
-{
-  GtkBinClass parent;
-};
-
-GType      gb_editor_tweak_widget_get_type (void);
-GtkWidget *gb_editor_tweak_widget_new      (void);
+G_DECLARE_FINAL_TYPE (GbEditorTweakWidget, gb_editor_tweak_widget, GB, EDITOR_TWEAK_WIDGET, GtkBin)
 
 G_END_DECLS
 
diff --git a/src/editor/gb-editor-view-actions.c b/src/editor/gb-editor-view-actions.c
new file mode 100644
index 0000000..a271898
--- /dev/null
+++ b/src/editor/gb-editor-view-actions.c
@@ -0,0 +1,271 @@
+/* gb-editor-view-actions.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gb-editor-view"
+
+#include <ide.h>
+
+#include "gb-editor-frame-private.h"
+#include "gb-editor-view-actions.h"
+#include "gb-editor-view-private.h"
+#include "gb-widget.h"
+
+static void
+gb_editor_view_actions_source_view_notify (IdeSourceView *source_view,
+                                           GParamSpec    *pspec,
+                                           GActionMap    *actions)
+{
+  g_autoptr(GVariant) param = NULL;
+  GtkSourceView *gsv;
+  GAction *action = NULL;
+
+  g_assert (IDE_IS_SOURCE_VIEW (source_view));
+  g_assert (pspec != NULL);
+  g_assert (G_IS_ACTION_MAP (actions));
+
+  gsv = GTK_SOURCE_VIEW (source_view);
+
+  if (g_str_equal (pspec->name, "show-line-numbers"))
+    {
+      gboolean show_line_numbers;
+
+      action = g_action_map_lookup_action (actions, "show-line-numbers");
+      show_line_numbers = gtk_source_view_get_show_line_numbers (gsv);
+      param = g_variant_new_boolean (show_line_numbers);
+    }
+  else if (g_str_equal (pspec->name, "show-right-margin"))
+    {
+      gboolean show_right_margin;
+
+      action = g_action_map_lookup_action (actions, "show-right-margin");
+      show_right_margin = gtk_source_view_get_show_right_margin (gsv);
+      param = g_variant_new_boolean (show_right_margin);
+    }
+  else if (g_str_equal (pspec->name, "highlight-current-line"))
+    {
+      gboolean highlight_current_line;
+
+      action = g_action_map_lookup_action (actions, "highlight-current-line");
+      highlight_current_line = gtk_source_view_get_highlight_current_line (gsv);
+      param = g_variant_new_boolean (highlight_current_line);
+    }
+  else if (g_str_equal (pspec->name, "auto-indent"))
+    {
+      gboolean auto_indent;
+
+      action = g_action_map_lookup_action (actions, "auto-indent");
+      g_object_get (source_view, "auto-indent", &auto_indent, NULL);
+      param = g_variant_new_boolean (auto_indent);
+    }
+  else if (g_str_equal (pspec->name, "tab-width"))
+    {
+      guint tab_width;
+
+      action = g_action_map_lookup_action (actions, "tab-width");
+      g_object_get (source_view, "tab-width", &tab_width, NULL);
+      param = g_variant_new_int32 (tab_width);
+    }
+  else if (g_str_equal (pspec->name, "insert-spaces-instead-of-tabs"))
+    {
+      gboolean use_spaces;
+
+      action = g_action_map_lookup_action (actions, "use-spaces");
+      g_object_get (source_view, "insert-spaces-instead-of-tabs", &use_spaces, NULL);
+      param = g_variant_new_boolean (use_spaces);
+    }
+  else if (g_str_equal (pspec->name, "smart-backspace"))
+    {
+      gboolean smart_backspace;
+
+      action = g_action_map_lookup_action (actions, "smart-backspace");
+      g_object_get (source_view, "smart-backspace", &smart_backspace, NULL);
+      param = g_variant_new_boolean (smart_backspace);
+    }
+
+  if (action && param)
+    {
+      g_simple_action_set_state (G_SIMPLE_ACTION (action), param);
+      param = NULL;
+    }
+}
+
+static void
+gb_editor_view_actions_language (GSimpleAction *action,
+                                 GVariant      *variant,
+                                 gpointer       user_data)
+{
+  GbEditorView *self = user_data;
+  GtkSourceLanguageManager *manager;
+  GtkSourceLanguage *language;
+  GtkSourceBuffer *buffer;
+  const gchar *name;
+
+  g_assert (GB_IS_EDITOR_VIEW (self));
+
+  manager = gtk_source_language_manager_get_default ();
+  name = g_variant_get_string (variant, NULL);
+  buffer = GTK_SOURCE_BUFFER (self->document);
+
+  if (name != NULL)
+    {
+      language = gtk_source_language_manager_get_language (manager, name);
+      gtk_source_buffer_set_language (buffer, language);
+    }
+}
+
+#define STATE_HANDLER_BOOLEAN(name,propname)                       \
+static void                                                        \
+gb_editor_view_actions_##name (GSimpleAction *action,              \
+                               GVariant      *variant,             \
+                               gpointer       user_data)           \
+{                                                                  \
+  GbEditorView *self = user_data;                                  \
+  gboolean val;                                                    \
+                                                                   \
+  g_assert (GB_IS_EDITOR_VIEW (self));                             \
+                                                                   \
+  val = g_variant_get_boolean (variant);                           \
+  g_object_set (self->frame1->source_view, propname, val, NULL);   \
+  if (self->frame2)                                                \
+    g_object_set (self->frame2->source_view, propname, val, NULL); \
+}
+
+#define STATE_HANDLER_INT(name,propname)                           \
+static void                                                        \
+gb_editor_view_actions_##name (GSimpleAction *action,              \
+                               GVariant      *variant,             \
+                               gpointer       user_data)           \
+{                                                                  \
+  GbEditorView *self = user_data;                                  \
+  gint val;                                                        \
+                                                                   \
+  g_assert (GB_IS_EDITOR_VIEW (self));                             \
+                                                                   \
+  val = g_variant_get_int32 (variant);                             \
+  g_object_set (self->frame1->source_view, propname, val, NULL);   \
+  if (self->frame2)                                                \
+    g_object_set (self->frame2->source_view, propname, val, NULL); \
+}
+
+STATE_HANDLER_BOOLEAN (auto_indent, "auto-indent")
+STATE_HANDLER_BOOLEAN (show_line_numbers, "show-line-numbers")
+STATE_HANDLER_BOOLEAN (show_right_margin, "show-right-margin")
+STATE_HANDLER_BOOLEAN (highlight_current_line, "highlight-current-line")
+STATE_HANDLER_BOOLEAN (use_spaces, "insert-spaces-instead-of-tabs")
+STATE_HANDLER_BOOLEAN (smart_backspace, "smart-backspace")
+STATE_HANDLER_INT (tab_width, "tab-width")
+
+static void
+save_file_cb (GObject      *object,
+              GAsyncResult *result,
+              gpointer      user_data)
+{
+  IdeBufferManager *buffer_manager = (IdeBufferManager *)object;
+  g_autoptr(GbEditorView) self = user_data;
+  GError *error = NULL;
+
+  if (!ide_buffer_manager_save_file_finish (buffer_manager, result, &error))
+    {
+      /* info bar */
+      g_warning ("%s", error->message);
+      g_clear_error (&error);
+    }
+
+  gb_widget_fade_hide (GTK_WIDGET (self->progress_bar));
+}
+
+static void
+gb_editor_view_actions_save (GSimpleAction *action,
+                             GVariant      *param,
+                             gpointer       user_data)
+{
+  GbEditorView *self = user_data;
+  IdeContext *context;
+  IdeBufferManager *buffer_manager;
+  IdeFile *file;
+  IdeProgress *progress = NULL;
+
+  g_assert (GB_IS_EDITOR_VIEW (self));
+
+  file = ide_buffer_get_file (IDE_BUFFER (self->document));
+  context = ide_buffer_get_context (IDE_BUFFER (self->document));
+  buffer_manager = ide_context_get_buffer_manager (context);
+
+#if 0
+  if (!file || is_temporary (file))
+    {
+      /* todo: dialog */
+    }
+#endif
+
+  ide_buffer_manager_save_file_async (buffer_manager,
+                                      IDE_BUFFER (self->document),
+                                      file,
+                                      &progress,
+                                      NULL,
+                                      save_file_cb,
+                                      g_object_ref (self));
+  g_object_bind_property (progress, "fraction", self->progress_bar, "fraction",
+                          G_BINDING_SYNC_CREATE);
+  gtk_widget_show (GTK_WIDGET (self->progress_bar));
+  g_clear_object (&progress);
+}
+
+static GActionEntry GbEditorViewActions[] = {
+  { "auto-indent", NULL, NULL, "false", gb_editor_view_actions_auto_indent },
+  { "language", NULL, "s", "''", gb_editor_view_actions_language },
+  { "highlight-current-line", NULL, NULL, "false", gb_editor_view_actions_highlight_current_line },
+  { "save", gb_editor_view_actions_save },
+  { "show-line-numbers", NULL, NULL, "false", gb_editor_view_actions_show_line_numbers },
+  { "show-right-margin", NULL, NULL, "false", gb_editor_view_actions_show_right_margin },
+  { "smart-backspace", NULL, NULL, "false", gb_editor_view_actions_smart_backspace },
+  { "tab-width", NULL, "i", "8", gb_editor_view_actions_tab_width },
+  { "use-spaces", NULL, "b", "false", gb_editor_view_actions_use_spaces },
+};
+
+void
+gb_editor_view_actions_init (GbEditorView *self)
+{
+  g_autoptr(GSimpleActionGroup) group = NULL;
+
+  group = g_simple_action_group_new ();
+  g_action_map_add_action_entries (G_ACTION_MAP (group), GbEditorViewActions,
+                                   G_N_ELEMENTS (GbEditorViewActions), self);
+  gtk_widget_insert_action_group (GTK_WIDGET (self), "editor-view", G_ACTION_GROUP (group));
+  gtk_widget_insert_action_group (GTK_WIDGET (self->tweak_widget), "editor-view",
+                                  G_ACTION_GROUP (group));
+
+#define WATCH_PROPERTY(name) \
+  G_STMT_START { \
+    g_signal_connect (self->frame1->source_view, \
+                      "notify::"name, \
+                      G_CALLBACK (gb_editor_view_actions_source_view_notify), \
+                      group); \
+    g_object_notify (G_OBJECT (self->frame1->source_view), name); \
+  } G_STMT_END
+
+  WATCH_PROPERTY ("auto-indent");
+  WATCH_PROPERTY ("highlight-current-line");
+  WATCH_PROPERTY ("insert-spaces-instead-of-tabs");
+  WATCH_PROPERTY ("show-line-numbers");
+  WATCH_PROPERTY ("show-right-margin");
+  WATCH_PROPERTY ("smart-backspace");
+  WATCH_PROPERTY ("tab-width");
+
+#undef WATCH_PROPERTY
+}
diff --git a/src/auto-indent/c-parse-helper.h b/src/editor/gb-editor-view-actions.h
similarity index 57%
copy from src/auto-indent/c-parse-helper.h
copy to src/editor/gb-editor-view-actions.h
index 418f518..f623ab2 100644
--- a/src/auto-indent/c-parse-helper.h
+++ b/src/editor/gb-editor-view-actions.h
@@ -1,6 +1,6 @@
-/* c-parse-helper.h
+/* gb-editor-view-actions.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,26 +16,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef C_PARSE_HELPER_H
-#define C_PARSE_HELPER_H
+#ifndef GB_EDITOR_VIEW_ACTIONS_H
+#define GB_EDITOR_VIEW_ACTIONS_H
 
-#include <glib.h>
+#include "gb-editor-view.h"
 
 G_BEGIN_DECLS
 
-typedef struct
-{
-  gchar *type;
-  gchar *name;
-  guint  ellipsis : 1;
-  guint  n_star   : 4;
-} Parameter;
-
-gboolean   parameter_validate (Parameter       *param);
-void       parameter_free     (Parameter       *p);
-Parameter *parameter_copy     (const Parameter *src);
-GSList    *parse_parameters   (const gchar     *text);
+void gb_editor_view_actions_init (GbEditorView *self);
 
 G_END_DECLS
 
-#endif /* C_PARSE_HELPER_H */
+#endif /* GB_EDITOR_VIEW_ACTIONS_H */
diff --git a/src/auto-indent/c-parse-helper.h b/src/editor/gb-editor-view-private.h
similarity index 51%
copy from src/auto-indent/c-parse-helper.h
copy to src/editor/gb-editor-view-private.h
index 418f518..280df02 100644
--- a/src/auto-indent/c-parse-helper.h
+++ b/src/editor/gb-editor-view-private.h
@@ -1,6 +1,6 @@
-/* c-parse-helper.h
+/* gb-editor-view-private.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,26 +16,31 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef C_PARSE_HELPER_H
-#define C_PARSE_HELPER_H
+#ifndef GB_EDITOR_VIEW_PRIVATE_H
+#define GB_EDITOR_VIEW_PRIVATE_H
 
-#include <glib.h>
+#include "gb-editor-document.h"
+#include "gb-editor-frame.h"
+#include "gb-editor-tweak-widget.h"
+#include "gb-view.h"
 
 G_BEGIN_DECLS
 
-typedef struct
+struct _GbEditorView
 {
-  gchar *type;
-  gchar *name;
-  guint  ellipsis : 1;
-  guint  n_star   : 4;
-} Parameter;
+  GbView               parent_instance;
 
-gboolean   parameter_validate (Parameter       *param);
-void       parameter_free     (Parameter       *p);
-Parameter *parameter_copy     (const Parameter *src);
-GSList    *parse_parameters   (const gchar     *text);
+  GbEditorDocument    *document;
+  GSettings           *settings;
+
+  GbEditorFrame       *frame1;
+  GbEditorFrame       *frame2;
+  GtkPaned            *paned;
+  GtkProgressBar      *progress_bar;
+  GtkMenuButton       *tweak_button;
+  GbEditorTweakWidget *tweak_widget;
+};
 
 G_END_DECLS
 
-#endif /* C_PARSE_HELPER_H */
+#endif /* GB_EDITOR_VIEW_PRIVATE_H */
diff --git a/src/editor/gb-editor-view.c b/src/editor/gb-editor-view.c
index 7576d44..99358a3 100644
--- a/src/editor/gb-editor-view.c
+++ b/src/editor/gb-editor-view.c
@@ -1,6 +1,6 @@
 /* gb-editor-view.c
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,951 +16,113 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define G_LOG_DOMAIN "editor-view"
-
 #include <glib/gi18n.h>
 
-#include "gb-animation.h"
-#include "gb-editor-frame.h"
 #include "gb-editor-frame-private.h"
-#include "gb-editor-tweak-widget.h"
 #include "gb-editor-view.h"
-#include "gb-glib.h"
-#include "gb-html-document.h"
-#include "gb-log.h"
-#include "gb-string.h"
+#include "gb-editor-view-actions.h"
+#include "gb-editor-view-private.h"
 #include "gb-widget.h"
 
-struct _GbEditorViewPrivate
-{
-  /* References owned by view */
-  GbEditorDocument *document;
-
-  /* Weak references */
-  GbAnimation     *progress_anim;
-
-  /* References owned by GtkWidget template */
-  GtkPaned        *paned;
-  GtkToggleButton *split_button;
-  GbEditorFrame   *frame;
-  GtkProgressBar  *progress_bar;
-  GtkLabel        *error_label;
-  GtkButton       *error_close_button;
-  GtkRevealer     *error_revealer;
-  GtkLabel        *modified_label;
-  GtkButton       *modified_reload_button;
-  GtkButton       *modified_cancel_button;
-  GtkRevealer     *modified_revealer;
-  GtkMenuButton   *tweak_button;
-  GtkMenuButton   *tweak_widget;
-
-  guint8           tab_width;
-  guint            auto_indent : 1;
-  guint            highlight_current_line : 1;
-  guint            show_line_numbers : 1;
-  guint            show_right_margin : 1;
-  guint            use_spaces : 1;
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (GbEditorView, gb_editor_view, GB_TYPE_DOCUMENT_VIEW)
+G_DEFINE_TYPE (GbEditorView, gb_editor_view, GB_TYPE_VIEW)
 
 enum {
   PROP_0,
-  PROP_AUTO_INDENT,
   PROP_DOCUMENT,
-  PROP_HIGHLIGHT_CURRENT_LINE,
-  PROP_SHOW_LINE_NUMBERS,
-  PROP_SHOW_RIGHT_MARGIN,
-  PROP_SPLIT_ENABLED,
-  PROP_TAB_WIDTH,
-  PROP_USE_SPACES,
   LAST_PROP
 };
 
 static GParamSpec *gParamSpecs [LAST_PROP];
 
-static void gb_editor_view_toggle_split (GbEditorView *view);
-
-GtkWidget *
-gb_editor_view_new (GbEditorDocument *document)
-{
-  return g_object_new (GB_TYPE_EDITOR_VIEW,
-                       "document", document,
-                       NULL);
-}
-
-static void
-gb_editor_view_action_set_state (GbEditorView *view,
-                                 const gchar  *action_name,
-                                 GVariant     *state)
-{
-  GActionGroup *group;
-  GAction *action;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-  g_return_if_fail (action_name);
-  g_return_if_fail (state);
-
-  group = gtk_widget_get_action_group (GTK_WIDGET (view), "editor-view");
-  action = g_action_map_lookup_action (G_ACTION_MAP (group), action_name);
-  g_simple_action_set_state (G_SIMPLE_ACTION (action), state);
-}
-
-static void
-apply_state_language (GSimpleAction *action,
-                      GVariant      *param,
-                      gpointer       user_data)
-{
-  GbEditorView *view = user_data;
-  GtkSourceLanguage *l = NULL;
-  const gchar *lang_id;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-
-  lang_id = g_variant_get_string (param, NULL);
-
-  if (!gb_str_empty0 (lang_id))
-    {
-      GtkSourceLanguageManager *m;
-
-      m = gtk_source_language_manager_get_default ();
-      l = gtk_source_language_manager_get_language (m, lang_id);
-    }
-
-  gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (view->priv->document), l);
-}
-
-gboolean
-gb_editor_view_get_auto_indent (GbEditorView *view)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), FALSE);
-
-  return view->priv->auto_indent;
-}
-
-void
-gb_editor_view_set_auto_indent (GbEditorView *view,
-                               gboolean      auto_indent)
-{
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-
-  view->priv->auto_indent = !!auto_indent;
-  gb_editor_view_action_set_state (view, "auto-indent",
-                                   g_variant_new_boolean (auto_indent));
-  g_object_notify_by_pspec (G_OBJECT (view), gParamSpecs [PROP_AUTO_INDENT]);
-}
-
-gboolean
-gb_editor_view_get_highlight_current_line (GbEditorView *view)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), FALSE);
-
-  return view->priv->highlight_current_line;
-}
-
-void
-gb_editor_view_set_highlight_current_line (GbEditorView *view,
-                                           gboolean      highlight_current_line)
-{
-  GVariant *variant;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-
-  view->priv->highlight_current_line = !!highlight_current_line;
-  variant = g_variant_new_boolean (highlight_current_line);
-  gb_editor_view_action_set_state (view, "highlight-current-line", variant);
-  g_object_notify_by_pspec (G_OBJECT (view),
-                            gParamSpecs [PROP_HIGHLIGHT_CURRENT_LINE]);
-}
-
-gboolean
-gb_editor_view_get_show_right_margin (GbEditorView *view)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), FALSE);
-
-  return view->priv->show_right_margin;
-}
-
-void
-gb_editor_view_set_show_right_margin (GbEditorView *view,
-                                      gboolean      show_right_margin)
-{
-  GVariant *variant;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-
-  view->priv->show_right_margin = !!show_right_margin;
-  variant = g_variant_new_boolean (show_right_margin);
-  gb_editor_view_action_set_state (view, "show-right-margin", variant);
-  g_object_notify_by_pspec (G_OBJECT (view),
-                            gParamSpecs [PROP_SHOW_RIGHT_MARGIN]);
-}
-
-gboolean
-gb_editor_view_get_show_line_numbers (GbEditorView *view)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), FALSE);
-
-  return view->priv->show_line_numbers;
-}
-
-void
-gb_editor_view_set_show_line_numbers (GbEditorView *view,
-                                      gboolean      show_line_numbers)
-{
-  GVariant *variant;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-
-  view->priv->show_line_numbers = !!show_line_numbers;
-  variant = g_variant_new_boolean (show_line_numbers);
-  gb_editor_view_action_set_state (view, "show-line-numbers", variant);
-  g_object_notify_by_pspec (G_OBJECT (view),
-                            gParamSpecs [PROP_SHOW_LINE_NUMBERS]);
-}
-
-guint
-gb_editor_view_get_tab_width (GbEditorView *view)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), 0);
-
-  return view->priv->tab_width;
-}
-
-void
-gb_editor_view_set_tab_width (GbEditorView *view,
-                              guint         tab_width)
-{
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-  g_return_if_fail (tab_width >= 1);
-  g_return_if_fail (tab_width <= 32);
-
-  if (tab_width != view->priv->tab_width)
-    {
-      view->priv->tab_width = tab_width;
-      gb_editor_view_action_set_state (view, "tab-width",
-                                       g_variant_new_int32 (tab_width));
-      g_object_notify_by_pspec (G_OBJECT (view),
-                                gParamSpecs [PROP_TAB_WIDTH]);
-    }
-}
-
-gboolean
-gb_editor_view_get_use_spaces (GbEditorView *view)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), FALSE);
-
-  return view->priv->use_spaces;
-}
-
-void
-gb_editor_view_set_use_spaces (GbEditorView *view,
-                               gboolean      use_spaces)
-{
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-
-  view->priv->use_spaces = !!use_spaces;
-  gb_editor_view_action_set_state (view, "use-spaces",
-                                   g_variant_new_boolean (use_spaces));
-  g_object_notify_by_pspec (G_OBJECT (view), gParamSpecs [PROP_USE_SPACES]);
-}
-
-static void
-gb_editor_view_notify_language (GbEditorView     *view,
-                                GParamSpec       *pspec,
-                                GbEditorDocument *document)
-{
-  GtkSourceLanguage *language;
-  const gchar *lang_id = "";
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  g_object_notify (G_OBJECT (view), "can-preview");
-
-  language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (document));
-  if (language)
-    lang_id = gtk_source_language_get_id (language);
-
-  gb_editor_view_action_set_state (view, "language",
-                                   g_variant_new_string (lang_id));
-}
-
-static void
-gb_editor_view_notify_progress (GbEditorView     *view,
-                                GParamSpec       *pspec,
-                                GbEditorDocument *document)
-{
-  GbEditorViewPrivate *priv;
-  gdouble progress;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  priv = view->priv;
-
-  progress = gb_editor_document_get_progress (document);
-
-  if (!gtk_widget_get_visible (GTK_WIDGET (priv->progress_bar)))
-    {
-      gtk_progress_bar_set_fraction (priv->progress_bar, 0.0);
-      gtk_widget_set_opacity (GTK_WIDGET (priv->progress_bar), 1.0);
-      gtk_widget_show (GTK_WIDGET (priv->progress_bar));
-    }
-
-  if (priv->progress_anim)
-    gb_animation_stop (priv->progress_anim);
-
-  gb_clear_weak_pointer (&priv->progress_anim);
-
-  priv->progress_anim = gb_object_animate (priv->progress_bar,
-                                           GB_ANIMATION_LINEAR,
-                                           250,
-                                           NULL,
-                                           "fraction", progress,
-                                           NULL);
-  gb_set_weak_pointer (priv->progress_anim, &priv->progress_anim);
-
-  if (progress == 1.0)
-    gb_widget_fade_hide (GTK_WIDGET (priv->progress_bar));
-}
-
-static gboolean
-gb_editor_view_get_can_preview (GbDocumentView *view)
-{
-  GbEditorViewPrivate *priv;
-  GtkSourceLanguage *language;
-  GtkSourceBuffer *buffer;
-  const gchar *lang_id;
-
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), FALSE);
-
-  priv = GB_EDITOR_VIEW (view)->priv;
-
-  buffer = GTK_SOURCE_BUFFER (priv->document);
-  language = gtk_source_buffer_get_language (buffer);
-  if (!language)
-    return FALSE;
-
-  lang_id = gtk_source_language_get_id (language);
-  if (!lang_id)
-    return FALSE;
-
-  return (g_str_equal (lang_id, "html") ||
-          g_str_equal (lang_id, "markdown"));
-}
-
-/**
- * gb_editor_view_create_preview:
- * @view: A #GbEditorView.
- *
- * Creates a new document that can be previewed by calling
- * gb_document_create_view() on the document.
- *
- * Returns: (transfer full): A #GbDocument.
- */
 static GbDocument *
-gb_editor_view_create_preview (GbDocumentView *view)
+gb_editor_view_get_document (GbView *view)
 {
   GbEditorView *self = (GbEditorView *)view;
-  GbDocument *document;
-  GbHtmlDocumentTransform transform = NULL;
-  GtkSourceBuffer *buffer;
-  GtkSourceLanguage *language;
-
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (self), NULL);
 
-  buffer = GTK_SOURCE_BUFFER (self->priv->document);
-  language = gtk_source_buffer_get_language (buffer);
-
-  if (language)
-    {
-      const gchar *lang_id;
+  g_assert (GB_IS_EDITOR_VIEW (self));
 
-      lang_id = gtk_source_language_get_id (language);
-
-      if (g_strcmp0 (lang_id, "markdown") == 0)
-        transform = gb_html_markdown_transform;
-    }
-
-  document = g_object_new (GB_TYPE_HTML_DOCUMENT,
-                           "buffer", buffer,
-                           NULL);
-
-  if (transform)
-    gb_html_document_set_transform_func (GB_HTML_DOCUMENT (document),
-                                         transform);
-
-  return document;
-}
-
-GbEditorFrame *
-gb_editor_view_get_frame1 (GbEditorView *view)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), NULL);
-
-  return view->priv->frame;
-}
-
-GbEditorFrame *
-gb_editor_view_get_frame2 (GbEditorView *view)
-{
-  GtkWidget *child2;
-
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), NULL);
-
-  child2 = gtk_paned_get_child2 (view->priv->paned);
-  if (GB_IS_EDITOR_FRAME (child2))
-    return GB_EDITOR_FRAME (child2);
-
-  return NULL;
-}
-
-static void
-gb_editor_view_hide_revealer_child (GtkRevealer *revealer)
-{
-  g_return_if_fail (GTK_IS_REVEALER (revealer));
-
-  gtk_revealer_set_reveal_child (revealer, FALSE);
-}
-
-static void
-gb_editor_view_file_changed_on_volume (GbEditorView     *view,
-                                       GParamSpec       *pspec,
-                                       GbEditorDocument *document)
-{
-  GtkSourceFile *source_file;
-  GFile *location;
-  gchar *path;
-  gchar *str;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  source_file = gb_editor_document_get_file (document);
-  location = gtk_source_file_get_location (source_file);
-
-  if (!location)
-    return;
-
-  if (g_file_is_native (location))
-    path = g_file_get_path (location);
-  else
-    path = g_file_get_uri (location);
-
-  str = g_strdup_printf (_("The file “%s” was modified outside of Builder."),
-                         path);
-
-  gtk_label_set_label (view->priv->modified_label, str);
-  gtk_revealer_set_reveal_child (view->priv->modified_revealer, TRUE);
-
-  g_free (path);
-  g_free (str);
-}
-
-static void
-gb_editor_view_reload_document (GbEditorView *view,
-                                GtkButton    *button)
-{
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-
-  gb_editor_document_reload (view->priv->document);
-  gtk_revealer_set_reveal_child (view->priv->modified_revealer, FALSE);
-}
-
-static void
-gb_editor_view_notify_error (GbEditorView     *view,
-                             GParamSpec       *pspec,
-                             GbEditorDocument *document)
-{
-  const GError *error;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-  g_return_if_fail (pspec);
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  error = gb_editor_document_get_error (document);
-
-  /* Ignore file not found errors */
-  if (error &&
-      (error->domain == G_IO_ERROR) &&
-      (error->code == G_IO_ERROR_NOT_FOUND))
-    error = NULL;
-
-  if (!error)
-    {
-      if (gtk_revealer_get_reveal_child (view->priv->error_revealer))
-        gtk_revealer_set_reveal_child (view->priv->error_revealer, FALSE);
-    }
-  else
-    {
-      gtk_label_set_label (view->priv->error_label, error->message);
-      gtk_revealer_set_reveal_child (view->priv->error_revealer, TRUE);
-    }
+  return GB_DOCUMENT (self->document);
 }
 
 static gboolean
-transform_language_to_string (GBinding     *binding,
-                              const GValue *from_value,
-                              GValue       *to_value,
-                              gpointer      user_data)
+language_to_string (GBinding     *binding,
+                    const GValue *from_value,
+                    GValue       *to_value,
+                    gpointer      user_data)
 {
   GtkSourceLanguage *language;
-  const gchar *str = _("Plain Text");
 
   language = g_value_get_object (from_value);
-  if (language)
-    str = gtk_source_language_get_name (language);
-  g_value_set_string (to_value, str);
-
+  if (language != NULL)
+    g_value_set_string (to_value, gtk_source_language_get_name (language));
   return TRUE;
 }
 
 static void
-gb_editor_view_connect (GbEditorView     *view,
-                        GbEditorDocument *document)
-{
-  GtkWidget *child2;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  gb_editor_frame_set_document (view->priv->frame, document);
-
-  child2 = gtk_paned_get_child2 (view->priv->paned);
-  if (GB_IS_EDITOR_FRAME (child2))
-    gb_editor_frame_set_document (GB_EDITOR_FRAME (child2), document);
-
-  g_signal_connect_object (document,
-                           "notify::language",
-                           G_CALLBACK (gb_editor_view_notify_language),
-                           view,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (document,
-                           "notify::progress",
-                           G_CALLBACK (gb_editor_view_notify_progress),
-                           view,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (view->priv->modified_cancel_button,
-                           "clicked",
-                           G_CALLBACK (gb_editor_view_hide_revealer_child),
-                           view->priv->modified_revealer,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (view->priv->modified_reload_button,
-                           "clicked",
-                           G_CALLBACK (gb_editor_view_reload_document),
-                           view,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (document,
-                           "notify::error",
-                           G_CALLBACK (gb_editor_view_notify_error),
-                           view,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (view->priv->error_close_button,
-                           "clicked",
-                           G_CALLBACK (gb_editor_view_hide_revealer_child),
-                           view->priv->error_revealer,
-                           G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (document,
-                           "notify::file-changed-on-volume",
-                           G_CALLBACK (gb_editor_view_file_changed_on_volume),
-                           view,
-                           G_CONNECT_SWAPPED);
-
-  g_object_bind_property_full (document, "language",
-                               view->priv->tweak_button, "label",
-                               G_BINDING_SYNC_CREATE,
-                               transform_language_to_string,
-                               NULL, NULL, NULL);
-}
-
-static void
-gb_editor_view_disconnect (GbEditorView     *view,
-                           GbEditorDocument *document)
-{
-  GtkWidget *child2;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
-
-  gb_editor_frame_set_document (view->priv->frame, NULL);
-
-  child2 = gtk_paned_get_child2 (view->priv->paned);
-  if (GB_IS_EDITOR_FRAME (child2))
-    gb_editor_frame_set_document (GB_EDITOR_FRAME (child2), document);
-
-  g_signal_handlers_disconnect_by_func (document,
-                                        G_CALLBACK (gb_editor_view_notify_language),
-                                        view);
-  g_signal_handlers_disconnect_by_func (document,
-                                        G_CALLBACK (gb_editor_view_notify_progress),
-                                        view);
-}
-
-static GbDocument *
-gb_editor_view_get_document (GbDocumentView *view)
-{
-  GbEditorViewPrivate *priv;
-
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), NULL);
-
-  priv = GB_EDITOR_VIEW (view)->priv;
-
-  return GB_DOCUMENT (priv->document);
-}
-
-static void
-gb_editor_view_set_document (GbEditorView     *view,
+gb_editor_view_set_document (GbEditorView     *self,
                              GbEditorDocument *document)
 {
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
+  g_return_if_fail (GB_IS_EDITOR_VIEW (self));
   g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
 
-  if (document != view->priv->document)
-    {
-      if (view->priv->document)
-        {
-          gb_editor_view_disconnect (view, document);
-          g_clear_object (&view->priv->document);
-        }
-
-      if (document)
-        {
-          view->priv->document = g_object_ref (document);
-          gb_editor_view_connect (view, document);
-        }
-
-      g_object_notify_by_pspec (G_OBJECT (view), gParamSpecs [PROP_DOCUMENT]);
-    }
-}
-
-static void
-gb_editor_view_switch_pane (GSimpleAction *action,
-                            GVariant      *parameter,
-                            gpointer       user_data)
-{
-  GbEditorView *view = user_data;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-
-  if (!gtk_widget_has_focus (GTK_WIDGET (view->priv->frame->priv->source_view)))
-    gtk_widget_grab_focus (GTK_WIDGET (view->priv->frame));
-  else
+  if (g_set_object (&self->document, document))
     {
-      GtkWidget *child2;
+      if (self->frame1)
+        gb_editor_frame_set_document (self->frame1, document);
 
-      child2 = gtk_paned_get_child2 (view->priv->paned);
-      if (child2)
-        gtk_widget_grab_focus (child2);
-    }
+      if (self->frame2)
+        gb_editor_frame_set_document (self->frame2, document);
 
-  EXIT;
-}
+      g_settings_bind (self->settings, "style-scheme-name",
+                       document, "style-scheme-name",
+                       G_SETTINGS_BIND_GET);
+      g_settings_bind (self->settings, "highlight-matching-brackets",
+                       document, "highlight-matching-brackets",
+                       G_SETTINGS_BIND_GET);
 
-static gboolean
-gb_editor_view_on_execute_command (GbEditorView *self,
-                                   const gchar  *command_text,
-                                   GbSourceVim  *vim)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (self), FALSE);
-  g_return_val_if_fail (command_text, FALSE);
-  g_return_val_if_fail (GB_IS_SOURCE_VIM (vim), FALSE);
+      g_object_bind_property_full (document, "language", self->tweak_button,
+                                   "label", G_BINDING_SYNC_CREATE,
+                                   language_to_string, NULL, NULL, NULL);
 
-  if (g_str_equal (command_text, "w"))
-    {
-      gb_widget_activate_action (GTK_WIDGET (self), "stack", "save", NULL);
-      return TRUE;
-    }
-  else if (g_str_equal (command_text, "wq"))
-    {
-      gb_widget_activate_action (GTK_WIDGET (self), "stack", "save", NULL);
-      gb_widget_activate_action (GTK_WIDGET (self), "stack", "close", NULL);
-      return TRUE;
-    }
-  else if (g_str_equal (command_text, "q"))
-    {
-      if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (self->priv->document)))
-        {
-          /* TODO: Plumb warning message */
-        }
-      else
-        gb_widget_activate_action (GTK_WIDGET (self), "stack", "close", NULL);
-      return TRUE;
-    }
-  else if (g_str_equal (command_text, "q!"))
-    {
-      /* TODO: don't prompt about saving */
-      gb_widget_activate_action (GTK_WIDGET (self), "stack", "close", NULL);
-      return TRUE;
+      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_DOCUMENT]);
     }
-
-  return FALSE;
 }
 
-static gboolean
-gb_editor_view_on_vim_split (GbEditorView     *self,
-                             GbSourceVimSplit  split,
-                             GbSourceVim      *vim)
+static GbView *
+gb_editor_view_create_split (GbView *view)
 {
-  GtkWidget *toplevel;
-  GtkWidget *focus = NULL;
-  gboolean ret = FALSE;
-
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (self), FALSE);
-  g_return_val_if_fail (split, FALSE);
-  g_return_val_if_fail (GB_IS_SOURCE_VIM (vim), FALSE);
-
-  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
-
-  switch (split)
-    {
-    case GB_SOURCE_VIM_SPLIT_HORIZONTAL:
-      focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
-      if (!gb_editor_view_get_split_enabled (self))
-        {
-          gb_editor_view_toggle_split (self);
-          ret = TRUE;
-        }
-      break;
-
-    case GB_SOURCE_VIM_SPLIT_VERTICAL:
-      focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
-      gb_widget_activate_action (GTK_WIDGET (self),
-                                 "stack", "split-document-right",
-                                 NULL);
-      ret = TRUE;
-      break;
-
-    case GB_SOURCE_VIM_SPLIT_CYCLE_NEXT:
-      if (gb_editor_view_get_split_enabled (self) &&
-          gtk_widget_has_focus (GTK_WIDGET (self->priv->frame->priv->source_view)))
-        gb_editor_view_switch_pane (NULL, NULL, self);
-      else
-        gb_widget_activate_action (GTK_WIDGET (self), "stack", "focus-right",
-                                   NULL);
-      break;
-
-    case GB_SOURCE_VIM_SPLIT_CYCLE_PREVIOUS:
-      {
-        GbEditorFrame *frame2;
-
-        frame2 = gb_editor_view_get_frame2 (self);
-
-        if (frame2 &&
-            gtk_widget_has_focus (GTK_WIDGET (frame2->priv->source_view)))
-          gb_editor_view_switch_pane (NULL, NULL, self);
-        else
-          gb_widget_activate_action (GTK_WIDGET (self), "stack", "focus-left",
-                                     NULL);
-      }
-      break;
-
-    case GB_SOURCE_VIM_SPLIT_CLOSE:
-      if (gb_editor_view_get_split_enabled (self))
-        {
-          /*
-           * TODO: copy state from frame2 to frame1 if frame2 was focused.
-           */
-          gb_editor_view_toggle_split (self);
-          ret = TRUE;
-        }
-      else
-        {
-          gb_widget_activate_action (GTK_WIDGET (self), "stack", "close", NULL);
-          ret = TRUE;
-        }
-      break;
+  GbEditorView *self = (GbEditorView *)view;
+  GbView *ret;
 
-    default:
-      break;
-    }
+  g_assert (GB_IS_EDITOR_VIEW (self));
 
-  if (focus)
-    gtk_widget_grab_focus (focus);
+  ret = g_object_new (GB_TYPE_EDITOR_VIEW,
+                      "document", self->document,
+                      "visible", TRUE,
+                      NULL);
 
   return ret;
 }
 
-static GbEditorFrame *
-gb_editor_view_create_frame (GbEditorView *view)
-{
-  GbSourceVim *vim;
-  GtkWidget *frame;
-
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), NULL);
-
-  frame = g_object_new (GB_TYPE_EDITOR_FRAME,
-                         "document", view->priv->document,
-                         "visible", TRUE,
-                         NULL);
-  vim = gb_source_view_get_vim (GB_EDITOR_FRAME (frame)->priv->source_view);
-  g_signal_connect_object (vim,
-                           "execute-command",
-                           G_CALLBACK (gb_editor_view_on_execute_command),
-                           view,
-                           G_CONNECT_SWAPPED);
-  g_signal_connect_object (vim,
-                           "split",
-                           G_CALLBACK (gb_editor_view_on_vim_split),
-                           view,
-                           G_CONNECT_SWAPPED);
-
-  g_object_bind_property (GB_EDITOR_FRAME (frame), "search-direction",
-                          vim, "search-direction", G_BINDING_SYNC_CREATE);
-  g_object_bind_property (GB_EDITOR_FRAME (frame)->priv->search_settings,
-                          "search-text", vim, "search-text",
-                          G_BINDING_SYNC_CREATE);
-  g_object_bind_property (view, "auto-indent",
-                          GB_EDITOR_FRAME (frame)->priv->source_view,
-                          "auto-indent",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (view, "highlight-current-line",
-                          GB_EDITOR_FRAME (frame)->priv->source_view,
-                          "highlight-current-line",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (view, "show-line-numbers",
-                          GB_EDITOR_FRAME (frame)->priv->source_view,
-                          "show-line-numbers",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (view, "show-right-margin",
-                          GB_EDITOR_FRAME (frame)->priv->source_view,
-                          "show-right-margin",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (view, "tab-width",
-                          GB_EDITOR_FRAME (frame)->priv->source_view,
-                          "tab-width",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (view, "use-spaces",
-                          GB_EDITOR_FRAME (frame)->priv->source_view,
-                          "insert-spaces-instead-of-tabs",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-
-  return GB_EDITOR_FRAME (frame);
-}
-
-static void
-gb_editor_view_toggle_split (GbEditorView *view)
-{
-  GbEditorViewPrivate *priv;
-  GtkWidget *child2;
-  gboolean active;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-
-  priv = view->priv;
-
-  if ((child2 = gtk_paned_get_child2 (priv->paned)))
-    {
-      gtk_widget_destroy (child2);
-      gtk_widget_grab_focus (GTK_WIDGET (priv->frame));
-      active = FALSE;
-    }
-  else
-    {
-      GbEditorFrame *frame;
-
-      frame = gb_editor_view_create_frame (view);
-      gtk_container_add_with_properties (GTK_CONTAINER (view->priv->paned),
-                                         GTK_WIDGET (frame),
-                                         "shrink", TRUE,
-                                         "resize", TRUE,
-                                         NULL);
-      gtk_widget_grab_focus (GTK_WIDGET (frame));
-      active = TRUE;
-    }
-
-  gb_editor_view_action_set_state (view, "toggle-split",
-                                   g_variant_new_boolean (active));
-
-  EXIT;
-}
-
-gboolean
-gb_editor_view_get_split_enabled (GbEditorView *view)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_VIEW (view), FALSE);
-
-  return !!gb_editor_view_get_frame2 (view);
-}
-
-void
-gb_editor_view_set_split_enabled (GbEditorView *view,
-                                  gboolean      split_enabled)
-{
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
-
-  if (split_enabled == gb_editor_view_get_split_enabled (view))
-    return;
-
-  gb_editor_view_toggle_split (view);
-  g_object_notify_by_pspec (G_OBJECT (view),
-                            gParamSpecs [PROP_SPLIT_ENABLED]);
-}
-
 static void
 gb_editor_view_grab_focus (GtkWidget *widget)
 {
-  GbEditorView *view = (GbEditorView *)widget;
-
-  ENTRY;
+  GbEditorView *self = (GbEditorView *)widget;
 
-  g_return_if_fail (GB_IS_EDITOR_VIEW (view));
+  g_assert (GB_IS_EDITOR_VIEW (self));
 
-  gtk_widget_grab_focus (GTK_WIDGET (view->priv->frame));
+  /* todo: track last focus frame */
 
-  EXIT;
+  gtk_widget_grab_focus (GTK_WIDGET (self->frame1->source_view));
 }
 
-#define STATE_HANDLER_BOOLEAN(name) \
-  static void \
-  apply_state_##name (GSimpleAction *action, \
-                      GVariant      *param, \
-                      gpointer       user_data) \
-  { \
-    GbEditorView *view = user_data; \
-    gboolean value; \
-    g_return_if_fail (GB_IS_EDITOR_VIEW (view)); \
-    value = g_variant_get_boolean (param); \
-    gb_editor_view_set_##name (view, value); \
-  }
-
-#define STATE_HANDLER_INT(name) \
-  static void \
-  apply_state_##name (GSimpleAction *action, \
-                      GVariant      *param, \
-                      gpointer       user_data) \
-  { \
-    GbEditorView *view = user_data; \
-    guint value; \
-    g_return_if_fail (GB_IS_EDITOR_VIEW (view)); \
-    value = g_variant_get_int32 (param); \
-    gb_editor_view_set_##name (view, value); \
-  }
-
-STATE_HANDLER_BOOLEAN (auto_indent)
-STATE_HANDLER_BOOLEAN (highlight_current_line)
-STATE_HANDLER_BOOLEAN (show_line_numbers)
-STATE_HANDLER_BOOLEAN (show_right_margin)
-STATE_HANDLER_BOOLEAN (split_enabled)
-STATE_HANDLER_INT     (tab_width)
-STATE_HANDLER_BOOLEAN (use_spaces)
-
 static void
 gb_editor_view_finalize (GObject *object)
 {
-  GbEditorView *view = (GbEditorView *)object;
+  GbEditorView *self = (GbEditorView *)object;
 
-  g_clear_object (&view->priv->document);
+  g_clear_object (&self->document);
+  g_clear_object (&self->settings);
 
   G_OBJECT_CLASS (gb_editor_view_parent_class)->finalize (object);
 }
@@ -975,37 +137,8 @@ gb_editor_view_get_property (GObject    *object,
 
   switch (prop_id)
     {
-    case PROP_AUTO_INDENT:
-      g_value_set_boolean (value, gb_editor_view_get_auto_indent (self));
-      break;
-
     case PROP_DOCUMENT:
-      g_value_set_object (value, self->priv->document);
-      break;
-
-    case PROP_HIGHLIGHT_CURRENT_LINE:
-      g_value_set_boolean (value,
-                           gb_editor_view_get_highlight_current_line (self));
-      break;
-
-    case PROP_SHOW_LINE_NUMBERS:
-      g_value_set_boolean (value, gb_editor_view_get_show_line_numbers (self));
-      break;
-
-    case PROP_SHOW_RIGHT_MARGIN:
-      g_value_set_boolean (value, gb_editor_view_get_show_right_margin (self));
-      break;
-
-    case PROP_SPLIT_ENABLED:
-      g_value_set_boolean (value, gb_editor_view_get_split_enabled (self));
-      break;
-
-    case PROP_TAB_WIDTH:
-      g_value_set_uint (value, gb_editor_view_get_tab_width (self));
-      break;
-
-    case PROP_USE_SPACES:
-      g_value_set_boolean (value, gb_editor_view_get_use_spaces (self));
+      g_value_set_object (value, gb_editor_view_get_document (GB_VIEW (self)));
       break;
 
     default:
@@ -1023,38 +156,10 @@ gb_editor_view_set_property (GObject      *object,
 
   switch (prop_id)
     {
-    case PROP_AUTO_INDENT:
-      gb_editor_view_set_auto_indent (self, g_value_get_boolean (value));
-      break;
-
     case PROP_DOCUMENT:
       gb_editor_view_set_document (self, g_value_get_object (value));
       break;
 
-    case PROP_HIGHLIGHT_CURRENT_LINE:
-      gb_editor_view_set_highlight_current_line (self, g_value_get_boolean (value));
-      break;
-
-    case PROP_SHOW_LINE_NUMBERS:
-      gb_editor_view_set_show_line_numbers (self, g_value_get_boolean (value));
-      break;
-
-    case PROP_SHOW_RIGHT_MARGIN:
-      gb_editor_view_set_show_right_margin (self, g_value_get_boolean (value));
-      break;
-
-    case PROP_SPLIT_ENABLED:
-      gb_editor_view_set_split_enabled (self, g_value_get_boolean (value));
-      break;
-
-    case PROP_TAB_WIDTH:
-      gb_editor_view_set_tab_width (self, g_value_get_uint (value));
-      break;
-
-    case PROP_USE_SPACES:
-      gb_editor_view_set_use_spaces (self, g_value_get_boolean (value));
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -1065,7 +170,7 @@ gb_editor_view_class_init (GbEditorViewClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-  GbDocumentViewClass *view_class = GB_DOCUMENT_VIEW_CLASS (klass);
+  GbViewClass *view_class = GB_VIEW_CLASS (klass);
 
   object_class->finalize = gb_editor_view_finalize;
   object_class->get_property = gb_editor_view_get_property;
@@ -1073,97 +178,24 @@ gb_editor_view_class_init (GbEditorViewClass *klass)
 
   widget_class->grab_focus = gb_editor_view_grab_focus;
 
+  view_class->create_split = gb_editor_view_create_split;
   view_class->get_document = gb_editor_view_get_document;
-  view_class->get_can_preview = gb_editor_view_get_can_preview;
-  view_class->create_preview = gb_editor_view_create_preview;
-
-  gParamSpecs [PROP_AUTO_INDENT] =
-    g_param_spec_boolean ("auto-indent",
-                         _("Auto Indent"),
-                         _("If we should use the auto-indentation engine."),
-                         FALSE,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_AUTO_INDENT,
-                                   gParamSpecs [PROP_AUTO_INDENT]);
 
   gParamSpecs [PROP_DOCUMENT] =
     g_param_spec_object ("document",
                          _("Document"),
-                         _("The document edited by the view."),
-                         GB_TYPE_DOCUMENT,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_DOCUMENT,
-                                   gParamSpecs [PROP_DOCUMENT]);
-
-  gParamSpecs [PROP_HIGHLIGHT_CURRENT_LINE] =
-    g_param_spec_boolean ("highlight-current-line",
-                          _("Highlight Current Line"),
-                          _("If the current line should be highlighted."),
-                          FALSE,
-                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_HIGHLIGHT_CURRENT_LINE,
-                                   gParamSpecs [PROP_HIGHLIGHT_CURRENT_LINE]);
-
-  gParamSpecs [PROP_SHOW_LINE_NUMBERS] =
-    g_param_spec_boolean ("show-line-numbers",
-                         _("Show Line Numbers"),
-                         _("If the line numbers should be shown."),
-                         FALSE,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_SHOW_LINE_NUMBERS,
-                                   gParamSpecs [PROP_SHOW_LINE_NUMBERS]);
-
-  gParamSpecs [PROP_SHOW_RIGHT_MARGIN] =
-    g_param_spec_boolean ("show-right-margin",
-                         _("Show Right Margin"),
-                         _("If we should show the right margin."),
-                         FALSE,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_SHOW_RIGHT_MARGIN,
-                                   gParamSpecs [PROP_SHOW_RIGHT_MARGIN]);
-
-  gParamSpecs [PROP_SPLIT_ENABLED] =
-    g_param_spec_boolean ("split-enabled",
-                         _("Split Enabled"),
-                         _("If the view split is enabled."),
-                         FALSE,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_SPLIT_ENABLED,
-                                   gParamSpecs [PROP_SPLIT_ENABLED]);
-
-  gParamSpecs [PROP_TAB_WIDTH] =
-    g_param_spec_uint ("tab-width",
-                         _("Tab Width"),
-                         _("The width a tab should be drawn as."),
-                         1,
-                         32,
-                         8,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_TAB_WIDTH,
-                                   gParamSpecs [PROP_TAB_WIDTH]);
-
-  gParamSpecs [PROP_USE_SPACES] =
-    g_param_spec_boolean ("use-spaces",
-                         _("Use Spaces"),
-                         _("If spaces should be used instead of tabs."),
-                         FALSE,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_USE_SPACES,
-                                   gParamSpecs [PROP_USE_SPACES]);
+                         _("The editor document."),
+                         GB_TYPE_EDITOR_DOCUMENT,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_DOCUMENT, gParamSpecs [PROP_DOCUMENT]);
 
   GB_WIDGET_CLASS_TEMPLATE (klass, "gb-editor-view.ui");
+
+  GB_WIDGET_CLASS_BIND (klass, GbEditorView, frame1);
   GB_WIDGET_CLASS_BIND (klass, GbEditorView, paned);
   GB_WIDGET_CLASS_BIND (klass, GbEditorView, progress_bar);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorView, split_button);
   GB_WIDGET_CLASS_BIND (klass, GbEditorView, tweak_button);
   GB_WIDGET_CLASS_BIND (klass, GbEditorView, tweak_widget);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorView, modified_revealer);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorView, modified_label);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorView, modified_cancel_button);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorView, modified_reload_button);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorView, error_label);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorView, error_revealer);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorView, error_close_button);
 
   g_type_ensure (GB_TYPE_EDITOR_FRAME);
   g_type_ensure (GB_TYPE_EDITOR_TWEAK_WIDGET);
@@ -1172,47 +204,9 @@ gb_editor_view_class_init (GbEditorViewClass *klass)
 static void
 gb_editor_view_init (GbEditorView *self)
 {
-  const GActionEntry entries[] = {
-    { "auto-indent", NULL, NULL, "false", apply_state_auto_indent },
-    { "highlight-current-line", NULL, NULL, "false",
-      apply_state_highlight_current_line },
-    { "language", NULL, "s", "''", apply_state_language },
-    { "show-line-numbers", NULL, NULL, "false", apply_state_show_line_numbers },
-    { "show-right-margin", NULL, NULL, "false", apply_state_show_right_margin },
-    { "switch-pane",  gb_editor_view_switch_pane },
-    { "tab-width", NULL, "i", "8", apply_state_tab_width },
-    { "toggle-split", NULL, NULL, "false", apply_state_split_enabled },
-    { "use-spaces", NULL, "b", "false", apply_state_use_spaces },
-  };
-  GSimpleActionGroup *actions;
-  GtkWidget *controls;
-
-  self->priv = gb_editor_view_get_instance_private (self);
-
   gtk_widget_init_template (GTK_WIDGET (self));
 
-  actions = g_simple_action_group_new ();
-
-  /*
-   * Unfortunately, we need to manually attach the action group in
-   * a few places due to the complexity of how they are handled.
-   */
-  g_action_map_add_action_entries (G_ACTION_MAP (actions), entries,
-                                   G_N_ELEMENTS (entries), self);
-  gtk_widget_insert_action_group (GTK_WIDGET (self), "editor-view",
-                                  G_ACTION_GROUP (actions));
-  controls = gb_document_view_get_controls (GB_DOCUMENT_VIEW (self));
-  gtk_widget_insert_action_group (GTK_WIDGET (controls), "editor-view",
-                                  G_ACTION_GROUP (actions));
-  gtk_widget_insert_action_group (GTK_WIDGET (self->priv->tweak_widget),
-                                  "editor-view", G_ACTION_GROUP (actions));
-
-  g_clear_object (&actions);
+  self->settings = g_settings_new ("org.gnome.builder.editor");
 
-  self->priv->frame = gb_editor_view_create_frame (self);
-  gtk_container_add_with_properties (GTK_CONTAINER (self->priv->paned),
-                                     GTK_WIDGET (self->priv->frame),
-                                     "shrink", TRUE,
-                                     "resize", TRUE,
-                                     NULL);
+  gb_editor_view_actions_init (self);
 }
diff --git a/src/editor/gb-editor-view.h b/src/editor/gb-editor-view.h
index 6d4b90f..e189414 100644
--- a/src/editor/gb-editor-view.h
+++ b/src/editor/gb-editor-view.h
@@ -1,6 +1,6 @@
 /* gb-editor-view.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,52 +19,13 @@
 #ifndef GB_EDITOR_VIEW_H
 #define GB_EDITOR_VIEW_H
 
-#include <gtk/gtk.h>
-
-#include "gb-document-view.h"
-#include "gb-editor-document.h"
-#include "gb-editor-frame.h"
+#include "gb-view.h"
 
 G_BEGIN_DECLS
 
-#define GB_TYPE_EDITOR_VIEW            (gb_editor_view_get_type())
-#define GB_EDITOR_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_EDITOR_VIEW, 
GbEditorView))
-#define GB_EDITOR_VIEW_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_EDITOR_VIEW, GbEditorView 
const))
-#define GB_EDITOR_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_EDITOR_VIEW, 
GbEditorViewClass))
-#define GB_IS_EDITOR_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_EDITOR_VIEW))
-#define GB_IS_EDITOR_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_EDITOR_VIEW))
-#define GB_EDITOR_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_EDITOR_VIEW, 
GbEditorViewClass))
-
-typedef struct _GbEditorView        GbEditorView;
-typedef struct _GbEditorViewClass   GbEditorViewClass;
-typedef struct _GbEditorViewPrivate GbEditorViewPrivate;
-
-struct _GbEditorView
-{
-  GbDocumentView parent;
-
-  /*< private >*/
-  GbEditorViewPrivate *priv;
-};
-
-struct _GbEditorViewClass
-{
-  GbDocumentViewClass parent;
-};
+#define GB_TYPE_EDITOR_VIEW (gb_editor_view_get_type())
 
-GType          gb_editor_view_get_type          (void);
-GtkWidget     *gb_editor_view_new               (GbEditorDocument *document);
-GbEditorFrame *gb_editor_view_get_frame1        (GbEditorView     *view);
-GbEditorFrame *gb_editor_view_get_frame2        (GbEditorView     *view);
-gboolean       gb_editor_view_get_split_enabled (GbEditorView     *view);
-void           gb_editor_view_set_split_enabled (GbEditorView     *view,
-                                                 gboolean          split_enabled);
-gboolean       gb_editor_view_get_use_spaces    (GbEditorView     *view);
-void           gb_editor_view_set_use_spaces    (GbEditorView     *view,
-                                                 gboolean          use_spaces);
-gboolean       gb_editor_view_get_auto_indent   (GbEditorView     *view);
-void           gb_editor_view_set_auto_indent   (GbEditorView     *view,
-                                                 gboolean          auto_indent);
+G_DECLARE_FINAL_TYPE (GbEditorView, gb_editor_view, GB, EDITOR_VIEW, GbView)
 
 G_END_DECLS
 
diff --git a/src/auto-indent/c-parse-helper.h b/src/editor/gb-editor-workspace-actions.c
similarity index 55%
copy from src/auto-indent/c-parse-helper.h
copy to src/editor/gb-editor-workspace-actions.c
index 418f518..82f688b 100644
--- a/src/auto-indent/c-parse-helper.h
+++ b/src/editor/gb-editor-workspace-actions.c
@@ -1,6 +1,6 @@
-/* c-parse-helper.h
+/* gb-editor-workspace-actions.c
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2014-2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,26 +16,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef C_PARSE_HELPER_H
-#define C_PARSE_HELPER_H
+#include "gb-editor-workspace-actions.h"
 
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-typedef struct
+void
+gb_editor_workspace_actions_init (GbEditorWorkspace *self)
 {
-  gchar *type;
-  gchar *name;
-  guint  ellipsis : 1;
-  guint  n_star   : 4;
-} Parameter;
-
-gboolean   parameter_validate (Parameter       *param);
-void       parameter_free     (Parameter       *p);
-Parameter *parameter_copy     (const Parameter *src);
-GSList    *parse_parameters   (const gchar     *text);
-
-G_END_DECLS
-
-#endif /* C_PARSE_HELPER_H */
+}
diff --git a/src/auto-indent/c-parse-helper.h b/src/editor/gb-editor-workspace-actions.h
similarity index 57%
copy from src/auto-indent/c-parse-helper.h
copy to src/editor/gb-editor-workspace-actions.h
index 418f518..c8bde9e 100644
--- a/src/auto-indent/c-parse-helper.h
+++ b/src/editor/gb-editor-workspace-actions.h
@@ -1,6 +1,6 @@
-/* c-parse-helper.h
+/* gb-editor-workspace-actions.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2014-2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,26 +16,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef C_PARSE_HELPER_H
-#define C_PARSE_HELPER_H
+#ifndef GB_EDITOR_WORKSPACE_ACTIONS_H
+#define GB_EDITOR_WORKSPACE_ACTIONS_H
 
-#include <glib.h>
+#include "gb-editor-workspace.h"
 
 G_BEGIN_DECLS
 
-typedef struct
-{
-  gchar *type;
-  gchar *name;
-  guint  ellipsis : 1;
-  guint  n_star   : 4;
-} Parameter;
-
-gboolean   parameter_validate (Parameter       *param);
-void       parameter_free     (Parameter       *p);
-Parameter *parameter_copy     (const Parameter *src);
-GSList    *parse_parameters   (const gchar     *text);
+void gb_editor_workspace_actions_init (GbEditorWorkspace *self);
 
 G_END_DECLS
 
-#endif /* C_PARSE_HELPER_H */
+#endif /* GB_EDITOR_WORKSPACE_ACTIONS_H */
diff --git a/src/auto-indent/c-parse-helper.h b/src/editor/gb-editor-workspace-private.h
similarity index 57%
copy from src/auto-indent/c-parse-helper.h
copy to src/editor/gb-editor-workspace-private.h
index 418f518..093c5ff 100644
--- a/src/auto-indent/c-parse-helper.h
+++ b/src/editor/gb-editor-workspace-private.h
@@ -1,6 +1,6 @@
-/* c-parse-helper.h
+/* gb-editor-workspace-private.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2014-2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,26 +16,21 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef C_PARSE_HELPER_H
-#define C_PARSE_HELPER_H
+#ifndef GB_EDITOR_WORKSPACE_PRIVATE_H
+#define GB_EDITOR_WORKSPACE_PRIVATE_H
 
-#include <glib.h>
+#include "gb-workspace.h"
+#include "gb-view-grid.h"
 
 G_BEGIN_DECLS
 
-typedef struct
+struct _GbEditorWorkspace
 {
-  gchar *type;
-  gchar *name;
-  guint  ellipsis : 1;
-  guint  n_star   : 4;
-} Parameter;
+  GbWorkspace  parent_instance;
 
-gboolean   parameter_validate (Parameter       *param);
-void       parameter_free     (Parameter       *p);
-Parameter *parameter_copy     (const Parameter *src);
-GSList    *parse_parameters   (const gchar     *text);
+  GbViewGrid  *view_grid;
+};
 
 G_END_DECLS
 
-#endif /* C_PARSE_HELPER_H */
+#endif /* GB_EDITOR_WORKSPACE_PRIVATE_H */
diff --git a/src/editor/gb-editor-workspace.c b/src/editor/gb-editor-workspace.c
index fdaba25..0c82659 100644
--- a/src/editor/gb-editor-workspace.c
+++ b/src/editor/gb-editor-workspace.c
@@ -1,6 +1,6 @@
 /* gb-editor-workspace.c
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2014-2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,424 +16,101 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define G_LOG_DOMAIN "editor-workspace"
+#define G_LOG_DOMAIN "gb-editor-workspace"
 
 #include <glib/gi18n.h>
-#include <gtksourceview/gtksource.h>
+#include <ide.h>
 
-#include "gb-devhelp-document.h"
-#include "gb-devhelp-view.h"
-#include "gb-document-grid.h"
 #include "gb-editor-document.h"
 #include "gb-editor-workspace.h"
-#include "gb-log.h"
-#include "gb-project-tree-builder.h"
-#include "gb-tree.h"
+#include "gb-editor-workspace-actions.h"
+#include "gb-editor-workspace-private.h"
+#include "gb-view-grid.h"
 #include "gb-widget.h"
-#include "gb-workbench.h"
-#include "gb-dnd.h"
 
-enum
-{
-  TARGET_URI_LIST = 100
-};
-
-static const GtkTargetEntry drop_types [] = {
-  { "text/uri-list", 0, TARGET_URI_LIST}
-};
-
-struct _GbEditorWorkspacePrivate
-{
-  GHashTable         *command_map;
-  GtkPaned           *paned;
-  gchar              *current_folder_uri;
-
-  /* References not owned by this instance */
-  GbDocumentGrid       *document_grid;
-  GbProjectTreeBuilder *project_tree_builder;
-  GtkBox               *sidebar;
-  GbTree               *tree;
-  GtkSizeGroup         *title_size_group;
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (GbEditorWorkspace, gb_editor_workspace,
-                            GB_TYPE_WORKSPACE)
-
-void
-gb_editor_workspace_open (GbEditorWorkspace *workspace,
-                          GFile             *file)
-{
-  GbEditorWorkspacePrivate *priv;
-  GbDocumentManager *manager;
-  GbWorkbench *workbench;
-  GbDocument *document;
-
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
-
-  priv = workspace->priv;
-
-  workbench = gb_widget_get_workbench (GTK_WIDGET (workspace));
-  manager = gb_workbench_get_document_manager (workbench);
-  document = gb_document_manager_find_with_file (manager, file);
-
-  if (!document)
-    {
-      gboolean close_untitled = FALSE;
-      GList *list;
-
-      /*
-       * If we have a single document open, and it is an untitled document,
-       * we want to close it so that it appears that this new document opens
-       * in its place.
-       */
-      list = gb_document_manager_get_documents (manager);
-      if ((g_list_length (list) == 1) &&
-          gb_document_is_untitled (list->data) &&
-          !gb_document_get_modified (list->data))
-        close_untitled = TRUE;
-      g_list_free (list);
-
-      /*
-       * Now open the new document.
-       */
-      document = GB_DOCUMENT (gb_editor_document_new ());
-      gb_editor_document_load_async (GB_EDITOR_DOCUMENT (document),
-                                     file, NULL, NULL, NULL);
-      gb_document_manager_add (manager, document);
-      gb_document_grid_focus_document (priv->document_grid, document);
-      g_object_unref (document);
-
-      /*
-       * Now close the existing views if necessary.
-       */
-      if (close_untitled)
-        gb_document_grid_close_untitled (priv->document_grid);
-    }
-  else
-    gb_document_grid_focus_document (priv->document_grid, document);
-}
-
-static void
-gb_editor_workspace_open_uri_list (GbEditorWorkspace  *workspace,
-                                   const gchar       **uri_list)
-{
-  GFile *file;
-  guint i;
-
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
-  g_return_if_fail (uri_list);
-
-  for (i = 0; uri_list [i]; i++)
-    {
-      file = g_file_new_for_commandline_arg (uri_list [i]);
-
-      if (file)
-        {
-          gb_editor_workspace_open (workspace, file);
-          g_clear_object (&file);
-        }
-      else
-        g_warning ("Received invalid URI target");
-    }
-}
+G_DEFINE_TYPE (GbEditorWorkspace, gb_editor_workspace, GB_TYPE_WORKSPACE)
 
 static void
-gb_editor_workspace_drag_data_received (GtkWidget        *widget,
-                                        GdkDragContext   *context,
-                                        gint              x,
-                                        gint              y,
-                                        GtkSelectionData *selection_data,
-                                        guint             info,
-                                        guint             timestamp,
-                                        gpointer          data)
+gb_editor_workspace__load_buffer_cb (GbEditorWorkspace *self,
+                                     IdeBuffer         *buffer,
+                                     IdeBufferManager  *buffer_manager)
 {
-  GbEditorWorkspace *workspace = (GbEditorWorkspace *)widget;
-  gchar **uri_list;
-  gboolean handled = FALSE;
+  IDE_ENTRY;
 
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
+  g_assert (GB_IS_EDITOR_WORKSPACE (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+  g_assert (GB_IS_EDITOR_DOCUMENT (buffer));
+  g_assert (IDE_IS_BUFFER_MANAGER (buffer_manager));
 
-  switch (info)
-    {
-    case TARGET_URI_LIST:
-      uri_list = gb_dnd_get_uri_list (selection_data);
-
-      if (uri_list)
-        {
-          gb_editor_workspace_open_uri_list (workspace,
-                                             (const gchar **)uri_list);
-                               g_strfreev (uri_list);
-        }
+  IDE_TRACE_MSG ("Loading %s.", ide_buffer_get_title (buffer));
 
-      handled = TRUE;
-      break;
+  gb_view_grid_focus_document (self->view_grid, GB_DOCUMENT (buffer));
 
-    default:
-      break;
-    }
-
-  gtk_drag_finish (context, handled, FALSE, timestamp);
+  IDE_EXIT;
 }
 
 static void
-gb_editor_workspace_action_jump_to_doc (GSimpleAction *action,
-                                        GVariant      *parameter,
-                                        gpointer       user_data)
+gb_editor_workspace_context_changed (GtkWidget  *workspace,
+                                     IdeContext *context)
 {
-  GbEditorWorkspacePrivate *priv;
-  GbEditorWorkspace *workspace = user_data;
-  GbDocumentManager *manager;
-  GbWorkbench *workbench;
-  const gchar *search_text;
-  GbDocument *document;
-  GbDocument *reffed = NULL;
-
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
-
-  priv = workspace->priv;
+  GbEditorWorkspace *self = (GbEditorWorkspace *)workspace;
 
-  search_text = g_variant_get_string (parameter, NULL);
-  if (!search_text || !*search_text)
-    return;
+  g_assert (GB_IS_EDITOR_WORKSPACE (self));
+  g_assert (!context || IDE_IS_CONTEXT (context));
 
-  workbench = gb_widget_get_workbench (GTK_WIDGET (workspace));
-  manager = gb_workbench_get_document_manager (workbench);
-  document = gb_document_manager_find_with_type (manager,
-                                                 GB_TYPE_DEVHELP_DOCUMENT);
-
-  if (!document)
+  if (context)
     {
-      document = GB_DOCUMENT (gb_devhelp_document_new ());
-      gb_document_manager_add (manager, document);
-      reffed = document;
-    }
+      IdeBufferManager *bufmgr;
+      g_autoptr(GPtrArray) buffers = NULL;
+      gsize i;
 
-  gb_devhelp_document_set_search (GB_DEVHELP_DOCUMENT (document), search_text);
-  gb_document_grid_focus_document (priv->document_grid, document);
-
-  g_clear_object (&reffed);
-}
-
-static void
-gb_editor_workspace_action_open_uri_list (GSimpleAction *action,
-                                          GVariant      *parameter,
-                                          gpointer       user_data)
-{
-  GbEditorWorkspace *workspace = user_data;
-  const gchar **uri_list;
+      bufmgr = ide_context_get_buffer_manager (context);
+      g_signal_connect_object (bufmgr,
+                               "load-buffer",
+                               G_CALLBACK (gb_editor_workspace__load_buffer_cb),
+                               self,
+                               G_CONNECT_SWAPPED);
 
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
+      buffers = ide_buffer_manager_get_buffers (bufmgr);
 
-  uri_list = g_variant_get_strv (parameter, NULL);
-  if(uri_list != NULL)
-    {
-      gb_editor_workspace_open_uri_list (workspace, uri_list);
-      g_free (uri_list);
-    }
-}
-
-void
-gb_editor_workspace_new_document (GbEditorWorkspace *workspace)
-{
-  GbDocumentManager *manager;
-  GbWorkbench *workbench;
-  GbDocument *document;
-
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
-
-  workbench = gb_widget_get_workbench (GTK_WIDGET (workspace));
-  manager = gb_workbench_get_document_manager (workbench);
-  document = GB_DOCUMENT (gb_editor_document_new ());
-
-  gb_document_manager_add (manager, document);
-  gb_document_grid_focus_document (workspace->priv->document_grid, document);
-
-  g_clear_object (&document);
-}
-
-static void
-gb_editor_workspace_action_new_document (GSimpleAction *action,
-                                         GVariant      *parameter,
-                                         gpointer       user_data)
-{
-  GbEditorWorkspace *workspace = user_data;
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
-  gb_editor_workspace_new_document (workspace);
-}
-
-static void
-gb_editor_workspace_action_toggle_sidebar (GSimpleAction *action,
-                                           GVariant      *parameter,
-                                           gpointer       user_data)
-{
-  GbEditorWorkspace *workspace = user_data;
-  GtkWidget *sidebar;
-
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
-
-  sidebar = GTK_WIDGET (workspace->priv->sidebar);
-  gtk_widget_set_visible (sidebar, !gtk_widget_get_visible (sidebar));
-}
-
-static void
-gb_editor_workspace_action_open (GSimpleAction *action,
-                                 GVariant      *parameter,
-                                 gpointer       user_data)
-{
-  GbEditorWorkspace *workspace = user_data;
-  GbEditorWorkspacePrivate *priv = workspace->priv;
-  GtkFileChooserDialog *dialog;
-  GtkWidget *toplevel;
-  GtkWidget *suggested;
-  GtkResponseType response;
-
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
-
-  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (workspace));
-
-  dialog = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
-                         "action", GTK_FILE_CHOOSER_ACTION_OPEN,
-                         "local-only", FALSE,
-                         "select-multiple", TRUE,
-                         "show-hidden", FALSE,
-                         "transient-for", toplevel,
-                         "title", _("Open Document"),
-                         NULL);
-
-  if (priv->current_folder_uri)
-    gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog),
-                                             priv->current_folder_uri);
-
-  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
-                          _("Cancel"), GTK_RESPONSE_CANCEL,
-                          _("Open"), GTK_RESPONSE_OK,
-                          NULL);
-
-  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
-
-  suggested = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog),
-                                                  GTK_RESPONSE_OK);
-  gtk_style_context_add_class (gtk_widget_get_style_context (suggested),
-                               GTK_STYLE_CLASS_SUGGESTED_ACTION);
-
-  response = gtk_dialog_run (GTK_DIALOG (dialog));
-
-  if (response == GTK_RESPONSE_OK)
-    {
-      GSList *files;
-      GSList *iter;
-      gchar *file_uri;
-      gchar *uri;
-
-      file_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
-      uri = g_path_get_dirname (file_uri);
-      if (g_strcmp0 (priv->current_folder_uri, uri) != 0)
-        {
-          g_free (priv->current_folder_uri);
-          priv->current_folder_uri = uri;
-          uri = NULL;
-        }
-      g_free (uri);
-      g_free (file_uri);
-
-      files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (dialog));
-
-      for (iter = files; iter; iter = iter->next)
+      for (i = 0; i < buffers->len; i++)
         {
-          gb_editor_workspace_open (workspace, G_FILE (iter->data));
-          g_clear_object (&iter->data);
+          IdeBuffer *buffer = g_ptr_array_index (buffers, i);
+          gb_editor_workspace__load_buffer_cb (self, buffer, bufmgr);
         }
-
-      g_slist_free (files);
     }
-
-  gtk_widget_destroy (GTK_WIDGET (dialog));
 }
 
 static void
 gb_editor_workspace_grab_focus (GtkWidget *widget)
 {
-  GbEditorWorkspace *workspace = (GbEditorWorkspace *)widget;
+  GbEditorWorkspace *self = (GbEditorWorkspace *)widget;
 
-  ENTRY;
+  g_assert (GB_IS_EDITOR_WORKSPACE (self));
 
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
-
-  gtk_widget_grab_focus (GTK_WIDGET (workspace->priv->document_grid));
-
-  EXIT;
-}
-
-static void
-gb_editor_workspace_context_set (GbEditorWorkspace *workspace,
-                                 GParamSpec        *pspec,
-                                 GbWorkbench       *workbench)
-{
-  GbEditorWorkspacePrivate *priv;
-  GbTreeNode *root;
-  IdeContext *context;
-
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-
-  priv = workspace->priv;
-
-  context = gb_workbench_get_context (workbench);
-
-  root = gb_tree_get_root (priv->tree);
-  gb_tree_node_set_item (root, G_OBJECT (context));
-
-  gb_project_tree_builder_set_context (priv->project_tree_builder, context);
-}
-
-static void
-gb_editor_workspace_map (GtkWidget *widget)
-{
-  GbEditorWorkspacePrivate *priv;
-  GbEditorWorkspace *workspace = (GbEditorWorkspace *)widget;
-  GbDocumentManager *document_manager;
-  GbWorkbench *workbench;
-
-  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
-
-  priv = workspace->priv;
-
-  GTK_WIDGET_CLASS (gb_editor_workspace_parent_class)->map (widget);
-
-  workbench = gb_widget_get_workbench (GTK_WIDGET (workspace));
-  document_manager = gb_workbench_get_document_manager (workbench);
-  gb_document_grid_set_document_manager (priv->document_grid, document_manager);
-
-  g_signal_connect_object (workbench,
-                           "notify::context",
-                           G_CALLBACK (gb_editor_workspace_context_set),
-                           widget,
-                           G_CONNECT_SWAPPED);
-
-  gb_editor_workspace_context_set (workspace, NULL, workbench);
+  gtk_widget_grab_focus (GTK_WIDGET (self->view_grid));
 }
 
 static void
 gb_editor_workspace_constructed (GObject *object)
 {
-  GbEditorWorkspacePrivate *priv = GB_EDITOR_WORKSPACE (object)->priv;
+  GbEditorWorkspace *self = (GbEditorWorkspace *)object;
+
+  IDE_ENTRY;
 
   G_OBJECT_CLASS (gb_editor_workspace_parent_class)->constructed (object);
 
-  priv->project_tree_builder = gb_project_tree_builder_new (NULL);
-  gb_tree_add_builder (priv->tree, GB_TREE_BUILDER (priv->project_tree_builder));
-  gb_tree_set_root (priv->tree, gb_tree_node_new ());
+  gb_editor_workspace_actions_init (self);
+
+  IDE_EXIT;
 }
 
 static void
 gb_editor_workspace_finalize (GObject *object)
 {
-  GbEditorWorkspacePrivate *priv = GB_EDITOR_WORKSPACE (object)->priv;
-
-  g_clear_pointer (&priv->command_map, g_hash_table_unref);
-  g_clear_pointer (&priv->current_folder_uri, g_free);
-
+  IDE_ENTRY;
   G_OBJECT_CLASS (gb_editor_workspace_parent_class)->finalize (object);
+  IDE_EXIT;
 }
 
 static void
@@ -446,58 +123,17 @@ gb_editor_workspace_class_init (GbEditorWorkspaceClass *klass)
   object_class->finalize = gb_editor_workspace_finalize;
 
   widget_class->grab_focus = gb_editor_workspace_grab_focus;
-  widget_class->map = gb_editor_workspace_map;
 
   GB_WIDGET_CLASS_TEMPLATE (klass, "gb-editor-workspace.ui");
-  GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, document_grid);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, paned);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, sidebar);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, title_size_group);
-  GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, tree);
+  GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, view_grid);
 
-  g_type_ensure (GB_TYPE_DOCUMENT_GRID);
-  g_type_ensure (GB_TYPE_TREE);
+  g_type_ensure (GB_TYPE_VIEW_GRID);
 }
 
 static void
-gb_editor_workspace_init (GbEditorWorkspace *workspace)
+gb_editor_workspace_init (GbEditorWorkspace *self)
 {
-  const GActionEntry entries[] = {
-    { "toggle-sidebar", gb_editor_workspace_action_toggle_sidebar },
-    { "open",           gb_editor_workspace_action_open },
-    { "new-document",   gb_editor_workspace_action_new_document },
-    { "jump-to-doc",    gb_editor_workspace_action_jump_to_doc,   "s" },
-    { "open-uri-list",  gb_editor_workspace_action_open_uri_list, "as" }
-  };
-  GSimpleActionGroup *actions;
-
-  workspace->priv = gb_editor_workspace_get_instance_private (workspace);
-
-  workspace->priv->command_map = g_hash_table_new (g_str_hash, g_str_equal);
-  workspace->priv->current_folder_uri = NULL;
-
-  gtk_widget_init_template (GTK_WIDGET (workspace));
-
-  actions = g_simple_action_group_new ();
-  g_action_map_add_action_entries (G_ACTION_MAP (actions),
-                                   entries, G_N_ELEMENTS (entries),
-                                   workspace);
-  gtk_widget_insert_action_group (GTK_WIDGET (workspace), "workspace",
-                                  G_ACTION_GROUP (actions));
-  g_clear_object (&actions);
-
-  /* Drag and drop support*/
-  gtk_drag_dest_set (GTK_WIDGET (workspace),
-                     GTK_DEST_DEFAULT_MOTION |
-                     GTK_DEST_DEFAULT_HIGHLIGHT |
-                     GTK_DEST_DEFAULT_DROP,
-                     drop_types,
-                     G_N_ELEMENTS (drop_types),
-                     GDK_ACTION_COPY);
-
-  g_signal_connect (workspace,
-                    "drag-data-received",
-                    G_CALLBACK(gb_editor_workspace_drag_data_received),
-                    NULL);
+  gtk_widget_init_template (GTK_WIDGET (self));
 
+  gb_widget_set_context_handler (self, gb_editor_workspace_context_changed);
 }
diff --git a/src/editor/gb-editor-workspace.h b/src/editor/gb-editor-workspace.h
index eaff983..5783cdf 100644
--- a/src/editor/gb-editor-workspace.h
+++ b/src/editor/gb-editor-workspace.h
@@ -1,6 +1,6 @@
 /* gb-editor-workspace.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2014-2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,35 +23,9 @@
 
 G_BEGIN_DECLS
 
-#define GB_TYPE_EDITOR_WORKSPACE            (gb_editor_workspace_get_type())
-#define GB_EDITOR_WORKSPACE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_EDITOR_WORKSPACE, 
GbEditorWorkspace))
-#define GB_EDITOR_WORKSPACE_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_EDITOR_WORKSPACE, 
GbEditorWorkspace const))
-#define GB_EDITOR_WORKSPACE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_EDITOR_WORKSPACE, 
GbEditorWorkspaceClass))
-#define GB_IS_EDITOR_WORKSPACE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_EDITOR_WORKSPACE))
-#define GB_IS_EDITOR_WORKSPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_EDITOR_WORKSPACE))
-#define GB_EDITOR_WORKSPACE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_EDITOR_WORKSPACE, 
GbEditorWorkspaceClass))
+#define GB_TYPE_EDITOR_WORKSPACE (gb_editor_workspace_get_type())
 
-typedef struct _GbEditorWorkspace        GbEditorWorkspace;
-typedef struct _GbEditorWorkspaceClass   GbEditorWorkspaceClass;
-typedef struct _GbEditorWorkspacePrivate GbEditorWorkspacePrivate;
-
-struct _GbEditorWorkspace
-{
-  GbWorkspace parent;
-
-  /*< private >*/
-  GbEditorWorkspacePrivate *priv;
-};
-
-struct _GbEditorWorkspaceClass
-{
-  GbWorkspaceClass parent_class;
-};
-
-GType gb_editor_workspace_get_type     (void);
-void  gb_editor_workspace_new_document (GbEditorWorkspace *workspace);
-void  gb_editor_workspace_open         (GbEditorWorkspace *workspace,
-                                        GFile             *file);
+G_DECLARE_FINAL_TYPE (GbEditorWorkspace, gb_editor_workspace, GB, EDITOR_WORKSPACE, GbWorkspace)
 
 G_END_DECLS
 
diff --git a/src/editor/gb-source-formatter.c b/src/editor/gb-source-formatter.c
index 8e97933..9dab8b5 100644
--- a/src/editor/gb-source-formatter.c
+++ b/src/editor/gb-source-formatter.c
@@ -20,8 +20,8 @@
 #define UNCRUSTIFY_CONFIG_DIRECTORY "/org/gnome/builder/editor/uncrustify/"
 
 #include <glib/gi18n.h>
+#include <ide.h>
 
-#include "gb-log.h"
 #include "gb-source-formatter.h"
 
 struct _GbSourceFormatterPrivate
@@ -194,7 +194,7 @@ gb_source_formatter_extract_configs (void)
   gchar *target_dir;
   guint i;
 
-  ENTRY;
+  IDE_ENTRY;
 
   target_dir = g_build_filename (g_get_user_config_dir (),
                                  "gnome-builder", "uncrustify",
@@ -213,7 +213,7 @@ gb_source_formatter_extract_configs (void)
     {
       g_warning ("%s", error->message);
       g_clear_error (&error);
-      GOTO (cleanup);
+      IDE_GOTO (cleanup);
     }
 
   for (i = 0; names [i]; i++)
@@ -255,7 +255,7 @@ cleanup:
   g_strfreev (names);
   g_free (target_dir);
 
-  EXIT;
+  IDE_EXIT;
 }
 
 static void
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index 4039565..2d7f0aa 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -3,134 +3,58 @@ noinst_LTLIBRARIES += libgnome-builder.la
 
 libgnome_builder_la_SOURCES = \
        $(gnome_builder_built_sources) \
-       src/animation/gb-animation.c \
-       src/animation/gb-animation.h \
-       src/animation/gb-frame-source.c \
-       src/animation/gb-frame-source.h \
+       cut-n-paste/trie.c \
+       cut-n-paste/trie.h \
        src/app/gb-application.c \
        src/app/gb-application.h \
-       src/auto-indent/c-parse-helper.c \
-       src/auto-indent/c-parse-helper.h \
-       src/auto-indent/gb-source-auto-indenter-c.c \
-       src/auto-indent/gb-source-auto-indenter-c.h \
-       src/auto-indent/gb-source-auto-indenter-python.c \
-       src/auto-indent/gb-source-auto-indenter-python.h \
-       src/auto-indent/gb-source-auto-indenter-xml.c \
-       src/auto-indent/gb-source-auto-indenter-xml.h \
-       src/auto-indent/gb-source-auto-indenter.c \
-       src/auto-indent/gb-source-auto-indenter.h \
-       src/code-assistant/gb-source-code-assistant-renderer.c \
-       src/code-assistant/gb-source-code-assistant-renderer.h \
-       src/code-assistant/gb-source-code-assistant.c \
-       src/code-assistant/gb-source-code-assistant.h \
-       src/commands/gb-command-bar-item.c \
-       src/commands/gb-command-bar-item.h \
+       src/app/gb-application-actions.c \
+       src/app/gb-application-actions.h \
+       src/app/gb-application-private.h \
        src/commands/gb-command-bar.c \
        src/commands/gb-command-bar.h \
-       src/commands/gb-command-gaction-provider.c \
-       src/commands/gb-command-gaction-provider.h \
-       src/commands/gb-command-gaction.c \
-       src/commands/gb-command-gaction.h \
+       src/commands/gb-command-bar-item.c \
+       src/commands/gb-command-bar-item.h \
        src/commands/gb-command-manager.c \
        src/commands/gb-command-manager.h \
        src/commands/gb-command-provider.c \
        src/commands/gb-command-provider.h \
        src/commands/gb-command-result.c \
        src/commands/gb-command-result.h \
-       src/commands/gb-command-vim-provider.c \
-       src/commands/gb-command-vim-provider.h \
-       src/commands/gb-command-vim.c \
-       src/commands/gb-command-vim.h \
        src/commands/gb-command.c \
        src/commands/gb-command.h \
-       src/credits/gb-credits-widget.c \
-       src/credits/gb-credits-widget.h \
-       src/devhelp/gb-devhelp-document.c \
-       src/devhelp/gb-devhelp-document.h \
-       src/devhelp/gb-devhelp-view.c \
-       src/devhelp/gb-devhelp-view.h \
-       src/dialogs/gb-close-confirmation-dialog.c \
-       src/dialogs/gb-close-confirmation-dialog.h \
-       src/documents/gb-document-grid.c \
-       src/documents/gb-document-grid.h \
-       src/documents/gb-document-manager.c \
-       src/documents/gb-document-manager.h \
-       src/documents/gb-document-menu-button.c \
-       src/documents/gb-document-menu-button.h \
-       src/documents/gb-document-private.h \
-       src/documents/gb-document-split.c \
-       src/documents/gb-document-split.h \
-       src/documents/gb-document-stack.c \
-       src/documents/gb-document-stack.h \
-       src/documents/gb-document-view.c \
-       src/documents/gb-document-view.h \
        src/documents/gb-document.c \
        src/documents/gb-document.h \
        src/editor/gb-editor-document.c \
        src/editor/gb-editor-document.h \
-       src/editor/gb-editor-file-mark.c \
-       src/editor/gb-editor-file-mark.h \
-       src/editor/gb-editor-file-marks.c \
-       src/editor/gb-editor-file-marks.h \
-       src/editor/gb-editor-frame-private.h \
        src/editor/gb-editor-frame.c \
        src/editor/gb-editor-frame.h \
-       src/editor/gb-editor-navigation-item.c \
-       src/editor/gb-editor-navigation-item.h \
+       src/editor/gb-editor-frame-actions.c \
+       src/editor/gb-editor-frame-actions.h \
+       src/editor/gb-editor-frame-private.h \
        src/editor/gb-editor-settings-widget.c \
        src/editor/gb-editor-settings-widget.h \
        src/editor/gb-editor-tweak-widget.c \
        src/editor/gb-editor-tweak-widget.h \
        src/editor/gb-editor-view.c \
        src/editor/gb-editor-view.h \
+       src/editor/gb-editor-view-actions.c \
+       src/editor/gb-editor-view-actions.h \
+       src/editor/gb-editor-view-private.h \
+       src/editor/gb-editor-workspace-actions.c \
+       src/editor/gb-editor-workspace-actions.h \
+       src/editor/gb-editor-workspace-private.h \
        src/editor/gb-editor-workspace.c \
        src/editor/gb-editor-workspace.h \
-       src/editor/gb-source-change-gutter-renderer.c \
-       src/editor/gb-source-change-gutter-renderer.h \
-       src/editor/gb-source-change-monitor.c \
-       src/editor/gb-source-change-monitor.h \
-       src/editor/gb-source-formatter.c \
-       src/editor/gb-source-formatter.h \
-       src/editor/gb-source-highlight-menu.c \
-       src/editor/gb-source-highlight-menu.h \
-       src/editor/gb-source-search-highlighter.c \
-       src/editor/gb-source-search-highlighter.h \
-       src/editor/gb-source-view.c \
-       src/editor/gb-source-view.h \
-       src/emacs/gb-source-emacs.c \
-       src/emacs/gb-source-emacs.h \
-       src/fuzzy/fuzzy.c \
-       src/fuzzy/fuzzy.h \
-       src/gca/gca-diagnostics.c \
-       src/gca/gca-diagnostics.h \
-       src/gca/gca-service.c \
-       src/gca/gca-service.h \
-       src/gca/gca-structs.c \
-       src/gca/gca-structs.h \
        src/gd/gd-tagged-entry.c \
        src/gd/gd-tagged-entry.h \
        src/gedit/gedit-close-button.c \
        src/gedit/gedit-close-button.h \
        src/gedit/gedit-menu-stack-switcher.c \
        src/gedit/gedit-menu-stack-switcher.h \
-       src/git/gb-git-search-provider.c \
-       src/git/gb-git-search-provider.h \
-       src/html/gb-html-completion-provider.c \
-       src/html/gb-html-completion-provider.h \
-       src/html/gb-html-document.c \
-       src/html/gb-html-document.h \
-       src/html/gb-html-view.c \
-       src/html/gb-html-view.h \
        src/keybindings/gb-keybindings.c \
        src/keybindings/gb-keybindings.h \
-       src/log/gb-log.c \
-       src/log/gb-log.h \
        src/nautilus/nautilus-floating-bar.c \
        src/nautilus/nautilus-floating-bar.h \
-       src/navigation/gb-navigation-item.c \
-       src/navigation/gb-navigation-item.h \
-       src/navigation/gb-navigation-list.c \
-       src/navigation/gb-navigation-list.h \
        src/preferences/gb-preferences-page-editor.c \
        src/preferences/gb-preferences-page-editor.h \
        src/preferences/gb-preferences-page-emacs.c \
@@ -149,56 +73,25 @@ libgnome_builder_la_SOURCES = \
        src/scrolledwindow/gb-scrolled-window.h \
        src/search/gb-search-box.c \
        src/search/gb-search-box.h \
-       src/search/gb-search-context.c \
-       src/search/gb-search-context.h \
-       src/search/gb-search-display.c \
-       src/search/gb-search-display.h \
        src/search/gb-search-display-group.c \
        src/search/gb-search-display-group.h \
        src/search/gb-search-display-row.c \
        src/search/gb-search-display-row.h \
-       src/search/gb-search-manager.c \
-       src/search/gb-search-manager.h \
-       src/search/gb-search-provider.c \
-       src/search/gb-search-provider.h \
-       src/search/gb-search-reducer.c \
-       src/search/gb-search-reducer.h \
-       src/search/gb-search-result.c \
-       src/search/gb-search-result.h \
+       src/search/gb-search-display.c \
+       src/search/gb-search-display.h \
        src/search/gb-search-types.h \
-       src/snippets/gb-source-snippet-chunk.c \
-       src/snippets/gb-source-snippet-chunk.h \
-       src/snippets/gb-source-snippet-completion-item.c \
-       src/snippets/gb-source-snippet-completion-item.h \
-       src/snippets/gb-source-snippet-completion-provider.c \
-       src/snippets/gb-source-snippet-completion-provider.h \
-       src/snippets/gb-source-snippet-context.c \
-       src/snippets/gb-source-snippet-context.h \
-       src/snippets/gb-source-snippet-parser.c \
-       src/snippets/gb-source-snippet-parser.h \
-       src/snippets/gb-source-snippet-private.h \
-       src/snippets/gb-source-snippet.c \
-       src/snippets/gb-source-snippet.h \
-       src/snippets/gb-source-snippets-manager.c \
-       src/snippets/gb-source-snippets-manager.h \
-       src/snippets/gb-source-snippets.c \
-       src/snippets/gb-source-snippets.h \
        src/support/gb-support.c \
        src/support/gb-support.h \
-       src/theatrics/gb-box-theatric.c \
-       src/theatrics/gb-box-theatric.h \
        src/tree/gb-tree-builder.c \
        src/tree/gb-tree-builder.h \
        src/tree/gb-tree-node.c \
        src/tree/gb-tree-node.h \
-       src/tree/gb-project-tree-builder.c \
-       src/tree/gb-project-tree-builder.h \
        src/tree/gb-tree.c \
        src/tree/gb-tree.h \
-       src/trie/trie.c \
-       src/trie/trie.h \
        src/util/gb-cairo.c \
        src/util/gb-cairo.h \
+       src/util/gb-dnd.c \
+       src/util/gb-dnd.h \
        src/util/gb-doc-seq.c \
        src/util/gb-doc-seq.h \
        src/util/gb-glib.h \
@@ -212,15 +105,63 @@ libgnome_builder_la_SOURCES = \
        src/util/gb-string.h \
        src/util/gb-widget.c \
        src/util/gb-widget.h \
-       src/util/gb-dnd.c \
-       src/util/gb-dnd.h \
-       src/vim/gb-source-vim.c \
-       src/vim/gb-source-vim.h \
+       src/views/gb-view-grid.c \
+       src/views/gb-view-grid.h \
+       src/views/gb-view-stack-actions.c \
+       src/views/gb-view-stack-actions.h \
+       src/views/gb-view-stack-private.h \
+       src/views/gb-view-stack.c \
+       src/views/gb-view-stack.h \
+       src/views/gb-view.c \
+       src/views/gb-view.h \
+       src/workbench/gb-workbench-actions.c \
+       src/workbench/gb-workbench-actions.h \
+       src/workbench/gb-workbench-private.h \
        src/workbench/gb-workbench-types.h \
        src/workbench/gb-workbench.c \
        src/workbench/gb-workbench.h \
        src/workbench/gb-workspace.c \
-       src/workbench/gb-workspace.h
+       src/workbench/gb-workspace.h \
+       $(NULL)
+
+disabled_files = \
+       src/commands/gb-command-gaction-provider.c \
+       src/commands/gb-command-gaction-provider.h \
+       src/commands/gb-command-gaction.c \
+       src/commands/gb-command-gaction.h \
+       src/commands/gb-command-vim-provider.c \
+       src/commands/gb-command-vim-provider.h \
+       src/commands/gb-command-vim.c \
+       src/commands/gb-command-vim.h \
+       src/devhelp/gb-devhelp-document.c \
+       src/devhelp/gb-devhelp-document.h \
+       src/devhelp/gb-devhelp-view.c \
+       src/devhelp/gb-devhelp-view.h \
+       src/documents/gb-document-grid.c \
+       src/documents/gb-document-grid.h \
+       src/documents/gb-document-private.h \
+       src/documents/gb-document-split.c \
+       src/documents/gb-document-split.h \
+       src/documents/gb-document-stack.c \
+       src/documents/gb-document-stack.h \
+       src/editor/gb-editor-frame-private.h \
+       src/editor/gb-editor-tweak-widget.c \
+       src/editor/gb-editor-tweak-widget.h \
+       src/editor/gb-editor-workspace.c \
+       src/editor/gb-editor-workspace.h \
+       src/editor/gb-source-formatter.c \
+       src/editor/gb-source-formatter.h \
+       src/editor/gb-source-highlight-menu.c \
+       src/editor/gb-source-highlight-menu.h \
+       src/html/gb-html-completion-provider.c \
+       src/html/gb-html-completion-provider.h \
+       src/html/gb-html-document.c \
+       src/html/gb-html-document.h \
+       src/html/gb-html-view.c \
+       src/html/gb-html-view.h \
+       src/tree/gb-project-tree-builder.c \
+       src/tree/gb-project-tree-builder.h \
+       $(NULL)
 
 libgnome_builder_la_LIBADD = \
        $(BUILDER_LIBS) \
@@ -234,39 +175,26 @@ libgnome_builder_la_CFLAGS = \
        $(MAINTAINER_CFLAGS) \
        -I$(top_builddir)/src/resources \
        -I$(top_builddir)/src/util \
+       -I$(top_srcdir)/cut-n-paste \
        -I$(top_srcdir)/libide \
-       -I$(top_srcdir)/src/animation \
        -I$(top_srcdir)/src/app \
-       -I$(top_srcdir)/src/auto-indent \
        -I$(top_srcdir)/src/commands \
-       -I$(top_srcdir)/src/code-assistant \
-       -I$(top_srcdir)/src/credits \
        -I$(top_srcdir)/src/devhelp \
-       -I$(top_srcdir)/src/dialogs \
        -I$(top_srcdir)/src/documents \
        -I$(top_srcdir)/src/editor \
-       -I$(top_srcdir)/src/emacs  \
-       -I$(top_srcdir)/src/fuzzy \
-       -I$(top_srcdir)/src/gca \
        -I$(top_srcdir)/src/gd \
        -I$(top_srcdir)/src/gedit \
-       -I$(top_srcdir)/src/git \
        -I$(top_srcdir)/src/html \
        -I$(top_srcdir)/src/keybindings \
-       -I$(top_srcdir)/src/log \
        -I$(top_srcdir)/src/nautilus \
-       -I$(top_srcdir)/src/navigation \
        -I$(top_srcdir)/src/preferences \
        -I$(top_srcdir)/src/resources \
        -I$(top_srcdir)/src/scrolledwindow \
        -I$(top_srcdir)/src/search \
-       -I$(top_srcdir)/src/snippets \
        -I$(top_srcdir)/src/support \
        -I$(top_srcdir)/src/tree \
-       -I$(top_srcdir)/src/trie \
-       -I$(top_srcdir)/src/theatrics \
        -I$(top_srcdir)/src/util \
-       -I$(top_srcdir)/src/vim \
+       -I$(top_srcdir)/src/views \
        -I$(top_srcdir)/src/workbench
 
 if ENABLE_TRACING
diff --git a/src/html/gb-html-view.c b/src/html/gb-html-view.c
index 967f18a..7983b93 100644
--- a/src/html/gb-html-view.c
+++ b/src/html/gb-html-view.c
@@ -20,11 +20,11 @@
 
 #include <glib/gi18n.h>
 #include <gtksourceview/gtksourcefile.h>
+#include <ide.h>
 #include <webkit2/webkit2.h>
 
 #include "gb-editor-document.h"
 #include "gb-html-view.h"
-#include "gb-log.h"
 
 struct _GbHtmlViewPrivate
 {
@@ -61,7 +61,7 @@ gb_html_view_changed (GbHtmlView    *view,
   gchar *content;
   gchar *base_uri = NULL;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_return_if_fail (GB_IS_HTML_VIEW (view));
   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
@@ -91,7 +91,7 @@ gb_html_view_changed (GbHtmlView    *view,
   g_free (content);
   g_free (base_uri);
 
-  EXIT;
+  IDE_EXIT;
 }
 
 static void
diff --git a/src/keybindings/gb-keybindings.c b/src/keybindings/gb-keybindings.c
index e202506..e2af70f 100644
--- a/src/keybindings/gb-keybindings.c
+++ b/src/keybindings/gb-keybindings.c
@@ -1,6 +1,6 @@
 /* gb-keybindings.c
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,183 +16,231 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define G_LOG_DOMAIN "keybindings"
+#define G_LOG_DOMAIN "gb-keybindings"
 
 #include <glib/gi18n.h>
+#include <ide.h>
 
-#include "gb-log.h"
 #include "gb-keybindings.h"
 
-struct _GbKeybindingsPrivate
+struct _GbKeybindings
 {
-  GHashTable *keybindings;
+  GObject         parent_instance;
+
+  GtkApplication *application;
+  GtkCssProvider *css_provider;
+  gchar          *mode;
+  guint           constructed : 1;
+};
+
+enum
+{
+  PROP_0,
+  PROP_APPLICATION,
+  PROP_MODE,
+  LAST_PROP
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GbKeybindings, gb_keybindings, G_TYPE_OBJECT)
+G_DEFINE_TYPE (GbKeybindings, gb_keybindings, G_TYPE_OBJECT)
+
+static GParamSpec *gParamSpecs [LAST_PROP];
 
 GbKeybindings *
-gb_keybindings_new (void)
+gb_keybindings_new (GtkApplication *application,
+                    const gchar    *mode)
 {
-  return g_object_new (GB_TYPE_KEYBINDINGS, NULL);
+  g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
+
+  return g_object_new (GB_TYPE_KEYBINDINGS,
+                       "application", application,
+                       "mode", mode,
+                       NULL);
 }
 
 static void
-gb_keybindings_load (GbKeybindings *keybindings,
-                     GKeyFile      *key_file)
+gb_keybindings_reload (GbKeybindings *self)
 {
-  GbKeybindingsPrivate *priv;
-  gchar **keys;
-  gchar **groups;
-  gchar *value;
-  guint i;
-  guint j;
+  const gchar *mode;
+  g_autofree gchar *path = NULL;
+  g_autoptr(GBytes) bytes = NULL;
+  g_autoptr(GError) error = NULL;
 
-  g_assert (GB_IS_KEYBINDINGS (keybindings));
-  g_assert (key_file);
+  IDE_ENTRY;
 
-  priv = keybindings->priv;
+  g_assert (GB_IS_KEYBINDINGS (self));
 
-  groups = g_key_file_get_groups (key_file, NULL);
+  mode = self->mode ? self->mode : "default";
+  IDE_TRACE_MSG ("Loading %s keybindings", mode);
+  path = g_strdup_printf ("/org/gnome/builder/keybindings/%s.css", mode);
+  bytes = g_resources_lookup_data (path, G_RESOURCE_LOOKUP_FLAGS_NONE, &error);
 
-  for (i = 0; groups[i]; i++)
-    {
-      keys = g_key_file_get_keys (key_file, groups[i], NULL, NULL);
-      if (!keys)
-        continue;
+  if (error == NULL)
+    gtk_css_provider_load_from_data (self->css_provider,
+                                     g_bytes_get_data (bytes, NULL),
+                                     g_bytes_get_size (bytes),
+                                     &error);
 
-      for (j = 0; keys[j]; j++)
-        {
-          value = g_key_file_get_string (key_file, groups[i], keys[j], NULL);
-          if (!value || !*value)
-            continue;
+  if (error)
+    g_warning ("%s", error->message);
 
-          g_hash_table_replace (priv->keybindings,
-                                g_strdup_printf ("%s.%s", groups[i], keys[j]),
-                                value);
-        }
+  IDE_EXIT;
+}
 
-      g_strfreev (keys);
-    }
+const gchar *
+gb_keybindings_get_mode (GbKeybindings *self)
+{
+  g_return_val_if_fail (GB_IS_KEYBINDINGS (self), NULL);
 
-  g_strfreev (groups);
+  return self->mode;
 }
 
-gboolean
-gb_keybindings_load_bytes (GbKeybindings *keybindings,
-                           GBytes        *bytes,
-                           GError       **error)
+void
+gb_keybindings_set_mode (GbKeybindings *self,
+                         const gchar   *mode)
 {
-  gconstpointer data;
-  GKeyFile *key_file;
-  gsize len = 0;
-  gboolean ret = FALSE;
-
-  ENTRY;
+  g_return_if_fail (GB_IS_KEYBINDINGS (self));
 
-  g_return_val_if_fail (GB_IS_KEYBINDINGS (keybindings), FALSE);
-  g_return_val_if_fail (bytes, FALSE);
+  if (mode != self->mode)
+    {
+      g_free (self->mode);
+      self->mode = g_strdup (mode);
+      if (self->constructed)
+        gb_keybindings_reload (self);
+      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_MODE]);
+    }
+}
 
-  key_file = g_key_file_new ();
-  data = g_bytes_get_data (bytes, &len);
-  if (!g_key_file_load_from_data (key_file, data, len,
-                                  G_KEY_FILE_NONE, error))
-    GOTO (cleanup);
+GtkApplication *
+gb_keybindings_get_application (GbKeybindings *self)
+{
+  g_return_val_if_fail (GB_IS_KEYBINDINGS (self), NULL);
 
-  gb_keybindings_load (keybindings, key_file);
+  return self->application;
+}
 
-  ret = TRUE;
+static void
+gb_keybindings_set_application (GbKeybindings  *self,
+                                GtkApplication *application)
+{
+  g_assert (GB_IS_KEYBINDINGS (self));
+  g_assert (!application || GTK_IS_APPLICATION (application));
 
-cleanup:
-  g_key_file_free (key_file);
+  if (application != self->application)
+    {
+      if (self->application)
+        {
+          /* remove keybindings */
+          g_clear_object (&self->application);
+        }
 
-  RETURN (ret);
+      if (application)
+        {
+          /* connect keybindings */
+          self->application = g_object_ref (application);
+        }
+    }
 }
 
-gboolean
-gb_keybindings_load_path (GbKeybindings *keybindings,
-                          const gchar   *path,
-                          GError       **error)
+static void
+gb_keybindings_parsing_error (GtkCssProvider *css_provider,
+                              GtkCssSection  *section,
+                              GError         *error,
+                              gpointer        user_data)
 {
-  GKeyFile *key_file;
-  gboolean ret = FALSE;
+  g_autofree gchar *filename = NULL;
+  GFile *file;
+  guint start_line;
+  guint end_line;
+
+  file = gtk_css_section_get_file (section);
+  filename = g_file_get_uri (file);
+  start_line = gtk_css_section_get_start_line (section);
+  end_line = gtk_css_section_get_end_line (section);
+
+  g_warning ("CSS parsing error in %s between lines %u and %u", filename, start_line, end_line);
+}
 
-  ENTRY;
+static void
+gb_keybindings_constructed (GObject *object)
+{
+  GbKeybindings *self = (GbKeybindings *)object;
+  GdkScreen *screen;
 
-  g_return_val_if_fail (GB_IS_KEYBINDINGS (keybindings), FALSE);
-  g_return_val_if_fail (path, FALSE);
+  IDE_ENTRY;
 
-  key_file = g_key_file_new ();
+  G_OBJECT_CLASS (gb_keybindings_parent_class)->constructed (object);
 
-  if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, error))
-    GOTO (cleanup);
+  screen = gdk_screen_get_default ();
+  gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (self->css_provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 
-  gb_keybindings_load (keybindings, key_file);
+  self->constructed = TRUE;
 
-cleanup:
-  g_key_file_free (key_file);
+  gb_keybindings_reload (self);
 
-  RETURN (ret);
+  IDE_EXIT;
 }
 
-void
-gb_keybindings_register (GbKeybindings  *keybindings,
-                         GtkApplication *application)
+static void
+gb_keybindings_finalize (GObject *object)
 {
-  GbKeybindingsPrivate *priv;
-  GHashTableIter iter;
-  const gchar *action_name;
-  const gchar *accelerator;
-  gchar *accel_list[2] = { NULL };
+  GbKeybindings *self = (GbKeybindings *)object;
 
-  g_return_if_fail (GB_IS_KEYBINDINGS (keybindings));
-  g_return_if_fail (GTK_IS_APPLICATION (application));
+  IDE_ENTRY;
 
-  priv = keybindings->priv;
+  g_clear_object (&self->application);
+  g_clear_object (&self->css_provider);
+  g_clear_pointer (&self->mode, g_free);
 
-  g_hash_table_iter_init (&iter, priv->keybindings);
+  G_OBJECT_CLASS (gb_keybindings_parent_class)->finalize (object);
 
-  while (g_hash_table_iter_next (&iter,
-                                 (gpointer *) &action_name,
-                                 (gpointer *) &accelerator))
-    {
-      accel_list[0] = (gchar *) accelerator;
-      gtk_application_set_accels_for_action (application,
-                                             action_name,
-                                             (const gchar* const*)accel_list);
-    }
+  IDE_EXIT;
 }
 
-void
-gb_keybindings_unregister (GbKeybindings  *keybindings,
-                           GtkApplication *application)
+static void
+gb_keybindings_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
 {
-  GHashTableIter iter;
-  const gchar *action_name;
-  const gchar *accelerator;
-  gchar *accels[] = { NULL };
+  GbKeybindings *self = GB_KEYBINDINGS (object);
 
-  g_return_if_fail (GB_IS_KEYBINDINGS (keybindings));
-  g_return_if_fail (GTK_IS_APPLICATION (application));
+  switch (prop_id)
+    {
+    case PROP_APPLICATION:
+      g_value_set_object (value, gb_keybindings_get_application (self));
+      break;
 
-  g_hash_table_iter_init (&iter, keybindings->priv->keybindings);
+    case PROP_MODE:
+      g_value_set_string (value, gb_keybindings_get_mode (self));
+      break;
 
-  while (g_hash_table_iter_next (&iter,
-                                 (gpointer *)&action_name,
-                                 (gpointer *)&accelerator))
-    gtk_application_set_accels_for_action (application, action_name,
-                                           (const gchar * const *)accels);
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
 }
 
 static void
-gb_keybindings_finalize (GObject *object)
+gb_keybindings_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
 {
-  GbKeybindingsPrivate *priv;
+  GbKeybindings *self = GB_KEYBINDINGS (object);
 
-  priv = GB_KEYBINDINGS (object)->priv;
+  switch (prop_id)
+    {
+    case PROP_APPLICATION:
+      gb_keybindings_set_application (self, g_value_get_object (value));
+      break;
 
-  g_clear_pointer (&priv->keybindings, g_hash_table_unref);
+    case PROP_MODE:
+      gb_keybindings_set_mode (self, g_value_get_string (value));
+      break;
 
-  G_OBJECT_CLASS (gb_keybindings_parent_class)->finalize (object);
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
 }
 
 static void
@@ -200,16 +248,35 @@ gb_keybindings_class_init (GbKeybindingsClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  object_class->constructed = gb_keybindings_constructed;
   object_class->finalize = gb_keybindings_finalize;
+  object_class->get_property = gb_keybindings_get_property;
+  object_class->set_property = gb_keybindings_set_property;
+
+  gParamSpecs [PROP_APPLICATION] =
+    g_param_spec_object ("application",
+                         _("Application"),
+                         _("The application to register keybindings for."),
+                         GTK_TYPE_APPLICATION,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_APPLICATION, gParamSpecs [PROP_APPLICATION]);
+
+  gParamSpecs [PROP_MODE] =
+    g_param_spec_string ("mode",
+                         _("Mode"),
+                         _("The name of the keybindings mode."),
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_MODE, gParamSpecs [PROP_MODE]);
 }
 
 static void
-gb_keybindings_init (GbKeybindings *keybindings)
+gb_keybindings_init (GbKeybindings *self)
 {
-  keybindings->priv = gb_keybindings_get_instance_private (keybindings);
+  self->css_provider = gtk_css_provider_new ();
 
-  keybindings->priv->keybindings = g_hash_table_new_full (g_str_hash,
-                                                          g_str_equal,
-                                                          g_free,
-                                                          g_free);
+  g_signal_connect (self->css_provider,
+                    "parsing-error",
+                    G_CALLBACK (gb_keybindings_parsing_error),
+                    NULL);
 }
diff --git a/src/keybindings/gb-keybindings.h b/src/keybindings/gb-keybindings.h
index 7d449ce..4053bae 100644
--- a/src/keybindings/gb-keybindings.h
+++ b/src/keybindings/gb-keybindings.h
@@ -1,6 +1,6 @@
 /* gb-keybindings.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2014-2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,43 +23,16 @@
 
 G_BEGIN_DECLS
 
-#define GB_TYPE_KEYBINDINGS            (gb_keybindings_get_type())
-#define GB_KEYBINDINGS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_KEYBINDINGS, 
GbKeybindings))
-#define GB_KEYBINDINGS_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_KEYBINDINGS, 
GbKeybindings const))
-#define GB_KEYBINDINGS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_KEYBINDINGS, 
GbKeybindingsClass))
-#define GB_IS_KEYBINDINGS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_KEYBINDINGS))
-#define GB_IS_KEYBINDINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_KEYBINDINGS))
-#define GB_KEYBINDINGS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_KEYBINDINGS, 
GbKeybindingsClass))
+#define GB_TYPE_KEYBINDINGS (gb_keybindings_get_type())
 
-typedef struct _GbKeybindings        GbKeybindings;
-typedef struct _GbKeybindingsClass   GbKeybindingsClass;
-typedef struct _GbKeybindingsPrivate GbKeybindingsPrivate;
+G_DECLARE_FINAL_TYPE (GbKeybindings, gb_keybindings, GB, KEYBINDINGS, GObject)
 
-struct _GbKeybindings
-{
-  GObject parent;
-
-  /*< private >*/
-  GbKeybindingsPrivate *priv;
-};
-
-struct _GbKeybindingsClass
-{
-  GObjectClass parent_class;
-};
-
-GType          gb_keybindings_get_type   (void);
-GbKeybindings *gb_keybindings_new        (void);
-gboolean       gb_keybindings_load_bytes (GbKeybindings   *keybindings,
-                                          GBytes          *bytes,
-                                          GError         **error);
-gboolean       gb_keybindings_load_path  (GbKeybindings   *keybindings,
-                                          const gchar     *path,
-                                          GError         **error);
-void           gb_keybindings_register   (GbKeybindings   *keybindings,
-                                          GtkApplication  *application);
-void           gb_keybindings_unregister (GbKeybindings   *keybindings,
-                                          GtkApplication  *application);
+GbKeybindings  *gb_keybindings_new             (GtkApplication *application,
+                                                const gchar    *mode);
+GtkApplication *gb_keybindings_get_application (GbKeybindings *self);
+const gchar    *gb_keybindings_get_mode        (GbKeybindings  *self);
+void            gb_keybindings_set_mode        (GbKeybindings  *self,
+                                                const gchar    *name);
 
 G_END_DECLS
 
diff --git a/src/main.c b/src/main.c
index b38e3a5..faf03c3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -29,7 +29,6 @@
 #include <locale.h>
 
 #include "gb-application.h"
-#include "gb-log.h"
 
 int
 main (int   argc,
@@ -49,7 +48,7 @@ main (int   argc,
 
   ide_set_program_name ("gnome-builder");
 
-  gb_log_init (TRUE, NULL);
+  ide_log_init (TRUE, NULL);
 
   g_message ("Initializing with Gtk+ version %d.%d.%d.",
              gtk_get_major_version (),
@@ -64,7 +63,7 @@ main (int   argc,
   ret = g_application_run (app, argc, argv);
   g_clear_object (&app);
 
-  gb_log_shutdown ();
+  ide_log_shutdown ();
 
   return ret;
 }
diff --git a/src/preferences/gb-preferences-page-editor.c b/src/preferences/gb-preferences-page-editor.c
index 6b11f06..21203b1 100644
--- a/src/preferences/gb-preferences-page-editor.c
+++ b/src/preferences/gb-preferences-page-editor.c
@@ -35,6 +35,7 @@ struct _GbPreferencesPageEditorPrivate
   GtkSwitch                         *show_line_numbers_switch;
   GtkSwitch                         *highlight_current_line_switch;
   GtkSwitch                         *highlight_matching_brackets_switch;
+  GtkSwitch                         *smart_backspace_switch;
   GtkSwitch                         *smart_home_end_switch;
   GtkSwitch                         *show_grid_lines_switch;
   GtkFontButton                     *font_button;
@@ -47,6 +48,7 @@ struct _GbPreferencesPageEditorPrivate
   GtkWidget                         *show_line_numbers_container;
   GtkWidget                         *highlight_current_line_container;
   GtkWidget                         *highlight_matching_brackets_container;
+  GtkWidget                         *smart_backspace_container;
   GtkWidget                         *smart_home_end_container;
   GtkWidget                         *show_grid_lines_container;
 };
@@ -92,7 +94,7 @@ gb_preferences_page_editor_constructed (GObject *object)
   g_settings_bind (priv->settings, "restore-insert-mark",
                    priv->restore_insert_mark_switch, "active",
                    G_SETTINGS_BIND_DEFAULT);
-  g_settings_bind (priv->settings, "show-diff",
+  g_settings_bind (priv->settings, "show-line-changes",
                    priv->show_diff_switch, "active",
                    G_SETTINGS_BIND_DEFAULT);
   g_settings_bind (priv->settings, "word-completion",
@@ -110,6 +112,9 @@ gb_preferences_page_editor_constructed (GObject *object)
   g_settings_bind (priv->settings, "smart-home-end",
                    priv->smart_home_end_switch, "active",
                    G_SETTINGS_BIND_DEFAULT);
+  g_settings_bind (priv->settings, "smart-backspace",
+                   priv->smart_backspace_switch, "active",
+                   G_SETTINGS_BIND_DEFAULT);
   g_settings_bind (priv->settings, "show-grid-lines",
                    priv->show_grid_lines_switch, "active",
                    G_SETTINGS_BIND_DEFAULT);
@@ -154,25 +159,27 @@ gb_preferences_page_editor_class_init (GbPreferencesPageEditorClass *klass)
 
   GB_WIDGET_CLASS_TEMPLATE (widget_class, "gb-preferences-page-editor.ui");
 
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, font_button);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, restore_insert_mark_switch);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, show_diff_switch);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, style_scheme_button);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, word_completion_switch);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, show_line_numbers_switch);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, highlight_current_line_switch);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, highlight_matching_brackets_switch);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, smart_home_end_switch);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, show_grid_lines_switch);
-
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, restore_insert_mark_container);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, word_completion_container);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, show_diff_container);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, show_line_numbers_container);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, highlight_current_line_container);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, highlight_matching_brackets_container);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, smart_home_end_container);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesPageEditor, show_grid_lines_container);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, font_button);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, restore_insert_mark_switch);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, show_diff_switch);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, style_scheme_button);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, word_completion_switch);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, show_line_numbers_switch);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, highlight_current_line_switch);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, highlight_matching_brackets_switch);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, smart_home_end_switch);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, smart_backspace_switch);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, show_grid_lines_switch);
+
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, restore_insert_mark_container);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, word_completion_container);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, show_diff_container);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, show_line_numbers_container);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, highlight_current_line_container);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, 
highlight_matching_brackets_container);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, smart_home_end_container);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, smart_backspace_container);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesPageEditor, show_grid_lines_container);
 }
 
 static void
@@ -223,8 +230,14 @@ gb_preferences_page_editor_init (GbPreferencesPageEditor *self)
                                                self->priv->smart_home_end_container,
                                                self->priv->smart_home_end_switch,
                                                NULL);
+  /* To translators: This is a list of keywords for the preferences page */
   gb_preferences_page_set_keywords_for_widget (GB_PREFERENCES_PAGE (self),
+                                               _("smart back backspace indent align"),
+                                               self->priv->smart_backspace_container,
+                                               self->priv->smart_backspace_switch,
+                                               NULL);
   /* To translators: This is a list of keywords for the preferences page */
+  gb_preferences_page_set_keywords_for_widget (GB_PREFERENCES_PAGE (self),
                                                _("show grid lines"),
                                                self->priv->show_grid_lines_container,
                                                self->priv->show_grid_lines_switch,
diff --git a/src/preferences/gb-preferences-page-emacs.c b/src/preferences/gb-preferences-page-emacs.c
index bc16f1e..e10e39d 100644
--- a/src/preferences/gb-preferences-page-emacs.c
+++ b/src/preferences/gb-preferences-page-emacs.c
@@ -41,6 +41,8 @@ gb_preferences_page_emacs_constructed (GObject *object)
 {
   GbPreferencesPageEmacsPrivate *priv;
   GbPreferencesPageEmacs *emacs = (GbPreferencesPageEmacs *)object;
+  GSimpleActionGroup *group;
+  GAction *action;
 
   g_return_if_fail (GB_IS_PREFERENCES_PAGE_EMACS (emacs));
 
@@ -48,9 +50,12 @@ gb_preferences_page_emacs_constructed (GObject *object)
 
   priv->editor_settings = g_settings_new ("org.gnome.builder.editor");
 
-  g_settings_bind (priv->editor_settings, "emacs-mode",
-                   priv->emacs_mode_switch, "active",
-                   G_SETTINGS_BIND_DEFAULT);
+  group = g_simple_action_group_new ();
+  action = g_settings_create_action (priv->editor_settings, "keybindings");
+  g_action_map_add_action (G_ACTION_MAP (group), action);
+  g_clear_object (&action);
+  gtk_widget_insert_action_group (GTK_WIDGET (emacs), "settings", G_ACTION_GROUP (group));
+  g_clear_object (&group);
 }
 
 static void
diff --git a/src/preferences/gb-preferences-page-vim.c b/src/preferences/gb-preferences-page-vim.c
index c9ca6f3..fddbead 100644
--- a/src/preferences/gb-preferences-page-vim.c
+++ b/src/preferences/gb-preferences-page-vim.c
@@ -44,6 +44,8 @@ gb_preferences_page_vim_constructed (GObject *object)
 {
   GbPreferencesPageVimPrivate *priv;
   GbPreferencesPageVim *vim = (GbPreferencesPageVim *)object;
+  GSimpleActionGroup *group;
+  GAction *action;
 
   g_return_if_fail (GB_IS_PREFERENCES_PAGE_VIM (vim));
 
@@ -52,12 +54,18 @@ gb_preferences_page_vim_constructed (GObject *object)
   priv->editor_settings = g_settings_new ("org.gnome.builder.editor");
   priv->vim_settings = g_settings_new ("org.gnome.builder.editor.vim");
 
-  g_settings_bind (priv->vim_settings, "scroll-off",
-                   priv->scroll_off_spin, "value",
-                   G_SETTINGS_BIND_DEFAULT);
-  g_settings_bind (priv->editor_settings, "vim-mode",
-                   priv->vim_mode_switch, "active",
-                   G_SETTINGS_BIND_DEFAULT);
+  group = g_simple_action_group_new ();
+
+  action = g_settings_create_action (priv->editor_settings, "keybindings");
+  g_action_map_add_action (G_ACTION_MAP (group), action);
+  g_clear_object (&action);
+
+  action = g_settings_create_action (priv->vim_settings, "scroll-off");
+  g_action_map_add_action (G_ACTION_MAP (group), action);
+  g_clear_object (&action);
+
+  gtk_widget_insert_action_group (GTK_WIDGET (vim), "settings", G_ACTION_GROUP (group));
+  g_clear_object (&group);
 }
 
 static void
diff --git a/src/preferences/gb-preferences-page.c b/src/preferences/gb-preferences-page.c
index c661327..d6de247 100644
--- a/src/preferences/gb-preferences-page.c
+++ b/src/preferences/gb-preferences-page.c
@@ -19,9 +19,9 @@
 #define G_LOG_DOMAIN "prefs-page"
 
 #include <glib/gi18n.h>
+#include <ide.h>
 
 #include "gb-preferences-page.h"
-#include "gb-log.h"
 #include "gb-string.h"
 
 struct _GbPreferencesPagePrivate
diff --git a/src/preferences/gb-preferences-window.c b/src/preferences/gb-preferences-window.c
index 98f417b..a79e58b 100644
--- a/src/preferences/gb-preferences-window.c
+++ b/src/preferences/gb-preferences-window.c
@@ -329,10 +329,10 @@ gb_preferences_window_class_init (GbPreferencesWindowClass *klass)
 
   GB_WIDGET_CLASS_TEMPLATE (widget_class, "gb-preferences-window.ui");
 
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesWindow, right_header_bar);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesWindow, search_bar);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesWindow, search_entry);
-  GB_WIDGET_CLASS_BIND (widget_class, GbPreferencesWindow, stack);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesWindow, right_header_bar);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesWindow, search_bar);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesWindow, search_entry);
+  GB_WIDGET_CLASS_BIND_PRIVATE (widget_class, GbPreferencesWindow, stack);
 
   g_type_ensure (GB_TYPE_PREFERENCES_PAGE_GIT);
   g_type_ensure (GB_TYPE_PREFERENCES_PAGE_EDITOR);
diff --git a/src/resources/css/builder.Adwaita.css b/src/resources/css/builder.Adwaita.css
index 6e29d3a..98bc405 100644
--- a/src/resources/css/builder.Adwaita.css
+++ b/src/resources/css/builder.Adwaita.css
@@ -138,15 +138,6 @@ GtkEntry.gb-command-bar-entry {
 
 
 /*
- * Styling of main window header bar.
- */
-GbWorkbench GtkHeaderBar {
-    border-bottom: none;
-    box-shadow: none;
-}
-
-
-/*
  * Tab header styling.
  */
 GtkMenuButton.tab-header-first .button,
@@ -219,3 +210,7 @@ GbSearchDisplayGroup GtkListBox .list-row {
 GbDocumentStack .button {
     transition: none;
 }
+
+GbViewStack GtkBox.header.notebook {
+    border-bottom: 1px solid @borders;
+}
diff --git a/src/resources/gnome-builder.gresource.xml b/src/resources/gnome-builder.gresource.xml
index 9cc5a62..31fc406 100644
--- a/src/resources/gnome-builder.gresource.xml
+++ b/src/resources/gnome-builder.gresource.xml
@@ -14,23 +14,21 @@
     <file>js/marked.js</file>
     <file>js/markdown-view.js</file>
 
-    <file>keybindings/default.ini</file>
-    <file>keybindings/emacs.ini</file>
-    <file>keybindings/vim.ini</file>
+    <file alias="keybindings/default.css">../../data/keybindings/default.css</file>
+    <file alias="keybindings/emacs.css">../../data/keybindings/emacs.css</file>
+    <file alias="keybindings/vim.css">../../data/keybindings/vim.css</file>
 
-    <file>language/defaults.ini</file>
+    <file alias="ui/gb-command-bar.ui">../../data/ui/gb-command-bar.ui</file>
+    <file alias="ui/gb-editor-frame.ui">../../data/ui/gb-editor-frame.ui</file>
+    <file alias="ui/gb-editor-settings-widget.ui">../../data/ui/gb-editor-settings-widget.ui</file>
+    <file alias="ui/gb-editor-tweak-widget.ui">../../data/ui/gb-editor-tweak-widget.ui</file>
+    <file alias="ui/gb-editor-view.ui">../../data/ui/gb-editor-view.ui</file>
+    <file alias="ui/gb-editor-workspace.ui">../../data/ui/gb-editor-workspace.ui</file>
+    <file alias="ui/gb-view-stack.ui">../../data/ui/gb-view-stack.ui</file>
+    <file alias="ui/gb-workbench.ui">../../data/ui/gb-workbench.ui</file>
 
-    <file>ui/gb-command-bar.ui</file>
     <file>ui/gb-command-bar-item.ui</file>
-    <file>ui/gb-credits-widget.ui</file>
     <file>ui/gb-devhelp-view.ui</file>
-    <file>ui/gb-document-stack.ui</file>
-    <file>ui/gb-document-menu-button.ui</file>
-    <file>ui/gb-editor-settings-widget.ui</file>
-    <file>ui/gb-editor-frame.ui</file>
-    <file>ui/gb-editor-tweak-widget.ui</file>
-    <file>ui/gb-editor-view.ui</file>
-    <file>ui/gb-editor-workspace.ui</file>
     <file>ui/gb-html-view.ui</file>
     <file>ui/gb-preferences-window.ui</file>
     <file>ui/gb-preferences-page-editor.ui</file>
@@ -41,6 +39,5 @@
     <file>ui/gb-search-box.ui</file>
     <file>ui/gb-search-display-group.ui</file>
     <file>ui/gb-search-display-row.ui</file>
-    <file>ui/gb-workbench.ui</file>
   </gresource>
 </gresources>
diff --git a/src/resources/gtk/menus.ui b/src/resources/gtk/menus.ui
index 66e8975..ea326ce 100644
--- a/src/resources/gtk/menus.ui
+++ b/src/resources/gtk/menus.ui
@@ -18,12 +18,8 @@
     <section>
       <attribute name="id">help-section</attribute>
       <item>
-        <attribute name="label" translatable="yes">_Help</attribute>
-        <attribute name="action">app.help</attribute>
-      </item>
-      <item>
         <attribute name="label" translatable="yes">_About</attribute>
-        <attribute name="action">win.about</attribute>
+        <attribute name="action">app.about</attribute>
       </item>
       <item>
         <attribute name="label" translatable="yes">_Quit</attribute>
diff --git a/src/resources/ui/gb-preferences-page-editor.ui b/src/resources/ui/gb-preferences-page-editor.ui
index 32ce0d3..0614f9a 100644
--- a/src/resources/ui/gb-preferences-page-editor.ui
+++ b/src/resources/ui/gb-preferences-page-editor.ui
@@ -92,7 +92,7 @@
               </packing>
             </child>
             <child>
-              <object class="GtkSwitch" id="show_grid_lines_switch">
+              <object class="GtkSwitch" id="smart_backspace_switch">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="valign">center</property>
@@ -103,6 +103,17 @@
               </packing>
             </child>
             <child>
+              <object class="GtkSwitch" id="show_grid_lines_switch">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="valign">center</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">9</property>
+              </packing>
+            </child>
+            <child>
               <object class="GtkBox" id="restore_insert_mark_container">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
@@ -411,6 +422,50 @@
               </packing>
             </child>
             <child>
+              <object class="GtkBox" id="smart_backspace_container">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="hexpand">True</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Smart Backspace&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                    <property name="xalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="label" translatable="yes">Backspace will remove extra spaces to keep you 
aligned with your indentation size.</property>
+                    <property name="xalign">0</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">8</property>
+              </packing>
+            </child>
+            <child>
               <object class="GtkBox" id="show_grid_lines_container">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
@@ -451,7 +506,7 @@
               </object>
               <packing>
                 <property name="left_attach">1</property>
-                <property name="top_attach">8</property>
+                <property name="top_attach">9</property>
               </packing>
             </child>
           </object>
diff --git a/src/resources/ui/gb-preferences-page-emacs.ui b/src/resources/ui/gb-preferences-page-emacs.ui
index 90cb6a7..34d68ee 100644
--- a/src/resources/ui/gb-preferences-page-emacs.ui
+++ b/src/resources/ui/gb-preferences-page-emacs.ui
@@ -16,6 +16,8 @@
             <property name="column_spacing">12</property>
             <child>
               <object class="GtkSwitch" id="emacs_mode_switch">
+                <property name="action-name">settings.keybindings</property>
+                <property name="action-target">'emacs'</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="valign">center</property>
diff --git a/src/resources/ui/gb-preferences-page-vim.ui b/src/resources/ui/gb-preferences-page-vim.ui
index b3560a9..569107b 100644
--- a/src/resources/ui/gb-preferences-page-vim.ui
+++ b/src/resources/ui/gb-preferences-page-vim.ui
@@ -16,6 +16,8 @@
             <property name="column_spacing">12</property>
             <child>
               <object class="GtkSwitch" id="vim_mode_switch">
+                <property name="action-name">settings.keybindings</property>
+                <property name="action-target">'vim'</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="valign">center</property>
diff --git a/src/search/gb-search-box.c b/src/search/gb-search-box.c
index f5f2c1a..af2ab33 100644
--- a/src/search/gb-search-box.c
+++ b/src/search/gb-search-box.c
@@ -16,17 +16,14 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define G_LOG_DOMAIN "search-box"
+#define G_LOG_DOMAIN "ide-search-box"
 
 #include <glib/gi18n.h>
 
 #include "gb-glib.h"
 #include "gb-scrolled-window.h"
 #include "gb-search-box.h"
-#include "gb-search-context.h"
 #include "gb-search-display.h"
-#include "gb-search-manager.h"
-#include "gb-search-result.h"
 #include "gb-string.h"
 #include "gb-widget.h"
 #include "gb-workbench.h"
@@ -34,16 +31,15 @@
 #define SHORT_DELAY_TIMEOUT_MSEC 30
 #define LONG_DELAY_TIMEOUT_MSEC  30
 
-struct _GbSearchBoxPrivate
+struct _GbSearchBox
 {
-  /* References owned by instance */
-  GbSearchManager *search_manager;
+  GtkBox           parent_instance;
 
   /* Weak references */
   GbWorkbench     *workbench;
   gulong           set_focus_handler;
 
-  /* References owned by template */
+  /* Template references */
   GtkMenuButton   *button;
   GbSearchDisplay *display;
   GtkSearchEntry  *entry;
@@ -52,15 +48,7 @@ struct _GbSearchBoxPrivate
   guint            delay_timeout;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GbSearchBox, gb_search_box, GTK_TYPE_BOX)
-
-enum {
-  PROP_0,
-  PROP_SEARCH_MANAGER,
-  LAST_PROP
-};
-
-static GParamSpec *gParamSpecs [LAST_PROP];
+G_DEFINE_TYPE (GbSearchBox, gb_search_box, GTK_TYPE_BOX)
 
 GtkWidget *
 gb_search_box_new (void)
@@ -68,58 +56,54 @@ gb_search_box_new (void)
   return g_object_new (GB_TYPE_SEARCH_BOX, NULL);
 }
 
-GbSearchManager *
-gb_search_box_get_search_manager (GbSearchBox *box)
+IdeSearchEngine *
+gb_search_box_get_search_engine (GbSearchBox *self)
 {
-  g_return_val_if_fail (GB_IS_SEARCH_BOX (box), NULL);
+  IdeContext *context;
+  IdeSearchEngine *search_engine;
 
-  return box->priv->search_manager;
-}
+  g_return_val_if_fail (GB_IS_SEARCH_BOX (self), NULL);
 
-void
-gb_search_box_set_search_manager (GbSearchBox     *box,
-                                  GbSearchManager *search_manager)
-{
-  g_return_if_fail (GB_IS_SEARCH_BOX (box));
-  g_return_if_fail (!search_manager || GB_IS_SEARCH_MANAGER (search_manager));
+  if (self->workbench == NULL)
+    return NULL;
 
-  if (box->priv->search_manager != search_manager)
-    {
-      g_clear_object (&box->priv->search_manager);
+  context = gb_workbench_get_context (self->workbench);
+  if (context == NULL)
+      return NULL;
 
-      if (search_manager)
-        box->priv->search_manager = g_object_ref (search_manager);
+  search_engine = ide_context_get_search_engine (context);
 
-      g_object_notify_by_pspec (G_OBJECT (box),
-                                gParamSpecs [PROP_SEARCH_MANAGER]);
-    }
+  return search_engine;
 }
 
 static gboolean
 gb_search_box_delay_cb (gpointer user_data)
 {
-  GbSearchBox *box = user_data;
-  GbSearchContext *context;
+  GbSearchBox *self = user_data;
+  IdeSearchEngine *search_engine;
+  IdeSearchContext *context;
   const gchar *search_text;
 
-  g_return_val_if_fail (GB_IS_SEARCH_BOX (box), G_SOURCE_REMOVE);
+  g_return_val_if_fail (GB_IS_SEARCH_BOX (self), G_SOURCE_REMOVE);
 
-  box->priv->delay_timeout = 0;
+  self->delay_timeout = 0;
 
-  context = gb_search_display_get_context (box->priv->display);
+  context = gb_search_display_get_context (self->display);
   if (context)
-    gb_search_context_cancel (context);
+    ide_search_context_cancel (context);
 
-  if (!box->priv->search_manager)
+  search_engine = gb_search_box_get_search_engine (self);
+  if (!search_engine)
     return G_SOURCE_REMOVE;
 
-  search_text = gtk_entry_get_text (GTK_ENTRY (box->priv->entry));
+  search_text = gtk_entry_get_text (GTK_ENTRY (self->entry));
   if (!search_text)
     return G_SOURCE_REMOVE;
 
-  context = gb_search_manager_search (box->priv->search_manager, NULL, search_text); /* TODO: Remove search 
text */
-  gb_search_display_set_context (box->priv->display, context);
-  gb_search_context_execute (context, search_text);
+  /* TODO: Remove search text */
+  context = ide_search_engine_search (search_engine, NULL, search_text);
+  gb_search_display_set_context (self->display, context);
+  ide_search_context_execute (context, search_text, 5);
   g_object_unref (context);
 
   return G_SOURCE_REMOVE;
@@ -135,36 +119,36 @@ gb_search_box_popover_closed (GbSearchBox *box,
 }
 
 static gboolean
-gb_search_box_entry_focus_in (GbSearchBox   *box,
+gb_search_box_entry_focus_in (GbSearchBox   *self,
                               GdkEventFocus *focus,
                               GtkWidget     *entry)
 {
   const gchar *text;
 
-  g_return_val_if_fail (GB_IS_SEARCH_BOX (box), FALSE);
+  g_return_val_if_fail (GB_IS_SEARCH_BOX (self), FALSE);
   g_return_val_if_fail (focus, FALSE);
   g_return_val_if_fail (GTK_IS_SEARCH_ENTRY (entry), FALSE);
 
-  text = gtk_entry_get_text (GTK_ENTRY (box->priv->entry));
+  text = gtk_entry_get_text (GTK_ENTRY (self->entry));
 
   if (!gb_str_empty0 (text))
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (box->priv->button), TRUE);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->button), TRUE);
 
   return GDK_EVENT_PROPAGATE;
 }
 
 static void
-gb_search_box_entry_activate (GbSearchBox    *box,
+gb_search_box_entry_activate (GbSearchBox    *self,
                               GtkSearchEntry *entry)
 {
-  g_return_if_fail (GB_IS_SEARCH_BOX (box));
+  g_return_if_fail (GB_IS_SEARCH_BOX (self));
   g_return_if_fail (GTK_IS_SEARCH_ENTRY (entry));
 
-  gb_search_display_activate (box->priv->display);
+  gb_search_display_activate (self->display);
 }
 
 static void
-gb_search_box_entry_changed (GbSearchBox    *box,
+gb_search_box_entry_changed (GbSearchBox    *self,
                              GtkSearchEntry *entry)
 {
   GtkToggleButton *button;
@@ -172,17 +156,17 @@ gb_search_box_entry_changed (GbSearchBox    *box,
   gboolean active;
   guint delay_msec = SHORT_DELAY_TIMEOUT_MSEC;
 
-  g_return_if_fail (GB_IS_SEARCH_BOX (box));
+  g_return_if_fail (GB_IS_SEARCH_BOX (self));
   g_return_if_fail (GTK_IS_SEARCH_ENTRY (entry));
 
-  button = GTK_TOGGLE_BUTTON (box->priv->button);
+  button = GTK_TOGGLE_BUTTON (self->button);
   text = gtk_entry_get_text (GTK_ENTRY (entry));
   active = !gb_str_empty0 (text);
 
   if (gtk_toggle_button_get_active (button) != active)
     gtk_toggle_button_set_active (button, active);
 
-  if (!box->priv->delay_timeout)
+  if (!self->delay_timeout)
     {
       const gchar *search_text;
 
@@ -191,19 +175,19 @@ gb_search_box_entry_changed (GbSearchBox    *box,
         {
           if (strlen (search_text) < 3)
             delay_msec = LONG_DELAY_TIMEOUT_MSEC;
-          box->priv->delay_timeout = g_timeout_add (delay_msec,
-                                                    gb_search_box_delay_cb,
-                                                    box);
+          self->delay_timeout = g_timeout_add (delay_msec,
+                                               gb_search_box_delay_cb,
+                                               self);
         }
     }
 }
 
 static gboolean
-gb_search_box_entry_key_press_event (GbSearchBox    *box,
+gb_search_box_entry_key_press_event (GbSearchBox    *self,
                                      GdkEventKey    *key,
                                      GtkSearchEntry *entry)
 {
-  g_return_val_if_fail (GB_IS_SEARCH_BOX (box), GDK_EVENT_PROPAGATE);
+  g_return_val_if_fail (GB_IS_SEARCH_BOX (self), GDK_EVENT_PROPAGATE);
   g_return_val_if_fail (key, GDK_EVENT_PROPAGATE);
   g_return_val_if_fail (GTK_IS_SEARCH_ENTRY (entry), GDK_EVENT_PROPAGATE);
 
@@ -213,7 +197,7 @@ gb_search_box_entry_key_press_event (GbSearchBox    *box,
       {
         GtkWidget *toplevel;
 
-        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (box->priv->button),
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->button),
                                       FALSE);
 
         toplevel = gtk_widget_get_toplevel (GTK_WIDGET (entry));
@@ -227,7 +211,7 @@ gb_search_box_entry_key_press_event (GbSearchBox    *box,
     case GDK_KEY_KP_Tab:
     case GDK_KEY_Down:
     case GDK_KEY_KP_Down:
-      gtk_widget_grab_focus (GTK_WIDGET (box->priv->display));
+      gtk_widget_grab_focus (GTK_WIDGET (self->display));
       return GDK_EVENT_STOP;
 
     default:
@@ -238,71 +222,71 @@ gb_search_box_entry_key_press_event (GbSearchBox    *box,
 }
 
 static void
-gb_search_box_display_result_activated (GbSearchBox     *box,
-                                        GbSearchResult  *result,
+gb_search_box_display_result_activated (GbSearchBox     *self,
+                                        IdeSearchResult *result,
                                         GbSearchDisplay *display)
 {
-  g_return_if_fail (GB_IS_SEARCH_BOX (box));
-  g_return_if_fail (GB_IS_SEARCH_RESULT (result));
+  g_return_if_fail (GB_IS_SEARCH_BOX (self));
+  g_return_if_fail (IDE_IS_SEARCH_RESULT (result));
   g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
 
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (box->priv->button), FALSE);
-  gtk_entry_set_text (GTK_ENTRY (box->priv->entry), "");
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->button), FALSE);
+  gtk_entry_set_text (GTK_ENTRY (self->entry), "");
 }
 
 static void
-gb_search_box_button_toggled (GbSearchBox     *box,
+gb_search_box_button_toggled (GbSearchBox     *self,
                               GtkToggleButton *button)
 {
-  g_return_if_fail (GB_IS_SEARCH_BOX (box));
+  g_return_if_fail (GB_IS_SEARCH_BOX (self));
   g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
 
   if (gtk_toggle_button_get_active (button))
     {
-      if (!gtk_widget_has_focus (GTK_WIDGET (box->priv->entry)))
-        gtk_widget_grab_focus (GTK_WIDGET (box->priv->entry));
+      if (!gtk_widget_has_focus (GTK_WIDGET (self->entry)))
+        gtk_widget_grab_focus (GTK_WIDGET (self->entry));
     }
   else
     {
-      gtk_widget_hide (GTK_WIDGET (box->priv->popover));
+      gtk_widget_hide (GTK_WIDGET (self->popover));
     }
 }
 
 static void
 gb_search_box_grab_focus (GtkWidget *widget)
 {
-  GbSearchBox *box = (GbSearchBox *)widget;
+  GbSearchBox *self = (GbSearchBox *)widget;
 
-  g_return_if_fail (GB_IS_SEARCH_BOX (box));
+  g_return_if_fail (GB_IS_SEARCH_BOX (self));
 
-  gtk_widget_grab_focus (GTK_WIDGET (box->priv->entry));
+  gtk_widget_grab_focus (GTK_WIDGET (self->entry));
 }
 
 static void
-gb_search_box_workbench_set_focus (GbSearchBox *box,
+gb_search_box_workbench_set_focus (GbSearchBox *self,
                                    GtkWidget   *focus,
                                    GbWorkbench *workbench)
 {
-  g_return_if_fail (GB_IS_SEARCH_BOX (box));
+  g_return_if_fail (GB_IS_SEARCH_BOX (self));
   g_return_if_fail (!focus || GTK_IS_WIDGET (focus));
   g_return_if_fail (GB_IS_WORKBENCH (workbench));
 
   if (!focus ||
-      (!gtk_widget_is_ancestor (focus, GTK_WIDGET (box)) &&
-       !gtk_widget_is_ancestor (focus, GTK_WIDGET (box->priv->popover))))
+      (!gtk_widget_is_ancestor (focus, GTK_WIDGET (self)) &&
+       !gtk_widget_is_ancestor (focus, GTK_WIDGET (self->popover))))
     {
-      gtk_entry_set_text (GTK_ENTRY (box->priv->entry), "");
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (box->priv->button), FALSE);
+      gtk_entry_set_text (GTK_ENTRY (self->entry), "");
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->button), FALSE);
     }
 }
 
 static void
 gb_search_box_map (GtkWidget *widget)
 {
-  GbSearchBox *box = (GbSearchBox *)widget;
+  GbSearchBox *self = (GbSearchBox *)widget;
   GtkWidget *toplevel;
 
-  g_return_if_fail (GB_IS_SEARCH_BOX (box));
+  g_return_if_fail (GB_IS_SEARCH_BOX (self));
 
   GTK_WIDGET_CLASS (gb_search_box_parent_class)->map (widget);
 
@@ -310,12 +294,12 @@ gb_search_box_map (GtkWidget *widget)
 
   if (GB_IS_WORKBENCH (toplevel))
     {
-      gb_set_weak_pointer (toplevel, &box->priv->workbench);
-      box->priv->set_focus_handler =
+      gb_set_weak_pointer (toplevel, &self->workbench);
+      self->set_focus_handler =
         g_signal_connect_object (toplevel,
                                  "set-focus",
                                  G_CALLBACK (gb_search_box_workbench_set_focus),
-                                 box,
+                                 self,
                                  G_CONNECT_SWAPPED | G_CONNECT_AFTER);
     }
 }
@@ -323,16 +307,14 @@ gb_search_box_map (GtkWidget *widget)
 static void
 gb_search_box_unmap (GtkWidget *widget)
 {
-  GbSearchBox *box = (GbSearchBox *)widget;
+  GbSearchBox *self = (GbSearchBox *)widget;
 
-  g_return_if_fail (GB_IS_SEARCH_BOX (box));
+  g_return_if_fail (GB_IS_SEARCH_BOX (self));
 
-  if (box->priv->workbench)
+  if (self->workbench)
     {
-      g_signal_handler_disconnect (box->priv->workbench,
-                                   box->priv->set_focus_handler);
-      box->priv->set_focus_handler = 0;
-      gb_clear_weak_pointer (&box->priv->workbench);
+      ide_clear_signal_handler (self->workbench, &self->set_focus_handler);
+      ide_clear_weak_pointer (&self->workbench);
     }
 
   GTK_WIDGET_CLASS (gb_search_box_parent_class)->unmap (widget);
@@ -341,48 +323,45 @@ gb_search_box_unmap (GtkWidget *widget)
 static void
 gb_search_box_constructed (GObject *object)
 {
-  GbSearchBoxPrivate *priv;
   GbSearchBox *self = (GbSearchBox *)object;
 
   g_return_if_fail (GB_IS_SEARCH_BOX (self));
 
-  priv = self->priv;
-
   G_OBJECT_CLASS (gb_search_box_parent_class)->constructed (object);
 
-  gtk_popover_set_relative_to (priv->popover, GTK_WIDGET (priv->entry));
+  gtk_popover_set_relative_to (self->popover, GTK_WIDGET (self->entry));
 
-  g_signal_connect_object (priv->popover,
+  g_signal_connect_object (self->popover,
                            "closed",
                            G_CALLBACK (gb_search_box_popover_closed),
                            self,
                            G_CONNECT_SWAPPED);
-  g_signal_connect_object (priv->entry,
+  g_signal_connect_object (self->entry,
                            "focus-in-event",
                            G_CALLBACK (gb_search_box_entry_focus_in),
                            self,
                            G_CONNECT_SWAPPED);
-  g_signal_connect_object (priv->entry,
+  g_signal_connect_object (self->entry,
                            "activate",
                            G_CALLBACK (gb_search_box_entry_activate),
                            self,
                            G_CONNECT_SWAPPED);
-  g_signal_connect_object (priv->entry,
+  g_signal_connect_object (self->entry,
                            "changed",
                            G_CALLBACK (gb_search_box_entry_changed),
                            self,
                            G_CONNECT_SWAPPED);
-  g_signal_connect_object (priv->entry,
+  g_signal_connect_object (self->entry,
                            "key-press-event",
                            G_CALLBACK (gb_search_box_entry_key_press_event),
                            self,
                            G_CONNECT_SWAPPED);
-  g_signal_connect_object (priv->display,
+  g_signal_connect_object (self->display,
                            "result-activated",
                            G_CALLBACK (gb_search_box_display_result_activated),
                            self,
                            G_CONNECT_SWAPPED);
-  g_signal_connect_object (priv->button,
+  g_signal_connect_object (self->button,
                            "toggled",
                            G_CALLBACK (gb_search_box_button_toggled),
                            self,
@@ -392,58 +371,18 @@ gb_search_box_constructed (GObject *object)
 static void
 gb_search_box_finalize (GObject *object)
 {
-  GbSearchBoxPrivate *priv = GB_SEARCH_BOX (object)->priv;
+  GbSearchBox *self = (GbSearchBox *)object;
 
-  if (priv->delay_timeout)
+  if (self->delay_timeout)
     {
-      g_source_remove (priv->delay_timeout);
-      priv->delay_timeout = 0;
+      g_source_remove (self->delay_timeout);
+      self->delay_timeout = 0;
     }
 
-  g_clear_object (&priv->search_manager);
-
   G_OBJECT_CLASS (gb_search_box_parent_class)->finalize (object);
 }
 
 static void
-gb_search_box_get_property (GObject    *object,
-                            guint       prop_id,
-                            GValue     *value,
-                            GParamSpec *pspec)
-{
-  GbSearchBox *self = GB_SEARCH_BOX (object);
-
-  switch (prop_id)
-    {
-    case PROP_SEARCH_MANAGER:
-      g_value_set_object (value, gb_search_box_get_search_manager (self));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
-}
-
-static void
-gb_search_box_set_property (GObject      *object,
-                            guint         prop_id,
-                            const GValue *value,
-                            GParamSpec   *pspec)
-{
-  GbSearchBox *self = GB_SEARCH_BOX (object);
-
-  switch (prop_id)
-    {
-    case PROP_SEARCH_MANAGER:
-      gb_search_box_set_search_manager (self, g_value_get_object (value));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
-}
-
-static void
 gb_search_box_class_init (GbSearchBoxClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -451,22 +390,11 @@ gb_search_box_class_init (GbSearchBoxClass *klass)
 
   object_class->constructed = gb_search_box_constructed;
   object_class->finalize = gb_search_box_finalize;
-  object_class->get_property = gb_search_box_get_property;
-  object_class->set_property = gb_search_box_set_property;
 
   widget_class->grab_focus = gb_search_box_grab_focus;
   widget_class->map = gb_search_box_map;
   widget_class->unmap = gb_search_box_unmap;
 
-  gParamSpecs [PROP_SEARCH_MANAGER] =
-    g_param_spec_object ("search-manager",
-                         _("Search Manager"),
-                         _("The search manager for the search box."),
-                         GB_TYPE_SEARCH_MANAGER,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_SEARCH_MANAGER,
-                                   gParamSpecs [PROP_SEARCH_MANAGER]);
-
   GB_WIDGET_CLASS_TEMPLATE (klass, "gb-search-box.ui");
   GB_WIDGET_CLASS_BIND (klass, GbSearchBox, button);
   GB_WIDGET_CLASS_BIND (klass, GbSearchBox, display);
@@ -480,8 +408,6 @@ gb_search_box_class_init (GbSearchBoxClass *klass)
 static void
 gb_search_box_init (GbSearchBox *self)
 {
-  self->priv = gb_search_box_get_instance_private (self);
-
   gtk_widget_init_template (GTK_WIDGET (self));
 
   /*
@@ -494,5 +420,5 @@ gb_search_box_init (GbSearchBox *self)
    *
    * https://bugzilla.gnome.org/show_bug.cgi?id=741529
    */
-  g_object_ref (self->priv->popover);
+  g_object_ref (self->popover);
 }
diff --git a/src/search/gb-search-box.h b/src/search/gb-search-box.h
index 6f3e32e..84623ac 100644
--- a/src/search/gb-search-box.h
+++ b/src/search/gb-search-box.h
@@ -20,41 +20,18 @@
 #define GB_SEARCH_BOX_H
 
 #include <gtk/gtk.h>
-
-#include "gb-search-manager.h"
+#include <ide.h>
 
 G_BEGIN_DECLS
 
-#define GB_TYPE_SEARCH_BOX            (gb_search_box_get_type())
-#define GB_SEARCH_BOX(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_SEARCH_BOX, GbSearchBox))
-#define GB_SEARCH_BOX_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_SEARCH_BOX, GbSearchBox 
const))
-#define GB_SEARCH_BOX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_SEARCH_BOX, 
GbSearchBoxClass))
-#define GB_IS_SEARCH_BOX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_SEARCH_BOX))
-#define GB_IS_SEARCH_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_SEARCH_BOX))
-#define GB_SEARCH_BOX_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_SEARCH_BOX, 
GbSearchBoxClass))
-
-typedef struct _GbSearchBox        GbSearchBox;
-typedef struct _GbSearchBoxClass   GbSearchBoxClass;
-typedef struct _GbSearchBoxPrivate GbSearchBoxPrivate;
-
-struct _GbSearchBox
-{
-  GtkBox parent;
-
-  /*< private >*/
-  GbSearchBoxPrivate *priv;
-};
+#define GB_TYPE_SEARCH_BOX (gb_search_box_get_type())
 
-struct _GbSearchBoxClass
-{
-  GtkBoxClass parent;
-};
+G_DECLARE_FINAL_TYPE (GbSearchBox, gb_search_box, GB, SEARCH_BOX, GtkBox)
 
-GType            gb_search_box_get_type           (void);
 GtkWidget       *gb_search_box_new                (void);
-GbSearchManager *gb_search_box_get_search_manager (GbSearchBox     *box);
-void             gb_search_box_set_search_manager (GbSearchBox     *box,
-                                                   GbSearchManager *search_manager);
+IdeSearchEngine *gb_search_box_get_search_engine  (GbSearchBox     *box);
+void             gb_search_box_set_search_engine  (GbSearchBox     *box,
+                                                   IdeSearchEngine *search_engine);
 
 G_END_DECLS
 
diff --git a/src/search/gb-search-display-group.c b/src/search/gb-search-display-group.c
index c5180fb..2b9f460 100644
--- a/src/search/gb-search-display-group.c
+++ b/src/search/gb-search-display-group.c
@@ -20,27 +20,25 @@
 
 #include "gb-search-display-group.h"
 #include "gb-search-display-row.h"
-#include "gb-search-provider.h"
-#include "gb-search-result.h"
 #include "gb-widget.h"
 
-struct _GbSearchDisplayGroupPrivate
+struct _GbSearchDisplayGroup
 {
+  GtkBox             parent_instance;
+
   /* References owned by instance */
-  GbSearchProvider *provider;
+  IdeSearchProvider *provider;
 
   /* References owned by template */
-  GtkLabel         *more_label;
-  GtkListBoxRow    *more_row;
-  GtkLabel         *label;
-  GtkListBox       *rows;
+  GtkLabel          *more_label;
+  GtkListBoxRow     *more_row;
+  GtkLabel          *label;
+  GtkListBox        *rows;
 
-  guint64           count;
+  guint64            count;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GbSearchDisplayGroup,
-                            gb_search_display_group,
-                            GTK_TYPE_BOX)
+G_DEFINE_TYPE (GbSearchDisplayGroup, gb_search_display_group, GTK_TYPE_BOX)
 
 enum {
   PROP_0,
@@ -60,14 +58,14 @@ static GQuark      gQuarkRow;
 static GParamSpec *gParamSpecs [LAST_PROP];
 static guint       gSignals [LAST_SIGNAL];
 
-GbSearchResult *
-gb_search_display_group_get_first (GbSearchDisplayGroup *group)
+IdeSearchResult *
+gb_search_display_group_get_first (GbSearchDisplayGroup *self)
 {
   GtkListBoxRow *row;
 
-  g_return_val_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group), NULL);
+  g_return_val_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self), NULL);
 
-  row = gtk_list_box_get_row_at_y (group->priv->rows, 1);
+  row = gtk_list_box_get_row_at_y (self->rows, 1);
 
   if (row)
     {
@@ -81,49 +79,49 @@ gb_search_display_group_get_first (GbSearchDisplayGroup *group)
   return NULL;
 }
 
-GbSearchProvider *
-gb_search_display_group_get_provider (GbSearchDisplayGroup *group)
+IdeSearchProvider *
+gb_search_display_group_get_provider (GbSearchDisplayGroup *self)
 {
-  g_return_val_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group), NULL);
+  g_return_val_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self), NULL);
 
-  return group->priv->provider;
+  return self->provider;
 }
 
 static void
-gb_search_display_group_set_provider (GbSearchDisplayGroup *group,
-                                      GbSearchProvider     *provider)
+gb_search_display_group_set_provider (GbSearchDisplayGroup *self,
+                                      IdeSearchProvider    *provider)
 {
   const gchar *verb;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
-  g_return_if_fail (!provider || GB_IS_SEARCH_PROVIDER (provider));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self));
+  g_return_if_fail (!provider || IDE_IS_SEARCH_PROVIDER (provider));
 
   if (provider)
     {
-      group->priv->provider = g_object_ref (provider);
-      verb = gb_search_provider_get_verb (provider);
-      gtk_label_set_label (group->priv->label, verb);
+      self->provider = g_object_ref (provider);
+      verb = ide_search_provider_get_verb (provider);
+      gtk_label_set_label (self->label, verb);
     }
 }
 
 static void
-gb_search_display_group_set_size_group (GbSearchDisplayGroup *group,
+gb_search_display_group_set_size_group (GbSearchDisplayGroup *self,
                                         GtkSizeGroup         *size_group)
 {
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self));
   g_return_if_fail (!size_group || GTK_IS_SIZE_GROUP (size_group));
 
   if (size_group)
-    gtk_size_group_add_widget (size_group, GTK_WIDGET (group->priv->label));
+    gtk_size_group_add_widget (size_group, GTK_WIDGET (self->label));
 }
 
 GtkWidget *
-gb_search_display_group_create_row (GbSearchResult *result)
+gb_search_display_group_create_row (IdeSearchResult *result)
 {
   GtkListBoxRow *row;
   GbSearchDisplayRow *disp_row;
 
-  g_return_val_if_fail (GB_IS_SEARCH_RESULT (result), NULL);
+  g_return_val_if_fail (IDE_IS_SEARCH_RESULT (result), NULL);
 
   row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
                       "visible", TRUE,
@@ -140,53 +138,53 @@ gb_search_display_group_create_row (GbSearchResult *result)
 }
 
 void
-gb_search_display_group_remove_result (GbSearchDisplayGroup *group,
-                                       GbSearchResult       *result)
+gb_search_display_group_remove_result (GbSearchDisplayGroup *self,
+                                       IdeSearchResult      *result)
 {
   GtkWidget *row;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
-  g_return_if_fail (GB_IS_SEARCH_RESULT (result));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self));
+  g_return_if_fail (IDE_IS_SEARCH_RESULT (result));
 
   row = g_object_get_qdata (G_OBJECT (result), gQuarkRow);
 
   if (row)
-    gtk_container_remove (GTK_CONTAINER (group->priv->rows), row);
+    gtk_container_remove (GTK_CONTAINER (self->rows), row);
 }
 
 void
-gb_search_display_group_add_result (GbSearchDisplayGroup *group,
-                                    GbSearchResult       *result)
+gb_search_display_group_add_result (GbSearchDisplayGroup *self,
+                                    IdeSearchResult      *result)
 {
   GtkWidget *row;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
-  g_return_if_fail (GB_IS_SEARCH_RESULT (result));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self));
+  g_return_if_fail (IDE_IS_SEARCH_RESULT (result));
 
   row = gb_search_display_group_create_row (result);
-  gtk_container_add (GTK_CONTAINER (group->priv->rows), row);
+  gtk_container_add (GTK_CONTAINER (self->rows), row);
 
-  gtk_list_box_invalidate_sort (group->priv->rows);
+  gtk_list_box_invalidate_sort (self->rows);
 
-  group->priv->count++;
+  self->count++;
 }
 
 void
-gb_search_display_group_set_count (GbSearchDisplayGroup *group,
+gb_search_display_group_set_count (GbSearchDisplayGroup *self,
                                    guint64               count)
 {
   GtkWidget *parent;
   gchar *markup;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self));
 
   markup = g_strdup_printf (_("%"G_GUINT64_FORMAT" more"), count);
-  gtk_label_set_label (group->priv->more_label, markup);
+  gtk_label_set_label (self->more_label, markup);
   g_free (markup);
 
-  parent = GTK_WIDGET (group->priv->more_row);
+  parent = GTK_WIDGET (self->more_row);
 
-  if ((count - group->priv->count) > 0)
+  if ((count - self->count) > 0)
     gtk_widget_show (parent);
   else
     gtk_widget_hide (parent);
@@ -200,8 +198,8 @@ compare_cb (GtkListBoxRow *row1,
   GtkListBoxRow *more_row = user_data;
   GtkWidget *child1;
   GtkWidget *child2;
-  GbSearchResult *result1;
-  GbSearchResult *result2;
+  IdeSearchResult *result1;
+  IdeSearchResult *result2;
   gfloat score1;
   gfloat score2;
 
@@ -216,8 +214,8 @@ compare_cb (GtkListBoxRow *row1,
   result1 = gb_search_display_row_get_result (GB_SEARCH_DISPLAY_ROW (child1));
   result2 = gb_search_display_row_get_result (GB_SEARCH_DISPLAY_ROW (child2));
 
-  score1 = gb_search_result_get_score (result1);
-  score2 = gb_search_result_get_score (result2);
+  score1 = ide_search_result_get_score (result1);
+  score2 = ide_search_result_get_score (result2);
 
   if (score1 < score2)
     return 1;
@@ -228,21 +226,21 @@ compare_cb (GtkListBoxRow *row1,
 }
 
 void
-gb_search_display_group_unselect (GbSearchDisplayGroup *group)
+gb_search_display_group_unselect (GbSearchDisplayGroup *self)
 {
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self));
 
-  gtk_list_box_unselect_all (group->priv->rows);
+  gtk_list_box_unselect_all (self->rows);
 }
 
 static void
-gb_search_display_group_row_activated (GbSearchDisplayGroup *group,
+gb_search_display_group_row_activated (GbSearchDisplayGroup *self,
                                        GtkListBoxRow        *row,
                                        GtkListBox           *list_box)
 {
   GtkWidget *child;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self));
   g_return_if_fail (!row || GTK_IS_LIST_BOX_ROW (row));
   g_return_if_fail (GTK_IS_LIST_BOX (list_box));
 
@@ -250,22 +248,22 @@ gb_search_display_group_row_activated (GbSearchDisplayGroup *group,
 
   if (GB_IS_SEARCH_DISPLAY_ROW (child))
     {
-      GbSearchResult *result;
+      IdeSearchResult *result;
 
       result = gb_search_display_row_get_result (GB_SEARCH_DISPLAY_ROW (child));
       if (result)
-        g_signal_emit (group, gSignals [RESULT_ACTIVATED], 0, result);
+        g_signal_emit (self, gSignals [RESULT_ACTIVATED], 0, result);
     }
 }
 
 static void
-gb_search_display_group_row_selected (GbSearchDisplayGroup *group,
+gb_search_display_group_row_selected (GbSearchDisplayGroup *self,
                                       GtkListBoxRow        *row,
                                       GtkListBox           *list_box)
 {
   GtkWidget *child;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self));
   g_return_if_fail (!row || GTK_IS_LIST_BOX_ROW (row));
   g_return_if_fail (GTK_IS_LIST_BOX (list_box));
 
@@ -275,46 +273,46 @@ gb_search_display_group_row_selected (GbSearchDisplayGroup *group,
 
       if (GB_IS_SEARCH_DISPLAY_ROW (child))
         {
-          GbSearchResult *result;
+          IdeSearchResult *result;
 
           result = gb_search_display_row_get_result (GB_SEARCH_DISPLAY_ROW (child));
           if (result)
-            g_signal_emit (group, gSignals [RESULT_SELECTED], 0, result);
+            g_signal_emit (self, gSignals [RESULT_SELECTED], 0, result);
         }
     }
 }
 
 void
-gb_search_display_group_focus_first (GbSearchDisplayGroup *group)
+gb_search_display_group_focus_first (GbSearchDisplayGroup *self)
 {
   GtkListBoxRow *row;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self));
 
-  row = gtk_list_box_get_row_at_y (group->priv->rows, 1);
+  row = gtk_list_box_get_row_at_y (self->rows, 1);
 
   if (row)
     {
-      gtk_list_box_unselect_all (group->priv->rows);
-      gtk_widget_child_focus (GTK_WIDGET (group->priv->rows), GTK_DIR_DOWN);
+      gtk_list_box_unselect_all (self->rows);
+      gtk_widget_child_focus (GTK_WIDGET (self->rows), GTK_DIR_DOWN);
     }
 }
 
 void
-gb_search_display_group_focus_last (GbSearchDisplayGroup *group)
+gb_search_display_group_focus_last (GbSearchDisplayGroup *self)
 {
   GtkAllocation alloc;
   GtkListBoxRow *row;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self));
 
-  gtk_widget_get_allocation (GTK_WIDGET (group->priv->rows), &alloc);
-  row = gtk_list_box_get_row_at_y (group->priv->rows, alloc.height - 2);
+  gtk_widget_get_allocation (GTK_WIDGET (self->rows), &alloc);
+  row = gtk_list_box_get_row_at_y (self->rows, alloc.height - 2);
 
   if (row)
     {
-      gtk_list_box_unselect_all (group->priv->rows);
-      gtk_widget_child_focus (GTK_WIDGET (group->priv->rows), GTK_DIR_UP);
+      gtk_list_box_unselect_all (self->rows);
+      gtk_widget_child_focus (GTK_WIDGET (self->rows), GTK_DIR_UP);
     }
 }
 
@@ -338,16 +336,16 @@ gb_search_display_group_header_cb (GtkListBoxRow *row,
 }
 
 static gboolean
-gb_search_display_group_keynav_failed (GbSearchDisplayGroup *group,
+gb_search_display_group_keynav_failed (GbSearchDisplayGroup *self,
                                        GtkDirectionType      dir,
                                        GtkListBox           *list_box)
 {
   gboolean ret = FALSE;
 
-  g_return_val_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group), FALSE);
+  g_return_val_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (self), FALSE);
   g_return_val_if_fail (GTK_IS_LIST_BOX (list_box), FALSE);
 
-  g_signal_emit_by_name (group, "keynav-failed", dir, &ret);
+  g_signal_emit_by_name (self, "keynav-failed", dir, &ret);
 
   return ret;
 }
@@ -355,9 +353,9 @@ gb_search_display_group_keynav_failed (GbSearchDisplayGroup *group,
 static void
 gb_search_display_group_finalize (GObject *object)
 {
-  GbSearchDisplayGroupPrivate *priv = GB_SEARCH_DISPLAY_GROUP (object)->priv;
+  GbSearchDisplayGroup *self = (GbSearchDisplayGroup *)object;
 
-  g_clear_object (&priv->provider);
+  g_clear_object (&self->provider);
 
   G_OBJECT_CLASS (gb_search_display_group_parent_class)->finalize (object);
 }
@@ -418,10 +416,8 @@ gb_search_display_group_class_init (GbSearchDisplayGroupClass *klass)
     g_param_spec_object ("provider",
                          _("Provider"),
                          _("The search provider"),
-                         GB_TYPE_SEARCH_PROVIDER,
-                         (G_PARAM_READWRITE |
-                          G_PARAM_CONSTRUCT_ONLY |
-                          G_PARAM_STATIC_STRINGS));
+                         IDE_TYPE_SEARCH_PROVIDER,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_PROVIDER,
                                    gParamSpecs [PROP_PROVIDER]);
 
@@ -430,9 +426,7 @@ gb_search_display_group_class_init (GbSearchDisplayGroupClass *klass)
                          _("Size Group"),
                          _("The size group for the label."),
                          GTK_TYPE_SIZE_GROUP,
-                         (G_PARAM_WRITABLE |
-                          G_PARAM_CONSTRUCT_ONLY |
-                          G_PARAM_STATIC_STRINGS));
+                         (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_SIZE_GROUP,
                                    gParamSpecs [PROP_SIZE_GROUP]);
 
@@ -443,10 +437,10 @@ gb_search_display_group_class_init (GbSearchDisplayGroupClass *klass)
                   0,
                   NULL,
                   NULL,
-                  g_cclosure_marshal_generic,
+                  g_cclosure_marshal_VOID__OBJECT,
                   G_TYPE_NONE,
                   1,
-                  GB_TYPE_SEARCH_RESULT);
+                  IDE_TYPE_SEARCH_RESULT);
 
   gSignals [RESULT_SELECTED] =
     g_signal_new ("result-selected",
@@ -455,10 +449,10 @@ gb_search_display_group_class_init (GbSearchDisplayGroupClass *klass)
                   0,
                   NULL,
                   NULL,
-                  g_cclosure_marshal_generic,
+                  g_cclosure_marshal_VOID__OBJECT,
                   G_TYPE_NONE,
                   1,
-                  GB_TYPE_SEARCH_RESULT);
+                  IDE_TYPE_SEARCH_RESULT);
 
   GB_WIDGET_CLASS_TEMPLATE (widget_class, "gb-search-display-group.ui");
   GB_WIDGET_CLASS_BIND (widget_class, GbSearchDisplayGroup, more_label);
@@ -472,29 +466,24 @@ gb_search_display_group_class_init (GbSearchDisplayGroupClass *klass)
 static void
 gb_search_display_group_init (GbSearchDisplayGroup *self)
 {
-  self->priv = gb_search_display_group_get_instance_private (self);
-
   gtk_widget_init_template (GTK_WIDGET (self));
 
-  gtk_list_box_set_sort_func (self->priv->rows, compare_cb,
-                              self->priv->more_row, NULL);
-
-  g_signal_connect_object (self->priv->rows,
+  g_signal_connect_object (self->rows,
                            "keynav-failed",
                            G_CALLBACK (gb_search_display_group_keynav_failed),
                            self,
                            G_CONNECT_SWAPPED);
-  g_signal_connect_object (self->priv->rows,
+  g_signal_connect_object (self->rows,
                            "row-activated",
                            G_CALLBACK (gb_search_display_group_row_activated),
                            self,
                            G_CONNECT_SWAPPED);
-  g_signal_connect_object (self->priv->rows,
+  g_signal_connect_object (self->rows,
                            "row-selected",
                            G_CALLBACK (gb_search_display_group_row_selected),
                            self,
                            G_CONNECT_SWAPPED);
-  gtk_list_box_set_header_func (self->priv->rows,
-                                gb_search_display_group_header_cb,
-                                NULL, NULL);
+
+  gtk_list_box_set_sort_func (self->rows, compare_cb, self->more_row, NULL);
+  gtk_list_box_set_header_func (self->rows, gb_search_display_group_header_cb, NULL, NULL);
 }
diff --git a/src/search/gb-search-display-group.h b/src/search/gb-search-display-group.h
index dbbcb27..a6e4b86 100644
--- a/src/search/gb-search-display-group.h
+++ b/src/search/gb-search-display-group.h
@@ -20,43 +20,26 @@
 #define GB_SEARCH_DISPLAY_GROUP_H
 
 #include <gtk/gtk.h>
-
-#include "gb-search-types.h"
+#include <ide.h>
 
 G_BEGIN_DECLS
 
-#define GB_SEARCH_DISPLAY_GROUP(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_SEARCH_DISPLAY_GROUP, GbSearchDisplayGroup))
-#define GB_SEARCH_DISPLAY_GROUP_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_SEARCH_DISPLAY_GROUP, GbSearchDisplayGroup const))
-#define GB_SEARCH_DISPLAY_GROUP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  
GB_TYPE_SEARCH_DISPLAY_GROUP, GbSearchDisplayGroupClass))
-#define GB_IS_SEARCH_DISPLAY_GROUP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GB_TYPE_SEARCH_DISPLAY_GROUP))
-#define GB_IS_SEARCH_DISPLAY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  
GB_TYPE_SEARCH_DISPLAY_GROUP))
-#define GB_SEARCH_DISPLAY_GROUP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  
GB_TYPE_SEARCH_DISPLAY_GROUP, GbSearchDisplayGroupClass))
-
-struct _GbSearchDisplayGroup
-{
-  GtkBox parent;
-
-  /*< private >*/
-  GbSearchDisplayGroupPrivate *priv;
-};
-
-struct _GbSearchDisplayGroupClass
-{
-  GtkBoxClass parent;
-};
-
-void              gb_search_display_group_clear         (GbSearchDisplayGroup *group);
-GbSearchProvider *gb_search_display_group_get_provider  (GbSearchDisplayGroup *group);
-void              gb_search_display_group_add_result    (GbSearchDisplayGroup *group,
-                                                         GbSearchResult       *result);
-void              gb_search_display_group_remove_result (GbSearchDisplayGroup *group,
-                                                         GbSearchResult       *result);
-void              gb_search_display_group_set_count     (GbSearchDisplayGroup *group,
-                                                         guint64               count);
-void              gb_search_display_group_unselect      (GbSearchDisplayGroup *group);
-void              gb_search_display_group_focus_first   (GbSearchDisplayGroup *group);
-void              gb_search_display_group_focus_last    (GbSearchDisplayGroup *group);
-GbSearchResult   *gb_search_display_group_get_first     (GbSearchDisplayGroup *group);
+#define GB_TYPE_SEARCH_DISPLAY_GROUP (gb_search_display_group_get_type())
+
+G_DECLARE_FINAL_TYPE (GbSearchDisplayGroup, gb_search_display_group, GB, SEARCH_DISPLAY_GROUP, GtkBox)
+
+void               gb_search_display_group_clear         (GbSearchDisplayGroup *group);
+IdeSearchProvider *gb_search_display_group_get_provider  (GbSearchDisplayGroup *group);
+void               gb_search_display_group_add_result    (GbSearchDisplayGroup *group,
+                                                          IdeSearchResult      *result);
+void               gb_search_display_group_remove_result (GbSearchDisplayGroup *group,
+                                                          IdeSearchResult      *result);
+void               gb_search_display_group_set_count     (GbSearchDisplayGroup *group,
+                                                          guint64               count);
+void               gb_search_display_group_unselect      (GbSearchDisplayGroup *group);
+void               gb_search_display_group_focus_first   (GbSearchDisplayGroup *group);
+void               gb_search_display_group_focus_last    (GbSearchDisplayGroup *group);
+IdeSearchResult   *gb_search_display_group_get_first     (GbSearchDisplayGroup *group);
 
 G_END_DECLS
 
diff --git a/src/search/gb-search-display-row.c b/src/search/gb-search-display-row.c
index f7fc31a..55a85f8 100644
--- a/src/search/gb-search-display-row.c
+++ b/src/search/gb-search-display-row.c
@@ -19,21 +19,21 @@
 #include <glib/gi18n.h>
 
 #include "gb-search-display-row.h"
-#include "gb-search-result.h"
 #include "gb-widget.h"
 
-struct _GbSearchDisplayRowPrivate
+struct _GbSearchDisplayRow
 {
-  GbSearchResult *result;
+  GtkBox           parent_instance;
+
+  IdeSearchResult *result;
 
   /* References owned by template */
-  GtkLabel *title;
-  GtkLabel *subtitle;
-  GtkProgressBar *progress;
+  GtkLabel        *title;
+  GtkLabel        *subtitle;
+  GtkProgressBar  *progress;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GbSearchDisplayRow, gb_search_display_row,
-                            GTK_TYPE_BOX)
+G_DEFINE_TYPE (GbSearchDisplayRow, gb_search_display_row, GTK_TYPE_BOX)
 
 enum {
   PROP_0,
@@ -45,50 +45,50 @@ static GParamSpec *gParamSpecs [LAST_PROP];
 
 static void
 gb_search_display_row_connect (GbSearchDisplayRow *row,
-                               GbSearchResult     *result)
+                               IdeSearchResult    *result)
 {
   const gchar *title;
   const gchar *subtitle;
   gfloat fraction;
 
   g_return_if_fail (GB_IS_SEARCH_DISPLAY_ROW (row));
-  g_return_if_fail (GB_IS_SEARCH_RESULT (result));
+  g_return_if_fail (IDE_IS_SEARCH_RESULT (result));
 
-  title = gb_search_result_get_title (result);
-  gtk_label_set_markup (row->priv->title, title);
+  title = ide_search_result_get_title (result);
+  gtk_label_set_markup (row->title, title);
 
-  subtitle = gb_search_result_get_subtitle (result);
+  subtitle = ide_search_result_get_subtitle (result);
   if (subtitle)
-    gtk_label_set_markup (row->priv->subtitle, subtitle);
-  gtk_widget_set_visible (GTK_WIDGET (row->priv->subtitle), !!subtitle);
+    gtk_label_set_markup (row->subtitle, subtitle);
+  gtk_widget_set_visible (GTK_WIDGET (row->subtitle), !!subtitle);
 
-  fraction = gb_search_result_get_score (result);
-  gtk_progress_bar_set_fraction (row->priv->progress, fraction);
-  gtk_widget_set_visible (GTK_WIDGET (row->priv->progress), (fraction > 0.0));
+  fraction = ide_search_result_get_score (result);
+  gtk_progress_bar_set_fraction (row->progress, fraction);
+  gtk_widget_set_visible (GTK_WIDGET (row->progress), (fraction > 0.0));
 }
 
-GbSearchResult *
+IdeSearchResult *
 gb_search_display_row_get_result (GbSearchDisplayRow *row)
 {
   g_return_val_if_fail (GB_IS_SEARCH_DISPLAY_ROW (row), NULL);
 
-  return row->priv->result;
+  return row->result;
 }
 
 void
 gb_search_display_row_set_result (GbSearchDisplayRow *row,
-                                  GbSearchResult     *result)
+                                  IdeSearchResult    *result)
 {
   g_return_if_fail (GB_IS_SEARCH_DISPLAY_ROW (row));
-  g_return_if_fail (GB_IS_SEARCH_RESULT (result));
+  g_return_if_fail (IDE_IS_SEARCH_RESULT (result));
 
-  if (result != row->priv->result)
+  if (result != row->result)
     {
-      g_clear_object (&row->priv->result);
+      g_clear_object (&row->result);
 
       if (result)
         {
-          row->priv->result = g_object_ref (result);
+          row->result = g_object_ref (result);
           gb_search_display_row_connect (row, result);
         }
 
@@ -99,9 +99,9 @@ gb_search_display_row_set_result (GbSearchDisplayRow *row,
 static void
 gb_search_display_row_finalize (GObject *object)
 {
-  GbSearchDisplayRowPrivate *priv = GB_SEARCH_DISPLAY_ROW (object)->priv;
+  GbSearchDisplayRow *self = (GbSearchDisplayRow *)object;
 
-  g_clear_object (&priv->result);
+  g_clear_object (&self->result);
 
   G_OBJECT_CLASS (gb_search_display_row_parent_class)->finalize (object);
 }
@@ -158,11 +158,9 @@ gb_search_display_row_class_init (GbSearchDisplayRowClass *klass)
     g_param_spec_object ("result",
                          _("Result"),
                          _("Result"),
-                         GB_TYPE_SEARCH_RESULT,
-                         (G_PARAM_READWRITE |
-                          G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_RESULT,
-                                   gParamSpecs [PROP_RESULT]);
+                         IDE_TYPE_SEARCH_RESULT,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_RESULT, gParamSpecs [PROP_RESULT]);
 
   GB_WIDGET_CLASS_TEMPLATE (widget_class, "gb-search-display-row.ui");
   GB_WIDGET_CLASS_BIND (widget_class, GbSearchDisplayRow, progress);
@@ -173,7 +171,5 @@ gb_search_display_row_class_init (GbSearchDisplayRowClass *klass)
 static void
 gb_search_display_row_init (GbSearchDisplayRow *self)
 {
-  self->priv = gb_search_display_row_get_instance_private (self);
-
   gtk_widget_init_template (GTK_WIDGET (self));
 }
diff --git a/src/search/gb-search-display-row.h b/src/search/gb-search-display-row.h
index 807a6c1..649a8a2 100644
--- a/src/search/gb-search-display-row.h
+++ b/src/search/gb-search-display-row.h
@@ -20,34 +20,17 @@
 #define GB_SEARCH_DISPLAY_ROW_H
 
 #include <gtk/gtk.h>
-
-#include "gb-search-types.h"
+#include <ide.h>
 
 G_BEGIN_DECLS
 
-#define GB_SEARCH_DISPLAY_ROW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_SEARCH_DISPLAY_ROW, GbSearchDisplayRow))
-#define GB_SEARCH_DISPLAY_ROW_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_SEARCH_DISPLAY_ROW, GbSearchDisplayRow const))
-#define GB_SEARCH_DISPLAY_ROW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  
GB_TYPE_SEARCH_DISPLAY_ROW, GbSearchDisplayRowClass))
-#define GB_IS_SEARCH_DISPLAY_ROW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GB_TYPE_SEARCH_DISPLAY_ROW))
-#define GB_IS_SEARCH_DISPLAY_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  
GB_TYPE_SEARCH_DISPLAY_ROW))
-#define GB_SEARCH_DISPLAY_ROW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  
GB_TYPE_SEARCH_DISPLAY_ROW, GbSearchDisplayRowClass))
-
-struct _GbSearchDisplayRow
-{
-  GtkBox parent;
-
-  /*< private >*/
-  GbSearchDisplayRowPrivate *priv;
-};
-
-struct _GbSearchDisplayRowClass
-{
-  GtkBoxClass parent;
-};
-
-GbSearchResult *gb_search_display_row_get_result (GbSearchDisplayRow *row);
-void            gb_search_display_row_set_result (GbSearchDisplayRow *row,
-                                                  GbSearchResult     *result);
+#define GB_TYPE_SEARCH_DISPLAY_ROW (gb_search_display_row_get_type())
+
+G_DECLARE_FINAL_TYPE (GbSearchDisplayRow, gb_search_display_row, GB, SEARCH_DISPLAY_ROW, GtkBox)
+
+IdeSearchResult *gb_search_display_row_get_result (GbSearchDisplayRow *row);
+void             gb_search_display_row_set_result (GbSearchDisplayRow *row,
+                                                   IdeSearchResult    *result);
 
 G_END_DECLS
 
diff --git a/src/search/gb-search-display.c b/src/search/gb-search-display.c
index da092c9..8561588 100644
--- a/src/search/gb-search-display.c
+++ b/src/search/gb-search-display.c
@@ -16,28 +16,31 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define G_LOG_DOMAIN "gb-search-display"
+
 #include <glib/gi18n.h>
+#include <ide.h>
 
 #include "gb-search-display.h"
 #include "gb-search-display-group.h"
-#include "gb-search-provider.h"
-#include "gb-search-result.h"
 
-struct _GbSearchDisplayPrivate
+struct _GbSearchDisplay
 {
-  GbSearchContext      *context;
-  GArray               *providers;
+  GtkBox                parent_instance;
+
+  IdeSearchContext     *context;
+  GPtrArray            *providers;
   GtkSizeGroup         *size_group;
   GbSearchDisplayGroup *last_group;
 };
 
 typedef struct
 {
-  GbSearchProvider     *provider;
+  IdeSearchProvider    *provider;
   GbSearchDisplayGroup *group;
 } ProviderEntry;
 
-G_DEFINE_TYPE_WITH_PRIVATE (GbSearchDisplay, gb_search_display, GTK_TYPE_BOX)
+G_DEFINE_TYPE (GbSearchDisplay, gb_search_display, GTK_TYPE_BOX)
 
 enum {
   PROP_0,
@@ -58,20 +61,28 @@ provider_entry_destroy (gpointer data)
 {
   ProviderEntry *entry = data;
 
+  IDE_ENTRY;
+
+  IDE_TRACE_MSG ("releasing %p", data);
+
+  ide_clear_weak_pointer (&entry->group);
   g_clear_object (&entry->provider);
+  g_free (entry);
+
+  IDE_EXIT;
 }
 
 static gint
 provider_entry_sort (gconstpointer ptra,
                      gconstpointer ptrb)
 {
-  const ProviderEntry *entrya = ptra;
-  const ProviderEntry *entryb = ptrb;
+  ProviderEntry **entrya = (ProviderEntry **)ptra;
+  ProviderEntry **entryb = (ProviderEntry **)ptrb;
   gint a;
   gint b;
 
-  a = gb_search_provider_get_priority ((GB_SEARCH_PROVIDER (entrya->provider)));
-  b = gb_search_provider_get_priority ((GB_SEARCH_PROVIDER (entryb->provider)));
+  a = ide_search_provider_get_priority ((IDE_SEARCH_PROVIDER ((*entrya)->provider)));
+  b = ide_search_provider_get_priority ((IDE_SEARCH_PROVIDER ((*entryb)->provider)));
 
   return a - b;
 }
@@ -83,50 +94,54 @@ gb_search_display_new (void)
 }
 
 static void
-gb_search_display_real_result_activated (GbSearchDisplay *display,
-                                         GbSearchResult  *result)
+gb_search_display_real_result_activated (GbSearchDisplay *self,
+                                         IdeSearchResult *result)
 {
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
-  g_return_if_fail (GB_IS_SEARCH_RESULT (result));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
+  g_return_if_fail (IDE_IS_SEARCH_RESULT (result));
 
-  gb_search_result_activate (result);
+#if 1
+  g_warning ("ACTICATE SEARCH RESULT");
+#else
+  ide_search_result_activate (result);
+#endif
 }
 
 static void
-gb_search_display_result_activated (GbSearchDisplay      *display,
-                                    GbSearchResult       *result,
+gb_search_display_result_activated (GbSearchDisplay      *self,
+                                    IdeSearchResult      *result,
                                     GbSearchDisplayGroup *group)
 {
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
-  g_return_if_fail (!result || GB_IS_SEARCH_RESULT (result));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
+  g_return_if_fail (!result || IDE_IS_SEARCH_RESULT (result));
   g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
 
-  g_signal_emit (display, gSignals [RESULT_ACTIVATED], 0, result);
+  g_signal_emit (self, gSignals [RESULT_ACTIVATED], 0, result);
 }
 
 static void
-gb_search_display_result_selected (GbSearchDisplay      *display,
-                                   GbSearchResult       *result,
+gb_search_display_result_selected (GbSearchDisplay      *self,
+                                   IdeSearchResult      *result,
                                    GbSearchDisplayGroup *group)
 {
   guint i;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
-  g_return_if_fail (!result || GB_IS_SEARCH_RESULT (result));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
+  g_return_if_fail (!result || IDE_IS_SEARCH_RESULT (result));
   g_return_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group));
 
-  for (i = 0; i < display->priv->providers->len; i++)
+  for (i = 0; i < self->providers->len; i++)
     {
       ProviderEntry *ptr;
 
-      ptr = &g_array_index (display->priv->providers, ProviderEntry, i);
-      if (ptr->group != group)
+      ptr = g_ptr_array_index (self->providers, i);
+      if ((ptr->group != NULL) && (ptr->group != group))
         gb_search_display_group_unselect (ptr->group);
     }
 }
 
 static gboolean
-gb_search_display_keynav_failed (GbSearchDisplay      *display,
+gb_search_display_keynav_failed (GbSearchDisplay      *self,
                                  GtkDirectionType      dir,
                                  GbSearchDisplayGroup *group)
 {
@@ -134,18 +149,18 @@ gb_search_display_keynav_failed (GbSearchDisplay      *display,
   GList *iter;
   gint position = -1;
 
-  g_return_val_if_fail (GB_IS_SEARCH_DISPLAY (display), FALSE);
+  g_return_val_if_fail (GB_IS_SEARCH_DISPLAY (self), FALSE);
   g_return_val_if_fail (GB_IS_SEARCH_DISPLAY_GROUP (group), FALSE);
 
-  gtk_container_child_get (GTK_CONTAINER (display), GTK_WIDGET (group),
+  gtk_container_child_get (GTK_CONTAINER (self), GTK_WIDGET (group),
                            "position", &position,
                            NULL);
 
   if (dir == GTK_DIR_DOWN)
     {
-      list = gtk_container_get_children (GTK_CONTAINER (display));
+      list = gtk_container_get_children (GTK_CONTAINER (self));
       iter = g_list_nth (list, position + 1);
-      if (iter && (iter->data != display->priv->last_group))
+      if (iter && (iter->data != self->last_group))
         {
           gb_search_display_group_unselect (group);
           gb_search_display_group_focus_first (iter->data);
@@ -154,7 +169,7 @@ gb_search_display_keynav_failed (GbSearchDisplay      *display,
     }
   else if (dir == GTK_DIR_UP && position > 0)
     {
-      list = gtk_container_get_children (GTK_CONTAINER (display));
+      list = gtk_container_get_children (GTK_CONTAINER (self));
       iter = g_list_nth (list, position - 1);
       if (iter)
         {
@@ -170,20 +185,18 @@ gb_search_display_keynav_failed (GbSearchDisplay      *display,
 void
 gb_search_display_activate (GbSearchDisplay *self)
 {
-  GbSearchDisplayPrivate *priv;
-  GbSearchResult *result = NULL;
+  IdeSearchResult *result = NULL;
   guint i;
 
   g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
 
-  priv = self->priv;
-
-  for (i = 0; !result && i < priv->providers->len; i++)
+  for (i = 0; !result && i < self->providers->len; i++)
     {
       ProviderEntry *ptr;
 
-      ptr = &g_array_index (self->priv->providers, ProviderEntry, i);
-      result = gb_search_display_group_get_first (ptr->group);
+      ptr = g_ptr_array_index (self->providers, i);
+      if (ptr->group != NULL)
+        result = gb_search_display_group_get_first (ptr->group);
     }
 
   if (result)
@@ -191,24 +204,24 @@ gb_search_display_activate (GbSearchDisplay *self)
 }
 
 static void
-gb_search_display_add_provider (GbSearchDisplay  *display,
-                                GbSearchProvider *provider)
+gb_search_display_add_provider (GbSearchDisplay   *self,
+                                IdeSearchProvider *provider)
 {
-  ProviderEntry entry = { 0 };
+  ProviderEntry *entry;
   guint i;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
-  g_return_if_fail (GB_IS_SEARCH_PROVIDER (provider));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
+  g_return_if_fail (IDE_IS_SEARCH_PROVIDER (provider));
 
   /*
    * Make sure we don't add an item twice. Probably can assert here, but
    * warning will do for now.
    */
-  for (i = 0; i < display->priv->providers->len; i++)
+  for (i = 0; i < self->providers->len; i++)
     {
       ProviderEntry *ptr;
 
-      ptr = &g_array_index (display->priv->providers, ProviderEntry, i);
+      ptr = g_ptr_array_index (self->providers, i);
 
       if (ptr->provider == provider)
         {
@@ -221,44 +234,46 @@ gb_search_display_add_provider (GbSearchDisplay  *display,
    * Add the entry to our array and sort the array to determine our target
    * widget packing position.
    */
-  entry.provider = g_object_ref (provider);
-  entry.group = g_object_new (GB_TYPE_SEARCH_DISPLAY_GROUP,
-                              "size-group", display->priv->size_group,
-                              "provider", provider,
-                              "visible", FALSE,
-                              NULL);
-  g_signal_connect_object (entry.group,
+  entry = g_new0 (ProviderEntry, 1);
+  entry->provider = g_object_ref (provider);
+  entry->group = g_object_new (GB_TYPE_SEARCH_DISPLAY_GROUP,
+                               "size-group", self->size_group,
+                               "provider", provider,
+                               "visible", FALSE,
+                               NULL);
+  g_object_add_weak_pointer (G_OBJECT (entry->group), (gpointer *)&entry->group);
+  g_signal_connect_object (entry->group,
                            "result-activated",
                            G_CALLBACK (gb_search_display_result_activated),
-                           display,
+                           self,
                            G_CONNECT_SWAPPED);
-  g_signal_connect_object (entry.group,
+  g_signal_connect_object (entry->group,
                            "result-selected",
                            G_CALLBACK (gb_search_display_result_selected),
-                           display,
+                           self,
                            G_CONNECT_SWAPPED);
-  g_signal_connect_object (entry.group,
+  g_signal_connect_object (entry->group,
                            "keynav-failed",
                            G_CALLBACK (gb_search_display_keynav_failed),
-                           display,
+                           self,
                            G_CONNECT_SWAPPED);
-  g_array_append_val (display->priv->providers, entry);
-  g_array_sort (display->priv->providers, provider_entry_sort);
+  g_ptr_array_add (self->providers, entry);
+  g_ptr_array_sort (self->providers, provider_entry_sort);
 
   /*
    * Find the location of the entry and use the index to pack the display
    * group widget.
    */
-  for (i = 0; i < display->priv->providers->len; i++)
+  for (i = 0; i < self->providers->len; i++)
     {
       ProviderEntry *ptr;
 
-      ptr = &g_array_index (display->priv->providers, ProviderEntry, i);
+      ptr = g_ptr_array_index (self->providers, i);
 
       if (ptr->provider == provider)
         {
-          gtk_container_add_with_properties (GTK_CONTAINER (display),
-                                             GTK_WIDGET (entry.group),
+          gtk_container_add_with_properties (GTK_CONTAINER (self),
+                                             GTK_WIDGET (entry->group),
                                              "position", i,
                                              NULL);
           break;
@@ -267,25 +282,27 @@ gb_search_display_add_provider (GbSearchDisplay  *display,
 }
 
 static void
-gb_search_display_remove_provider (GbSearchDisplay  *display,
-                                   GbSearchProvider *provider)
+gb_search_display_remove_provider (GbSearchDisplay   *self,
+                                   IdeSearchProvider *provider)
 {
   guint i;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
-  g_return_if_fail (GB_IS_SEARCH_PROVIDER (provider));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
+  g_return_if_fail (IDE_IS_SEARCH_PROVIDER (provider));
 
-  for (i = 0; i < display->priv->providers->len; i++)
+  for (i = 0; i < self->providers->len; i++)
     {
       ProviderEntry *ptr;
 
-      ptr = &g_array_index (display->priv->providers, ProviderEntry, i);
+      ptr = g_ptr_array_index (self->providers, i);
 
       if (ptr->provider == provider)
         {
-          gtk_container_remove (GTK_CONTAINER (display),
-                                GTK_WIDGET (ptr->group));
-          g_array_remove_index (display->priv->providers, i);
+          GbSearchDisplayGroup *group = ptr->group;
+
+          if (group)
+            gtk_container_remove (GTK_CONTAINER (self), GTK_WIDGET (group));
+          g_ptr_array_remove_index (self->providers, i);
           return;
         }
     }
@@ -294,173 +311,174 @@ gb_search_display_remove_provider (GbSearchDisplay  *display,
 }
 
 static void
-gb_search_display_result_added (GbSearchDisplay  *display,
-                                GbSearchProvider *provider,
-                                GbSearchResult   *result,
-                                GbSearchContext  *context)
+gb_search_display_result_added (GbSearchDisplay   *self,
+                                IdeSearchProvider *provider,
+                                IdeSearchResult   *result,
+                                IdeSearchContext  *context)
 {
   guint i;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
-  g_return_if_fail (GB_IS_SEARCH_PROVIDER (provider));
-  g_return_if_fail (GB_IS_SEARCH_RESULT (result));
-  g_return_if_fail (GB_IS_SEARCH_CONTEXT (context));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
+  g_return_if_fail (IDE_IS_SEARCH_PROVIDER (provider));
+  g_return_if_fail (IDE_IS_SEARCH_RESULT (result));
+  g_return_if_fail (IDE_IS_SEARCH_CONTEXT (context));
 
-  for (i = 0; i < display->priv->providers->len; i++)
+  for (i = 0; i < self->providers->len; i++)
     {
       ProviderEntry *ptr;
 
-      ptr = &g_array_index (display->priv->providers, ProviderEntry, i);
+      ptr = g_ptr_array_index (self->providers, i);
 
       if (ptr->provider == provider)
         {
-          gb_search_display_group_add_result (ptr->group, result);
-          gtk_widget_show (GTK_WIDGET (ptr->group));
+          if (ptr->group != NULL)
+            {
+              gb_search_display_group_add_result (ptr->group, result);
+              gtk_widget_show (GTK_WIDGET (ptr->group));
+            }
           break;
         }
     }
 }
 
 static void
-gb_search_display_result_removed (GbSearchDisplay  *display,
-                                  GbSearchProvider *provider,
-                                  GbSearchResult   *result,
-                                  GbSearchContext  *context)
+gb_search_display_result_removed (GbSearchDisplay   *self,
+                                  IdeSearchProvider *provider,
+                                  IdeSearchResult   *result,
+                                  IdeSearchContext  *context)
 {
   guint i;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
-  g_return_if_fail (GB_IS_SEARCH_PROVIDER (provider));
-  g_return_if_fail (GB_IS_SEARCH_RESULT (result));
-  g_return_if_fail (GB_IS_SEARCH_CONTEXT (context));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
+  g_return_if_fail (IDE_IS_SEARCH_PROVIDER (provider));
+  g_return_if_fail (IDE_IS_SEARCH_RESULT (result));
+  g_return_if_fail (IDE_IS_SEARCH_CONTEXT (context));
 
-  for (i = 0; i < display->priv->providers->len; i++)
+  for (i = 0; i < self->providers->len; i++)
     {
       ProviderEntry *ptr;
 
-      ptr = &g_array_index (display->priv->providers, ProviderEntry, i);
+      ptr = g_ptr_array_index (self->providers, i);
 
       if (ptr->provider == provider)
         {
-          gb_search_display_group_remove_result (ptr->group, result);
+          if (ptr->group != NULL)
+            gb_search_display_group_remove_result (ptr->group, result);
           break;
         }
     }
 }
 
 static void
-gb_search_display_count_set (GbSearchDisplay  *display,
-                             GbSearchProvider *provider,
-                             guint64           count,
-                             GbSearchContext  *context)
+gb_search_display_count_set (GbSearchDisplay   *self,
+                             IdeSearchProvider *provider,
+                             guint64            count,
+                             IdeSearchContext  *context)
 {
   guint i;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
-  g_return_if_fail (GB_IS_SEARCH_PROVIDER (provider));
-  g_return_if_fail (GB_IS_SEARCH_CONTEXT (context));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
+  g_return_if_fail (IDE_IS_SEARCH_PROVIDER (provider));
+  g_return_if_fail (IDE_IS_SEARCH_CONTEXT (context));
 
-  for (i = 0; i < display->priv->providers->len; i++)
+  for (i = 0; i < self->providers->len; i++)
     {
       ProviderEntry *ptr;
 
-      ptr = &g_array_index (display->priv->providers, ProviderEntry, i);
+      ptr = g_ptr_array_index (self->providers, i);
 
       if (ptr->provider == provider)
         {
-          gb_search_display_group_set_count (ptr->group, count);
+          if (ptr->group != NULL)
+            gb_search_display_group_set_count (ptr->group, count);
           break;
         }
     }
 }
 
 static void
-gb_search_display_connect_context (GbSearchDisplay *display,
-                                   GbSearchContext *context)
+gb_search_display_connect_context (GbSearchDisplay  *self,
+                                   IdeSearchContext *context)
 {
   const GList *providers;
   const GList *iter;
 
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
-  g_return_if_fail (GB_IS_SEARCH_CONTEXT (context));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
+  g_return_if_fail (IDE_IS_SEARCH_CONTEXT (context));
 
-  providers = gb_search_context_get_providers (context);
+  providers = ide_search_context_get_providers (context);
 
   for (iter = providers; iter; iter = iter->next)
-    gb_search_display_add_provider (display, iter->data);
+    gb_search_display_add_provider (self, iter->data);
 
   g_signal_connect_object (context,
                            "result-added",
                            G_CALLBACK (gb_search_display_result_added),
-                           display,
+                           self,
                            G_CONNECT_SWAPPED);
   g_signal_connect_object (context,
                            "result-removed",
                            G_CALLBACK (gb_search_display_result_removed),
-                           display,
+                           self,
                            G_CONNECT_SWAPPED);
   g_signal_connect_object (context,
                            "count-set",
                            G_CALLBACK (gb_search_display_count_set),
-                           display,
+                           self,
                            G_CONNECT_SWAPPED);
 }
 
 static void
-gb_search_display_disconnect_context (GbSearchDisplay *display,
-                                      GbSearchContext *context)
+gb_search_display_disconnect_context (GbSearchDisplay  *self,
+                                      IdeSearchContext *context)
 {
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
-  g_return_if_fail (GB_IS_SEARCH_CONTEXT (context));
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
+  g_return_if_fail (IDE_IS_SEARCH_CONTEXT (context));
 
-  while (display->priv->providers->len)
+  g_signal_handlers_disconnect_by_func (context,
+                                        G_CALLBACK (gb_search_display_result_added),
+                                        self);
+
+  while (self->providers->len)
     {
       ProviderEntry *ptr;
 
-      ptr = &g_array_index (display->priv->providers, ProviderEntry,
-                            display->priv->providers->len - 1);
-      gb_search_display_remove_provider (display, ptr->provider);
+      ptr = g_ptr_array_index (self->providers,
+                               self->providers->len - 1);
+      gb_search_display_remove_provider (self, ptr->provider);
     }
-
-  g_signal_handlers_disconnect_by_func (context,
-                                        G_CALLBACK (gb_search_display_result_added),
-                                        display);
 }
 
-GbSearchContext *
-gb_search_display_get_context (GbSearchDisplay *display)
+IdeSearchContext *
+gb_search_display_get_context (GbSearchDisplay *self)
 {
-  g_return_val_if_fail (GB_IS_SEARCH_DISPLAY (display), NULL);
+  g_return_val_if_fail (GB_IS_SEARCH_DISPLAY (self), NULL);
 
-  return display->priv->context;
+  return self->context;
 }
 
 void
-gb_search_display_set_context (GbSearchDisplay *display,
-                               GbSearchContext *context)
+gb_search_display_set_context (GbSearchDisplay  *self,
+                               IdeSearchContext *context)
 {
-  GbSearchDisplayPrivate *priv;
-
-  g_return_if_fail (GB_IS_SEARCH_DISPLAY (display));
-  g_return_if_fail (!context || GB_IS_SEARCH_CONTEXT (context));
-
-  priv = display->priv;
+  g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
+  g_return_if_fail (!context || IDE_IS_SEARCH_CONTEXT (context));
 
-  if (priv->context != context)
+  if (self->context != context)
     {
-      if (priv->context)
+      if (self->context)
         {
-          gb_search_display_disconnect_context (display, priv->context);
-          g_clear_object (&display->priv->context);
+          gb_search_display_disconnect_context (self, self->context);
+          g_clear_object (&self->context);
         }
 
       if (context)
         {
-          priv->context = g_object_ref (context);
-          gb_search_display_connect_context (display, priv->context);
+          self->context = g_object_ref (context);
+          gb_search_display_connect_context (self, self->context);
         }
 
-      g_object_notify_by_pspec (G_OBJECT (display), gParamSpecs [PROP_CONTEXT]);
+      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_CONTEXT]);
     }
 }
 
@@ -471,11 +489,11 @@ gb_search_display_grab_focus (GtkWidget *widget)
 
   g_return_if_fail (GB_IS_SEARCH_DISPLAY (self));
 
-  if (self->priv->providers->len)
+  if (self->providers->len)
     {
       ProviderEntry *ptr;
 
-      ptr = &g_array_index (self->priv->providers, ProviderEntry, 0);
+      ptr = g_ptr_array_index (self->providers, 0);
       gtk_widget_child_focus (GTK_WIDGET (ptr->group), GTK_DIR_DOWN);
     }
 }
@@ -483,11 +501,11 @@ gb_search_display_grab_focus (GtkWidget *widget)
 static void
 gb_search_display_dispose (GObject *object)
 {
-  GbSearchDisplayPrivate *priv = GB_SEARCH_DISPLAY (object)->priv;
+  GbSearchDisplay *self = (GbSearchDisplay *)object;
 
-  g_clear_pointer (&priv->providers, g_array_unref);
-  g_clear_object (&priv->context);
-  g_clear_object (&priv->size_group);
+  g_clear_pointer (&self->providers, g_ptr_array_unref);
+  g_clear_object (&self->context);
+  g_clear_object (&self->size_group);
 
   G_OBJECT_CLASS (gb_search_display_parent_class)->dispose (object);
 }
@@ -542,50 +560,41 @@ gb_search_display_class_init (GbSearchDisplayClass *klass)
   object_class->get_property = gb_search_display_get_property;
   object_class->set_property = gb_search_display_set_property;
 
-  klass->result_activated = gb_search_display_real_result_activated;
-
   gParamSpecs [PROP_CONTEXT] =
     g_param_spec_object ("context",
                          _("Context"),
                          _("The active search context."),
-                         GB_TYPE_SEARCH_CONTEXT,
-                         (G_PARAM_READWRITE |
-                          G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_CONTEXT,
-                                   gParamSpecs [PROP_CONTEXT]);
+                         IDE_TYPE_SEARCH_CONTEXT,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_CONTEXT, gParamSpecs [PROP_CONTEXT]);
 
   gSignals [RESULT_ACTIVATED] =
-    g_signal_new ("result-activated",
-                  G_TYPE_FROM_CLASS (klass),
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (GbSearchDisplayClass, result_activated),
-                  NULL,
-                  NULL,
-                  g_cclosure_marshal_generic,
-                  G_TYPE_NONE,
-                  1,
-                  GB_TYPE_SEARCH_RESULT);
+    g_signal_new_class_handler ("result-activated",
+                                G_TYPE_FROM_CLASS (klass),
+                                G_SIGNAL_RUN_LAST,
+                                G_CALLBACK (gb_search_display_real_result_activated),
+                                NULL, NULL,
+                                g_cclosure_marshal_VOID__OBJECT,
+                                G_TYPE_NONE,
+                                1,
+                                IDE_TYPE_SEARCH_RESULT);
 }
 
 static void
 gb_search_display_init (GbSearchDisplay *self)
 {
-  self->priv = gb_search_display_get_instance_private (self);
-
-  self->priv->providers = g_array_new (FALSE, FALSE, sizeof (ProviderEntry));
-  g_array_set_clear_func (self->priv->providers,
-                          (GDestroyNotify)provider_entry_destroy);
+  self->providers = g_ptr_array_new_with_free_func (provider_entry_destroy);
 
-  self->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+  self->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
   gtk_orientable_set_orientation (GTK_ORIENTABLE (self),
                                   GTK_ORIENTATION_VERTICAL);
 
-  self->priv->last_group = g_object_new (GB_TYPE_SEARCH_DISPLAY_GROUP,
-                                         "size-group", self->priv->size_group,
+  self->last_group = g_object_new (GB_TYPE_SEARCH_DISPLAY_GROUP,
+                                         "size-group", self->size_group,
                                          "visible", TRUE,
                                          "vexpand", TRUE,
                                          NULL);
   gtk_container_add (GTK_CONTAINER (self),
-                     GTK_WIDGET (self->priv->last_group));
+                     GTK_WIDGET (self->last_group));
 }
diff --git a/src/search/gb-search-display.h b/src/search/gb-search-display.h
index 7958c21..66cdc89 100644
--- a/src/search/gb-search-display.h
+++ b/src/search/gb-search-display.h
@@ -20,39 +20,18 @@
 #define GB_SEARCH_DISPLAY_H
 
 #include <gtk/gtk.h>
-
-#include "gb-search-types.h"
+#include <ide.h>
 
 G_BEGIN_DECLS
 
-#define GB_SEARCH_DISPLAY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_SEARCH_DISPLAY, 
GbSearchDisplay))
-#define GB_SEARCH_DISPLAY_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_SEARCH_DISPLAY, 
GbSearchDisplay const))
-#define GB_SEARCH_DISPLAY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_SEARCH_DISPLAY, 
GbSearchDisplayClass))
-#define GB_IS_SEARCH_DISPLAY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_SEARCH_DISPLAY))
-#define GB_IS_SEARCH_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_SEARCH_DISPLAY))
-#define GB_SEARCH_DISPLAY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_SEARCH_DISPLAY, 
GbSearchDisplayClass))
-
-struct _GbSearchDisplay
-{
-  GtkBox parent;
-
-  /*< private >*/
-  GbSearchDisplayPrivate *priv;
-};
-
-struct _GbSearchDisplayClass
-{
-  GtkBoxClass parent;
-
-  void (*result_activated) (GbSearchDisplay *display,
-                            GbSearchResult  *result);
-};
-
-GtkWidget       *gb_search_display_new         (void);
-void             gb_search_display_activate    (GbSearchDisplay *display);
-GbSearchContext *gb_search_display_get_context (GbSearchDisplay *display);
-void             gb_search_display_set_context (GbSearchDisplay *display,
-                                                GbSearchContext *context);
+#define GB_TYPE_SEARCH_DISPLAY (gb_search_display_get_type())
+
+G_DECLARE_FINAL_TYPE (GbSearchDisplay, gb_search_display, GB, SEARCH_DISPLAY, GtkBin)
+
+void              gb_search_display_activate    (GbSearchDisplay  *display);
+IdeSearchContext *gb_search_display_get_context (GbSearchDisplay  *display);
+void              gb_search_display_set_context (GbSearchDisplay  *display,
+                                                 IdeSearchContext *context);
 
 G_END_DECLS
 
diff --git a/src/tree/gb-tree.c b/src/tree/gb-tree.c
index b808d81..037424d 100644
--- a/src/tree/gb-tree.c
+++ b/src/tree/gb-tree.c
@@ -19,8 +19,8 @@
 #define G_LOG_DOMAIN "tree"
 
 #include <glib/gi18n.h>
+#include <ide.h>
 
-#include "gb-log.h"
 #include "gb-tree.h"
 #include "gb-tree-node.h"
 
@@ -98,14 +98,14 @@ gb_tree_unselect (GbTree *tree)
 {
   GtkTreeSelection *selection;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_return_if_fail (GB_IS_TREE (tree));
 
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
   gtk_tree_selection_unselect_all (selection);
 
-  EXIT;
+  IDE_EXIT;
 }
 
 /**
@@ -123,7 +123,7 @@ gb_tree_select (GbTree     *tree,
   GbTreePrivate *priv;
   GtkTreePath *path;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_return_if_fail (GB_IS_TREE (tree));
   g_return_if_fail (GB_IS_TREE_NODE (node));
@@ -143,7 +143,7 @@ gb_tree_select (GbTree     *tree,
   gtk_tree_selection_select_path (selection, path);
   gtk_tree_path_free (path);
 
-  EXIT;
+  IDE_EXIT;
 }
 
 static void
@@ -188,7 +188,7 @@ gb_tree_popup (GbTree         *tree,
   gboolean at_least_one_visible = FALSE;
   guint i;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_return_if_fail (GB_IS_TREE (tree));
   g_return_if_fail (GB_IS_TREE_NODE (node));
@@ -221,7 +221,7 @@ gb_tree_popup (GbTree         *tree,
                     button->button,
                     button->time);
 
-  EXIT;
+  IDE_EXIT;
 }
 
 /**
@@ -242,7 +242,7 @@ gb_tree_selection_changed (GbTree           *tree,
   GbTreeNode *unselection;
   gint i;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_return_if_fail (GB_IS_TREE (tree));
   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
@@ -273,7 +273,7 @@ gb_tree_selection_changed (GbTree           *tree,
         }
     }
 
-  EXIT;
+  IDE_EXIT;
 }
 
 /**
@@ -416,7 +416,7 @@ gb_tree_add_builder_foreach_cb (GtkTreeModel *model,
   GbTreeNode *node = NULL;
   GbTreeBuilder *builder = (GbTreeBuilder *) user_data;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
   g_return_val_if_fail (path != NULL, FALSE);
@@ -426,7 +426,7 @@ gb_tree_add_builder_foreach_cb (GtkTreeModel *model,
   gb_tree_builder_build_node (builder, node);
   g_clear_object (&node);
 
-  RETURN (FALSE);
+  IDE_RETURN (FALSE);
 }
 
 /**
@@ -442,7 +442,7 @@ gb_tree_add_builder (GbTree        *tree,
 {
   GbTreePrivate *priv;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_return_if_fail (GB_IS_TREE (tree));
   g_return_if_fail (GB_IS_TREE_BUILDER (builder));
@@ -460,7 +460,7 @@ gb_tree_add_builder (GbTree        *tree,
   if (GB_TREE_BUILDER_GET_CLASS (builder)->added)
     GB_TREE_BUILDER_GET_CLASS (builder)->added (builder, GTK_WIDGET (tree));
 
-  EXIT;
+  IDE_EXIT;
 }
 
 /**
@@ -474,7 +474,7 @@ void
 gb_tree_remove_builder (GbTree        *tree,
                         GbTreeBuilder *builder)
 {
-  ENTRY;
+  IDE_ENTRY;
 
   g_return_if_fail (GB_IS_TREE (tree));
   g_return_if_fail (GB_IS_TREE_BUILDER (builder));
@@ -484,7 +484,7 @@ gb_tree_remove_builder (GbTree        *tree,
 
   g_ptr_array_remove (tree->priv->builders, builder);
 
-  EXIT;
+  IDE_EXIT;
 }
 
 /**
@@ -520,7 +520,7 @@ gb_tree_set_root (GbTree     *tree,
   GbTreeBuilder *builder;
   gint i;
 
-  ENTRY;
+  IDE_ENTRY;
 
   g_return_if_fail (GB_IS_TREE (tree));
 
@@ -540,7 +540,7 @@ gb_tree_set_root (GbTree     *tree,
         }
     }
 
-  EXIT;
+  IDE_EXIT;
 }
 
 void
diff --git a/src/util/gb-widget.c b/src/util/gb-widget.c
index e244678..4f73d84 100644
--- a/src/util/gb-widget.c
+++ b/src/util/gb-widget.c
@@ -16,9 +16,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <ide.h>
 #include <math.h>
 
-#include "gb-animation.h"
 #include "gb-cairo.h"
 #include "gb-rgba.h"
 #include "gb-widget.h"
@@ -176,14 +176,14 @@ gb_widget_fade_hide (GtkWidget *widget)
   if (gtk_widget_get_visible (widget))
     {
       frame_clock = gtk_widget_get_frame_clock (widget);
-      gb_object_animate_full (widget,
-                              GB_ANIMATION_LINEAR,
-                              1000,
-                              frame_clock,
-                              hide_callback,
-                              g_object_ref (widget),
-                              "opacity", 0.0,
-                              NULL);
+      ide_object_animate_full (widget,
+                               IDE_ANIMATION_LINEAR,
+                               1000,
+                               frame_clock,
+                               hide_callback,
+                               g_object_ref (widget),
+                               "opacity", 0.0,
+                               NULL);
     }
 }
 
@@ -199,14 +199,14 @@ gb_widget_fade_show (GtkWidget *widget)
       frame_clock = gtk_widget_get_frame_clock (widget);
       gtk_widget_set_opacity (widget, 0.0);
       gtk_widget_show (widget);
-      gb_object_animate_full (widget,
-                              GB_ANIMATION_LINEAR,
-                              500,
-                              frame_clock,
-                              NULL,
-                              NULL,
-                              "opacity", 1.0,
-                              NULL);
+      ide_object_animate_full (widget,
+                               IDE_ANIMATION_LINEAR,
+                               500,
+                               frame_clock,
+                               NULL,
+                               NULL,
+                               "opacity", 1.0,
+                               NULL);
     }
 }
 
@@ -274,74 +274,64 @@ gb_widget_get_context (GtkWidget *widget)
 }
 
 static void
-gb_widget_bind_context_notify (GtkWidget  *widget,
-                               GParamSpec *pspec,
-                               gpointer    user_data)
+gb_widget_notify_context (GtkWidget  *toplevel,
+                          GParamSpec *pspec,
+                          GtkWidget  *widget)
 {
-  GbWorkbench *workbench = (GbWorkbench *)widget;
-  GtkWidget *child = user_data;
-  IdeContext *context;
+  GbWidgetContextHandler handler;
+  IdeContext *context = NULL;
 
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-  g_return_if_fail (GTK_IS_WIDGET (child));
+  handler = g_object_get_data (G_OBJECT (widget), "GB_CONTEXT_HANDLER");
+  if (!handler)
+    return;
 
-  context = gb_workbench_get_context (workbench);
-  g_object_set (child, "context", context, NULL);
+  g_object_get (toplevel, "context", &context, NULL);
+  handler (widget, context);
+  g_clear_object (&context);
 }
 
 static void
-gb_widget_bind_context_hierarchy_changed (GtkWidget *widget,
-                                          GtkWidget *previous_toplevel,
-                                          gpointer   user_data)
+gb_widget_hierarchy_changed (GtkWidget *widget,
+                             GtkWidget *previous_toplevel,
+                             gpointer   user_data)
 {
-  GbWorkbench *workbench;
+  GtkWidget *toplevel;
 
-  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_assert (GTK_IS_WIDGET (widget));
 
-  if (GB_IS_WORKBENCH (previous_toplevel))
+  if (GTK_IS_WINDOW (previous_toplevel))
     g_signal_handlers_disconnect_by_func (previous_toplevel,
-                                          G_CALLBACK (gb_widget_bind_context_notify),
+                                          G_CALLBACK (gb_widget_notify_context),
                                           widget);
 
-  workbench = gb_widget_get_workbench (widget);
+  toplevel = gtk_widget_get_toplevel (widget);
 
-  if (workbench)
+  if (GTK_IS_WINDOW (toplevel))
     {
-      IdeContext *context;
-
-      g_signal_connect_object (workbench,
+      g_signal_connect_object (toplevel,
                                "notify::context",
-                               G_CALLBACK (gb_widget_bind_context_notify),
+                               G_CALLBACK (gb_widget_notify_context),
                                widget,
                                0);
-      context = gb_workbench_get_context (workbench);
-      g_object_set (widget, "context", context, NULL);
+      gb_widget_notify_context (toplevel, NULL, widget);
     }
 }
 
 void
-gb_widget_bind_context (GtkWidget *widget)
+gb_widget_set_context_handler (gpointer               widget,
+                               GbWidgetContextHandler handler)
 {
-  GParamSpec *pspec;
-  IdeContext *context;
+  GtkWidget *toplevel;
 
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
-  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (widget), "context");
-
-  if (!pspec || (pspec->value_type != IDE_TYPE_CONTEXT))
-    {
-      g_warning ("%s() requires a widget with a context property named "
-                 "\"context\".", G_STRFUNC);
-      return;
-    }
+  g_object_set_data (G_OBJECT (widget), "GB_CONTEXT_HANDLER", handler);
 
   g_signal_connect (widget,
                     "hierarchy-changed",
-                    G_CALLBACK (gb_widget_bind_context_hierarchy_changed),
+                    G_CALLBACK (gb_widget_hierarchy_changed),
                     NULL);
 
-  context = gb_widget_get_context (widget);
-  if (context)
-    g_object_set (widget, "context", context, NULL);
+  if ((toplevel = gtk_widget_get_toplevel (widget)))
+    gb_widget_hierarchy_changed (widget, NULL, NULL);
 }
diff --git a/src/util/gb-widget.h b/src/util/gb-widget.h
index 1257882..b3aa907 100644
--- a/src/util/gb-widget.h
+++ b/src/util/gb-widget.h
@@ -30,25 +30,30 @@ G_BEGIN_DECLS
   gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass), \
                                               "/org/gnome/builder/ui/"name)
 #define GB_WIDGET_CLASS_BIND(klass, TN, field) \
-  gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), \
-                                                TN, field)
-
-void             gb_widget_bind_context    (GtkWidget    *widget);
-IdeContext      *gb_widget_get_context     (GtkWidget    *widget);
-void             gb_widget_add_style_class (gpointer      widget,
-                                            const gchar  *class_name);
-cairo_surface_t *gb_widget_snapshot        (GtkWidget    *widget,
-                                            gint          width,
-                                            gint          height,
-                                            gdouble       alpha,
-                                            gboolean      draw_border);
-GbWorkbench     *gb_widget_get_workbench   (GtkWidget    *widget);
-void             gb_widget_fade_hide       (GtkWidget    *widget);
-void             gb_widget_fade_show       (GtkWidget    *widget);
-void             gb_widget_activate_action (GtkWidget    *widget,
-                                            const gchar  *prefix,
-                                            const gchar  *action_name,
-                                            GVariant     *parameter);
+  gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS (klass), TN, field)
+#define GB_WIDGET_CLASS_BIND_PRIVATE(klass, TN, field) \
+  gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), TN, field)
+
+typedef void (*GbWidgetContextHandler) (GtkWidget  *widget,
+                                        IdeContext *context);
+
+IdeContext      *gb_widget_get_context         (GtkWidget    *widget);
+void             gb_widget_add_style_class     (gpointer      widget,
+                                                const gchar  *class_name);
+cairo_surface_t *gb_widget_snapshot            (GtkWidget    *widget,
+                                                gint          width,
+                                                gint          height,
+                                                gdouble       alpha,
+                                                gboolean      draw_border);
+GbWorkbench     *gb_widget_get_workbench       (GtkWidget    *widget);
+void             gb_widget_fade_hide           (GtkWidget    *widget);
+void             gb_widget_fade_show           (GtkWidget    *widget);
+void             gb_widget_activate_action     (GtkWidget    *widget,
+                                                const gchar  *prefix,
+                                                const gchar  *action_name,
+                                                GVariant     *parameter);
+void             gb_widget_set_context_handler (gpointer      widget,
+                                                GbWidgetContextHandler handler);
 
 G_END_DECLS
 
diff --git a/src/views/gb-view-grid.c b/src/views/gb-view-grid.c
new file mode 100644
index 0000000..5c9e09b
--- /dev/null
+++ b/src/views/gb-view-grid.c
@@ -0,0 +1,631 @@
+/* gb-view-grid.c
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gb-view-grid"
+
+#include <glib/gi18n.h>
+
+#include "gb-view.h"
+#include "gb-view-grid.h"
+#include "gb-widget.h"
+
+struct _GbViewGrid
+{
+  GtkBin       parent_instance;
+  GbViewStack *last_focus;
+};
+
+G_DEFINE_TYPE (GbViewGrid, gb_view_grid, GTK_TYPE_BIN)
+
+static void gb_view_grid_reposition (GbViewGrid *self);
+
+GtkWidget *
+gb_view_grid_new (void)
+{
+  return g_object_new (GB_TYPE_VIEW_GRID, NULL);
+}
+
+static void
+gb_view_grid_remove_stack (GbViewGrid  *self,
+                           GbViewStack *stack)
+{
+  GtkWidget *new_focus;
+  GList *stacks;
+  GList *iter;
+
+  g_return_if_fail (GB_IS_VIEW_GRID (self));
+  g_return_if_fail (GB_IS_VIEW_STACK (stack));
+
+  stacks = gb_view_grid_get_stacks (self);
+
+  /* refuse to remove the stack if there is only one */
+  if (g_list_length (stacks) == 1)
+    return;
+
+  new_focus = gb_view_grid_get_stack_before (self, stack);
+  if (!new_focus)
+    new_focus = gb_view_grid_get_stack_after (self, stack);
+
+  for (iter = stacks; iter; iter = iter->next)
+    {
+      GbViewStack *item = GB_VIEW_STACK (iter->data);
+
+      if (item == stack)
+        {
+          if (!iter->prev)
+            {
+              GtkWidget *paned;
+              GtkWidget *child2;
+
+              /*
+               * This is the first stack in the grid. All we need to do to get
+               * to a consistent state is to take the child2 paned and replace
+               * our toplevel paned with it.
+               */
+              paned = gtk_bin_get_child (GTK_BIN (self));
+              child2 = gtk_paned_get_child2 (GTK_PANED (paned));
+              g_object_ref (child2);
+              gtk_container_remove (GTK_CONTAINER (paned), child2);
+              gtk_container_remove (GTK_CONTAINER (self), paned);
+              gtk_container_add (GTK_CONTAINER (self), child2);
+              g_object_unref (child2);
+            }
+          else if (!iter->next)
+            {
+              GtkWidget *paned;
+              GtkWidget *grandparent;
+
+              /*
+               * This is the last stack in the grid. All we need to do to get
+               * to a consistent state is remove our parent paned from the
+               * grandparent.
+               */
+              paned = gtk_widget_get_parent (GTK_WIDGET (stack));
+              grandparent = gtk_widget_get_parent (paned);
+              gtk_container_remove (GTK_CONTAINER (grandparent), paned);
+            }
+          else if (iter->next && iter->prev)
+            {
+              GtkWidget *grandparent;
+              GtkWidget *paned;
+              GtkWidget *child2;
+
+              /*
+               * This stack is somewhere in the middle. All we need to do to
+               * get into a consistent state is take our parent paneds child2
+               * and put it in our parent's location.
+               */
+              paned = gtk_widget_get_parent (GTK_WIDGET (stack));
+              grandparent = gtk_widget_get_parent (paned);
+              child2 = gtk_paned_get_child2 (GTK_PANED (paned));
+              g_object_ref (child2);
+              gtk_container_remove (GTK_CONTAINER (paned), child2);
+              gtk_container_remove (GTK_CONTAINER (grandparent), paned);
+              gtk_container_add (GTK_CONTAINER (grandparent), child2);
+              g_object_unref (child2);
+            }
+          else
+            g_assert_not_reached ();
+
+          gb_view_grid_reposition (self);
+
+          break;
+        }
+    }
+
+  if (new_focus)
+    gtk_widget_grab_focus (new_focus);
+
+  g_list_free (stacks);
+}
+
+static GtkWidget *
+gb_view_grid_get_first_stack (GbViewGrid *self)
+{
+  GtkWidget *child;
+
+  g_return_val_if_fail (GB_IS_VIEW_GRID (self), NULL);
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+
+  if (GTK_IS_PANED (child))
+    {
+      child = gtk_paned_get_child1 (GTK_PANED (child));
+      if (GB_IS_VIEW_STACK (child))
+        return child;
+    }
+
+  return NULL;
+}
+
+static GtkWidget *
+gb_view_grid_get_last_stack (GbViewGrid *self)
+{
+  GtkWidget *child;
+  GtkWidget *child2;
+
+  g_return_val_if_fail (GB_IS_VIEW_GRID (self), NULL);
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+
+  while (GTK_IS_PANED (child) &&
+         (child2 = gtk_paned_get_child2 (GTK_PANED (child))))
+    child = child2;
+
+  child = gtk_paned_get_child1 (GTK_PANED (child));
+
+  if (GB_IS_VIEW_STACK (child))
+    return child;
+
+  return NULL;
+}
+
+static void
+gb_view_grid_focus_neighbor (GbViewGrid       *self,
+                             GtkDirectionType  dir,
+                             GbViewStack      *stack)
+{
+  GtkWidget *neighbor;
+
+  g_return_if_fail (GB_IS_VIEW_GRID (self));
+  g_return_if_fail (GB_IS_VIEW_STACK (stack));
+
+  switch ((int)dir)
+    {
+    case GTK_DIR_LEFT:
+      neighbor = gb_view_grid_get_stack_before (self, stack);
+      if (!neighbor)
+        neighbor = gb_view_grid_get_last_stack (self);
+      break;
+
+    case GTK_DIR_RIGHT:
+      neighbor = gb_view_grid_get_stack_after (self, stack);
+      if (!neighbor)
+        neighbor = gb_view_grid_get_first_stack (self);
+      break;
+
+    default:
+      neighbor = NULL;
+      break;
+    }
+
+  if (neighbor != NULL)
+    gtk_widget_grab_focus (neighbor);
+}
+
+static void
+gb_view_grid_stack_empty (GbViewGrid  *self,
+                          GbViewStack *stack)
+{
+  GList *stacks;
+
+  g_return_if_fail (GB_IS_VIEW_GRID (self));
+  g_return_if_fail (GB_IS_VIEW_STACK (stack));
+
+  stacks = gb_view_grid_get_stacks (self);
+
+  g_assert (stacks != NULL);
+
+  if (g_list_length (stacks) == 1)
+    goto cleanup;
+
+  gb_view_grid_focus_neighbor (self, GTK_DIR_LEFT, stack);
+  gb_view_grid_remove_stack (self, stack);
+
+cleanup:
+  g_list_free (stacks);
+}
+
+static GtkPaned *
+gb_view_grid_create_paned (GbViewGrid *self)
+{
+  return g_object_new (GTK_TYPE_PANED,
+                       "orientation", GTK_ORIENTATION_HORIZONTAL,
+                       "visible", TRUE,
+                       NULL);
+}
+
+static GbViewStack *
+gb_view_grid_create_stack (GbViewGrid *self)
+{
+  GbViewStack *stack;
+
+  g_assert (GB_IS_VIEW_GRID (self));
+
+  stack = g_object_new (GB_TYPE_VIEW_STACK,
+                        "visible", TRUE,
+                        NULL);
+
+  g_signal_connect_object (stack,
+                           "empty",
+                           G_CALLBACK (gb_view_grid_stack_empty),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  return stack;
+}
+
+static void
+gb_view_grid_reposition (GbViewGrid *self)
+{
+  GtkAllocation alloc;
+  GtkWidget *paned;
+  GtkWidget *stack;
+  guint count = 0;
+  guint position;
+
+  g_return_if_fail (GB_IS_VIEW_GRID (self));
+
+  gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
+
+  paned = gtk_bin_get_child (GTK_BIN (self));
+
+  if (!GTK_IS_PANED (paned))
+    return;
+
+  stack = gtk_paned_get_child1 (GTK_PANED (paned));
+  g_assert (GB_IS_VIEW_STACK (stack));
+
+  do
+    {
+      count++;
+      stack = gb_view_grid_get_stack_after (self, GB_VIEW_STACK (stack));
+      g_assert (!stack || GB_IS_VIEW_STACK (stack));
+    }
+  while (stack);
+
+  position = alloc.width / count;
+
+  stack = gtk_paned_get_child1 (GTK_PANED (paned));
+  g_assert (GB_IS_VIEW_STACK (stack));
+  do
+    {
+      paned = gtk_widget_get_parent (stack);
+      gtk_paned_set_position (GTK_PANED (paned), position);
+      stack = gb_view_grid_get_stack_after (self, GB_VIEW_STACK (stack));
+      g_assert (!stack|| GB_IS_VIEW_STACK (stack));
+    }
+  while (stack);
+}
+
+/**
+ * gb_view_grid_get_stacks:
+ *
+ * Fetches all of the stacks in the grid. The resulting #GList should be
+ * freed with g_list_free().
+ *
+ * Returns: (transfer container) (element-type GbViewStack*): A #GList.
+ */
+GList *
+gb_view_grid_get_stacks (GbViewGrid *self)
+{
+  GtkWidget *paned;
+  GList *list = NULL;
+
+  g_return_val_if_fail (GB_IS_VIEW_GRID (self), NULL);
+
+  paned = gtk_bin_get_child (GTK_BIN (self));
+
+  while (paned)
+    {
+      GtkWidget *stack;
+
+      stack = gtk_paned_get_child1 (GTK_PANED (paned));
+
+      if (GB_IS_VIEW_STACK (stack))
+        list = g_list_append (list, stack);
+
+      paned = gtk_paned_get_child2 (GTK_PANED (paned));
+    }
+
+#ifndef IDE_DISABLE_TRACE
+  {
+    GList *iter;
+
+    for (iter = list; iter; iter = iter->next)
+      g_assert (GB_IS_VIEW_STACK (iter->data));
+  }
+#endif
+
+  return list;
+}
+
+GtkWidget *
+gb_view_grid_add_stack_before (GbViewGrid  *self,
+                               GbViewStack *stack)
+{
+  GbViewStack *new_stack;
+  GtkWidget *parent;
+  GtkWidget *grandparent;
+  GtkPaned *new_paned;
+
+  g_return_val_if_fail (GB_IS_VIEW_GRID (self), NULL);
+
+  new_paned = gb_view_grid_create_paned (self);
+  new_stack = gb_view_grid_create_stack (self);
+  gtk_container_add (GTK_CONTAINER (new_paned), GTK_WIDGET (new_stack));
+
+  parent = gtk_widget_get_parent (GTK_WIDGET (stack));
+  grandparent = gtk_widget_get_parent (GTK_WIDGET (parent));
+
+  if (GTK_IS_PANED (grandparent))
+    {
+      g_object_ref (parent);
+      gtk_container_remove (GTK_CONTAINER (grandparent), GTK_WIDGET (parent));
+      gtk_container_add_with_properties (GTK_CONTAINER (grandparent),
+                                         GTK_WIDGET (new_paned),
+                                         "shrink", FALSE,
+                                         "resize", TRUE,
+                                         NULL);
+      gtk_container_add_with_properties (GTK_CONTAINER (new_paned),
+                                         GTK_WIDGET (parent),
+                                         "shrink", FALSE,
+                                         "resize", TRUE,
+                                         NULL);
+      g_object_unref (parent);
+    }
+  else if (GB_IS_VIEW_GRID (grandparent))
+    {
+      g_object_ref (parent);
+      gtk_container_remove (GTK_CONTAINER (grandparent), GTK_WIDGET (parent));
+      gtk_container_add (GTK_CONTAINER (grandparent), GTK_WIDGET (new_paned));
+      gtk_container_add_with_properties (GTK_CONTAINER (new_paned), parent,
+                                         "shrink", FALSE,
+                                         "resize", TRUE,
+                                         NULL);
+      g_object_unref (parent);
+    }
+  else
+    g_assert_not_reached ();
+
+  gb_view_grid_reposition (self);
+
+  return GTK_WIDGET (new_stack);
+}
+
+GtkWidget *
+gb_view_grid_add_stack_after (GbViewGrid  *self,
+                              GbViewStack *stack)
+{
+  GbViewStack *new_stack;
+  GtkWidget *parent;
+  GtkPaned *new_paned;
+
+  g_return_val_if_fail (GB_IS_VIEW_GRID (self), NULL);
+
+  new_paned = gb_view_grid_create_paned (self);
+  new_stack = gb_view_grid_create_stack (self);
+  gtk_container_add (GTK_CONTAINER (new_paned), GTK_WIDGET (new_stack));
+
+  parent = gtk_widget_get_parent (GTK_WIDGET (stack));
+
+  if (GTK_IS_PANED (parent))
+    {
+      GtkWidget *child2;
+
+      child2 = gtk_paned_get_child2 (GTK_PANED (parent));
+
+      if (child2)
+        {
+          g_object_ref (child2);
+          gtk_container_remove (GTK_CONTAINER (parent), child2);
+        }
+
+      gtk_container_add_with_properties (GTK_CONTAINER (parent),
+                                         GTK_WIDGET (new_paned),
+                                         "shrink", FALSE,
+                                         "resize", TRUE,
+                                         NULL);
+
+      if (child2)
+        {
+          gtk_container_add_with_properties (GTK_CONTAINER (new_paned), child2,
+                                             "shrink", FALSE,
+                                             "resize", TRUE,
+                                             NULL);
+          g_object_unref (child2);
+        }
+    }
+  else
+    g_assert_not_reached ();
+
+  gb_view_grid_reposition (self);
+
+  return GTK_WIDGET (new_stack);
+}
+
+GtkWidget *
+gb_view_grid_get_stack_before (GbViewGrid  *self,
+                               GbViewStack *stack)
+{
+  GtkWidget *parent;
+
+  g_return_val_if_fail (GB_IS_VIEW_GRID (self), NULL);
+  g_return_val_if_fail (GB_IS_VIEW_STACK (stack), NULL);
+
+  parent = gtk_widget_get_parent (GTK_WIDGET (stack));
+
+  if (GTK_IS_PANED (parent))
+    {
+      parent = gtk_widget_get_parent (parent);
+      if (GTK_IS_PANED (parent))
+        return gtk_paned_get_child1 (GTK_PANED (parent));
+    }
+
+  return NULL;
+}
+
+GtkWidget *
+gb_view_grid_get_stack_after (GbViewGrid  *self,
+                              GbViewStack *stack)
+{
+  GtkWidget *parent;
+
+  g_return_val_if_fail (GB_IS_VIEW_GRID (self), NULL);
+  g_return_val_if_fail (GB_IS_VIEW_STACK (stack), NULL);
+
+  parent = gtk_widget_get_parent (GTK_WIDGET (stack));
+
+  if (GTK_IS_PANED (parent))
+    {
+      GtkWidget *child2;
+
+      child2 = gtk_paned_get_child2 (GTK_PANED (parent));
+      if (GTK_IS_PANED (child2))
+        return gtk_paned_get_child1 (GTK_PANED (child2));
+    }
+
+  return NULL;
+}
+
+void
+gb_view_grid_focus_document (GbViewGrid *self,
+                             GbDocument *document)
+{
+  GList *stacks;
+  GList *iter;
+
+  g_return_if_fail (GB_IS_VIEW_GRID (self));
+  g_return_if_fail (GB_IS_DOCUMENT (document));
+
+  stacks = gb_view_grid_get_stacks (self);
+
+  for (iter = stacks; iter; iter = iter->next)
+    {
+      GbViewStack *stack = iter->data;
+      GtkWidget *view;
+
+      view = gb_view_stack_find_with_document (stack, document);
+
+      if (view)
+        {
+          gb_view_stack_focus_document (stack, document);
+          goto cleanup;
+        }
+    }
+
+  g_assert (stacks);
+
+  if (self->last_focus)
+    gb_view_stack_focus_document (self->last_focus, document);
+  else
+    gb_view_stack_focus_document (stacks->data, document);
+
+cleanup:
+  g_list_free (stacks);
+}
+
+static void
+gb_view_grid_grab_focus (GtkWidget *widget)
+{
+  GbViewGrid *self = (GbViewGrid *)widget;
+  GList *stacks;
+
+  g_return_if_fail (GB_IS_VIEW_GRID (self));
+
+  if (self->last_focus)
+    {
+      gtk_widget_grab_focus (GTK_WIDGET (self->last_focus));
+      return;
+    }
+
+  stacks = gb_view_grid_get_stacks (self);
+  if (stacks)
+    gtk_widget_grab_focus (stacks->data);
+  g_list_free (stacks);
+}
+
+static void
+gb_view_grid_toplevel_set_focus (GtkWidget  *toplevel,
+                                 GtkWidget  *focus,
+                                 GbViewGrid *self)
+{
+  g_return_if_fail (GB_IS_VIEW_GRID (self));
+
+  if (focus && gtk_widget_is_ancestor (focus, GTK_WIDGET (self)))
+    {
+      GtkWidget *parent = focus;
+
+      while (parent && !GB_IS_VIEW_STACK (parent))
+        parent = gtk_widget_get_parent (parent);
+
+      if (GB_IS_VIEW_STACK (parent))
+        ide_set_weak_pointer (&self->last_focus, GB_VIEW_STACK (parent));
+    }
+}
+
+static void
+gb_view_grid_hierarchy_changed (GtkWidget *widget,
+                                GtkWidget *previous_toplevel)
+{
+  GbViewGrid *self = (GbViewGrid *)widget;
+  GtkWidget *toplevel;
+
+  g_return_if_fail (GB_IS_VIEW_GRID (self));
+
+  if (GTK_IS_WINDOW (previous_toplevel))
+    g_signal_handlers_disconnect_by_func (previous_toplevel,
+                                          G_CALLBACK (gb_view_grid_toplevel_set_focus),
+                                          self);
+
+  toplevel = gtk_widget_get_toplevel (widget);
+  if (GTK_IS_WINDOW (toplevel))
+    g_signal_connect (toplevel,
+                      "set-focus",
+                      G_CALLBACK (gb_view_grid_toplevel_set_focus),
+                      self);
+}
+
+static void
+gb_view_grid_finalize (GObject *object)
+{
+  GbViewGrid *self = (GbViewGrid *)object;
+
+  ide_clear_weak_pointer (&self->last_focus);
+
+  G_OBJECT_CLASS (gb_view_grid_parent_class)->finalize (object);
+}
+
+static void
+gb_view_grid_class_init (GbViewGridClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->finalize = gb_view_grid_finalize;
+
+  widget_class->grab_focus = gb_view_grid_grab_focus;
+  widget_class->hierarchy_changed = gb_view_grid_hierarchy_changed;
+}
+
+static void
+gb_view_grid_init (GbViewGrid *self)
+{
+  GbViewStack *stack;
+  GtkPaned *paned;
+
+  paned = gb_view_grid_create_paned (self);
+  stack = gb_view_grid_create_stack (self);
+
+  gtk_container_add_with_properties (GTK_CONTAINER (paned), GTK_WIDGET (stack),
+                                     "shrink", FALSE,
+                                     "resize", TRUE,
+                                     NULL);
+
+  gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (paned));
+}
diff --git a/src/views/gb-view-grid.h b/src/views/gb-view-grid.h
new file mode 100644
index 0000000..acf915c
--- /dev/null
+++ b/src/views/gb-view-grid.h
@@ -0,0 +1,48 @@
+/* gb-document-grid.h
+ *
+ * Copyright (C) 2014-2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_DOCUMENT_GRID_H
+#define GB_DOCUMENT_GRID_H
+
+#include <gtk/gtk.h>
+
+#include "gb-document.h"
+#include "gb-view-stack.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_VIEW_GRID (gb_view_grid_get_type())
+
+G_DECLARE_FINAL_TYPE (GbViewGrid, gb_view_grid, GB, VIEW_GRID, GtkBin)
+
+GtkWidget *gb_view_grid_new                  (void);
+GtkWidget *gb_view_grid_add_stack_after      (GbViewGrid  *grid,
+                                              GbViewStack *stack);
+GtkWidget *gb_view_grid_add_stack_before     (GbViewGrid  *grid,
+                                              GbViewStack *stack);
+GtkWidget *gb_view_grid_get_stack_after      (GbViewGrid  *grid,
+                                              GbViewStack *stack);
+GtkWidget *gb_view_grid_get_stack_before     (GbViewGrid  *grid,
+                                              GbViewStack *stack);
+GList     *gb_view_grid_get_stacks           (GbViewGrid  *grid);
+void       gb_view_grid_focus_document       (GbViewGrid  *grid,
+                                              GbDocument  *document);
+
+G_END_DECLS
+
+#endif /* GB_DOCUMENT_GRID_H */
diff --git a/src/views/gb-view-stack-actions.c b/src/views/gb-view-stack-actions.c
new file mode 100644
index 0000000..6426426
--- /dev/null
+++ b/src/views/gb-view-stack-actions.c
@@ -0,0 +1,125 @@
+/* gb-view-stack-actions.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gb-view-stack.h"
+#include "gb-view-stack-actions.h"
+#include "gb-view-stack-private.h"
+
+static void
+gb_view_stack_actions_close (GSimpleAction *action,
+                             GVariant      *param,
+                             gpointer       user_data)
+{
+  GbViewStack *self = user_data;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+}
+
+static void
+gb_view_stack_actions_move_left (GSimpleAction *action,
+                                 GVariant      *param,
+                                 gpointer       user_data)
+{
+  GbViewStack *self = user_data;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+}
+
+static void
+gb_view_stack_actions_move_right (GSimpleAction *action,
+                                  GVariant      *param,
+                                  gpointer       user_data)
+{
+  GbViewStack *self = user_data;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+}
+
+static void
+gb_view_stack_actions_save (GSimpleAction *action,
+                            GVariant      *param,
+                            gpointer       user_data)
+{
+  GbViewStack *self = user_data;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+}
+
+static void
+gb_view_stack_actions_save_as (GSimpleAction *action,
+                               GVariant      *param,
+                               gpointer       user_data)
+{
+  GbViewStack *self = user_data;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+}
+
+static void
+gb_view_stack_actions_split_down (GSimpleAction *action,
+                                  GVariant      *param,
+                                  gpointer       user_data)
+{
+  GbViewStack *self = user_data;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+}
+
+static void
+gb_view_stack_actions_split_left (GSimpleAction *action,
+                                  GVariant      *param,
+                                  gpointer       user_data)
+{
+  GbViewStack *self = user_data;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+}
+
+static void
+gb_view_stack_actions_split_right (GSimpleAction *action,
+                                   GVariant      *param,
+                                   gpointer       user_data)
+{
+  GbViewStack *self = user_data;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+}
+
+static const GActionEntry gGbViewStackActions[] = {
+  { "close",       gb_view_stack_actions_close },
+  { "move-left",   gb_view_stack_actions_move_left },
+  { "move-right",  gb_view_stack_actions_move_right },
+  { "save",        gb_view_stack_actions_save },
+  { "save-as",     gb_view_stack_actions_save_as },
+  { "split-down",  gb_view_stack_actions_split_down },
+  { "split-left",  gb_view_stack_actions_split_left },
+  { "split-right", gb_view_stack_actions_split_right },
+};
+
+void
+gb_view_stack_actions_init (GbViewStack *self)
+{
+  GSimpleActionGroup *actions;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+
+  actions = g_simple_action_group_new ();
+  g_action_map_add_action_entries (G_ACTION_MAP (actions), gGbViewStackActions,
+                                   G_N_ELEMENTS (gGbViewStackActions), self);
+  gtk_widget_insert_action_group (GTK_WIDGET (self), "view", G_ACTION_GROUP (actions));
+}
diff --git a/src/views/gb-view-stack-actions.h b/src/views/gb-view-stack-actions.h
new file mode 100644
index 0000000..8b51a80
--- /dev/null
+++ b/src/views/gb-view-stack-actions.h
@@ -0,0 +1,30 @@
+/* gb-view-stack-actions.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_VIEW_STACK_ACTIONS_H
+#define GB_VIEW_STACK_ACTIONS_H
+
+#include "gb-view-stack.h"
+
+G_BEGIN_DECLS
+
+void gb_view_stack_actions_init (GbViewStack *self);
+
+G_END_DECLS
+
+#endif /* GB_VIEW_STACK_ACTIONS_H */
diff --git a/src/views/gb-view-stack-private.h b/src/views/gb-view-stack-private.h
new file mode 100644
index 0000000..c837eb2
--- /dev/null
+++ b/src/views/gb-view-stack-private.h
@@ -0,0 +1,49 @@
+/* gb-view-stack-private.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_VIEW_STACK_PRIVATE_H
+#define GB_VIEW_STACK_PRIVATE_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+struct _GbViewStack
+{
+  GtkBin      parent_instance;
+
+  GList      *focus_history;
+
+  /* Weak references */
+  GtkWidget  *active_view;
+  GBinding   *title_binding;
+
+  /* Template references */
+  GtkStack   *controls_stack;
+  GtkButton  *go_backward;
+  GtkButton  *go_forward;
+  GtkPopover *popover;
+  GtkStack   *stack;
+  GtkLabel   *title_label;
+
+  guint       focused : 1;
+};
+
+G_END_DECLS
+
+#endif /* GB_VIEW_STACK_PRIVATE_H */
diff --git a/src/views/gb-view-stack.c b/src/views/gb-view-stack.c
new file mode 100644
index 0000000..e78cc25
--- /dev/null
+++ b/src/views/gb-view-stack.c
@@ -0,0 +1,409 @@
+/* gb-view-stack.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n.h>
+#include <ide.h>
+
+#include "gb-view.h"
+#include "gb-view-stack.h"
+#include "gb-view-stack-actions.h"
+#include "gb-view-stack-private.h"
+#include "gb-widget.h"
+
+G_DEFINE_TYPE (GbViewStack, gb_view_stack, GTK_TYPE_BIN)
+
+enum {
+  PROP_0,
+  PROP_ACTIVE_VIEW,
+  LAST_PROP
+};
+
+enum {
+  EMPTY,
+  LAST_SIGNAL
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+static guint       gSignals [LAST_SIGNAL];
+
+static void
+gb_view_stack_add (GtkContainer *container,
+                   GtkWidget    *child)
+{
+  GbViewStack *self = (GbViewStack *)container;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+
+  if (GB_IS_VIEW (child))
+    {
+      GtkWidget *controls;
+
+      self->focus_history = g_list_prepend (self->focus_history, child);
+      controls = gb_view_get_controls (GB_VIEW (child));
+      if (controls)
+        gtk_container_add (GTK_CONTAINER (self->controls_stack), controls);
+      gtk_container_add (GTK_CONTAINER (self->stack), child);
+      gtk_stack_set_visible_child (self->stack, child);
+    }
+  else
+    {
+      GTK_CONTAINER_CLASS (gb_view_stack_parent_class)->add (container, child);
+    }
+}
+
+static void
+gb_view_stack_remove (GtkContainer *container,
+                      GtkWidget    *child)
+{
+  GbViewStack *self = (GbViewStack *)container;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+
+  if (GB_IS_VIEW (child))
+    {
+      self->focus_history = g_list_remove (self->focus_history, child);
+      gtk_container_remove (GTK_CONTAINER (self->stack), child);
+      if (self->focus_history)
+        gtk_stack_set_visible_child (self->stack, self->focus_history->data);
+      else
+        g_signal_emit (self, gSignals [EMPTY], 0);
+    }
+  else
+    {
+      GTK_CONTAINER_CLASS (gb_view_stack_parent_class)->remove (container, child);
+    }
+}
+
+static void
+gb_view_stack__notify_visible_child (GbViewStack *self,
+                                     GParamSpec  *pspec,
+                                     GtkStack    *stack)
+{
+  GtkWidget *visible_child;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+  g_assert (GTK_IS_STACK (stack));
+
+  visible_child = gtk_stack_get_visible_child (stack);
+
+  gb_view_stack_set_active_view (self, visible_child);
+}
+
+static void
+gb_view_stack__set_focus (GbViewStack *self,
+                          GtkWidget   *focus_widget,
+                          GtkWindow   *toplevel)
+{
+  g_assert (GB_IS_VIEW_STACK (self));
+  g_assert (!focus_widget || GTK_IS_WIDGET (focus_widget));
+  g_assert (!toplevel || GTK_IS_WIDGET (toplevel));
+
+  self->focused = focus_widget && gtk_widget_is_ancestor (GTK_WIDGET (self), focus_widget);
+}
+
+static void
+gb_view_stack_hierarchy_changed (GtkWidget *widget,
+                                 GtkWidget *previous_toplevel)
+{
+  GbViewStack *self = (GbViewStack *)widget;
+  GtkWidget *toplevel;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+  g_assert (!previous_toplevel || GTK_IS_WIDGET (previous_toplevel));
+
+  if (GTK_IS_WINDOW (previous_toplevel))
+    g_signal_handlers_disconnect_by_func (previous_toplevel,
+                                          G_CALLBACK (gb_view_stack__set_focus),
+                                          self);
+
+  toplevel = gtk_widget_get_toplevel (widget);
+  if (GTK_IS_WINDOW (toplevel))
+    g_signal_connect_object (toplevel,
+                             "set-focus",
+                             G_CALLBACK (gb_view_stack__set_focus),
+                             self,
+                             G_CONNECT_SWAPPED);
+}
+
+static gboolean
+gb_view_stack_draw (GtkWidget *widget,
+                    cairo_t   *cr)
+{
+  GbViewStack *self = (GbViewStack *)widget;
+  GtkStyleContext *style_context;
+  gboolean ret;
+
+  g_assert (GB_IS_VIEW_STACK (self));
+  g_assert (cr);
+
+  style_context = gtk_widget_get_style_context (widget);
+  gtk_style_context_save (style_context);
+  if (self->focused)
+    gtk_style_context_add_class (style_context, "focused");
+  ret = GTK_WIDGET_CLASS (gb_view_stack_parent_class)->draw (widget, cr);
+  gtk_style_context_restore (style_context);
+
+  return ret;
+}
+
+static void
+gb_view_stack_constructed (GObject *object)
+{
+  GbViewStack *self = (GbViewStack *)object;
+
+  G_OBJECT_CLASS (gb_view_stack_parent_class)->constructed (object);
+
+  gb_view_stack_actions_init (self);
+}
+
+static void
+gb_view_stack_finalize (GObject *object)
+{
+  GbViewStack *self = (GbViewStack *)object;
+
+  g_clear_pointer (&self->focus_history, g_list_free);
+  ide_clear_weak_pointer (&self->title_binding);
+  ide_clear_weak_pointer (&self->active_view);
+
+  G_OBJECT_CLASS (gb_view_stack_parent_class)->finalize (object);
+}
+
+static void
+gb_view_stack_get_property (GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  GbViewStack *self = GB_VIEW_STACK (object);
+
+  switch (prop_id)
+    {
+    case PROP_ACTIVE_VIEW:
+      g_value_set_object (value, gb_view_stack_get_active_view (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gb_view_stack_set_property (GObject      *object,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  GbViewStack *self = GB_VIEW_STACK (object);
+
+  switch (prop_id)
+    {
+    case PROP_ACTIVE_VIEW:
+      gb_view_stack_set_active_view (self, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gb_view_stack_class_init (GbViewStackClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+  object_class->constructed = gb_view_stack_constructed;
+  object_class->finalize = gb_view_stack_finalize;
+  object_class->get_property = gb_view_stack_get_property;
+  object_class->set_property = gb_view_stack_set_property;
+
+  widget_class->draw = gb_view_stack_draw;
+  widget_class->hierarchy_changed = gb_view_stack_hierarchy_changed;
+
+  container_class->add = gb_view_stack_add;
+  container_class->remove = gb_view_stack_remove;
+
+  gParamSpecs [PROP_ACTIVE_VIEW] =
+    g_param_spec_object ("active-view",
+                         _("Active View"),
+                         _("The active view."),
+                         GB_TYPE_VIEW,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_ACTIVE_VIEW, gParamSpecs [PROP_ACTIVE_VIEW]);
+
+  gSignals [EMPTY] = g_signal_new ("empty",
+                                   G_TYPE_FROM_CLASS (klass),
+                                   G_SIGNAL_RUN_LAST,
+                                   0,
+                                   NULL, NULL,
+                                   g_cclosure_marshal_VOID__VOID,
+                                   G_TYPE_NONE,
+                                   0);
+
+  GB_WIDGET_CLASS_TEMPLATE (klass, "gb-view-stack.ui");
+  GB_WIDGET_CLASS_BIND (klass, GbViewStack, controls_stack);
+  GB_WIDGET_CLASS_BIND (klass, GbViewStack, go_backward);
+  GB_WIDGET_CLASS_BIND (klass, GbViewStack, go_forward);
+  GB_WIDGET_CLASS_BIND (klass, GbViewStack, popover);
+  GB_WIDGET_CLASS_BIND (klass, GbViewStack, stack);
+  GB_WIDGET_CLASS_BIND (klass, GbViewStack, title_label);
+}
+
+static void
+gb_view_stack_init (GbViewStack *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  g_signal_connect_object (self->stack,
+                           "notify::visible-child",
+                           G_CALLBACK (gb_view_stack__notify_visible_child),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+GtkWidget *
+gb_view_stack_new (void)
+{
+  return g_object_new (GB_TYPE_VIEW_STACK, NULL);
+}
+
+GtkWidget *
+gb_view_stack_get_active_view (GbViewStack *self)
+{
+  g_return_val_if_fail (GB_IS_VIEW_STACK (self), NULL);
+
+  return self->active_view;
+}
+
+void
+gb_view_stack_set_active_view (GbViewStack *self,
+                               GtkWidget   *active_view)
+{
+  g_return_if_fail (GB_IS_VIEW_STACK (self));
+  g_return_if_fail (!active_view || GB_IS_VIEW (active_view));
+
+  if (self->active_view != active_view)
+    {
+      if (self->active_view)
+        {
+          self->focus_history = g_list_remove (self->focus_history, self->active_view);
+          if (self->title_binding)
+            g_binding_unbind (self->title_binding);
+          ide_clear_weak_pointer (&self->title_binding);
+          gtk_label_set_label (self->title_label, NULL);
+          ide_clear_weak_pointer (&self->active_view);
+          gtk_widget_hide (GTK_WIDGET (self->controls_stack));
+        }
+
+      if (active_view)
+        {
+          GtkWidget *controls;
+          GBinding *binding;
+
+          self->focus_history = g_list_prepend (self->focus_history, active_view);
+          if (active_view != gtk_stack_get_visible_child (self->stack))
+            gtk_stack_set_visible_child (self->stack, active_view);
+          binding = g_object_bind_property (active_view, "title",
+                                            self->title_label, "label",
+                                            G_BINDING_SYNC_CREATE);
+          ide_set_weak_pointer (&self->title_binding, binding);
+          ide_set_weak_pointer (&self->active_view, active_view);
+          controls = gb_view_get_controls (GB_VIEW (active_view));
+          if (controls)
+            {
+              gtk_stack_set_visible_child (self->controls_stack, controls);
+              gtk_widget_show (GTK_WIDGET (self->controls_stack));
+            }
+        }
+
+      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_ACTIVE_VIEW]);
+    }
+}
+
+GtkWidget *
+gb_view_stack_find_with_document (GbViewStack *self,
+                                  GbDocument  *document)
+{
+  GtkWidget *ret = NULL;
+  GList *iter;
+  GList *children;
+
+  g_return_val_if_fail (GB_IS_VIEW_STACK (self), NULL);
+  g_return_val_if_fail (GB_IS_DOCUMENT (document), NULL);
+
+  children = gtk_container_get_children (GTK_CONTAINER (self->stack));
+
+  for (iter = children; iter; iter = iter->next)
+    {
+      GbView *view = iter->data;
+      GbDocument *item;
+
+      g_assert (GB_IS_VIEW (view));
+
+      item = gb_view_get_document (view);
+
+      if (item == document)
+        {
+          ret = GTK_WIDGET (view);
+          break;
+        }
+    }
+
+  g_list_free (children);
+
+  return ret;
+}
+
+void
+gb_view_stack_focus_document (GbViewStack *self,
+                              GbDocument  *document)
+{
+  GtkWidget *view;
+
+  g_return_if_fail (GB_IS_VIEW_STACK (self));
+  g_return_if_fail (GB_IS_DOCUMENT (document));
+
+  view = gb_view_stack_find_with_document (self, document);
+
+  if (view != NULL && GB_IS_VIEW (view))
+    {
+      gb_view_stack_set_active_view (self, view);
+      return;
+    }
+
+  view = gb_document_create_view (document);
+
+  if (view == NULL)
+    {
+      g_warning ("Document %s failed to create a view",
+                 gb_document_get_title (document));
+      return;
+    }
+
+  if (!GB_IS_VIEW (view))
+    {
+      g_warning ("Document %s did not create a GbView instance.",
+                 gb_document_get_title (document));
+      return;
+    }
+
+  gb_view_stack_add (GTK_CONTAINER (self), view);
+  gb_view_stack_set_active_view (self, view);
+  gtk_widget_grab_focus (view);
+}
diff --git a/src/views/gb-view-stack.h b/src/views/gb-view-stack.h
new file mode 100644
index 0000000..07e0ea9
--- /dev/null
+++ b/src/views/gb-view-stack.h
@@ -0,0 +1,43 @@
+/* gb-view-stack.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_VIEW_STACK_H
+#define GB_VIEW_STACK_H
+
+#include <gtk/gtk.h>
+
+#include "gb-document.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_VIEW_STACK (gb_view_stack_get_type())
+
+G_DECLARE_FINAL_TYPE (GbViewStack, gb_view_stack, GB, VIEW_STACK, GtkBin)
+
+GtkWidget *gb_view_stack_new                (void);
+GtkWidget *gb_view_stack_get_active_view    (GbViewStack *self);
+void       gb_view_stack_set_active_view    (GbViewStack *self,
+                                             GtkWidget   *active_view);
+GtkWidget *gb_view_stack_find_with_document (GbViewStack *self,
+                                             GbDocument  *document);
+void       gb_view_stack_focus_document     (GbViewStack *self,
+                                             GbDocument  *document);
+
+G_END_DECLS
+
+#endif /* GB_VIEW_STACK_H */
diff --git a/src/views/gb-view.c b/src/views/gb-view.c
new file mode 100644
index 0000000..963e184
--- /dev/null
+++ b/src/views/gb-view.c
@@ -0,0 +1,240 @@
+/* gb-view.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n.h>
+
+#include "gb-view.h"
+
+typedef struct
+{
+  GtkBox *controls;
+} GbViewPrivate;
+
+static void buildable_iface_init (GtkBuildableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GbView, gb_view, GTK_TYPE_BOX,
+                         G_ADD_PRIVATE (GbView)
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init))
+
+enum {
+  PROP_0,
+  PROP_CAN_SPLIT,
+  PROP_DOCUMENT,
+  PROP_TITLE,
+  LAST_PROP
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+
+/**
+ * gb_view_get_can_split:
+ * @self: A #GbView.
+ *
+ * Checks if @self can create a split view. If so, %TRUE is returned. Otherwise, %FALSE.
+ *
+ * Returns: %TRUE if @self can create a split.
+ */
+gboolean
+gb_view_get_can_split (GbView *self)
+{
+  g_return_val_if_fail (GB_IS_VIEW (self), FALSE);
+
+  if (GB_VIEW_GET_CLASS (self)->get_can_split)
+    return GB_VIEW_GET_CLASS (self)->get_can_split (self);
+
+  return FALSE;
+}
+
+/**
+ * gb_view_create_split:
+ * @self: A #GbView.
+ *
+ * Creates a new view similar to @self that can be displayed in a split.
+ * If the view does not support splits, %NULL will be returned.
+ *
+ * Returns: (transfer full): A #GbView.
+ */
+GbView *
+gb_view_create_split (GbView *self)
+{
+  g_return_val_if_fail (GB_IS_VIEW (self), NULL);
+
+  if (GB_VIEW_GET_CLASS (self)->create_split)
+    return GB_VIEW_GET_CLASS (self)->create_split (self);
+
+  return NULL;
+}
+
+/**
+ * gb_view_get_controls:
+ * @self: A #GbView.
+ *
+ * Gets the controls for the view.
+ *
+ * Returns: (transfer none) (nullable): A #GtkWidget.
+ */
+GtkWidget *
+gb_view_get_controls (GbView *self)
+{
+  GbViewPrivate *priv = gb_view_get_instance_private (self);
+
+  g_return_val_if_fail (GB_IS_VIEW (self), NULL);
+
+  return GTK_WIDGET (priv->controls);
+}
+
+/**
+ * gb_view_get_document:
+ * @self: A #GbView.
+ *
+ * Gets the document for the view.
+ *
+ * Returns: (transfer none): A #GbDocument.
+ */
+GbDocument *
+gb_view_get_document (GbView *self)
+{
+  g_return_val_if_fail (GB_IS_VIEW (self), NULL);
+
+  if (GB_VIEW_GET_CLASS (self)->get_document)
+    return GB_VIEW_GET_CLASS (self)->get_document (self);
+
+  return NULL;
+}
+
+const gchar *
+gb_view_get_title (GbView *self)
+{
+  GbDocument *document;
+
+  if (GB_VIEW_GET_CLASS (self)->get_title)
+    return GB_VIEW_GET_CLASS (self)->get_title (self);
+
+  document = gb_view_get_document (self);
+
+  return gb_document_get_title (document);
+}
+
+static void
+gb_view_destroy (GtkWidget *widget)
+{
+  GbView *self = (GbView *)widget;
+  GbViewPrivate *priv = gb_view_get_instance_private (self);
+
+  g_clear_object (&priv->controls);
+
+  GTK_WIDGET_CLASS (gb_view_parent_class)->destroy (widget);
+}
+
+static void
+gb_view_get_property (GObject    *object,
+                      guint       prop_id,
+                      GValue     *value,
+                      GParamSpec *pspec)
+{
+  GbView *self = GB_VIEW (object);
+
+  switch (prop_id)
+    {
+    case PROP_CAN_SPLIT:
+      g_value_set_boolean (value, gb_view_get_can_split (self));
+      break;
+
+    case PROP_DOCUMENT:
+      g_value_set_object (value, gb_view_get_document (self));
+      break;
+
+    case PROP_TITLE:
+      g_value_set_string (value, gb_view_get_title (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+
+static void
+gb_view_class_init (GbViewClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->get_property = gb_view_get_property;
+
+  widget_class->destroy = gb_view_destroy;
+
+  gParamSpecs [PROP_CAN_SPLIT] =
+    g_param_spec_boolean ("can-split",
+                          _("Can Split"),
+                          _("If the view can be split."),
+                          FALSE,
+                          (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_CAN_SPLIT, gParamSpecs [PROP_CAN_SPLIT]);
+
+  gParamSpecs [PROP_DOCUMENT] =
+    g_param_spec_object ("document",
+                         _("Document"),
+                         _("The underlying document."),
+                         GB_TYPE_DOCUMENT,
+                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_DOCUMENT, gParamSpecs [PROP_DOCUMENT]);
+
+  gParamSpecs [PROP_TITLE] =
+    g_param_spec_string ("title",
+                         _("Title"),
+                         _("The view title."),
+                         NULL,
+                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_TITLE, gParamSpecs [PROP_TITLE]);
+}
+
+static void
+gb_view_init (GbView *self)
+{
+  GbViewPrivate *priv = gb_view_get_instance_private (self);
+  GtkBox *controls;
+
+  controls = g_object_new (GTK_TYPE_BOX,
+                           "orientation", GTK_ORIENTATION_HORIZONTAL,
+                           "visible", TRUE,
+                           NULL);
+  priv->controls = g_object_ref_sink (controls);
+}
+
+static GObject *
+gb_view_get_internal_child (GtkBuildable *buildable,
+                            GtkBuilder   *builder,
+                            const gchar  *childname)
+{
+  GbView *self = (GbView *)buildable;
+  GbViewPrivate *priv = gb_view_get_instance_private (self);
+
+  g_assert (GB_IS_VIEW (self));
+
+  if (g_strcmp0 (childname, "controls") == 0)
+    return G_OBJECT (priv->controls);
+
+  return NULL;
+}
+
+static void
+buildable_iface_init (GtkBuildableIface *iface)
+{
+  iface->get_internal_child = gb_view_get_internal_child;
+}
diff --git a/src/views/gb-view.h b/src/views/gb-view.h
new file mode 100644
index 0000000..86b9019
--- /dev/null
+++ b/src/views/gb-view.h
@@ -0,0 +1,50 @@
+/* gb-view.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_VIEW_H
+#define GB_VIEW_H
+
+#include <gtk/gtk.h>
+
+#include "gb-document.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_VIEW (gb_view_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (GbView, gb_view, GB, VIEW, GtkBox)
+
+struct _GbViewClass
+{
+  GtkBinClass parent;
+
+  gboolean     (*get_can_split) (GbView *self);
+  GbDocument  *(*get_document)  (GbView *self);
+  const gchar *(*get_title)     (GbView *self);
+  GbView      *(*create_split)  (GbView *self);
+};
+
+GbView      *gb_view_create_split  (GbView *self);
+gboolean     gb_view_get_can_split (GbView *self);
+GbDocument  *gb_view_get_document  (GbView *self);
+const gchar *gb_view_get_title     (GbView *self);
+GtkWidget   *gb_view_get_controls  (GbView *self);
+
+G_END_DECLS
+
+#endif /* GB_VIEW_H */
diff --git a/src/workbench/gb-workbench-actions.c b/src/workbench/gb-workbench-actions.c
new file mode 100644
index 0000000..7f54a69
--- /dev/null
+++ b/src/workbench/gb-workbench-actions.c
@@ -0,0 +1,81 @@
+/* gb-workbench-actions.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gb-workbench-actions"
+
+#include "gb-workbench.h"
+#include "gb-workbench-actions.h"
+#include "gb-workbench-private.h"
+
+static void
+gb_workbench_actions_build (GSimpleAction *action,
+                            GVariant      *parameter,
+                            gpointer       user_data)
+{
+}
+
+static void
+gb_workbench_actions_global_search (GSimpleAction *action,
+                                    GVariant      *parameter,
+                                    gpointer       user_data)
+{
+  GbWorkbench *self = user_data;
+
+  g_assert (GB_IS_WORKBENCH (self));
+
+  gtk_widget_grab_focus (GTK_WIDGET (self->search_box));
+}
+
+static void
+gb_workbench_actions_save_all (GSimpleAction *action,
+                               GVariant      *parameter,
+                               gpointer       user_data)
+{
+}
+
+static void
+gb_workbench_actions_show_command_bar (GSimpleAction *action,
+                                       GVariant      *parameter,
+                                       gpointer       user_data)
+{
+  GbWorkbench *self = user_data;
+
+  g_assert (GB_IS_WORKBENCH (self));
+
+  gb_command_bar_show (self->command_bar);
+}
+
+static const GActionEntry GbWorkbenchActions[] = {
+  { "build",            gb_workbench_actions_build },
+  { "global-search",    gb_workbench_actions_global_search },
+  { "save-all",         gb_workbench_actions_save_all },
+  { "show-command-bar", gb_workbench_actions_show_command_bar },
+};
+
+void
+gb_workbench_actions_init (GbWorkbench *self)
+{
+  GSimpleActionGroup *actions;
+
+  g_assert (GB_IS_WORKBENCH (self));
+
+  actions = g_simple_action_group_new ();
+  g_action_map_add_action_entries (G_ACTION_MAP (actions), GbWorkbenchActions,
+                                   G_N_ELEMENTS (GbWorkbenchActions), self);
+  gtk_widget_insert_action_group (GTK_WIDGET (self), "workbench", G_ACTION_GROUP (actions));
+}
diff --git a/src/auto-indent/c-parse-helper.h b/src/workbench/gb-workbench-actions.h
similarity index 57%
rename from src/auto-indent/c-parse-helper.h
rename to src/workbench/gb-workbench-actions.h
index 418f518..316a70e 100644
--- a/src/auto-indent/c-parse-helper.h
+++ b/src/workbench/gb-workbench-actions.h
@@ -1,6 +1,6 @@
-/* c-parse-helper.h
+/* gb-workbench-actions.h
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,26 +16,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef C_PARSE_HELPER_H
-#define C_PARSE_HELPER_H
+#ifndef GB_WORKBENCH_ACTIONS_H
+#define GB_WORKBENCH_ACTIONS_H
 
-#include <glib.h>
+#include "gb-workbench-types.h"
 
 G_BEGIN_DECLS
 
-typedef struct
-{
-  gchar *type;
-  gchar *name;
-  guint  ellipsis : 1;
-  guint  n_star   : 4;
-} Parameter;
-
-gboolean   parameter_validate (Parameter       *param);
-void       parameter_free     (Parameter       *p);
-Parameter *parameter_copy     (const Parameter *src);
-GSList    *parse_parameters   (const gchar     *text);
+void gb_workbench_actions_init (GbWorkbench *workbench);
 
 G_END_DECLS
 
-#endif /* C_PARSE_HELPER_H */
+#endif /* GB_WORKBENCH_ACTIONS_H */
diff --git a/src/workbench/gb-workbench-private.h b/src/workbench/gb-workbench-private.h
new file mode 100644
index 0000000..0114375
--- /dev/null
+++ b/src/workbench/gb-workbench-private.h
@@ -0,0 +1,60 @@
+/* gb-workbench-private.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_WORKBENCH_PRIVATE_H
+#define GB_WORKBENCH_PRIVATE_H
+
+#include <gtk/gtk.h>
+#include <ide.h>
+
+#include "gb-command-bar.h"
+#include "gb-command-manager.h"
+#include "gb-editor-workspace.h"
+#include "gb-search-box.h"
+#include "gb-workbench-types.h"
+#include "gedit-menu-stack-switcher.h"
+
+G_BEGIN_DECLS
+
+struct _GbWorkbench
+{
+  GtkApplicationWindow    parent_instance;
+
+  /* Owned reference */
+  GbCommandManager       *command_manager;
+  IdeContext             *context;
+  GCancellable           *unload_cancellable;
+
+  /* Weak reference */
+  GbWorkspace            *active_workspace;
+
+  /* Template references */
+  GbCommandBar           *command_bar;
+  GbEditorWorkspace      *editor_workspace;
+  GeditMenuStackSwitcher *gear_menu_button;
+  GbSearchBox            *search_box;
+  GtkStack               *stack;
+
+  guint                   disposing;
+  guint                   building : 1;
+  guint                   unloading : 1;
+};
+
+G_END_DECLS
+
+#endif /* GB_WORKBENCH_PRIVATE_H */
diff --git a/src/workbench/gb-workbench-types.h b/src/workbench/gb-workbench-types.h
index 0fbe0a5..9c5f6b3 100644
--- a/src/workbench/gb-workbench-types.h
+++ b/src/workbench/gb-workbench-types.h
@@ -23,13 +23,8 @@
 
 G_BEGIN_DECLS
 
-typedef struct _GbWorkbench        GbWorkbench;
-typedef struct _GbWorkbenchClass   GbWorkbenchClass;
-typedef struct _GbWorkbenchPrivate GbWorkbenchPrivate;
-
-typedef struct _GbWorkspace        GbWorkspace;
-typedef struct _GbWorkspaceClass   GbWorkspaceClass;
-typedef struct _GbWorkspacePrivate GbWorkspacePrivate;
+typedef struct _GbWorkbench GbWorkbench;
+typedef struct _GbWorkspace GbWorkspace;
 
 G_END_DECLS
 
diff --git a/src/workbench/gb-workbench.c b/src/workbench/gb-workbench.c
index 58d352c..414c273 100644
--- a/src/workbench/gb-workbench.c
+++ b/src/workbench/gb-workbench.c
@@ -1,6 +1,6 @@
 /* gb-workbench.c
  *
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2014-2015 Christian Hergert <christian hergert me>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,808 +16,129 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define G_LOG_DOMAIN "workbench"
+#define G_LOG_DOMAIN "gb-workbench"
 
 #include <glib/gi18n.h>
-#include <libgit2-glib/ggit.h>
-
-#include "gb-command-bar.h"
-#include "gb-command-gaction-provider.h"
-#include "gb-command-manager.h"
-#include "gb-command-vim-provider.h"
-#include "gb-close-confirmation-dialog.h"
-#include "gb-credits-widget.h"
-#include "gb-document-manager.h"
-#include "gb-editor-workspace.h"
-#include "gb-git-search-provider.h"
-#include "gb-glib.h"
-#include "gb-log.h"
-#include "gb-search-box.h"
-#include "gb-search-manager.h"
+#include <ide.h>
+
 #include "gb-widget.h"
+#include "gb-workbench-actions.h"
+#include "gb-workbench-private.h"
 #include "gb-workbench.h"
-#include "gedit-menu-stack-switcher.h"
-
-struct _GbWorkbenchPrivate
-{
-  GbCommandManager       *command_manager;
-  GbDocumentManager      *document_manager;
-  GbNavigationList       *navigation_list;
-  GbSearchManager        *search_manager;
-  IdeContext             *context;
-
-  guint                   search_timeout;
-  guint                   disposing;
-  guint                   building : 1;
-
-  GbWorkspace            *active_workspace;
-  GbCommandBar           *command_bar;
-  GbCreditsWidget        *credits;
-  GbWorkspace            *editor;
-  GeditMenuStackSwitcher *gear_menu_button;
-  GtkHeaderBar           *header_bar;
-  GtkButton              *run_button;
-  GbSearchBox            *search_box;
-  GtkStack               *stack;
-};
+#include "gb-workspace.h"
 
-typedef struct
-{
-  GCancellable *cancellable;
-  gint          outstanding;
-} SavedState;
+G_DEFINE_TYPE (GbWorkbench, gb_workbench, GTK_TYPE_APPLICATION_WINDOW)
 
 enum {
   PROP_0,
+  PROP_ACTIVE_WORKSPACE,
   PROP_COMMAND_MANAGER,
   PROP_CONTEXT,
-  PROP_NAVIGATION_LIST,
   LAST_PROP
 };
 
-enum {
-  WORKSPACE_CHANGED,
-  LAST_SIGNAL
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (GbWorkbench, gb_workbench,
-                            GTK_TYPE_APPLICATION_WINDOW)
-
 static GParamSpec *gParamSpecs [LAST_PROP];
-static guint       gSignals [LAST_SIGNAL];
-
-IdeContext *
-gb_workbench_get_context (GbWorkbench *workbench)
-{
-  g_return_val_if_fail (GB_IS_WORKBENCH (workbench), NULL);
-
-  return workbench->priv->context;
-}
-
-void
-gb_workbench_set_context (GbWorkbench *workbench,
-                          IdeContext  *context)
-{
-  GbWorkbenchPrivate *priv;
-
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-  g_return_if_fail (!context || IDE_IS_CONTEXT (context));
-
-  priv = workbench->priv;
-
-  if (g_set_object (&priv->context, context))
-    g_object_notify_by_pspec (G_OBJECT (workbench), gParamSpecs [PROP_CONTEXT]);
-}
-
-/**
- * gb_workbench_get_command_manager:
- *
- * Retrieves the command manager for the workspace.
- *
- * Returns: (transfer none) (type GbCommandManager*): A #GbCommandManager.
- */
-GbCommandManager *
-gb_workbench_get_command_manager (GbWorkbench *workbench)
-{
-  g_return_val_if_fail (GB_IS_WORKBENCH (workbench), NULL);
-
-  return workbench->priv->command_manager;
-}
-
-/**
- * gb_workbench_get_document_manager:
- * @workbench: A #GbWorkbench
- *
- * Retrieves the document manager for the workbench.
- *
- * Returns: (transfer none): A #GbDocumentManager.
- */
-GbDocumentManager *
-gb_workbench_get_document_manager (GbWorkbench *workbench)
-{
-  g_return_val_if_fail (GB_IS_WORKBENCH (workbench), NULL);
-
-  return workbench->priv->document_manager;
-}
-
-/**
- * gb_workbench_get_navigation_list:
- *
- * Fetches the navigation list for the workbench. This can be used to move
- * between edit points between workspaces.
- *
- * Returns: (transfer none): A #GbNavigationlist.
- */
-GbNavigationList *
-gb_workbench_get_navigation_list (GbWorkbench *workbench)
-{
-  g_return_val_if_fail (GB_IS_WORKBENCH (workbench), NULL);
-
-  return workbench->priv->navigation_list;
-}
-
-static gboolean
-gb_workbench_key_press_event (GtkWidget   *widget,
-                              GdkEventKey *event)
-{
-  GbWorkbench *self = (GbWorkbench *)widget;
-
-  g_return_val_if_fail (GB_IS_WORKBENCH (self), FALSE);
-  g_return_val_if_fail (event, FALSE);
-
-  switch (event->keyval)
-    {
-    case GDK_KEY_KP_Enter:
-    case GDK_KEY_Return:
-    case GDK_KEY_Escape:
-    case GDK_KEY_space:
-      if (gb_credits_widget_is_rolling (self->priv->credits))
-        {
-          gb_credits_widget_stop (self->priv->credits);
-          return GDK_EVENT_STOP;
-        }
-      break;
-
-    default:
-      break;
-    }
-
-  return GTK_WIDGET_CLASS (gb_workbench_parent_class)->key_press_event (widget, event);
-}
 
 static void
-load_repository_func (GTask        *task,
-                      gpointer      source_object,
-                      gpointer      task_data,
-                      GCancellable *cancellable)
+gb_workbench_set_context (GbWorkbench *self,
+                          IdeContext  *context)
 {
-  GbSearchProvider *provider;
-  GgitRepository *repository;
-  GError *error = NULL;
-  GFile *file = task_data;
-
-  g_return_if_fail (G_IS_TASK (task));
-  g_return_if_fail (GB_IS_WORKBENCH (source_object));
-  g_return_if_fail (G_IS_FILE (file));
-
-  repository = ggit_repository_open (file, &error);
-
-  if (!repository)
-    {
-      g_task_return_error (task, error);
-      return;
-    }
+  g_return_if_fail (GB_IS_WORKBENCH (self));
+  g_return_if_fail (IDE_IS_CONTEXT (context));
 
-  provider = g_object_new (GB_TYPE_GIT_SEARCH_PROVIDER,
-                           "workbench", source_object,
-                           "repository", repository,
-                           NULL);
-  g_task_return_pointer (task, provider, g_object_unref);
-  g_clear_object (&repository);
+  if (g_set_object (&self->context, context))
+    g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_CONTEXT]);
 }
 
 static void
-repository_loaded (GObject      *object,
-                   GAsyncResult *result,
-                   gpointer      unused)
+gb_workbench__unload_cb (GObject      *object,
+                         GAsyncResult *result,
+                         gpointer      user_data)
 {
-  GbWorkbench *workbench = (GbWorkbench *)object;
-  GbSearchProvider *provider;
+  IdeContext *context = (IdeContext *)object;
+  g_autoptr(GbWorkbench) self = user_data;
   GError *error = NULL;
-  GTask *task = (GTask *)result;
 
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-  g_return_if_fail (G_IS_TASK (task));
-
-  provider = g_task_propagate_pointer (task, &error);
-
-  if (!provider)
+  if (!ide_context_unload_finish (context, result, &error))
     {
-      g_printerr ("%s\n", error->message);
+      g_warning ("%s", error->message);
       g_clear_error (&error);
     }
-  else
-    {
-      gb_search_manager_add_provider (workbench->priv->search_manager,
-                                      provider);
-      g_clear_object (&provider);
-    }
-}
-
-GbSearchManager *
-gb_workbench_get_search_manager (GbWorkbench *workbench)
-{
-  GbWorkbenchPrivate *priv;
-
-  g_return_val_if_fail (GB_IS_WORKBENCH (workbench), NULL);
-
-  priv = workbench->priv;
-
-  if (!priv->search_manager)
-    {
-      GFile *file;
-      GTask *task;
-
-      priv->search_manager = gb_search_manager_new ();
-
-      /* TODO: Keep repository in sync with loaded project */
-      file = g_file_new_for_path (".");
-      task = g_task_new (workbench, NULL, repository_loaded, NULL);
-      g_task_set_task_data (task, g_object_ref (file), g_object_unref);
-      g_task_run_in_thread (task, load_repository_func);
-      g_clear_object (&task);
-      g_clear_object (&file);
-    }
-
-  return priv->search_manager;
-}
-
-/**
- * gb_workbench_get_active_workspace:
- *
- * Retrieves the active workspace.
- *
- * Returns: (transfer none): A #GbWorkbench.
- */
-GbWorkspace *
-gb_workbench_get_active_workspace (GbWorkbench *workbench)
-{
-   GtkWidget *child;
-
-   g_return_val_if_fail (GB_IS_WORKBENCH (workbench), NULL);
-
-   child = gtk_stack_get_visible_child (workbench->priv->stack);
-
-   return GB_WORKSPACE (child);
-}
-
-/**
- * gb_workbench_get_workspace:
- * @type: A #GType descending from #GbWorkspace
- *
- * Retrieves the workspace of type @type.
- *
- * Returns: (transfer none) (nullable): A #GbWorkspace or %NULL.
- */
-GbWorkspace *
-gb_workbench_get_workspace (GbWorkbench *workbench,
-                            GType        type)
-{
-  g_return_val_if_fail (GB_IS_WORKBENCH (workbench), NULL);
-  g_return_val_if_fail (g_type_is_a (type, GB_TYPE_WORKSPACE), NULL);
-
-  if (type == GB_TYPE_EDITOR_WORKSPACE)
-    return GB_WORKSPACE (workbench->priv->editor);
-
-  return NULL;
-}
-
-static void
-gb_workbench_roll_credits (GbWorkbench *workbench)
-{
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-
-  gb_credits_widget_start (workbench->priv->credits);
-}
-
-static void
-gb_workbench_workspace_changed (GbWorkbench *workbench,
-                                GbWorkspace *workspace)
-{
-  GbWorkbenchPrivate *priv;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-  g_return_if_fail (GB_IS_WORKSPACE (workspace));
-
-  priv = workbench->priv;
-
-  gb_clear_weak_pointer (&priv->active_workspace);
-
-  if (workspace)
-    {
-      gb_set_weak_pointer (workspace, &priv->active_workspace);
-      gtk_widget_grab_focus (GTK_WIDGET (workspace));
-    }
-
-  EXIT;
-}
-
-static void
-gb_workbench_stack_child_changed (GbWorkbench *workbench,
-                                  GParamSpec  *pspec,
-                                  GtkStack    *stack)
-{
-  GtkWidget *child;
-
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-  g_return_if_fail (GTK_IS_STACK (stack));
-
-  child = gtk_stack_get_visible_child (stack);
-  g_assert (!child || GB_IS_WORKSPACE (child));
-
-  if (GB_IS_WORKSPACE (child))
-    {
-      GActionGroup *action_group;
-
-      /*
-       * Some actions need to be propagated from the workspace to the
-       * toplevel. This way the header bar can activate them.
-       */
-      action_group = gtk_widget_get_action_group (child, "workspace");
-      gtk_widget_insert_action_group (GTK_WIDGET (workbench),
-                                      "workspace", action_group);
-    }
-
-  if (child)
-    g_signal_emit (workbench, gSignals[WORKSPACE_CHANGED], 0, child);
-}
-
-static void
-gb_workbench_realize (GtkWidget *widget)
-{
-  GbWorkbench *workbench = (GbWorkbench *)widget;
-
-  if (GTK_WIDGET_CLASS (gb_workbench_parent_class)->realize)
-    GTK_WIDGET_CLASS (gb_workbench_parent_class)->realize (widget);
-
-  gtk_widget_grab_focus (GTK_WIDGET (workbench->priv->editor));
-}
-
-static void
-gb_workbench_action_go_forward (GSimpleAction *action,
-                                GVariant      *variant,
-                                gpointer       user_data)
-{
-  GbWorkbench *workbench = user_data;
-
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-
-  if (gb_navigation_list_get_can_go_forward (workbench->priv->navigation_list))
-    gb_navigation_list_go_forward (workbench->priv->navigation_list);
-}
-
-static void
-gb_workbench_action_go_backward (GSimpleAction *action,
-                                 GVariant      *variant,
-                                 gpointer       user_data)
-{
-  GbWorkbench *workbench = user_data;
-
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-
-  if (gb_navigation_list_get_can_go_backward (workbench->priv->navigation_list))
-    gb_navigation_list_go_backward (workbench->priv->navigation_list);
-}
-
-static void
-gb_workbench_action_toggle_command_bar (GSimpleAction *action,
-                                        GVariant      *parameters,
-                                        gpointer       user_data)
-{
-  GbWorkbench *workbench = user_data;
-  gboolean show = TRUE;
-
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-
-  show = g_variant_get_boolean (parameters);
-
-  if (show)
-    gb_command_bar_show (workbench->priv->command_bar);
-  else
-    gb_command_bar_hide (workbench->priv->command_bar);
-}
-
-static void
-gb_workbench_action_show_command_bar (GSimpleAction *action,
-                                      GVariant      *parameters,
-                                      gpointer       user_data)
-{
-  GVariant *b;
-
-  g_return_if_fail (GB_IS_WORKBENCH (user_data));
-
-  b = g_variant_new_boolean (TRUE);
-  gb_workbench_action_toggle_command_bar (NULL, b, user_data);
-  g_variant_unref (b);
-}
-
-static void
-build_cb (GObject      *object,
-          GAsyncResult *result,
-          gpointer      user_data)
-{
-  IdeBuilder *builder = (IdeBuilder *)object;
-  g_autoptr(GbWorkbench) workbench = user_data;
-  g_autoptr(IdeBuildResult) build_result = NULL;
-  g_autoptr(GError) error = NULL;
-
-  g_return_if_fail (IDE_IS_BUILDER (builder));
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-
-  workbench->priv->building = FALSE;
-
-  g_print ("Build finished.\n");
-
-  build_result = ide_builder_build_finish (builder, result, &error);
-
-  if (!build_result)
-    {
-      /*
-       * TODO: Focus build output pane?
-       */
-    }
-}
-
-static void
-gb_workbench_action_build (GSimpleAction *action,
-                           GVariant      *parameters,
-                           gpointer       user_data)
-{
-  GbWorkbenchPrivate *priv;
-  GbWorkbench *workbench = user_data;
-
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-
-  priv = workbench->priv;
-
-  if (priv->building)
-    {
-      /*
-       * TODO: Can we have multiple parallel builds? Seems okay as long as they
-       *       are for different devices.
-       */
-      g_message (_("Already building.\n"));
-      return;
-    }
-
-  if (priv->context)
-    {
-      IdeDeviceManager *device_manager;
-      IdeBuildSystem *build_system;
-      g_autoptr(IdeDevice) device = NULL;
-      GPtrArray *devices;
-      guint i;
-
-      /*
-       * TODO: Add combo to select the target device we are working with.
-       */
-
-      device_manager = ide_context_get_device_manager (priv->context);
-      build_system = ide_context_get_build_system (priv->context);
-
-      devices = ide_device_manager_get_devices (device_manager);
-      for (i = 0; i < devices->len; i++)
-        {
-          IdeDevice *item = g_ptr_array_index (devices, i);
-
-          if (IDE_IS_LOCAL_DEVICE (item))
-            {
-              device = g_object_ref (item);
-              break;
-            }
-        }
-      g_ptr_array_unref (devices);
-
-      if (device)
-        {
-          g_autoptr(IdeBuilder) builder = NULL;
-          g_autoptr(GError) error = NULL;
-          g_autoptr(GKeyFile) config = NULL;
-
-          /*
-           * TODO: This should come from the current workspace configuration
-           *       for the build. We probably need to persist this between
-           *       runs as well.
-           */
-          config = g_key_file_new ();
-
-          builder = ide_build_system_get_builder (build_system,
-                                                  config,
-                                                  device,
-                                                  &error);
-
-          if (!builder)
-            {
-              g_warning ("%s\n", error->message);
-              return;
-            }
-
-          /*
-           * TODO: We should attach to the results progress signal so that we
-           *       can proxy that to the build status in the workbench.
-           */
-          priv->building = TRUE;
-          ide_builder_build_async (builder,
-                                   NULL,
-                                   NULL,
-                                   build_cb,
-                                   g_object_ref (workbench));
-        }
-    }
-}
 
-static void
-gb_workbench_action_global_search (GSimpleAction *action,
-                                   GVariant      *parameters,
-                                   gpointer       user_data)
-{
-  GbWorkbench *workbench = user_data;
-
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-
-  gtk_widget_grab_focus (GTK_WIDGET (workbench->priv->search_box));
-}
-
-static void
-gb_workbench_action_roll_credits (GSimpleAction *action,
-                                  GVariant      *parameters,
-                                  gpointer       user_data)
-{
-  GbWorkbench *workbench = user_data;
-
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-
-  gb_workbench_roll_credits (workbench);
+  self->unloading = FALSE;
+  g_clear_object (&self->context);
+  gtk_window_close (GTK_WINDOW (self));
 }
 
-static void
-gb_workbench_action_save_all (GSimpleAction *action,
-                              GVariant      *parameters,
-                              gpointer       user_data)
+static gboolean
+gb_workbench_delete_event (GtkWidget   *widget,
+                           GdkEventAny *event)
 {
-  GbWorkbench *workbench = user_data;
-  GList *list;
-  GList *iter;
-
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
+  GbWorkbench *self = (GbWorkbench *)widget;
 
-  list = gb_document_manager_get_documents (workbench->priv->document_manager);
+  g_assert (GB_IS_WORKBENCH (self));
 
-  for (iter = list; iter; iter = iter->next)
+  if (self->unloading)
     {
-      GbDocument *document = GB_DOCUMENT (iter->data);
-
-      /* This will not save files which do not have location set */
-      if (gb_document_get_modified (document))
-        gb_document_save_async (document, GTK_WIDGET (workbench),
-                                NULL, NULL, NULL);
+      /* Second attempt to kill things, cancel clean shutdown */
+      g_cancellable_cancel (self->unload_cancellable);
+      return TRUE;
     }
 
-  g_list_free (list);
-}
-
-static void
-gb_workbench_navigation_changed (GbWorkbench      *workbench,
-                                 GParamSpec       *pspec,
-                                 GbNavigationList *list)
-{
-  GbWorkbenchPrivate *priv;
-  GbNavigationItem *item;
-  GbWorkspace *workspace;
-
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-  g_return_if_fail (GB_IS_NAVIGATION_LIST (list));
-
-  priv = workbench->priv;
-
-  item = gb_navigation_list_get_current_item (list);
-
-  if (item)
+  if (self->context != NULL)
     {
-      workspace = gb_navigation_item_get_workspace (item);
-      if (workspace)
-        gtk_stack_set_visible_child (priv->stack, GTK_WIDGET (workspace));
-      gb_navigation_item_activate (item);
+      g_assert (!self->unload_cancellable);
+
+      self->unloading = TRUE;
+      self->unload_cancellable = g_cancellable_new ();
+      ide_context_unload_async (self->context,
+                                self->unload_cancellable,
+                                gb_workbench__unload_cb,
+                                g_object_ref (self));
+      return TRUE;
     }
-}
-
-static void
-gb_workbench_save_cb (GObject      *object,
-                      GAsyncResult *result,
-                      gpointer      user_data)
-{
-  SavedState *state = user_data;
-
-  GbDocument *document = (GbDocument *)object;
-
-  gb_document_save_finish (document, result, NULL);
-
-  state->outstanding--;
-}
-
-static void
-gb_workbench_save_as_cb (GObject      *object,
-                         GAsyncResult *result,
-                         gpointer      user_data)
-{
-  SavedState *state = user_data;
-
-  GbDocument *document = (GbDocument *)object;
-
-  gb_document_save_as_finish (document, result, NULL);
-
-  state->outstanding--;
-}
-
-static void
-gb_workbench_begin_save (GbWorkbench *workbench,
-                         GbDocument  *document,
-                         SavedState  *state)
-{
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-  g_return_if_fail (GB_IS_DOCUMENT (document));
-  g_return_if_fail (state);
 
-  state->outstanding++;
-
-  gb_document_save_async (document,
-                          GTK_WIDGET (workbench),
-                          state->cancellable,
-                          gb_workbench_save_cb,
-                          state);
-}
-
-static void
-gb_workbench_begin_save_as (GbWorkbench *workbench,
-                            GbDocument  *document,
-                            SavedState  *state)
-{
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-  g_return_if_fail (GB_IS_DOCUMENT (document));
-  g_return_if_fail (state);
-
-  state->outstanding++;
-
-  gb_document_save_as_async (document,
-                             GTK_WIDGET (workbench),
-                             state->cancellable,
-                             gb_workbench_save_as_cb,
-                             state);
-}
-
-static void
-gb_workbench_wait_for_saved (GbWorkbench *workbench,
-                             GtkDialog   *dialog,
-                             SavedState  *state)
-{
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-  g_return_if_fail (GTK_IS_DIALOG (dialog));
-  g_return_if_fail (state);
-
-  gtk_widget_set_sensitive (GTK_WIDGET (dialog), FALSE);
-  while (state->outstanding)
-    gtk_main_iteration_do (TRUE);
-  gtk_widget_set_sensitive (GTK_WIDGET (dialog), TRUE);
+  return FALSE;
 }
 
 static gboolean
-gb_workbench_confirm_close (GbWorkbench *workbench)
+gb_workbench_draw (GtkWidget *widget,
+                   cairo_t   *cr)
 {
-  GbDocumentManager *document_manager;
-  gboolean ret = FALSE;
-  GList *unsaved = NULL;
-
-  g_return_val_if_fail (GB_IS_WORKBENCH (workbench), FALSE);
-
-  document_manager = gb_workbench_get_document_manager (workbench);
-  unsaved = gb_document_manager_get_unsaved_documents (document_manager);
+  GbWorkbench *self = (GbWorkbench *)widget;
+  GtkStyleContext *style_context;
+  gboolean ret;
 
-  if (unsaved)
-    {
-      GbCloseConfirmationDialog *close;
-      SavedState state = { 0 };
-      GtkWidget *dialog;
-      GList *selected;
-      GList *iter;
-      gint response_id;
-
-      dialog = gb_close_confirmation_dialog_new (GTK_WINDOW (workbench),
-                                                 unsaved);
-      close = GB_CLOSE_CONFIRMATION_DIALOG (dialog);
-      response_id = gtk_dialog_run (GTK_DIALOG (dialog));
-      selected = gb_close_confirmation_dialog_get_selected_documents (close);
-
-      switch (response_id)
-        {
-        case GTK_RESPONSE_YES:
-          state.cancellable = g_cancellable_new ();
-
-          for (iter = selected; iter; iter = iter->next)
-            {
-              GbDocument *document = GB_DOCUMENT (iter->data);
-
-              if (gb_document_is_untitled (document))
-                gb_workbench_begin_save_as (workbench, document, &state);
-              else
-                gb_workbench_begin_save (workbench, document, &state);
-            }
-
-          gb_workbench_wait_for_saved (workbench, GTK_DIALOG (dialog), &state);
-          g_clear_object (&state.cancellable);
-          break;
-
-        case GTK_RESPONSE_NO:
-          break;
-
-        case GTK_RESPONSE_DELETE_EVENT:
-        case GTK_RESPONSE_CANCEL:
-          ret = TRUE;
-          break;
-
-        default:
-          g_assert_not_reached ();
-        }
-
-      g_list_free (selected);
-      gtk_widget_hide (dialog);
-      gtk_widget_destroy (dialog);
-    }
+  g_assert (GB_IS_WORKBENCH (self));
 
-  g_list_free (unsaved);
+  style_context = gtk_widget_get_style_context (widget);
+  gtk_style_context_save (style_context);
+  if (self->building)
+    gtk_style_context_add_class (style_context, "building");
+  ret = GTK_WIDGET_CLASS (gb_workbench_parent_class)->draw (widget, cr);
+  gtk_style_context_restore (style_context);
 
   return ret;
 }
 
-static gboolean
-gb_workbench_delete_event (GtkWidget   *widget,
-                           GdkEventAny *event)
-{
-  GbWorkbench *workbench = (GbWorkbench *)widget;
-
-  g_return_val_if_fail (GB_IS_WORKBENCH (workbench), FALSE);
-
-  if (!gb_workbench_confirm_close (workbench))
-    {
-      if (GTK_WIDGET_CLASS (gb_workbench_parent_class)->delete_event)
-        return GTK_WIDGET_CLASS (gb_workbench_parent_class)->delete_event (widget, event);
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
 static void
-gb_workbench_add_command_provider (GbWorkbench *workbench,
-                                   GType        type)
+gb_workbench_realize (GtkWidget *widget)
 {
-  GbCommandProvider *provider;
+  GbWorkbench *self = (GbWorkbench *)widget;
 
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
-  g_return_if_fail (g_type_is_a (type, GB_TYPE_COMMAND_PROVIDER));
+  if (GTK_WIDGET_CLASS (gb_workbench_parent_class)->realize)
+    GTK_WIDGET_CLASS (gb_workbench_parent_class)->realize (widget);
 
-  provider = g_object_new (type, "workbench", workbench, NULL);
-  gb_command_manager_add_provider (workbench->priv->command_manager, provider);
+  gtk_widget_grab_focus (GTK_WIDGET (self->editor_workspace));
 }
 
 static void
 gb_workbench_set_focus (GtkWindow *window,
                         GtkWidget *widget)
 {
-  GbWorkbench *workbench = (GbWorkbench *)window;
+  GbWorkbench *self = (GbWorkbench *)window;
 
-  g_return_if_fail (GB_IS_WORKBENCH (workbench));
+  g_return_if_fail (GB_IS_WORKBENCH (self));
 
   /*
    * The goal here is to focus the current workspace if we are trying to
@@ -826,7 +147,7 @@ gb_workbench_set_focus (GtkWindow *window,
 
   GTK_WINDOW_CLASS (gb_workbench_parent_class)->set_focus (window, widget);
 
-  if (!widget && !workbench->priv->disposing)
+  if (!widget && !self->disposing)
     {
       GbWorkspace *workspace;
 
@@ -837,131 +158,69 @@ gb_workbench_set_focus (GtkWindow *window,
        * for reentrancy later, but if that happens, we are probably doing
        * something else wrong.
        */
-      workspace = gb_workbench_get_active_workspace (workbench);
+      workspace = gb_workbench_get_active_workspace (self);
       if (workspace)
         gtk_widget_grab_focus (GTK_WIDGET (workspace));
     }
 }
 
 static void
-on_context_new_cb (GObject      *object,
-                   GAsyncResult *result,
-                   gpointer      user_data)
-{
-  g_autoptr(GbWorkbench) self = user_data;
-  g_autoptr(IdeContext) context = NULL;
-  g_autoptr(GError) error = NULL;
-
-  context = ide_context_new_finish (result, &error);
-
-  if (!context)
-    g_warning ("%s\n", error->message);
-  else
-    gb_workbench_set_context (self, context);
-}
-
-static void
 gb_workbench_constructed (GObject *object)
 {
-  static const GActionEntry actions[] = {
-    { "build",              gb_workbench_action_build },
-    { "global-search",      gb_workbench_action_global_search },
-    { "go-backward",        gb_workbench_action_go_backward },
-    { "go-forward",         gb_workbench_action_go_forward },
-    { "show-command-bar",   gb_workbench_action_show_command_bar },
-    { "toggle-command-bar", gb_workbench_action_toggle_command_bar, "b" },
-    { "save-all",           gb_workbench_action_save_all },
-    { "about",              gb_workbench_action_roll_credits },
-  };
-  GbWorkbenchPrivate *priv;
-  GbWorkbench *workbench = (GbWorkbench *)object;
-  GbSearchManager *search_manager;
+  GbWorkbench *self = (GbWorkbench *)object;
   GtkApplication *app;
-  GAction *action;
   GMenu *menu;
 
-  g_assert (GB_IS_WORKBENCH (workbench));
-
-  ENTRY;
-
-  priv = workbench->priv;
+  IDE_ENTRY;
 
   G_OBJECT_CLASS (gb_workbench_parent_class)->constructed (object);
 
+  gb_workbench_actions_init (self);
+
   app = GTK_APPLICATION (g_application_get_default ());
   menu = gtk_application_get_menu_by_id (app, "gear-menu");
-  gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (priv->gear_menu_button),
-                                  G_MENU_MODEL (menu));
-
-  g_signal_connect_object (priv->stack,
-                           "notify::visible-child",
-                           G_CALLBACK (gb_workbench_stack_child_changed),
-                           workbench,
-                           (G_CONNECT_SWAPPED | G_CONNECT_AFTER));
+  gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (self->gear_menu_button), G_MENU_MODEL (menu));
 
-  g_action_map_add_action_entries (G_ACTION_MAP (workbench), actions,
-                                   G_N_ELEMENTS (actions), workbench);
+  if (self->active_workspace)
+    gtk_widget_grab_focus (GTK_WIDGET (self->active_workspace));
+  else
+    gtk_widget_grab_focus (GTK_WIDGET (self->editor_workspace));
 
-  g_signal_connect_object (priv->navigation_list,
-                           "notify::current-item",
-                           G_CALLBACK (gb_workbench_navigation_changed),
-                           workbench,
-                           G_CONNECT_SWAPPED);
+  IDE_EXIT;
+}
 
-  action = g_action_map_lookup_action (G_ACTION_MAP (workbench), "go-backward");
-  g_object_bind_property (priv->navigation_list, "can-go-backward",
-                          action, "enabled", G_BINDING_SYNC_CREATE);
+static void
+gb_workbench_dispose (GObject *object)
+{
+  GbWorkbench *self = (GbWorkbench *)object;
 
-  action = g_action_map_lookup_action (G_ACTION_MAP (workbench), "go-forward");
-  g_object_bind_property (priv->navigation_list, "can-go-forward",
-                          action, "enabled", G_BINDING_SYNC_CREATE);
+  IDE_ENTRY;
 
-  search_manager = gb_workbench_get_search_manager (workbench);
-  gb_search_box_set_search_manager (workbench->priv->search_box,
-                                    search_manager);
+  self->disposing++;
 
-  gb_workbench_stack_child_changed (workbench, NULL, priv->stack);
+  g_clear_object (&self->command_manager);
+  g_clear_object (&self->unload_cancellable);
 
-  /*
-   * TODO: Dummy code until we have real project loading.
-   */
-  {
-    g_autoptr(GFile) project_dir = g_file_new_for_path (".");
+  G_OBJECT_CLASS (gb_workbench_parent_class)->dispose (object);
 
-    ide_context_new_async (project_dir,
-                           NULL,
-                           on_context_new_cb,
-                           g_object_ref (workbench));
-  }
+  self->disposing--;
 
-  EXIT;
+  IDE_EXIT;
 }
 
 static void
-gb_workbench_dispose (GObject *object)
+gb_workbench_finalize (GObject *object)
 {
-  GbWorkbenchPrivate *priv = GB_WORKBENCH (object)->priv;
-
-  ENTRY;
-
-  priv->disposing++;
-
-  if (priv->search_timeout)
-    {
-      g_source_remove (priv->search_timeout);
-      priv->search_timeout = 0;
-    }
+  GbWorkbench *self = (GbWorkbench *)object;
 
-  g_clear_object (&priv->command_manager);
-  g_clear_object (&priv->document_manager);
-  g_clear_object (&priv->navigation_list);
-  g_clear_object (&priv->search_manager);
+  IDE_ENTRY;
 
-  G_OBJECT_CLASS (gb_workbench_parent_class)->dispose (object);
+  ide_clear_weak_pointer (&self->active_workspace);
+  g_clear_object (&self->context);
 
-  priv->disposing--;
+  G_OBJECT_CLASS (gb_workbench_parent_class)->finalize (object);
 
-  EXIT;
+  IDE_EXIT;
 }
 
 static void
@@ -974,6 +233,10 @@ gb_workbench_get_property (GObject    *object,
 
   switch (prop_id)
     {
+    case PROP_ACTIVE_WORKSPACE:
+      g_value_set_object (value, gb_workbench_get_active_workspace (self));
+      break;
+
     case PROP_COMMAND_MANAGER:
       g_value_set_object (value, gb_workbench_get_command_manager (self));
       break;
@@ -982,10 +245,6 @@ gb_workbench_get_property (GObject    *object,
       g_value_set_object (value, gb_workbench_get_context (self));
       break;
 
-    case PROP_NAVIGATION_LIST:
-      g_value_set_object (value, gb_workbench_get_navigation_list (self));
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -1001,6 +260,10 @@ gb_workbench_set_property (GObject      *object,
 
   switch (prop_id)
     {
+    case PROP_ACTIVE_WORKSPACE:
+      gb_workbench_set_active_workspace (self, g_value_get_object (value));
+      break;
+
     case PROP_CONTEXT:
       gb_workbench_set_context (self, g_value_get_object (value));
       break;
@@ -1019,88 +282,153 @@ gb_workbench_class_init (GbWorkbenchClass *klass)
 
   object_class->constructed = gb_workbench_constructed;
   object_class->dispose = gb_workbench_dispose;
+  object_class->finalize = gb_workbench_finalize;
   object_class->get_property = gb_workbench_get_property;
   object_class->set_property = gb_workbench_set_property;
 
+  widget_class->draw = gb_workbench_draw;
   widget_class->realize = gb_workbench_realize;
   widget_class->delete_event = gb_workbench_delete_event;
-  widget_class->key_press_event = gb_workbench_key_press_event;
 
   window_class->set_focus = gb_workbench_set_focus;
 
-  klass->workspace_changed = gb_workbench_workspace_changed;
+  gParamSpecs [PROP_ACTIVE_WORKSPACE] =
+    g_param_spec_object ("active-workspace",
+                         _("Active Workspace"),
+                         _("The active workspace"),
+                         GB_TYPE_WORKSPACE,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_ACTIVE_WORKSPACE,
+                                   gParamSpecs [PROP_ACTIVE_WORKSPACE]);
 
   gParamSpecs [PROP_COMMAND_MANAGER] =
     g_param_spec_object ("command-manager",
                          _("Command Manager"),
-                         _("The command manager for the workspace."),
+                         _("The command manager for the workbench"),
                          GB_TYPE_COMMAND_MANAGER,
-                         (G_PARAM_READABLE |
-                          G_PARAM_STATIC_STRINGS));
+                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_COMMAND_MANAGER,
                                    gParamSpecs [PROP_COMMAND_MANAGER]);
 
+  /**
+   * GbWorkbench:context:
+   *
+   * The "context" property is the #IdeContext that shall be worked upon in
+   * the #GbWorkbench. This must be set during workbench creation. Use
+   * another window or dialog to choose the project information before
+   * creating a workbench window.
+   */
   gParamSpecs [PROP_CONTEXT] =
     g_param_spec_object ("context",
                          _("Context"),
-                         _("The IDE context for the workbench."),
+                         _("The IdeContext for the workbench."),
                          IDE_TYPE_CONTEXT,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_CONTEXT,
-                                   gParamSpecs [PROP_CONTEXT]);
-
-  gParamSpecs [PROP_NAVIGATION_LIST] =
-    g_param_spec_object ("navigation-list",
-                         _("Navigation List"),
-                         _("The navigation list for the workbench."),
-                         GB_TYPE_NAVIGATION_LIST,
-                         (G_PARAM_READABLE |
-                          G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_NAVIGATION_LIST,
-                                   gParamSpecs [PROP_NAVIGATION_LIST]);
-
-  gSignals [WORKSPACE_CHANGED] =
-    g_signal_new ("workspace-changed",
-                  G_OBJECT_CLASS_TYPE (object_class),
-                  G_SIGNAL_RUN_FIRST,
-                  G_STRUCT_OFFSET (GbWorkbenchClass, workspace_changed),
-                  NULL,
-                  NULL,
-                  g_cclosure_marshal_VOID__OBJECT,
-                  G_TYPE_NONE,
-                  1,
-                  GB_TYPE_WORKSPACE);
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_CONTEXT, gParamSpecs [PROP_CONTEXT]);
 
   GB_WIDGET_CLASS_TEMPLATE (klass, "gb-workbench.ui");
   GB_WIDGET_CLASS_BIND (klass, GbWorkbench, command_bar);
-  GB_WIDGET_CLASS_BIND (klass, GbWorkbench, credits);
-  GB_WIDGET_CLASS_BIND (klass, GbWorkbench, editor);
+  GB_WIDGET_CLASS_BIND (klass, GbWorkbench, editor_workspace);
   GB_WIDGET_CLASS_BIND (klass, GbWorkbench, gear_menu_button);
-  GB_WIDGET_CLASS_BIND (klass, GbWorkbench, header_bar);
-  GB_WIDGET_CLASS_BIND (klass, GbWorkbench, run_button);
   GB_WIDGET_CLASS_BIND (klass, GbWorkbench, search_box);
   GB_WIDGET_CLASS_BIND (klass, GbWorkbench, stack);
 
   g_type_ensure (GB_TYPE_COMMAND_BAR);
-  g_type_ensure (GB_TYPE_CREDITS_WIDGET);
   g_type_ensure (GB_TYPE_EDITOR_WORKSPACE);
   g_type_ensure (GB_TYPE_SEARCH_BOX);
   g_type_ensure (GEDIT_TYPE_MENU_STACK_SWITCHER);
 }
 
 static void
-gb_workbench_init (GbWorkbench *workbench)
+gb_workbench_init (GbWorkbench *self)
+{
+  IDE_ENTRY;
+
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  self->command_manager = gb_command_manager_new ();
+
+  IDE_EXIT;
+}
+
+/**
+ * gb_workbench_get_context:
+ * @self: A #GbWorkbench.
+ *
+ * Gets the #IdeContext for the workbench.
+ *
+ * Returns: (transfer none): An #IdeContext.
+ */
+IdeContext *
+gb_workbench_get_context (GbWorkbench *self)
 {
-  workbench->priv = gb_workbench_get_instance_private (workbench);
+  g_return_val_if_fail (GB_IS_WORKBENCH (self), NULL);
 
-  workbench->priv->document_manager = gb_document_manager_new ();
-  workbench->priv->command_manager = gb_command_manager_new ();
-  workbench->priv->navigation_list = gb_navigation_list_new (workbench);
+  return self->context;
+}
+
+/**
+ * gb_workbench_get_active_workspace:
+ * @self: A #GbWorkbench.
+ *
+ * Gets the currently selected workspace.
+ *
+ * Returns: (transfer none): An #GbWorkspace.
+ */
+GbWorkspace *
+gb_workbench_get_active_workspace (GbWorkbench *self)
+{
+  g_return_val_if_fail (GB_IS_WORKBENCH (self), NULL);
+
+  return self->active_workspace;
+}
 
-  gtk_widget_init_template (GTK_WIDGET (workbench));
+void
+gb_workbench_set_active_workspace (GbWorkbench *self,
+                                   GbWorkspace *workspace)
+{
+  g_return_if_fail (GB_IS_WORKBENCH (self));
+  g_return_if_fail (GB_IS_WORKSPACE (workspace));
+
+  if (ide_set_weak_pointer (&self->active_workspace, workspace))
+    gtk_stack_set_visible_child (self->stack, GTK_WIDGET (workspace));
+}
+
+void
+gb_workbench_open (GbWorkbench *self,
+                   GFile       *file)
+{
+  g_autoptr(IdeFile) idefile = NULL;
+  IdeBufferManager *buffer_manager;
+  IdeProject *project;
+
+  g_return_if_fail (GB_IS_WORKBENCH (self));
+  g_return_if_fail (self->unloading == FALSE);
+  g_return_if_fail (self->context);
+
+  /*
+   * TODO: We probably want to dispatch this based on the type. But for now,
+   *       we will just try to open it with the buffer manager.
+   */
+
+  buffer_manager = ide_context_get_buffer_manager (self->context);
+  project = ide_context_get_project (self->context);
+  idefile = ide_project_get_project_file (project, file);
+  ide_buffer_manager_load_file_async (buffer_manager, idefile, FALSE, NULL, NULL, NULL, NULL);
+}
+
+/**
+ * gb_workbench_get_command_manager:
+ * @self: A #GbWorkbench.
+ *
+ * Gets the command manager for the workbench. This may be moved into libide.
+ *
+ * Returns: (transfer none): A #GbCommandManager.
+ */
+GbCommandManager *
+gb_workbench_get_command_manager (GbWorkbench *self)
+{
+  g_return_val_if_fail (GB_IS_WORKBENCH (self), NULL);
 
-  gb_workbench_add_command_provider (workbench,
-                                     GB_TYPE_COMMAND_GACTION_PROVIDER);
-  gb_workbench_add_command_provider (workbench,
-                                     GB_TYPE_COMMAND_VIM_PROVIDER);
+  return self->command_manager;
 }
diff --git a/src/workbench/gb-workbench.h b/src/workbench/gb-workbench.h
index 08fbea5..54ea1bf 100644
--- a/src/workbench/gb-workbench.h
+++ b/src/workbench/gb-workbench.h
@@ -23,46 +23,21 @@
 #include <ide.h>
 
 #include "gb-command-manager.h"
-#include "gb-document-manager.h"
-#include "gb-navigation-list.h"
 #include "gb-workbench-types.h"
 
 G_BEGIN_DECLS
 
-#define GB_TYPE_WORKBENCH            (gb_workbench_get_type())
-#define GB_WORKBENCH(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_WORKBENCH, GbWorkbench))
-#define GB_WORKBENCH_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_WORKBENCH, GbWorkbench 
const))
-#define GB_WORKBENCH_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_WORKBENCH, 
GbWorkbenchClass))
-#define GB_IS_WORKBENCH(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_WORKBENCH))
-#define GB_IS_WORKBENCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_WORKBENCH))
-#define GB_WORKBENCH_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_WORKBENCH, 
GbWorkbenchClass))
+#define GB_TYPE_WORKBENCH (gb_workbench_get_type())
 
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (GbWorkbench, g_object_unref)
+G_DECLARE_FINAL_TYPE (GbWorkbench, gb_workbench, GB, WORKBENCH, GtkApplicationWindow)
 
-struct _GbWorkbench
-{
-  GtkApplicationWindow parent;
-
-  /*< private >*/
-  GbWorkbenchPrivate *priv;
-};
-
-struct _GbWorkbenchClass
-{
-  GtkApplicationWindowClass parent_class;
-
-  void (*workspace_changed) (GbWorkbench *workbench,
-                             GbWorkspace *workspace);
-};
-
-GType              gb_workbench_get_type             (void);
-IdeContext        *gb_workbench_get_context          (GbWorkbench *workbench);
-GbNavigationList  *gb_workbench_get_navigation_list  (GbWorkbench *workbench);
-GbDocumentManager *gb_workbench_get_document_manager (GbWorkbench *workbench);
-GbWorkspace       *gb_workbench_get_active_workspace (GbWorkbench *workbench);
-GbWorkspace       *gb_workbench_get_workspace        (GbWorkbench *workbench,
-                                                      GType        type);
-GbCommandManager  *gb_workbench_get_command_manager  (GbWorkbench *workbench);
+IdeContext       *gb_workbench_get_context          (GbWorkbench *self);
+GbWorkspace      *gb_workbench_get_active_workspace (GbWorkbench *self);
+void              gb_workbench_set_active_workspace (GbWorkbench *self,
+                                                     GbWorkspace *workspace);
+void              gb_workbench_open                 (GbWorkbench *self,
+                                                     GFile       *file);
+GbCommandManager *gb_workbench_get_command_manager  (GbWorkbench *self);
 
 G_END_DECLS
 
diff --git a/src/workbench/gb-workspace.c b/src/workbench/gb-workspace.c
index aa4c70b..64351e5 100644
--- a/src/workbench/gb-workspace.c
+++ b/src/workbench/gb-workspace.c
@@ -20,11 +20,11 @@
 
 #include "gb-workspace.h"
 
-struct _GbWorkspacePrivate
+typedef struct
 {
   gchar *icon_name;
   gchar *title;
-};
+} GbWorkspacePrivate;
 
 enum {
   PROP_0,
@@ -38,51 +38,62 @@ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GbWorkspace, gb_workspace, GTK_TYPE_BIN)
 static GParamSpec *gParamSpecs[LAST_PROP];
 
 const gchar *
-gb_workspace_get_icon_name (GbWorkspace *workspace)
+gb_workspace_get_icon_name (GbWorkspace *self)
 {
-  g_return_val_if_fail (GB_IS_WORKSPACE (workspace), NULL);
+  GbWorkspacePrivate *priv = gb_workspace_get_instance_private (self);
+
+  g_return_val_if_fail (GB_IS_WORKSPACE (self), NULL);
 
-  return workspace->priv->icon_name;
+  return priv->icon_name;
 }
 
 void
-gb_workspace_set_icon_name (GbWorkspace *workspace,
+gb_workspace_set_icon_name (GbWorkspace *self,
                             const gchar *icon_name)
 {
-  g_return_if_fail (GB_IS_WORKSPACE (workspace));
+  GbWorkspacePrivate *priv = gb_workspace_get_instance_private (self);
+
+  g_return_if_fail (GB_IS_WORKSPACE (self));
 
-  g_free (workspace->priv->icon_name);
-  workspace->priv->icon_name = g_strdup (icon_name);
-  g_object_notify_by_pspec (G_OBJECT (workspace),
-                            gParamSpecs[PROP_ICON_NAME]);
+  if (priv->icon_name != icon_name)
+    {
+      g_free (priv->icon_name);
+      priv->icon_name = g_strdup (icon_name);
+      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs[PROP_ICON_NAME]);
+    }
 }
 
 const gchar *
-gb_workspace_get_title (GbWorkspace *workspace)
+gb_workspace_get_title (GbWorkspace *self)
 {
-  g_return_val_if_fail (GB_IS_WORKSPACE (workspace), NULL);
+  GbWorkspacePrivate *priv = gb_workspace_get_instance_private (self);
 
-  return workspace->priv->title;
+  g_return_val_if_fail (GB_IS_WORKSPACE (self), NULL);
+
+  return priv->title;
 }
 
 void
-gb_workspace_set_title (GbWorkspace *workspace,
+gb_workspace_set_title (GbWorkspace *self,
                         const gchar *title)
 {
-  g_return_if_fail (GB_IS_WORKSPACE (workspace));
+  GbWorkspacePrivate *priv = gb_workspace_get_instance_private (self);
+
+  g_return_if_fail (GB_IS_WORKSPACE (self));
 
-  g_free (workspace->priv->title);
-  workspace->priv->title = g_strdup (title);
-  g_object_notify_by_pspec (G_OBJECT (workspace),
-                            gParamSpecs[PROP_TITLE]);
+  if (priv->title != title)
+    {
+      g_free (priv->title);
+      priv->title = g_strdup (title);
+      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_TITLE]);
+    }
 }
 
 static void
 gb_workspace_finalize (GObject *object)
 {
-  GbWorkspacePrivate *priv;
-
-  priv = GB_WORKSPACE (object)->priv;
+  GbWorkspace *self = (GbWorkspace *)object;
+  GbWorkspacePrivate *priv = gb_workspace_get_instance_private (self);
 
   g_clear_pointer (&priv->icon_name, g_free);
   g_clear_pointer (&priv->title, g_free);
@@ -96,16 +107,16 @@ gb_workspace_get_property (GObject    *object,
                            GValue     *value,
                            GParamSpec *pspec)
 {
-  GbWorkspace *workspace = GB_WORKSPACE (object);
+  GbWorkspace *self = GB_WORKSPACE (object);
 
   switch (prop_id)
     {
     case PROP_ICON_NAME:
-      g_value_set_string (value, gb_workspace_get_icon_name (workspace));
+      g_value_set_string (value, gb_workspace_get_icon_name (self));
       break;
 
     case PROP_TITLE:
-      g_value_set_string (value, gb_workspace_get_title (workspace));
+      g_value_set_string (value, gb_workspace_get_title (self));
       break;
 
     default:
@@ -119,16 +130,16 @@ gb_workspace_set_property (GObject      *object,
                            const GValue *value,
                            GParamSpec   *pspec)
 {
-  GbWorkspace *workspace = GB_WORKSPACE (object);
+  GbWorkspace *self = GB_WORKSPACE (object);
 
   switch (prop_id)
     {
     case PROP_ICON_NAME:
-      gb_workspace_set_icon_name (workspace, g_value_get_string (value));
+      gb_workspace_set_icon_name (self, g_value_get_string (value));
       break;
 
     case PROP_TITLE:
-      gb_workspace_set_title (workspace, g_value_get_string (value));
+      gb_workspace_set_title (self, g_value_get_string (value));
       break;
 
     default:
@@ -153,8 +164,7 @@ gb_workspace_class_init (GbWorkspaceClass *klass)
                          NULL,
                          (G_PARAM_READWRITE |
                           G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_TITLE,
-                                   gParamSpecs[PROP_TITLE]);
+  g_object_class_install_property (object_class, PROP_TITLE, gParamSpecs[PROP_TITLE]);
 
   gParamSpecs[PROP_ICON_NAME] =
     g_param_spec_string ("icon-name",
@@ -163,12 +173,10 @@ gb_workspace_class_init (GbWorkspaceClass *klass)
                          NULL,
                          (G_PARAM_READWRITE |
                           G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_ICON_NAME,
-                                   gParamSpecs[PROP_ICON_NAME]);
+  g_object_class_install_property (object_class, PROP_ICON_NAME, gParamSpecs[PROP_ICON_NAME]);
 }
 
 static void
 gb_workspace_init (GbWorkspace *workspace)
 {
-  workspace->priv = gb_workspace_get_instance_private (workspace);
 }
diff --git a/src/workbench/gb-workspace.h b/src/workbench/gb-workspace.h
index 46346f3..cffbbed 100644
--- a/src/workbench/gb-workspace.h
+++ b/src/workbench/gb-workspace.h
@@ -25,33 +25,20 @@
 
 G_BEGIN_DECLS
 
-#define GB_TYPE_WORKSPACE            (gb_workspace_get_type())
-#define GB_WORKSPACE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_WORKSPACE, GbWorkspace))
-#define GB_WORKSPACE_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_WORKSPACE, GbWorkspace 
const))
-#define GB_WORKSPACE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_WORKSPACE, 
GbWorkspaceClass))
-#define GB_IS_WORKSPACE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_WORKSPACE))
-#define GB_IS_WORKSPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_WORKSPACE))
-#define GB_WORKSPACE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_WORKSPACE, 
GbWorkspaceClass))
-
-struct _GbWorkspace
-{
-  GtkBin parent;
+#define GB_TYPE_WORKSPACE (gb_workspace_get_type())
 
-  /*< private >*/
-  GbWorkspacePrivate *priv;
-};
+G_DECLARE_DERIVABLE_TYPE (GbWorkspace, gb_workspace, GB, WORKSPACE, GtkBin)
 
 struct _GbWorkspaceClass
 {
   GtkBinClass parent_class;
 };
 
-GType         gb_workspace_get_type      (void);
-const gchar  *gb_workspace_get_icon_name (GbWorkspace *workspace);
-void          gb_workspace_set_icon_name (GbWorkspace *workspace,
+const gchar  *gb_workspace_get_icon_name (GbWorkspace *self);
+void          gb_workspace_set_icon_name (GbWorkspace *self,
                                           const gchar *icon_name);
-const gchar  *gb_workspace_get_title     (GbWorkspace *workspace);
-void          gb_workspace_set_title     (GbWorkspace *workspace,
+const gchar  *gb_workspace_get_title     (GbWorkspace *self);
+void          gb_workspace_set_title     (GbWorkspace *self,
                                           const gchar *title);
 
 G_END_DECLS
diff --git a/tests/tests.mk b/tests/tests.mk
index a23dce7..0962d15 100644
--- a/tests/tests.mk
+++ b/tests/tests.mk
@@ -1,15 +1,8 @@
 noinst_PROGRAMS += test-c-parse-helper
 TESTS += test-c-parse-helper
-test_c_parse_helper_SOURCES = tests/test-c-parse-helper.c
-test_c_parse_helper_CFLAGS = $(libgnome_builder_la_CFLAGS)
-test_c_parse_helper_LDADD = libgnome-builder.la
-
-
-noinst_PROGRAMS += test-navigation-list
-TESTS += test-navigation-list
-test_navigation_list_SOURCES = tests/test-navigation-list.c
-test_navigation_list_CFLAGS = $(libgnome_builder_la_CFLAGS)
-test_navigation_list_LDADD = libgnome-builder.la
+test_c_parse_helper_SOURCES = tests/test-c-parse-helper.c libide/c/c-parse-helper.c
+test_c_parse_helper_CFLAGS = $(libide_1_0_la_CFLAGS) -I$(top_srcdir)/libide/c/
+test_c_parse_helper_LDADD = $(LIBIDE_LIBS)
 
 
 noinst_PROGRAMS += test-ide-context
diff --git a/tools/ide-search.c b/tools/ide-search.c
index ae4e939..f9fb53c 100644
--- a/tools/ide-search.c
+++ b/tools/ide-search.c
@@ -95,7 +95,7 @@ context_cb (GObject      *object,
                     G_CALLBACK (on_completed_cb),
                     g_object_ref (context));
 
-  ide_search_context_execute (search_context, gSearchTerms);
+  ide_search_context_execute (search_context, gSearchTerms, 0);
 }
 
 gint



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