[gnome-builder] GbEditorTab: new tab design using GbEditorFrame and splits



commit c106d85929214e2c3957b9a2385ad0ce14da1289
Author: Christian Hergert <christian hergert me>
Date:   Mon Dec 1 20:09:40 2014 -0800

    GbEditorTab: new tab design using GbEditorFrame and splits

 src/editor/gb-editor-tab-private.h        |   99 +--
 src/editor/gb-editor-tab.c                | 1463 +++++++++--------------------
 src/editor/gb-editor-tab.h                |   31 +-
 src/resources/gnome-builder.gresource.xml |    1 +
 src/resources/ui/gb-editor-tab.ui         |  154 +---
 src/resources/ui/gb-editor-workspace.ui   |   30 +-
 6 files changed, 527 insertions(+), 1251 deletions(-)
---
diff --git a/src/editor/gb-editor-tab-private.h b/src/editor/gb-editor-tab-private.h
index fd597b6..8b65539 100644
--- a/src/editor/gb-editor-tab-private.h
+++ b/src/editor/gb-editor-tab-private.h
@@ -19,104 +19,35 @@
 #ifndef GB_EDITOR_TAB_PRIVATE_H
 #define GB_EDITOR_TAB_PRIVATE_H
 
-#include <gtk/gtk.h>
 #include <gtksourceview/gtksource.h>
 
 #include "gb-animation.h"
-#include "gb-box-theatric.h"
 #include "gb-editor-document.h"
-#include "gb-markdown-preview.h"
-#include "gb-notebook.h"
-#include "gb-source-change-monitor.h"
-#include "gb-source-search-highlighter.h"
-#include "gb-source-view.h"
-#include "gca-service.h"
-#include "gd-tagged-entry.h"
-#include "nautilus-floating-bar.h"
+#include "gb-editor-frame.h"
+#include "gb-editor-tab.h"
 
 G_BEGIN_DECLS
 
 struct _GbEditorTabPrivate
 {
-  /*
-   * Our underlying document, the GtkTextBuffer.
-   */
-  GbEditorDocument *document;
-
-  /*
-   * Search releated components.
-   */
-  GbSourceSearchHighlighter *search_highlighter;
-  GtkSourceSearchSettings   *search_settings;
-  GtkSourceSearchContext    *search_context;
-
-  /*
-   * Change (add, change, etc) tracking of the editor.
-   */
-  GbSourceChangeMonitor *change_monitor;
-  GtkSourceGutterRenderer *change_renderer;
-
-  /*
-   * Weak reference bindings for tracking settings.
-   */
-  GBinding *auto_indent_binding;
-  GBinding *highlight_current_line_binding;
-  GBinding *highlight_matching_brackets_binding;
-  GBinding *insert_spaces_instead_of_tabs_binding;
-  GBinding *right_margin_position_binding;
-  GBinding *show_line_marks_binding;
-  GBinding *show_line_numbers_binding;
-  GBinding *show_right_margin_binding;
-  GBinding *smart_home_end_binding;
-  GBinding *tab_width_binding;
+  /* Widgets owned by GtkBuilder */
+  GbEditorFrame    *frame;
+  GtkPaned         *paned;
+  GtkProgressBar   *progress_bar;
+  GtkToggleButton  *split_button;
 
-  /*
-   * Tab related widgets, filled in with GtkBuilder templates.
-   */
-  NautilusFloatingBar *floating_bar;
-  GtkButton           *go_down_button;
-  GtkButton           *go_up_button;
-  GtkOverlay          *overlay;
-  GtkSpinner          *parsing_spinner;
-  GtkBox              *preview_container;
-  GtkProgressBar      *progress_bar;
-  GtkRevealer         *revealer;
-  GtkScrolledWindow   *scroller;
-  GbSourceView        *source_view;
-  GdTaggedEntry       *search_entry;
-  GdTaggedEntryTag    *search_entry_tag;
+  /* Weak references */
+  GbEditorFrame    *last_frame;
+  GbAnimation      *progress_animation;
 
-  /*
-   * Information about our target file and encoding.
-   */
-  GtkSourceFile *file;
-
-  /*
-   * Code Assistance.
-   */
-  GCancellable            *gca_cancellable;
-  GcaService              *gca_service;
-  gchar                   *gca_tmpfile;
-  gint                     gca_tmpfd;
-  gulong                   gca_buffer_changed_handler;
-  guint                    gca_parse_timeout;
-  gulong                   gca_tooltip_handler;
-  GArray                  *gca_diagnostics;
-  gulong                   gca_draw_layer;
-  GtkSourceGutterRenderer *gca_gutter;
-  GHashTable              *gca_error_lines;
-
-  /*
-   * Animation for save progress.
-   */
-  GbAnimation *save_animation;
+  /* Objects owned by GbEditorTab */
+  GbEditorDocument *document;
 
-  /*
-   * If we want to use word completion in this editor.
-   */
-  guint enable_word_completion : 1;
+  guint             unsaved_id;
 };
 
+GbEditorFrame *gb_editor_tab_get_last_frame (GbEditorTab *tab);
+
 G_END_DECLS
 
 #endif /* GB_EDITOR_TAB_PRIVATE_H */
diff --git a/src/editor/gb-editor-tab.c b/src/editor/gb-editor-tab.c
index 18f1a45..823fe10 100644
--- a/src/editor/gb-editor-tab.c
+++ b/src/editor/gb-editor-tab.c
@@ -16,1271 +16,690 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define G_LOG_DOMAIN "editor"
+#define G_LOG_DOMAIN "editor-tab"
 
 #include <glib/gi18n.h>
 
-#include "gb-editor-code-assistant.h"
-#include "gb-editor-file-mark.h"
-#include "gb-editor-file-marks.h"
+#include "gb-doc-seq.h"
+#include "gb-editor-frame-private.h"
 #include "gb-editor-tab.h"
 #include "gb-editor-tab-private.h"
-#include "gb-editor-workspace.h"
-#include "gb-gtk.h"
+#include "gb-editor-file-mark.h"
+#include "gb-editor-file-marks.h"
 #include "gb-log.h"
-#include "gb-rgba.h"
-#include "gb-source-change-gutter-renderer.h"
-#include "gb-source-highlight-menu.h"
-#include "gb-source-snippet.h"
-#include "gb-source-snippets-manager.h"
-#include "gb-source-snippets.h"
-#include "gb-string.h"
+#include "gb-markdown-tab.h"
 #include "gb-widget.h"
-#include "gb-workbench.h"
-
-#define GB_EDITOR_TAB_UI_RESOURCE "/org/gnome/builder/ui/gb-editor-tab.ui"
-
-enum {
-  PROP_0,
-  PROP_DOCUMENT,
-  PROP_FILE,
-  LAST_PROP
-};
 
 G_DEFINE_TYPE_WITH_PRIVATE (GbEditorTab, gb_editor_tab, GB_TYPE_TAB)
 
-static GParamSpec *gParamSpecs[LAST_PROP];
-
-GtkWidget *
+GbEditorTab *
 gb_editor_tab_new (void)
 {
   return g_object_new (GB_TYPE_EDITOR_TAB, NULL);
 }
 
-/**
- * gb_editor_tab_get_is_default:
- * @tab: A #GbEditorTab.
- *
- * Returns #TRUE if the tab has not been modified since being created
- * from an empty state. This means the tab is a candidate to be
- * dropped or repurposed for loading a new file.
- *
- * Returns: #TRUE if tab is in default state.
- */
-gboolean
-gb_editor_tab_get_is_default (GbEditorTab *tab)
-{
-  GbEditorTabPrivate *priv;
-  GtkTextIter begin;
-  GtkTextIter end;
-
-  g_return_val_if_fail (GB_IS_EDITOR_TAB (tab), FALSE);
-
-  priv = tab->priv;
-
-  if (gtk_source_file_get_location (priv->file))
-    return FALSE;
-
-  if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (priv->document)))
-    return FALSE;
-
-  gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (priv->document), &begin, &end);
-
-  if (gtk_text_iter_compare (&begin, &end) != 0)
-    return FALSE;
-
-  return TRUE;
-}
-
-/**
- * gb_editor_tab_get_document:
- * @tab: A #GbEditorTab.
- *
- * Fetches the document for the tab.
- *
- * Returns: (transfer none): A #GbEditorDocument.
- */
-GbEditorDocument *
-gb_editor_tab_get_document (GbEditorTab *tab)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_TAB (tab), NULL);
-
-  return tab->priv->document;
-}
-
-/**
- * gb_editor_tab_get_file:
- * @tab: A #GbEditorTab.
- *
- * Returns the current file for this tab, if there is one.
- * If no file has been specified, then NULL is returned.
- *
- * Returns: (transfer none): A #GtkSourceFile.
- */
-GtkSourceFile *
-gb_editor_tab_get_file (GbEditorTab *tab)
-{
-  g_return_val_if_fail (GB_IS_EDITOR_TAB (tab), NULL);
-
-  return tab->priv->file;
-}
-
 static void
-set_search_position_label (GbEditorTab *tab,
-                           const gchar *text)
+gb_editor_tab_progress_cb (goffset  current_num_bytes,
+                           goffset  total_num_bytes,
+                           gpointer user_data)
 {
   GbEditorTabPrivate *priv;
+  GbEditorTab *tab = user_data;
+  gdouble fraction;
 
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
   priv = tab->priv;
 
-  if (!text || !*text)
+  if (priv->progress_animation)
     {
-      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;
+      g_object_remove_weak_pointer (G_OBJECT (priv->progress_animation),
+                                    (gpointer *)&priv->progress_animation);
+      gb_animation_stop (priv->progress_animation);
+      priv->progress_animation = NULL;
     }
 
-  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);
-    }
+  fraction = total_num_bytes
+           ? ((gdouble)current_num_bytes / (gdouble)total_num_bytes)
+           : 1.0;
 
-  gd_tagged_entry_tag_set_label (priv->search_entry_tag, text);
+  priv->progress_animation =
+    gb_object_animate (priv->progress_bar,
+                       GB_ANIMATION_LINEAR,
+                       250,
+                       NULL,
+                       "fraction", fraction,
+                       NULL);
+  g_object_add_weak_pointer (G_OBJECT (priv->progress_animation),
+                             (gpointer *)&priv->progress_animation);
 }
 
 static void
-update_search_position_label (GbEditorTab *tab)
+gb_editor_tab_save_cb (GObject      *source_object,
+                       GAsyncResult *result,
+                       gpointer      user_data)
 {
-  GbEditorTabPrivate *priv;
-  GtkStyleContext *context;
-  GtkTextIter begin;
-  GtkTextIter end;
-  const gchar *search_text;
-  gchar *text;
-  gint count;
-  gint pos;
-
-  g_assert (GB_IS_EDITOR_TAB (tab));
+  GbEditorTab *tab = user_data;
+  GbEditorDocument *document = (GbEditorDocument *)source_object;
+  GError *error = NULL;
 
-  priv = tab->priv;
+  ENTRY;
 
-  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);
+  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
+  g_return_if_fail (G_IS_ASYNC_RESULT (result));
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
-  if ((pos == -1) || (count == -1))
+  if (!gb_editor_document_save_finish (document, result, &error))
     {
-      /*
-       * We are not yet done scanning the buffer.
-       * We will be updated when we know more, so just hide it for now.
-       */
-      set_search_position_label (tab, NULL);
-      return;
+      g_print ("%s\n", error->message);
+      //gb_editor_tab_set_error (tab, error);
+      g_clear_error (&error);
     }
 
-  context = gtk_widget_get_style_context (GTK_WIDGET (priv->search_entry));
-  search_text = gtk_entry_get_text (GTK_ENTRY (priv->search_entry));
+  gb_widget_fade_hide (GTK_WIDGET (tab->priv->progress_bar));
 
-  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);
-  set_search_position_label (tab, text);
-  g_free (text);
-}
-
-static void
-on_search_occurrences_notify (GbEditorTab            *tab,
-                              GParamSpec             *pspec,
-                              GtkSourceSearchContext *search_context)
-{
-  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
-  g_return_if_fail (GTK_SOURCE_IS_SEARCH_CONTEXT (search_context));
+  g_object_unref (tab);
 
-  update_search_position_label (tab);
+  EXIT;
 }
 
 static void
-gb_editor_tab_cursor_moved (GbEditorTab      *tab,
-                            GbEditorDocument *document)
+gb_editor_tab_do_save (GbEditorTab *tab)
 {
-  GtkSourceView *source_view;
-  GtkTextBuffer *buffer;
-  GbSourceVim *vim;
-  GtkTextIter iter;
-  GtkTextMark *mark;
-  const gchar *phrase;
-  gchar *text;
-  guint ln;
-  guint col;
+  ENTRY;
 
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
-  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
 
-  source_view = GTK_SOURCE_VIEW (tab->priv->source_view);
-  buffer = GTK_TEXT_BUFFER (document);
+  gtk_progress_bar_set_fraction (tab->priv->progress_bar, 0.0);
+  gtk_widget_show (GTK_WIDGET (tab->priv->progress_bar));
 
-  mark = gtk_text_buffer_get_insert (buffer);
-  gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
+  gb_editor_document_save_async (tab->priv->document,
+                                 NULL, /* cancellable */
+                                 gb_editor_tab_progress_cb,
+                                 tab,
+                                 NULL,
+                                 gb_editor_tab_save_cb,
+                                 g_object_ref (tab));
 
-  ln = gtk_text_iter_get_line (&iter);
-  col = gtk_source_view_get_visual_column (source_view, &iter);
-
-  vim = gb_source_view_get_vim (tab->priv->source_view);
-  phrase = gb_source_vim_get_phrase (vim);
-
-  if (!gb_str_empty0 (phrase))
-    text = g_strdup_printf (_("%s\tLine %u, Column %u"),
-                            phrase, ln + 1, col + 1);
-  else
-    text = g_strdup_printf (_("Line %u, Column %u"), ln + 1, col + 1);
-
-  nautilus_floating_bar_set_primary_label (tab->priv->floating_bar, text);
-  g_free (text);
-
-  update_search_position_label (tab);
+  EXIT;
 }
 
-static void
-gb_editor_tab_language_changed (GbEditorTab     *tab,
-                                GParamSpec      *pspec,
-                                GtkSourceBuffer *buffer)
+void
+gb_editor_tab_save_as (GbEditorTab *tab)
 {
-  GtkSourceLanguage *language;
+  const gchar *title;
+  GtkWidget *toplevel;
+  GtkDialog *dialog;
+  GtkWidget *suggested;
+  GFile *chosen_file;
+  guint response;
+
+  ENTRY;
 
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
-  g_return_if_fail (GTK_SOURCE_IS_BUFFER (buffer));
 
-  language = gtk_source_buffer_get_language (buffer);
+  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tab));
+  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);
 
-  gb_editor_code_assistant_destroy (tab);
-  if (language)
-    gb_editor_code_assistant_init (tab);
-}
+  title = gb_tab_get_title (GB_TAB (tab));
+  gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), title);
 
-static void
-gb_editor_tab_modified_changed (GbEditorTab   *tab,
-                                GtkTextBuffer *buffer)
-{
-  gboolean dirty;
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                          _("Cancel"), GTK_RESPONSE_CANCEL,
+                          _("Save"), GTK_RESPONSE_OK,
+                          NULL);
 
-  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
-  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
 
-  dirty = gtk_text_buffer_get_modified (buffer);
-  gb_tab_set_dirty (GB_TAB (tab), dirty);
-}
+  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);
 
-static void
-gb_editor_tab_freeze_drag (GbTab *tab)
-{
-  GbEditorTab *editor = (GbEditorTab *) tab;
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_widget_hide (GTK_WIDGET (dialog));
 
-  ENTRY;
+  if (response == GTK_RESPONSE_OK)
+    {
+      GtkSourceFile *sfile;
 
-  g_return_if_fail (GB_IS_EDITOR_TAB (editor));
+      sfile = gb_editor_document_get_file (tab->priv->document);
+      chosen_file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
+      gtk_source_file_set_location (sfile, chosen_file);
+      gb_editor_tab_do_save (tab);
+      g_clear_object (&chosen_file);
+    }
 
-  /*
-   * WORKAROUND:
-   *
-   * Unset drag 'n drop for the source view so that it doesn't
-   * highjack drop target signals when what we really want is to
-   * be dropped into a notebook.
-   */
-  gtk_drag_dest_unset (GTK_WIDGET (editor->priv->source_view));
+  gtk_widget_destroy (GTK_WIDGET (dialog));
 
   EXIT;
 }
 
-static void
-gb_editor_tab_thaw_drag (GbTab *tab)
+void
+gb_editor_tab_save (GbEditorTab *tab)
 {
-  GbEditorTabPrivate *priv;
-  GtkTargetList *target_list;
-  GbEditorTab *editor = (GbEditorTab *) tab;
+  GtkSourceFile *file;
+  gboolean has_location;
 
   ENTRY;
 
-  g_return_if_fail (GB_IS_EDITOR_TAB (editor));
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
-  priv = editor->priv;
+  file = gb_editor_document_get_file (tab->priv->document);
+  has_location = !!gtk_source_file_get_location (file);
 
-  /*
-   * WORKAROUND:
-   *
-   * Restore drag 'n drop for this tab. These match the values in
-   * gtktextview.c.
-   */
-  gtk_drag_dest_set (GTK_WIDGET (priv->source_view), 0, NULL, 0,
-                     GDK_ACTION_COPY | GDK_ACTION_MOVE);
-  target_list = gtk_target_list_new (NULL, 0);
-  gtk_drag_dest_set_target_list (GTK_WIDGET (priv->source_view), target_list);
-  gtk_target_list_unref (target_list);
+  if (has_location)
+    gb_editor_tab_do_save (tab);
+  else
+    gb_editor_tab_save_as (tab);
 
   EXIT;
 }
 
 static void
-gb_editor_tab_grab_focus (GtkWidget *widget)
+gb_editor_tab_open_file_cb (GObject      *source_object,
+                            GAsyncResult *result,
+                            gpointer      user_data)
 {
-  GbEditorTab *tab = (GbEditorTab *) widget;
+  GbEditorTab *tab = user_data;
+  GbEditorDocument *document = (GbEditorDocument *)source_object;
+  GError *error = NULL;
 
   ENTRY;
 
+  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
+  g_return_if_fail (G_IS_ASYNC_RESULT (result));
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
-  gtk_widget_grab_focus (GTK_WIDGET (tab->priv->source_view));
-
-  EXIT;
-}
-
-static gboolean
-on_search_entry_key_press_event (GdTaggedEntry *entry,
-                                 GdkEventKey   *event,
-                                 GbEditorTab   *tab)
-{
-  g_assert (GD_IS_TAGGED_ENTRY (entry));
-  g_assert (GB_IS_EDITOR_TAB (tab));
-
-  if (event->keyval == GDK_KEY_Escape)
+  if (!gb_editor_document_load_finish (document, result, &error))
     {
-      gtk_revealer_set_reveal_child (tab->priv->revealer, FALSE);
-      gb_source_view_set_show_shadow (tab->priv->source_view, FALSE);
-      gtk_widget_grab_focus (GTK_WIDGET (tab->priv->source_view));
-      return GDK_EVENT_STOP;
+      g_print ("%s\n", error->message);
+      //gb_editor_tab_set_error (tab, error);
+      g_clear_error (&error);
     }
 
-  return GDK_EVENT_PROPAGATE;
-}
+  gb_editor_tab_restore_file_mark (tab);
 
-static gboolean
-on_search_entry_focus_in (GdTaggedEntry *entry,
-                          GdkEvent      *event,
-                          GbEditorTab   *tab)
-{
-  g_return_val_if_fail (GD_IS_TAGGED_ENTRY (entry), FALSE);
-  g_return_val_if_fail (GB_IS_EDITOR_TAB (tab), FALSE);
-
-  gtk_widget_queue_draw (GTK_WIDGET (tab->priv->source_view));
-
-  return FALSE;
-}
-
-static gboolean
-on_search_entry_focus_out (GdTaggedEntry *entry,
-                           GdkEvent      *event,
-                           GbEditorTab   *tab)
-{
-  g_return_val_if_fail (GD_IS_TAGGED_ENTRY (entry), FALSE);
-  g_return_val_if_fail (GB_IS_EDITOR_TAB (tab), FALSE);
-
-  gtk_widget_queue_draw (GTK_WIDGET (tab->priv->source_view));
-
-  return FALSE;
-}
-
-static gboolean
-do_delayed_animation (gpointer data)
-{
-  GbEditorTabPrivate *priv;
-  GbBoxTheatric *theatric;
-  GdkFrameClock *frame_clock;
-  GbEditorTab *tab = data;
-  GtkTextView *text_view;
-  GtkTextBuffer *buffer;
-  GtkSourceStyleScheme *scheme;
-  GtkSourceStyle *style;
-  GdkRectangle begin_rect;
-  GdkRectangle end_rect;
-  GtkTextIter begin;
-  GtkTextIter end;
-  GdkRGBA rgba;
-  gchar *color;
-
-  priv = tab->priv;
-
-  gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (priv->document),
-                                        &begin, &end);
-  if (gtk_text_iter_compare (&begin, &end) == 0)
-    return G_SOURCE_REMOVE;
-
-  text_view = GTK_TEXT_VIEW (priv->source_view);
-  buffer = gtk_text_view_get_buffer (text_view);
-  scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (buffer));
-  style = gtk_source_style_scheme_get_style (scheme, "search-match");
-  g_object_get (style, "background", &color, NULL);
-  gdk_rgba_parse (&rgba, color);
-  gb_rgba_shade (&rgba, &rgba, 1.2);
-  g_free (color);
-  color = gdk_rgba_to_string (&rgba);
-
-  gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->source_view),
-                                   &begin, &begin_rect);
-  gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (priv->source_view),
-                                         GTK_TEXT_WINDOW_WIDGET,
-                                         begin_rect.x,
-                                         begin_rect.y,
-                                         &begin_rect.x,
-                                         &begin_rect.y);
-
-  gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->source_view),
-                                   &end, &end_rect);
-  gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (priv->source_view),
-                                         GTK_TEXT_WINDOW_WIDGET,
-                                         end_rect.x,
-                                         end_rect.y,
-                                         &end_rect.x,
-                                         &end_rect.y);
-
-  /*
-   * TODO: This might actually need to wrap around more.
-   */
-  gdk_rectangle_union (&begin_rect, &end_rect, &begin_rect);
-
-#define X_GROW 25
-#define Y_GROW 25
-
-  end_rect = begin_rect;
-  end_rect.x -= X_GROW;
-  end_rect.y -= Y_GROW;
-  end_rect.width += X_GROW * 2;
-  end_rect.height += Y_GROW * 2;
-
-  theatric = g_object_new (GB_TYPE_BOX_THEATRIC,
-                           "target", priv->source_view,
-                           "x", begin_rect.x,
-                           "y", begin_rect.y,
-                           "width", begin_rect.width,
-                           "height", begin_rect.height,
-                           "background", color,
-                           "alpha", 0.5,
-                           NULL);
-
-  frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (priv->source_view));
-
-  gb_object_animate (theatric,
-                     GB_ANIMATION_EASE_OUT_CUBIC,
-                     250,
-                     frame_clock,
-                     "alpha", 0.0,
-                     "height", end_rect.height,
-                     "width", end_rect.width,
-                     "x", end_rect.x,
-                     "y", end_rect.y,
-                     NULL);
-
-#undef X_GROW
-#undef Y_GROW
+  gb_widget_fade_hide (GTK_WIDGET (tab->priv->progress_bar));
 
   g_object_unref (tab);
-  g_free (color);
-
-  return G_SOURCE_REMOVE;
-}
 
-static void
-delayed_animation (GbEditorTab *tab)
-{
-  g_timeout_add (200, do_delayed_animation, g_object_ref (tab));
+  EXIT;
 }
 
-static void
-select_and_animate (GbEditorTab       *tab,
-                    const GtkTextIter *begin,
-                    const GtkTextIter *end)
+void
+gb_editor_tab_open_file (GbEditorTab *tab,
+                         GFile       *file)
 {
-  GbEditorTabPrivate *priv;
-  GtkTextIter copy;
+  ENTRY;
 
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
-  g_return_if_fail (begin);
-  g_return_if_fail (end);
 
-  priv = tab->priv;
+  gtk_progress_bar_set_fraction (tab->priv->progress_bar, 0.0);
+  gtk_widget_show (GTK_WIDGET (tab->priv->progress_bar));
 
-  gtk_text_iter_assign (&copy, begin);
+  gb_editor_document_load_async (tab->priv->document,
+                                 file,
+                                 NULL, /* cancellable */
+                                 gb_editor_tab_progress_cb,
+                                 tab,
+                                 NULL,
+                                 gb_editor_tab_open_file_cb,
+                                 g_object_ref (tab));
 
-#if 0
-  /* select the entire word */
-  gtk_text_buffer_select_range (GTK_TEXT_BUFFER (priv->document), begin, end);
-#else
-  /* move the cursor to the first character of the word */
-  gtk_text_buffer_select_range (GTK_TEXT_BUFFER (priv->document), begin, begin);
-#endif
-  gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->source_view), &copy, 0.0,
-                                TRUE, 0.5, 0.5);
-
-  if (!gtk_text_iter_equal (begin, end))
-    delayed_animation (tab);
+  EXIT;
 }
 
-static void
-gb_editor_tab_move_next_match (GbEditorTab *tab)
+void
+gb_editor_tab_restore_file_mark (GbEditorTab *tab)
 {
   GbEditorTabPrivate *priv;
-  GtkTextBuffer *buffer;
-  GtkTextIter select_begin;
-  GtkTextIter select_end;
-  GtkTextIter match_begin;
-  GtkTextIter match_end;
-  gboolean has_selection;
-
-  ENTRY;
+  GtkSourceFile *file;
+  GSettings *settings;
+  gboolean restore_mark;
+  GFile *location;
 
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
   priv = tab->priv;
 
-  buffer = GTK_TEXT_BUFFER (priv->document);
-
-  /*
-   * Start by trying from our current location.
-   */
-  has_selection = gtk_text_buffer_get_selection_bounds (buffer, &select_begin,
-                                                        &select_end);
-  if (!has_selection)
-    if (!gtk_text_iter_forward_char (&select_end))
-      gtk_text_buffer_get_end_iter (buffer, &select_end);
+  settings = g_settings_new ("org.gnome.builder.editor");
+  restore_mark = g_settings_get_boolean (settings, "restore-insert-mark");
+  g_object_unref (settings);
 
-  if (gtk_source_search_context_forward (priv->search_context, &select_end,
-                                         &match_begin, &match_end))
+  if (!restore_mark)
     {
-      select_and_animate (tab, &match_begin, &match_end);
-      EXIT;
-    }
-
-  /*
-   * Didn't find anything, let's try from the beginning of the buffer.
-   */
+      GtkTextIter iter;
 
-  gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (priv->document),
-                              &select_begin, &select_end);
-
-  if (gtk_source_search_context_forward (priv->search_context, &select_begin,
-                                         &match_begin, &match_end))
-    {
-      select_and_animate (tab, &match_begin, &match_end);
-      EXIT;
+      gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (tab->priv->document),
+                                      &iter);
+      gtk_text_buffer_select_range (GTK_TEXT_BUFFER (tab->priv->document),
+                                    &iter, &iter);
+      return;
     }
 
-  EXIT;
-}
-
-static void
-gb_editor_tab_move_previous_match (GbEditorTab *tab)
-{
-  GbEditorTabPrivate *priv;
-  GtkTextIter select_begin;
-  GtkTextIter select_end;
-  GtkTextIter match_begin;
-  GtkTextIter match_end;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+  file = gb_editor_document_get_file (priv->document);
+  location = gtk_source_file_get_location (file);
 
-  priv = tab->priv;
-
-  gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (priv->document),
-                                        &select_begin, &select_end);
-
-  if (gtk_source_search_context_backward (priv->search_context, &select_begin,
-                                          &match_begin, &match_end))
-    GOTO (found_match);
-  else
+  if (location)
     {
-      /*
-       * We need to wrap around from the end to find the last search result.
-       */
-      gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (priv->document),
-                                    &select_begin);
-      if (gtk_source_search_context_backward (priv->search_context,
-                                              &select_begin, &match_begin,
-                                              &match_end))
-        GOTO (found_match);
-    }
-
-  EXIT;
+      GbEditorFileMarks *marks;
+      GbEditorFileMark *mark;
+      guint line;
+      guint column;
 
-found_match:
-  select_and_animate (tab, &match_begin, &match_end);
+      marks = gb_editor_file_marks_get_default ();
+      mark = gb_editor_file_marks_get_for_file (marks, location);
 
-  EXIT;
-}
-
-static void
-on_search_entry_activate (GdTaggedEntry *search_entry,
-                          GbEditorTab   *tab)
-{
-  g_return_if_fail (GD_IS_TAGGED_ENTRY (search_entry));
-  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+      if (mark)
+        {
+          line = gb_editor_file_mark_get_line (mark);
+          column = gb_editor_file_mark_get_column (mark);
 
-  gb_editor_tab_move_next_match (tab);
-  gtk_widget_grab_focus (GTK_WIDGET (tab->priv->source_view));
+          gb_editor_tab_scroll_to_line (tab, line, column);
+        }
+    }
 }
 
-static gboolean
-on_source_view_focus_in_event (GbSourceView *view,
-                               GdkEvent     *event,
-                               GbEditorTab  *tab)
+void
+gb_editor_tab_toggle_split (GbEditorTab *tab)
 {
-  g_return_val_if_fail (GB_IS_EDITOR_TAB (tab), FALSE);
+  gboolean active;
 
-  gtk_revealer_set_reveal_child (tab->priv->revealer, FALSE);
-  gtk_source_search_context_set_highlight (tab->priv->search_context, FALSE);
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
-  return GDK_EVENT_PROPAGATE;
+  active = gtk_toggle_button_get_active (tab->priv->split_button);
+  gtk_toggle_button_set_active (tab->priv->split_button, !active);
 }
 
 static void
-on_source_view_populate_popup (GtkTextView *text_view,
-                               GtkWidget   *popup,
-                               GbEditorTab *tab)
+gb_editor_tab_on_frame_focused (GbEditorTab   *tab,
+                                GbEditorFrame *frame)
 {
-  GbWorkbench *workbench;
-  GbWorkspace *workspace;
+  GbEditorTabPrivate *priv;
 
-  g_return_if_fail (GB_IS_SOURCE_VIEW (text_view));
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+  g_return_if_fail (GB_IS_EDITOR_FRAME (frame));
 
-  if (GTK_IS_MENU (popup))
-    {
-      PangoFontDescription *font = NULL;
-      GtkStyleContext *context;
-      GMenuModel *model;
-      GtkWidget *menu_item;
-      GtkWidget *menu;
-      GtkWidget *separator;
-
-      workbench = GB_WORKBENCH (gtk_widget_get_toplevel (GTK_WIDGET (text_view)));
-      workspace = gb_workbench_get_active_workspace (workbench);
-
-      /*
-       * WORKAROUND:
-       *
-       * GtkSourceView (and really, GtkTextView) inherit the font for the
-       * popup window from the GtkTextView. This is problematic since we
-       * override it to be a font such as Monospace.
-       *
-       * The following code works around that by applying the font that
-       * is the default for the editor tab to the popup window.
-       */
-      context = gtk_widget_get_style_context (GTK_WIDGET (tab));
-      gtk_style_context_get (context, GTK_STATE_FLAG_NORMAL,
-                             "font", &font,
-                             NULL);
-      if (font)
-        {
-          gtk_widget_override_font (popup, font);
-          pango_font_description_free (font);
-        }
+  priv = tab->priv;
 
-      /*
-       * TODO: Add menu for controlling font size.
-       */
-
-      /*
-       * Add separator.
-       */
-      separator = gtk_separator_menu_item_new ();
-      gtk_menu_shell_prepend (GTK_MENU_SHELL (popup), GTK_WIDGET (separator));
-      gtk_widget_show (separator);
-
-      /*
-       * Add menu for highlight mode.
-       */
-      model = gb_source_highlight_menu_new ();
-      menu = gtk_menu_new_from_model (model);
-      menu_item = gtk_menu_item_new_with_label (_("Highlight Mode"));
-      gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
-      gtk_menu_shell_prepend (GTK_MENU_SHELL (popup), GTK_WIDGET (menu_item));
-      gtk_widget_insert_action_group (GTK_WIDGET (menu_item), "editor",
-                                      gb_workspace_get_actions (workspace));
-      gtk_widget_show (GTK_WIDGET (menu_item));
-      g_object_unref (model);
+  if (priv->last_frame)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (priv->last_frame),
+                                    (gpointer *)&priv->last_frame);
+      priv->last_frame = NULL;
     }
-}
 
-static void
-on_source_view_push_snippet (GbSourceView           *source_view,
-                             GbSourceSnippet        *snippet,
-                             GbSourceSnippetContext *context,
-                             GtkTextIter            *iter,
-                             GbEditorTab            *tab)
-{
-  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_TAB (tab));
-
-  file = gtk_source_file_get_location (tab->priv->file);
-  g_assert (!file || G_IS_FILE (file));
-
-  if (file)
+  if (frame)
     {
-      gchar *name = g_file_get_basename (file);
-      gb_source_snippet_context_add_variable (context, "filename", name);
-      g_free (name);
+      priv->last_frame = frame;
+      g_object_add_weak_pointer (G_OBJECT (priv->last_frame),
+                                  (gpointer *)&priv->last_frame);
     }
 }
 
 static void
-on_source_view_begin_search (GbSourceView     *source_view,
-                             GtkDirectionType  direction,
-                             const gchar      *search_text,
-                             GbEditorTab      *tab)
+gb_editor_tab_on_split_toggled (GbEditorTab     *tab,
+                                GtkToggleButton *button)
 {
   GbEditorTabPrivate *priv;
+  GtkWidget *child2;
 
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
-  g_return_if_fail (GB_IS_SOURCE_VIEW (source_view));
 
   priv = tab->priv;
 
-  if (search_text)
-    gtk_entry_set_text (GTK_ENTRY (priv->search_entry), search_text);
-
-  gtk_revealer_set_reveal_child (priv->revealer, TRUE);
-  gtk_source_search_context_set_highlight (priv->search_context, TRUE);
-  gtk_widget_grab_focus (GTK_WIDGET (priv->search_entry));
+  child2 = gtk_paned_get_child2 (priv->paned);
 
-  if (search_text)
+  if (child2)
     {
-      if (direction == GTK_DIR_DOWN)
-        gb_editor_tab_move_next_match (tab);
-      else if (direction == GTK_DIR_UP)
-        gb_editor_tab_move_previous_match (tab);
+      gtk_container_remove (GTK_CONTAINER (priv->paned), child2);
     }
   else
     {
-      const gchar *text;
-      guint len;
-
-      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);
+      child2 = g_object_new (GB_TYPE_EDITOR_FRAME,
+                             "document", priv->document,
+                             "visible", TRUE,
+                             NULL);
+      gtk_paned_add2 (priv->paned, child2);
+      gtk_container_child_set (GTK_CONTAINER (priv->paned), child2,
+                               "resize", TRUE,
+                               "shrink", FALSE,
+                               NULL);
+      g_signal_connect_object (child2,
+                               "focused",
+                               G_CALLBACK (gb_editor_tab_on_frame_focused),
+                               tab,
+                               G_CONNECT_SWAPPED);
+      gtk_widget_grab_focus (child2);
     }
 }
 
+GbEditorFrame *
+gb_editor_tab_get_last_frame (GbEditorTab *tab)
+{
+  g_return_val_if_fail (GB_IS_EDITOR_TAB (tab), NULL);
+
+  if (tab->priv->last_frame)
+    return tab->priv->last_frame;
+
+  return tab->priv->frame;
+}
+
 void
 gb_editor_tab_scroll_to_line (GbEditorTab *tab,
                               guint        line,
                               guint        line_offset)
 {
+  GbEditorFrame *frame;
   GtkTextIter iter;
 
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
+  frame = gb_editor_tab_get_last_frame (tab);
+
   gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (tab->priv->document),
                                     &iter, line);
-  gtk_text_iter_set_line_offset (&iter, line_offset);
+  for (; line_offset; line_offset--)
+    {
+      if (gtk_text_iter_ends_line (&iter))
+        break;
+      if (!gtk_text_iter_forward_char (&iter))
+        break;
+    }
+
   gtk_text_buffer_select_range (GTK_TEXT_BUFFER (tab->priv->document),
                                 &iter, &iter);
-  gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (tab->priv->source_view), &iter,
+
+  gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (frame->priv->source_view), &iter,
                                 0.0, FALSE, 0.0, 0.5);
 }
 
 static void
-on_vim_command_visibility_toggled (GbSourceVim *vim,
-                                   gboolean     visible,
-                                   GbEditorTab *tab)
+gb_editor_tab_scroll (GbEditorTab      *tab,
+                      GtkDirectionType  dir)
 {
-  GbWorkbench *workbench;
-  GAction *action;
-  GVariant *params;
-
-  ENTRY;
+  GtkAdjustment *vadj;
+  GbEditorFrame *last_frame;
+  GtkScrolledWindow *scroller;
+  GtkTextMark *insert;
+  GtkTextView *view;
+  GtkTextBuffer *buffer;
+  GdkRectangle rect;
+  GtkTextIter iter;
+  gdouble amount;
+  gdouble value;
+  gdouble upper;
 
-  g_return_if_fail (GB_IS_SOURCE_VIM (vim));
-  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+  g_assert (GB_IS_EDITOR_TAB (tab));
 
-  workbench = gb_widget_get_workbench (GTK_WIDGET (tab));
-  if (!workbench)
-    return;
+  last_frame = gb_editor_tab_get_last_frame (tab);
+  scroller = last_frame->priv->scrolled_window;
+  view = GTK_TEXT_VIEW (last_frame->priv->source_view);
+  buffer = GTK_TEXT_BUFFER (last_frame->priv->document);
 
-  action = g_action_map_lookup_action (G_ACTION_MAP (workbench),
-                                       "toggle-command-bar");
-  if (!action)
-    return;
+  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);
 
-  params = g_variant_new_boolean (visible);
-  g_action_activate (action, params);
+  amount = (dir == GTK_DIR_UP) ? -rect.height : rect.height;
 
-  EXIT;
+  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
-on_vim_begin_search (GbSourceVim *vim,
-                     const gchar *search_text,
-                     GbEditorTab *tab)
+void
+gb_editor_tab_scroll_up (GbEditorTab *tab)
 {
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
-  gb_source_view_begin_search (tab->priv->source_view, GTK_DIR_DOWN,
-                               search_text);
+  gb_editor_tab_scroll (tab, GTK_DIR_UP);
 }
 
-static void
-on_vim_notify_phrase (GbSourceVim *vim,
-                      GParamSpec  *pspec,
-                      GbEditorTab *tab)
+void
+gb_editor_tab_scroll_down (GbEditorTab *tab)
 {
-  g_return_if_fail (GB_IS_SOURCE_VIM (vim));
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
-  gb_editor_tab_cursor_moved (tab, tab->priv->document);
+  gb_editor_tab_scroll (tab, GTK_DIR_DOWN);
 }
 
 static void
-on_vim_notify_mode (GbSourceVim *vim,
-                    GParamSpec  *pspec,
-                    GbEditorTab *tab)
+gb_editor_tab_grab_focus (GtkWidget *widget)
 {
-  GbSourceVimMode mode;
+  GbEditorFrame *last_frame;
 
-  g_return_if_fail (GB_IS_SOURCE_VIM (vim));
-  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+  g_return_if_fail (GB_IS_EDITOR_TAB (widget));
 
-  mode = gb_source_vim_get_mode (vim);
+  last_frame = gb_editor_tab_get_last_frame (GB_EDITOR_TAB (widget));
 
-  if (mode != GB_SOURCE_VIM_INSERT)
-    gb_source_view_clear_snippets (tab->priv->source_view);
+  gtk_widget_grab_focus (GTK_WIDGET (last_frame));
 }
 
-static gboolean
-transform_file_to_language (GBinding     *binding,
-                            const GValue *src_value,
-                            GValue       *dst_value,
-                            gpointer      user_data)
+static void
+gb_editor_tab_update_title (GbEditorTab *tab)
 {
-  GbEditorTab *tab = user_data;
-  GtkSourceLanguage *language = NULL;
+  GtkSourceFile *file;
   GFile *location;
+  gchar *title;
 
-  g_assert (GB_IS_EDITOR_TAB (tab));
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
-  location = g_value_get_object (src_value);
+  file = gb_editor_document_get_file (tab->priv->document);
+  location = gtk_source_file_get_location (file);
 
   if (location)
     {
-      GtkSourceLanguageManager *manager;
-      gchar *filename;
-      gchar *content_type = NULL;
-
-      filename = g_file_get_basename (location);
-
-      /*
-       * TODO: Load content_type using g_file_query_info().
-       *       Also, don't do this here, do it async.
-       */
-
-      manager = gtk_source_language_manager_get_default ();
-      language = gtk_source_language_manager_guess_language (manager, filename,
-                                                             content_type);
-      gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (tab->priv->document),
-                                      language);
-
-      gb_editor_code_assistant_destroy (tab);
+      if (tab->priv->unsaved_id)
+        {
+          gb_doc_seq_release (tab->priv->unsaved_id);
+          tab->priv->unsaved_id = 0;
+        }
 
-      g_free (filename);
-      g_free (content_type);
+      title = g_file_get_basename (location);
+      gb_tab_set_title (GB_TAB (tab), title);
+      g_free (title);
+    }
+  else
+    {
+      if (!tab->priv->unsaved_id)
+        {
+          tab->priv->unsaved_id = gb_doc_seq_acquire ();
+          title = g_strdup_printf (_("unsaved %u"), tab->priv->unsaved_id);
+          gb_tab_set_title (GB_TAB (tab), title);
+          g_free (title);
+        }
     }
-
-  g_value_set_object (dst_value, language);
-
-  return TRUE;
 }
 
-static gboolean
-transform_file_to_title (GBinding     *binding,
-                         const GValue *src_value,
-                         GValue       *dst_value,
-                         gpointer      user_data)
+static void
+gb_editor_tab_on_notify_location (GbEditorTab   *tab,
+                                  GParamSpec    *pspec,
+                                  GtkSourceFile *file)
 {
-  GbEditorTab *tab = user_data;
-  gchar *title;
-  GFile *file;
-
-  g_return_val_if_fail (GB_IS_EDITOR_TAB (tab), FALSE);
-  g_return_val_if_fail (G_VALUE_HOLDS (src_value, G_TYPE_FILE), FALSE);
-  g_return_val_if_fail (G_VALUE_HOLDS (dst_value, G_TYPE_STRING), FALSE);
 
-  file = g_value_get_object (src_value);
-
-  if (file)
-    title = g_file_get_basename (file);
-  else
-    title = g_strdup (_("unsaved file"));
-
-  g_value_take_string (dst_value, title);
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+  g_return_if_fail (GTK_SOURCE_IS_FILE (file));
 
-  return TRUE;
+  gb_editor_tab_update_title (tab);
 }
 
 static void
-gb_editor_tab_constructed (GObject *object)
+gb_editor_tab_on_modified_changed (GbEditorTab   *tab,
+                                   GtkTextBuffer *buffer)
 {
-  GtkSourceCompletion *comp;
-  GbEditorTabPrivate *priv;
-  GbEditorTab *tab = (GbEditorTab *) object;
-  GbSourceVim *vim;
-  GtkSourceGutter *gutter;
-
-  ENTRY;
+  gboolean modified;
 
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
-  priv = tab->priv;
+  modified = gtk_text_buffer_get_modified (buffer);
+  gb_tab_set_dirty (GB_TAB (tab), modified);
 
-  if (!priv->document)
-    priv->document = gb_editor_document_new ();
-
-  gtk_text_view_set_buffer (GTK_TEXT_VIEW (priv->source_view),
-                            GTK_TEXT_BUFFER (priv->document));
-
-  if (!priv->file)
-    priv->file = gtk_source_file_new ();
-
-  if (!priv->change_monitor)
-    priv->change_monitor = gb_source_change_monitor_new (GTK_TEXT_BUFFER (priv->document));
-
-  priv->search_settings =
-    g_object_new (GTK_SOURCE_TYPE_SEARCH_SETTINGS,
-                  NULL);
-
-  priv->search_context =
-    g_object_new (GTK_SOURCE_TYPE_SEARCH_CONTEXT,
-                  "buffer", priv->document,
-                  "settings", priv->search_settings,
-                  "highlight", TRUE,
-                  NULL);
-
-  priv->search_highlighter =
-    g_object_new (GB_TYPE_SOURCE_SEARCH_HIGHLIGHTER,
-                  "search-context", priv->search_context,
-                  "search-settings", priv->search_settings,
-                  NULL);
-  g_object_set (priv->source_view,
-                "search-highlighter", priv->search_highlighter,
-                NULL);
-
-  g_signal_connect_swapped (priv->document,
-                            "notify::language",
-                            G_CALLBACK (gb_editor_tab_language_changed),
-                            tab);
-  g_signal_connect_swapped (priv->document,
-                            "modified-changed",
-                            G_CALLBACK (gb_editor_tab_modified_changed),
-                            tab);
-  g_signal_connect_swapped (priv->document,
-                            "cursor-moved",
-                            G_CALLBACK (gb_editor_tab_cursor_moved),
-                            tab);
-
-  g_signal_connect (priv->source_view,
-                    "focus-in-event",
-                    G_CALLBACK (on_source_view_focus_in_event),
-                    tab);
-  g_signal_connect (priv->source_view,
-                    "populate-popup",
-                    G_CALLBACK (on_source_view_populate_popup),
-                    tab);
-  g_signal_connect (priv->source_view,
-                    "push-snippet",
-                    G_CALLBACK (on_source_view_push_snippet),
-                    tab);
-  g_signal_connect (priv->source_view,
-                    "begin-search",
-                    G_CALLBACK (on_source_view_begin_search),
-                    tab);
-
-  g_signal_connect_swapped (priv->go_down_button,
-                            "clicked",
-                            G_CALLBACK (gb_editor_tab_move_next_match),
-                            tab);
-  g_signal_connect_swapped (priv->go_up_button,
-                            "clicked",
-                            G_CALLBACK (gb_editor_tab_move_previous_match),
-                            tab);
-
-  g_signal_connect_object (priv->search_context,
-                           "notify::occurrences-count",
-                           G_CALLBACK (on_search_occurrences_notify),
-                           tab,
-                           G_CONNECT_SWAPPED);
-
-
-  /*
-   * WORKAROUND:
-   *
-   * Once GtkSourceView exports this as an internal child, we can do this from
-   * the gb-editor-tab.ui file.
-   */
-  comp = gtk_source_view_get_completion (GTK_SOURCE_VIEW (priv->source_view));
-  g_object_set (comp,
-                "show-headers", FALSE,
-                "select-on-show", TRUE,
-                NULL);
-
-  g_signal_connect (priv->search_entry,
-                    "activate",
-                    G_CALLBACK (on_search_entry_activate),
-                    tab);
-  g_signal_connect (priv->search_entry,
-                    "key-press-event",
-                    G_CALLBACK (on_search_entry_key_press_event),
-                    tab);
-  g_signal_connect (priv->search_entry,
-                    "focus-in-event",
-                    G_CALLBACK (on_search_entry_focus_in),
-                    tab);
-  g_signal_connect (priv->search_entry,
-                    "focus-out-event",
-                    G_CALLBACK (on_search_entry_focus_out),
-                    tab);
-  g_object_bind_property (priv->search_entry, "text",
-                          priv->search_settings, "search-text",
-                          G_BINDING_SYNC_CREATE);
-
-  g_object_bind_property (priv->revealer, "reveal-child",
-                          priv->source_view, "show-shadow",
-                          G_BINDING_SYNC_CREATE);
-
-  g_object_bind_property (priv->file, "location",
-                          priv->change_monitor, "file",
-                          G_BINDING_SYNC_CREATE);
-  g_object_bind_property_full (priv->file, "location", tab, "title",
-                               G_BINDING_SYNC_CREATE, transform_file_to_title,
-                               NULL, tab, NULL);
-  g_object_bind_property_full (priv->file, "location", priv->document,
-                               "language", G_BINDING_SYNC_CREATE,
-                               transform_file_to_language, NULL, tab, NULL);
-
-  gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (priv->source_view),
-                                       GTK_TEXT_WINDOW_LEFT);
-  priv->change_renderer =
-      g_object_new (GB_TYPE_SOURCE_CHANGE_GUTTER_RENDERER,
-                    "change-monitor", priv->change_monitor,
-                    "size", 2,
-                    "visible", TRUE,
-                    "xpad", 1,
-                    NULL);
-  gtk_source_gutter_insert (gutter, priv->change_renderer, 0);
-
-  vim = gb_source_view_get_vim (priv->source_view);
-  g_signal_connect (vim,
-                    "command-visibility-toggled",
-                    G_CALLBACK (on_vim_command_visibility_toggled),
-                    tab);
-  g_signal_connect (vim,
-                    "begin-search",
-                    G_CALLBACK (on_vim_begin_search),
-                    tab);
-  g_signal_connect (vim,
-                    "notify::phrase",
-                    G_CALLBACK (on_vim_notify_phrase),
-                    tab);
-  g_signal_connect (vim,
-                    "notify::mode",
-                    G_CALLBACK (on_vim_notify_mode),
-                    tab);
-
-#if 0
-  g_settings_bind (settings, "word-completion", tab, "enable-word-completion",
-                   G_SETTINGS_BIND_DEFAULT);
-#endif
-
-  gb_editor_tab_cursor_moved (tab, priv->document);
-
-  EXIT;
+  /* notify helper for tab labels wanting to render dirty tabs specially */
+  g_object_notify (G_OBJECT (tab), "title");
 }
 
 void
-gb_editor_tab_load_file_mark (GbEditorTab *tab)
+gb_editor_tab_find (GbEditorTab *tab)
 {
-  GbEditorFileMarks *marks;
-  GbEditorFileMark *mark;
-  GtkTextBuffer *buffer;
-  GtkTextIter iter;
-  GSettings *settings;
-  gboolean load_mark;
-  GFile *file;
-  guint line;
-  guint column;
+  GbEditorFrame *frame;
 
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
-  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 (tab->priv->document);
-
-  if (!load_mark)
-    {
-      gtk_text_buffer_get_start_iter (buffer, &iter);
-      gtk_text_buffer_select_range (buffer, &iter, &iter);
-      gb_gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (tab->priv->source_view),
-                                       &iter, 0.0, TRUE, 0.5, 0.5);
-      return;
-    }
-
-  file = gtk_source_file_get_location (tab->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);
-  gb_gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (tab->priv->source_view),
-                                   &iter, 0.0, TRUE, 0.5, 0.5);
+  frame = gb_editor_tab_get_last_frame (tab);
+  gb_editor_frame_find (frame, NULL);
 }
 
-static void
-gb_editor_tab_save_file_mark (GbEditorTab *tab)
+void
+gb_editor_tab_reformat (GbEditorTab *tab)
 {
-  GbEditorFileMarks *marks;
-  GbEditorFileMark *mark;
-  GtkTextBuffer *buffer;
-  GtkTextIter iter;
-  GtkTextMark *insert;
-  GFile *file;
+  GbEditorFrame *frame;
 
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
-  buffer = GTK_TEXT_BUFFER (tab->priv->document);
-  insert = gtk_text_buffer_get_insert (buffer);
-  gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
+  frame = gb_editor_tab_get_last_frame (tab);
+  gb_editor_frame_reformat (frame);
+}
 
-  file = gtk_source_file_get_location (tab->priv->file);
-  if (!file)
-    return;
+static gboolean
+markdown_preview_title (GBinding     *binding,
+                        const GValue *from_value,
+                        GValue       *to_value,
+                        gpointer      user_data)
+{
+  gchar *str;
+
+  str = g_strdup_printf (_("%s (Markdown Preview)"),
+                         g_value_get_string (from_value));
+  g_value_take_string (to_value, str);
 
-  marks = gb_editor_file_marks_get_default ();
-  mark = gb_editor_file_marks_get_for_file (marks, file);
-  gb_editor_file_mark_set_line (mark, gtk_text_iter_get_line (&iter));
-  gb_editor_file_mark_set_column (mark, gtk_text_iter_get_line_offset (&iter));
+  return TRUE;
 }
 
-static void
-gb_editor_tab_close (GbTab *tab)
+
+GbTab *
+gb_editor_tab_preview (GbEditorTab *tab)
 {
   GbEditorTabPrivate *priv;
-  GtkTextBuffer *buffer;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+  GtkSourceLanguage *lang;
+  const gchar *lang_id;
+  GbTab *preview = NULL;
 
-  priv = GB_EDITOR_TAB (tab)->priv;
+  g_return_val_if_fail (GB_IS_EDITOR_TAB (tab), NULL);
 
-  buffer = GTK_TEXT_BUFFER (priv->document);
+  priv = tab->priv;
 
-  if (gtk_text_buffer_get_modified (buffer))
-    g_message ("TODO: handle dirty editor state.");
+  lang = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (priv->document));
 
-  gb_editor_tab_save_file_mark (GB_EDITOR_TAB (tab));
+  if (!lang || !(lang_id = gtk_source_language_get_id (lang)))
+    return NULL;
 
-  gtk_widget_destroy (GTK_WIDGET (tab));
+  if (g_str_equal (lang_id, "markdown"))
+    {
+      preview = g_object_new (GB_TYPE_MARKDOWN_TAB,
+                              "buffer", priv->document,
+                              "visible", TRUE,
+                              NULL);
+      g_object_bind_property_full (tab, "title", preview, "title",
+                                   G_BINDING_SYNC_CREATE,
+                                   markdown_preview_title,
+                                   NULL, NULL, NULL);
+    }
 
-  EXIT;
+  return preview;
 }
 
 static void
-gb_editor_tab_dispose (GObject *object)
+gb_editor_tab_constructed (GObject *object)
 {
-  GbEditorTab *tab = (GbEditorTab *) object;
+  GbEditorTabPrivate *priv;
+  GbEditorTab *tab = (GbEditorTab *)object;
+  GtkSourceFile *file;
 
-  ENTRY;
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
-  g_assert (GB_IS_EDITOR_TAB (tab));
+  priv = tab->priv;
 
-  gb_editor_code_assistant_destroy (tab);
+  G_OBJECT_CLASS (gb_editor_tab_parent_class)->constructed (object);
 
-  g_clear_object (&tab->priv->change_monitor);
-  g_clear_object (&tab->priv->search_entry_tag);
-  g_clear_object (&tab->priv->file);
-  g_clear_object (&tab->priv->search_highlighter);
-  g_clear_object (&tab->priv->search_settings);
-  g_clear_object (&tab->priv->search_context);
-  g_clear_object (&tab->priv->document);
+  priv->document = g_object_new (GB_TYPE_EDITOR_DOCUMENT,
+                                 NULL);
+  gb_editor_frame_set_document (priv->frame, priv->document);
 
-  G_OBJECT_CLASS (gb_editor_tab_parent_class)->dispose (object);
+  g_signal_connect_object (priv->document,
+                           "modified-changed",
+                           G_CALLBACK (gb_editor_tab_on_modified_changed),
+                           tab,
+                           G_CONNECT_SWAPPED);
 
-  EXIT;
-}
+  file = gb_editor_document_get_file (priv->document);
+  g_signal_connect_object (file,
+                           "notify::location",
+                           G_CALLBACK (gb_editor_tab_on_notify_location),
+                           tab,
+                           G_CONNECT_SWAPPED);
 
-static void
-gb_editor_tab_finalize (GObject *object)
-{
-  ENTRY;
+  g_signal_connect_object (priv->frame,
+                           "focused",
+                           G_CALLBACK (gb_editor_tab_on_frame_focused),
+                           tab,
+                           G_CONNECT_SWAPPED);
 
-  G_OBJECT_CLASS (gb_editor_tab_parent_class)->finalize (object);
+  g_signal_connect_object (priv->split_button,
+                           "toggled",
+                           G_CALLBACK (gb_editor_tab_on_split_toggled),
+                           tab,
+                           G_CONNECT_SWAPPED);
 
-  EXIT;
+  gb_editor_tab_update_title (tab);
 }
 
 static void
-gb_editor_tab_get_property (GObject    *object,
-                            guint       prop_id,
-                            GValue     *value,
-                            GParamSpec *pspec)
+gb_editor_tab_dispose (GObject *object)
 {
-  GbEditorTab *tab = GB_EDITOR_TAB (object);
+  GbEditorTabPrivate *priv = GB_EDITOR_TAB (object)->priv;
 
-  switch (prop_id)
-    {
-    case PROP_DOCUMENT:
-      g_value_set_object (value, gb_editor_tab_get_document (tab));
-      break;
+  g_clear_object (&priv->document);
 
-    case PROP_FILE:
-      g_value_set_object (value, gb_editor_tab_get_file (tab));
-      break;
+  if (priv->last_frame)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (priv->last_frame),
+                                    (gpointer *)&priv->last_frame);
+      priv->last_frame = NULL;
+    }
 
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  if (priv->progress_animation)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (priv->progress_animation),
+                                    (gpointer *)&priv->progress_animation);
+      priv->progress_animation = NULL;
     }
+
+  G_OBJECT_CLASS (gb_editor_tab_parent_class)->dispose (object);
 }
 
 static void
-gb_editor_tab_set_property (GObject      *object,
-                            guint         prop_id,
-                            const GValue *value,
-                            GParamSpec   *pspec)
+gb_editor_tab_finalize (GObject *object)
 {
-#if 0
-  GbEditorTab *tab = GB_EDITOR_TAB (object);
-#endif
+  GbEditorTabPrivate *priv = GB_EDITOR_TAB (object)->priv;
 
-  switch (prop_id)
+  if (priv->unsaved_id)
     {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      gb_doc_seq_release (priv->unsaved_id);
+      priv->unsaved_id = 0;
     }
+
+  G_OBJECT_CLASS (gb_editor_tab_parent_class)->finalize (object);
 }
 
 static void
@@ -1288,61 +707,21 @@ gb_editor_tab_class_init (GbEditorTabClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-  GbTabClass *tab_class = GB_TAB_CLASS (klass);
 
   object_class->constructed = gb_editor_tab_constructed;
   object_class->dispose = gb_editor_tab_dispose;
   object_class->finalize = gb_editor_tab_finalize;
-  object_class->get_property = gb_editor_tab_get_property;
-  object_class->set_property = gb_editor_tab_set_property;
 
   widget_class->grab_focus = gb_editor_tab_grab_focus;
 
-  tab_class->close = gb_editor_tab_close;
-  tab_class->freeze_drag = gb_editor_tab_freeze_drag;
-  tab_class->thaw_drag = gb_editor_tab_thaw_drag;
-
-  gParamSpecs [PROP_DOCUMENT] =
-    g_param_spec_object ("document",
-                         _("Document"),
-                         _("The document to edit."),
-                         GB_TYPE_EDITOR_DOCUMENT,
-                         (G_PARAM_READABLE |
-                          G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_DOCUMENT,
-                                   gParamSpecs[PROP_DOCUMENT]);
-
-  gParamSpecs [PROP_FILE] =
-    g_param_spec_object ("file",
-                         _("File"),
-                         _("The file for the tab."),
-                         GTK_SOURCE_TYPE_FILE,
-                         (G_PARAM_READABLE |
-                          G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_FILE,
-                                   gParamSpecs [PROP_FILE]);
-
   gtk_widget_class_set_template_from_resource (widget_class,
-                                               GB_EDITOR_TAB_UI_RESOURCE);
-
-  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, floating_bar);
-  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, go_down_button);
-  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, go_up_button);
-  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, overlay);
-  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, parsing_spinner);
-  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, preview_container);
+                                               "/org/gnome/builder/ui/gb-editor-tab.ui");
+  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, frame);
+  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, paned);
   gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, progress_bar);
-  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, revealer);
-  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, scroller);
-  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, search_entry);
-  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, source_view);
-
-  g_type_ensure (GB_TYPE_EDITOR_DOCUMENT);
-  g_type_ensure (GB_TYPE_SOURCE_CHANGE_MONITOR);
-  g_type_ensure (GB_TYPE_SOURCE_VIEW);
-  g_type_ensure (GB_TYPE_SOURCE_SEARCH_HIGHLIGHTER);
-  g_type_ensure (GD_TYPE_TAGGED_ENTRY);
-  g_type_ensure (NAUTILUS_TYPE_FLOATING_BAR);
+  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, split_button);
+
+  g_type_ensure (GB_TYPE_EDITOR_FRAME);
 }
 
 static void
diff --git a/src/editor/gb-editor-tab.h b/src/editor/gb-editor-tab.h
index b7e2625..6013923 100644
--- a/src/editor/gb-editor-tab.h
+++ b/src/editor/gb-editor-tab.h
@@ -19,8 +19,10 @@
 #ifndef GB_EDITOR_TAB_H
 #define GB_EDITOR_TAB_H
 
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
 #include "gb-tab.h"
-#include "gb-editor-document.h"
 
 G_BEGIN_DECLS
 
@@ -49,17 +51,22 @@ struct _GbEditorTabClass
   GbTabClass parent_class;
 };
 
-GType             gb_editor_tab_get_type       (void) G_GNUC_CONST;
-GtkWidget        *gb_editor_tab_new            (void);
-GbEditorDocument *gb_editor_tab_get_document   (GbEditorTab                *tab);
-GtkSourceFile    *gb_editor_tab_get_file       (GbEditorTab                *tab);
-void              gb_editor_tab_set_font_desc  (GbEditorTab                *tab,
-                                                const PangoFontDescription *font_desc);
-gboolean          gb_editor_tab_get_is_default (GbEditorTab                *tab);
-void              gb_editor_tab_load_file_mark (GbEditorTab                *tab);
-void              gb_editor_tab_scroll_to_line (GbEditorTab                *tab,
-                                                guint                       line,
-                                                guint                       line_offset);
+GbEditorTab *gb_editor_tab_new               (void);
+GType        gb_editor_tab_get_type          (void) G_GNUC_CONST;
+void         gb_editor_tab_save              (GbEditorTab *tab);
+void         gb_editor_tab_save_as           (GbEditorTab *tab);
+void         gb_editor_tab_open_file         (GbEditorTab *tab,
+                                              GFile       *file);
+void         gb_editor_tab_scroll_up         (GbEditorTab *tab);
+void         gb_editor_tab_scroll_down       (GbEditorTab *tab);
+void         gb_editor_tab_toggle_split      (GbEditorTab *tab);
+void         gb_editor_tab_find              (GbEditorTab *tab);
+void         gb_editor_tab_reformat          (GbEditorTab *tab);
+void         gb_editor_tab_scroll_to_line    (GbEditorTab *tab,
+                                              guint        line,
+                                              guint        line_offset);
+void         gb_editor_tab_restore_file_mark (GbEditorTab *tab);
+GbTab       *gb_editor_tab_preview           (GbEditorTab *tab);
 
 G_END_DECLS
 
diff --git a/src/resources/gnome-builder.gresource.xml b/src/resources/gnome-builder.gresource.xml
index 96516db..07ad845 100644
--- a/src/resources/gnome-builder.gresource.xml
+++ b/src/resources/gnome-builder.gresource.xml
@@ -23,6 +23,7 @@
     <file>ui/gb-credits-widget.ui</file>
     <file>ui/gb-devhelp-tab.ui</file>
     <file>ui/gb-editor-settings-widget.ui</file>
+    <file>ui/gb-editor-frame.ui</file>
     <file>ui/gb-editor-tab.ui</file>
     <file>ui/gb-editor-workspace.ui</file>
     <file>ui/gb-preferences-window.ui</file>
diff --git a/src/resources/ui/gb-editor-tab.ui b/src/resources/ui/gb-editor-tab.ui
index 56c9fef..3f9476c 100644
--- a/src/resources/ui/gb-editor-tab.ui
+++ b/src/resources/ui/gb-editor-tab.ui
@@ -4,135 +4,75 @@
   <template class="GbEditorTab" parent="GbTab">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
-    <property name="orientation">horizontal</property>
     <property name="expand">True</property>
-    <child internal-child="content">
-      <object class="GtkBox" id="content">
+    <child internal-child="controls">
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <style>
+          <class name="linked"/>
+        </style>
+        <child>
+          <object class="GtkComboBox" id="symbol_browser">
+            <property name="visible">true</property>
+            <property name="hexpand">true</property>
+            <style>
+              <class name="tab-control-first"/>
+            </style>
+          </object>
+        </child>
         <child>
-          <object class="GtkOverlay" id="overlay">
+          <object class="GtkToggleButton" id="split_button">
             <property name="visible">True</property>
+            <property name="tooltip_text">Split tab vertically</property>
+            <style>
+              <class name="image-button"/>
+              <class name="tab-control-last"/>
+            </style>
             <child>
-              <object class="GtkScrolledWindow" id="scroller">
+              <object class="GtkImage">
                 <property name="visible">True</property>
-                <property name="expand">True</property>
-                <child>
-                  <object class="GbSourceView" id="source_view">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="show_line_numbers">True</property>
-                    <property name="show_right_margin">True</property>
-                    <property name="right_margin_position">80</property>
-                  </object>
-                </child>
+                <property name="icon_size">1</property>
+                <property name="icon_name">builder-split-tab</property>
               </object>
             </child>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child internal-child="content">
+      <object class="GtkBox" id="content">
+        <child>
+          <object class="GtkOverlay">
+            <property name="visible">true</property>
             <child type="overlay">
               <object class="GtkProgressBar" id="progress_bar">
-                <property name="visible">False</property>
-                <property name="halign">fill</property>
-                <property name="valign">start</property>
+                <property name="visible">false</property>
                 <property name="fraction">0.0</property>
+                <property name="valign">start</property>
+                <property name="halign">fill</property>
+                <property name="vexpand">false</property>
                 <style>
                   <class name="osd"/>
                 </style>
               </object>
             </child>
-            <child type="overlay">
-              <object class="NautilusFloatingBar" id="floating_bar">
-                <property name="visible">True</property>
-                <property name="halign">end</property>
-                <property name="valign">end</property>
+            <child>
+              <object class="GtkPaned" id="paned">
+                <property name="visible">true</property>
+                <property name="orientation">vertical</property>
+                <property name="vexpand">true</property>
                 <child>
-                  <object class="GtkSpinner" id="parsing_spinner">
-                    <property name="visible">False</property>
-                    <property name="active">False</property>
-                    <property name="margin-start">6</property>
-                    <property name="tooltip-text" translatable="yes">Currently parsing document.</property>
+                  <object class="GbEditorFrame" id="frame">
+                    <property name="visible">true</property>
+                    <property name="vexpand">true</property>
                   </object>
                   <packing>
-                    <property name="pack_type">GTK_PACK_START</property>
-                    <property name="position">0</property>
+                    <property name="resize">true</property>
+                    <property name="shrink">false</property>
                   </packing>
                 </child>
               </object>
             </child>
-            <child type="overlay">
-              <object class="GtkRevealer" id="revealer">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="halign">end</property>
-                <property name="valign">start</property>
-                <child>
-                  <object class="GtkFrame" id="frame">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="margin_end">12</property>
-                    <style>
-                      <class name="gb-search-slider"/>
-                    </style>
-                    <child>
-                      <object class="GtkBox" id="hbox">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="orientation">horizontal</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" id="go_up_button">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <child>
-                              <object class="GtkImage" id="up_image">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_size">1</property>
-                                <property name="icon_name">go-up-symbolic</property>
-                              </object>
-                            </child>
-                          </object>
-                        </child>
-                        <child>
-                          <object class="GtkButton" id="go_down_button">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <child>
-                              <object class="GtkImage" id="down_image">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_size">1</property>
-                                <property name="icon_name">go-down-symbolic</property>
-                              </object>
-                            </child>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-            </child>
-          </object>
-        </child>
-      </object>
-    </child>
-    <child internal-child="footer">
-      <object class="GtkBox">
-        <child>
-          <object class="GtkBox" id="preview_container">
-            <property name="orientation">horizontal</property>
-            <property name="visible">False</property>
-            <property name="hexpand">True</property>
           </object>
         </child>
       </object>
diff --git a/src/resources/ui/gb-editor-workspace.ui b/src/resources/ui/gb-editor-workspace.ui
index 26e4635..705d989 100644
--- a/src/resources/ui/gb-editor-workspace.ui
+++ b/src/resources/ui/gb-editor-workspace.ui
@@ -8,20 +8,38 @@
         <property name="orientation">horizontal</property>
         <property name="position">250</property>
         <child>
-          <object class="GtkScrolledWindow" id="scroller">
-            <property name="visible">False</property>
+          <object class="GtkBox">
+            <property name="visible">false</property>
+            <property name="orientation">vertical</property>
             <child>
-              <object class="GbTree" id="tree">
-                <property name="headers-visible">False</property>
+              <object class="GtkLabel" id="project_label">
+                <property name="name">project-title</property>
                 <property name="visible">True</property>
+                <property name="label"></property>
+                <property name="xalign">0.0</property>
+                <style>
+                  <class name="button"/>
+                </style>
+              </object>
+            </child>
+            <child>
+              <object class="GtkScrolledWindow" id="scroller">
+                <property name="visible">True</property>
+                <property name="vexpand">True</property>
+                <child>
+                  <object class="GbTree" id="tree">
+                    <property name="headers-visible">False</property>
+                    <property name="visible">true</property>
+                  </object>
+                </child>
               </object>
             </child>
           </object>
         </child>
         <child>
-          <object class="GbMultiNotebook" id="multi_notebook">
-            <property name="group-name">GB_EDITOR_WORKSPACE</property>
+          <object class="GbTabGrid" id="tab_grid">
             <property name="visible">True</property>
+            <property name="hexpand">True</property>
           </object>
         </child>
       </object>


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