[gnome-builder/wip/libide-merge] restore vim style command bar



commit 8cb558c5de4ee6a60cc19616b40f7f5959d88ff3
Author: Christian Hergert <christian hergert me>
Date:   Fri Mar 20 01:40:14 2015 -0700

    restore vim style command bar

 src/commands/gb-command-vim-provider.c |  123 ++-----
 src/commands/gb-command-vim-provider.h |   29 +--
 src/commands/gb-command-vim.c          |   42 +--
 src/gnome-builder.mk                   |   11 +-
 src/vim/gb-vim.c                       |  632 ++++++++++++++++++++++++++++++++
 src/vim/gb-vim.h                       |   47 +++
 src/workbench/gb-workbench.c           |    7 +-
 7 files changed, 734 insertions(+), 157 deletions(-)
---
diff --git a/src/commands/gb-command-vim-provider.c b/src/commands/gb-command-vim-provider.c
index 67d0a4f..b34c452 100644
--- a/src/commands/gb-command-vim-provider.c
+++ b/src/commands/gb-command-vim-provider.c
@@ -16,56 +16,37 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define G_LOG_DOMAIN "vim-command-provider"
+#define G_LOG_DOMAIN "gb-vim-command-provider"
 
-#if 0
+#include <ide.h>
 
-#include "gb-editor-view.h"
-#include "gb-editor-frame-private.h"
 #include "gb-command-vim.h"
 #include "gb-command-vim-provider.h"
-#include "gb-source-view.h"
-#include "gb-source-vim.h"
+#include "gb-editor-frame.h"
+#include "gb-editor-frame-private.h"
+#include "gb-editor-view.h"
+#include "gb-editor-view-private.h"
+#include "gb-vim.h"
 #include "gb-workbench.h"
-#include "trie.h"
 
-struct _GbCommandVimProviderPrivate
+struct _GbCommandVimProvider
 {
-  Trie *trie;
+  GbCommandProvider parent_instance;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GbCommandVimProvider, gb_command_vim_provider,
-                            GB_TYPE_COMMAND_PROVIDER)
-
-GbCommandProvider *
-gb_command_vim_provider_new (GbWorkbench *workbench)
-{
-  return g_object_new (GB_TYPE_COMMAND_VIM_PROVIDER,
-                       "workbench", workbench,
-                       NULL);
-}
+G_DEFINE_TYPE (GbCommandVimProvider, gb_command_vim_provider, GB_TYPE_COMMAND_PROVIDER)
 
 static GbCommand *
 gb_command_vim_provider_lookup (GbCommandProvider *provider,
                                 const gchar       *command_text)
 {
+  IdeSourceView *source_view;
   GbWorkbench *workbench;
-  GSettings *settings;
-  GbDocumentView *active_view;
-  GbEditorFrame *frame;
+  GbView *active_view;
 
   g_return_val_if_fail (GB_IS_COMMAND_VIM_PROVIDER (provider), NULL);
   g_return_val_if_fail (command_text, NULL);
 
-  /* Fetch our editor gsettings */
-  settings = g_object_get_data (G_OBJECT (provider), "editor-settings");
-  if (!G_IS_SETTINGS (settings))
-    return NULL;
-
-  /* Make sure vim-mode is enabled */
-  if (!g_settings_get_boolean (settings, "vim-mode"))
-    return NULL;
-
   /* Make sure we have a workbench */
   workbench = gb_command_provider_get_workbench (provider);
   if (!GB_IS_WORKBENCH (workbench))
@@ -77,29 +58,14 @@ gb_command_vim_provider_lookup (GbCommandProvider *provider,
     return NULL;
 
   /* TODO: Perhaps get the last focused frame? */
-  frame = gb_editor_view_get_frame1 (GB_EDITOR_VIEW (active_view));
-  if (!GB_IS_EDITOR_FRAME (frame))
+  source_view = GB_EDITOR_VIEW (active_view)->frame1->source_view;
+  if (!IDE_IS_SOURCE_VIEW (source_view))
     return NULL;
 
-  /* See if GbEditorVim recognizes this command */
-  if (gb_source_vim_is_command (command_text))
-    return g_object_new (GB_TYPE_COMMAND_VIM,
-                         "command-text", command_text,
-                         "source-view", frame->priv->source_view,
-                         NULL);
-
-  return NULL;
-}
-
-static gboolean
-traverse_func (Trie        *trie,
-               const gchar *key,
-               gpointer     value,
-               gpointer     user_data)
-{
-  GPtrArray *ar = user_data;
-  g_ptr_array_add (ar, g_strdup (key));
-  return FALSE;
+  return g_object_new (GB_TYPE_COMMAND_VIM,
+                       "command-text", command_text,
+                       "source-view", source_view,
+                       NULL);
 }
 
 static void
@@ -107,39 +73,23 @@ gb_command_vim_provider_complete (GbCommandProvider *provider,
                                   GPtrArray         *completions,
                                   const gchar       *initial_command_text)
 {
-  GbCommandVimProvider *self = (GbCommandVimProvider *)provider;
+  gchar **results;
+  gsize i;
 
   g_return_if_fail (GB_IS_COMMAND_VIM_PROVIDER (provider));
   g_return_if_fail (completions);
   g_return_if_fail (initial_command_text);
 
-  trie_traverse (self->priv->trie,
-                 initial_command_text,
-                 G_PRE_ORDER,
-                 G_TRAVERSE_LEAVES,
-                 -1,
-                 traverse_func,
-                 completions);
-}
-
-static void
-gb_command_vim_provider_finalize (GObject *object)
-{
-  GbCommandVimProvider *provider = (GbCommandVimProvider *)object;
-
-  trie_destroy (provider->priv->trie);
-  provider->priv->trie = NULL;
-
-  G_OBJECT_CLASS (gb_command_vim_provider_parent_class)->finalize (object);
+  results = gb_vim_complete (initial_command_text);
+  for (i = 0; results [i]; i++)
+    g_ptr_array_add (completions, results [i]);
+  g_free (results);
 }
 
 static void
 gb_command_vim_provider_class_init (GbCommandVimProviderClass *klass)
 {
   GbCommandProviderClass *provider_class = GB_COMMAND_PROVIDER_CLASS (klass);
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  object_class->finalize = gb_command_vim_provider_finalize;
 
   provider_class->lookup = gb_command_vim_provider_lookup;
   provider_class->complete = gb_command_vim_provider_complete;
@@ -148,29 +98,4 @@ gb_command_vim_provider_class_init (GbCommandVimProviderClass *klass)
 static void
 gb_command_vim_provider_init (GbCommandVimProvider *self)
 {
-  static const gchar *commands[] = {
-    "colorscheme ",
-    "edit",
-    "nohl",
-    "set ",
-    "sort",
-    "split",
-    "syntax ",
-    "vsplit",
-    NULL
-  };
-  GSettings *settings;
-  guint i;
-
-  self->priv = gb_command_vim_provider_get_instance_private (self);
-
-  self->priv->trie = trie_new (NULL);
-  for (i = 0; commands [i]; i++)
-    trie_insert (self->priv->trie, commands [i], (gchar *)commands [i]);
-
-  settings = g_settings_new ("org.gnome.builder.editor");
-  g_object_set_data_full (G_OBJECT (self), "editor-settings", settings,
-                          g_object_unref);
 }
-
-#endif
diff --git a/src/commands/gb-command-vim-provider.h b/src/commands/gb-command-vim-provider.h
index 994f987..5e4dffe 100644
--- a/src/commands/gb-command-vim-provider.h
+++ b/src/commands/gb-command-vim-provider.h
@@ -23,33 +23,10 @@
 
 G_BEGIN_DECLS
 
-#define GB_TYPE_COMMAND_VIM_PROVIDER            (gb_command_vim_provider_get_type())
-#define GB_COMMAND_VIM_PROVIDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_COMMAND_VIM_PROVIDER, GbCommandVimProvider))
-#define GB_COMMAND_VIM_PROVIDER_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_COMMAND_VIM_PROVIDER, GbCommandVimProvider const))
-#define GB_COMMAND_VIM_PROVIDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  
GB_TYPE_COMMAND_VIM_PROVIDER, GbCommandVimProviderClass))
-#define GB_IS_COMMAND_VIM_PROVIDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GB_TYPE_COMMAND_VIM_PROVIDER))
-#define GB_IS_COMMAND_VIM_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  
GB_TYPE_COMMAND_VIM_PROVIDER))
-#define GB_COMMAND_VIM_PROVIDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  
GB_TYPE_COMMAND_VIM_PROVIDER, GbCommandVimProviderClass))
+#define GB_TYPE_COMMAND_VIM_PROVIDER (gb_command_vim_provider_get_type())
 
-typedef struct _GbCommandVimProvider        GbCommandVimProvider;
-typedef struct _GbCommandVimProviderClass   GbCommandVimProviderClass;
-typedef struct _GbCommandVimProviderPrivate GbCommandVimProviderPrivate;
-
-struct _GbCommandVimProvider
-{
-  GbCommandProvider parent;
-
-  /*< private >*/
-  GbCommandVimProviderPrivate *priv;
-};
-
-struct _GbCommandVimProviderClass
-{
-  GbCommandProviderClass parent;
-};
-
-GType              gb_command_vim_provider_get_type (void);
-GbCommandProvider *gb_command_vim_provider_new      (GbWorkbench *workbench);
+G_DECLARE_FINAL_TYPE (GbCommandVimProvider, gb_command_vim_provider,
+                      GB, COMMAND_VIM_PROVIDER, GbCommandProvider)
 
 G_END_DECLS
 
diff --git a/src/commands/gb-command-vim.c b/src/commands/gb-command-vim.c
index 11c8d36..dbff795 100644
--- a/src/commands/gb-command-vim.c
+++ b/src/commands/gb-command-vim.c
@@ -20,6 +20,7 @@
 #include <ide.h>
 
 #include "gb-command-vim.h"
+#include "gb-vim.h"
 
 struct _GbCommandVimPrivate
 {
@@ -51,26 +52,10 @@ 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 || IDE_IS_SOURCE_VIEW (source_view));
+  g_return_if_fail (IDE_IS_SOURCE_VIEW (source_view));
 
-  if (source_view != vim->priv->source_view)
-    {
-      if (vim->priv->source_view)
-        {
-          g_object_remove_weak_pointer (G_OBJECT (vim->priv->source_view),
-                                        (gpointer *)&vim->priv->source_view);
-          vim->priv->source_view = NULL;
-        }
-
-      if (source_view)
-        {
-          vim->priv->source_view = source_view;
-          g_object_add_weak_pointer (G_OBJECT (vim->priv->source_view),
-                                     (gpointer *)&vim->priv->source_view);
-        }
-
-      g_object_notify_by_pspec (G_OBJECT (vim), gParamSpecs [PROP_SOURCE_VIEW]);
-    }
+  if (ide_set_weak_pointer (&vim->priv->source_view, source_view))
+    g_object_notify_by_pspec (G_OBJECT (vim), gParamSpecs [PROP_SOURCE_VIEW]);
 }
 
 const gchar *
@@ -92,8 +77,7 @@ gb_command_vim_set_command_text (GbCommandVim *vim,
     {
       g_free (vim->priv->command_text);
       vim->priv->command_text = g_strdup (command_text);
-      g_object_notify_by_pspec (G_OBJECT (vim),
-                                gParamSpecs [PROP_COMMAND_TEXT]);
+      g_object_notify_by_pspec (G_OBJECT (vim), gParamSpecs [PROP_COMMAND_TEXT]);
     }
 }
 
@@ -106,12 +90,16 @@ gb_command_vim_execute (GbCommand *command)
 
   if (self->priv->source_view)
     {
-#if 0
-      GbSourceVim *vim;
+      GtkSourceView *source_view = (GtkSourceView *)self->priv->source_view;
+      GError *error = NULL;
+
+      IDE_TRACE_MSG ("Executing Vim command: %s", self->priv->command_text);
 
-      vim = gb_source_view_get_vim (self->priv->source_view);
-      gb_source_vim_execute_command (vim, self->priv->command_text);
-#endif
+      if (!gb_vim_execute (source_view, self->priv->command_text, &error))
+        {
+          g_warning ("%s", error->message);
+          g_clear_error (&error);
+        }
     }
 
   return NULL;
@@ -122,7 +110,7 @@ gb_command_vim_finalize (GObject *object)
 {
   GbCommandVimPrivate *priv = GB_COMMAND_VIM (object)->priv;
 
-  gb_command_vim_set_source_view (GB_COMMAND_VIM (object), NULL);
+  ide_clear_weak_pointer (&priv->source_view);
   g_clear_pointer (&priv->command_text, g_free);
 
   G_OBJECT_CLASS (gb_command_vim_parent_class)->finalize (object);
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index 73167b2..2803774 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -24,6 +24,10 @@ libgnome_builder_la_SOURCES = \
        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/documents/gb-document.c \
@@ -122,6 +126,8 @@ libgnome_builder_la_SOURCES = \
        src/views/gb-view-stack.h \
        src/views/gb-view.c \
        src/views/gb-view.h \
+       src/vim/gb-vim.c \
+       src/vim/gb-vim.h \
        src/workbench/gb-workbench-actions.c \
        src/workbench/gb-workbench-actions.h \
        src/workbench/gb-workbench-private.h \
@@ -133,10 +139,6 @@ libgnome_builder_la_SOURCES = \
        $(NULL)
 
 disabled_files = \
-       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 \
@@ -181,6 +183,7 @@ libgnome_builder_la_CFLAGS = \
        -I$(top_srcdir)/src/tree \
        -I$(top_srcdir)/src/util \
        -I$(top_srcdir)/src/views \
+       -I$(top_srcdir)/src/vim \
        -I$(top_srcdir)/src/workbench
 
 if ENABLE_TRACING
diff --git a/src/vim/gb-vim.c b/src/vim/gb-vim.c
new file mode 100644
index 0000000..2c51c64
--- /dev/null
+++ b/src/vim/gb-vim.c
@@ -0,0 +1,632 @@
+/* gb-vim.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 <errno.h>
+#include <glib/gi18n.h>
+#include <ide.h>
+
+#include "gb-vim.h"
+
+G_DEFINE_QUARK (gb-vim-error-quark, gb_vim_error)
+
+typedef gboolean (*GbVimSetFunc)     (GtkSourceView  *source_view,
+                                       const gchar    *key,
+                                       const gchar    *value,
+                                       GError        **error);
+typedef gboolean (*GbVimCommandFunc) (GtkSourceView  *source_view,
+                                       const gchar    *command,
+                                       const gchar    *options,
+                                       GError        **error);
+
+typedef struct
+{
+  gchar         *name;
+  GbVimSetFunc  func;
+} GbVimSet;
+
+typedef struct
+{
+  gchar *name;
+  gchar *alias;
+} GbVimSetAlias;
+
+typedef struct
+{
+  gchar             *name;
+  GbVimCommandFunc  func;
+} GbVimCommand;
+
+static gboolean
+int32_parse (gint         *value,
+             const gchar  *str,
+             gint          lower,
+             gint          upper,
+             const gchar  *param_name,
+             GError      **error)
+{
+  gint64 v64;
+
+  g_assert (value);
+  g_assert (str);
+  g_assert_cmpint (lower, <=, upper);
+  g_assert (param_name);
+
+  v64 = g_ascii_strtoll (str, NULL, 10);
+
+  if (((v64 == G_MININT64) || (v64 == G_MAXINT64)) && (errno == ERANGE))
+    {
+      g_set_error (error,
+                   GB_VIM_ERROR,
+                   GB_VIM_ERROR_NOT_NUMBER,
+                   _("Number required"));
+      return FALSE;
+    }
+
+  if ((v64 < lower) || (v64 > upper))
+    {
+      g_set_error (error,
+                   GB_VIM_ERROR,
+                   GB_VIM_ERROR_NUMBER_OUT_OF_RANGE,
+                   _("%"G_GINT64_FORMAT" is invalid for %s"),
+                   v64, param_name);
+      return FALSE;
+    }
+
+  *value = v64;
+
+  return TRUE;
+}
+
+static gboolean
+gb_vim_set_autoindent (GtkSourceView  *source_view,
+                       const gchar    *key,
+                       const gchar    *value,
+                       GError        **error)
+{
+  g_object_set (source_view, "auto-indent", TRUE, NULL);
+  return TRUE;
+}
+
+
+static gboolean
+gb_vim_set_expandtab (GtkSourceView  *source_view,
+                      const gchar    *key,
+                      const gchar    *value,
+                      GError        **error)
+{
+  g_object_set (source_view, "insert-spaces-instead-of-tabs", TRUE, NULL);
+  return TRUE;
+}
+
+static gboolean
+gb_vim_set_filetype (GtkSourceView  *source_view,
+                     const gchar    *key,
+                     const gchar    *value,
+                     GError        **error)
+{
+  GtkSourceLanguageManager *manager;
+  GtkSourceLanguage *language;
+  GtkTextBuffer *buffer;
+
+  if (0 == g_strcmp0 (value, "cs"))
+    value = "c-sharp";
+  else if (0 == g_strcmp0 (value, "xhmtl"))
+    value = "html";
+  else if (0 == g_strcmp0 (value, "javascript"))
+    value = "js";
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
+  manager = gtk_source_language_manager_get_default ();
+  language = gtk_source_language_manager_get_language (manager, value);
+
+  if (language == NULL)
+    {
+      g_set_error (error,
+                   GB_VIM_ERROR,
+                   GB_VIM_ERROR_UNKNOWN_OPTION,
+                   _("Cannot find language '%s'"),
+                   value);
+      return FALSE;
+    }
+
+  g_object_set (buffer, "language", language, NULL);
+
+  return TRUE;
+}
+
+static gboolean
+gb_vim_set_noautoindent (GtkSourceView  *source_view,
+                         const gchar    *key,
+                         const gchar    *value,
+                         GError        **error)
+{
+  g_object_set (source_view, "auto-indent", FALSE, NULL);
+  return TRUE;
+}
+
+static gboolean
+gb_vim_set_noexpandtab (GtkSourceView  *source_view,
+                        const gchar    *key,
+                        const gchar    *value,
+                        GError        **error)
+{
+  g_object_set (source_view, "insert-spaces-instead-of-tabs", FALSE, NULL);
+  return TRUE;
+}
+
+static gboolean
+gb_vim_set_nonumber (GtkSourceView  *source_view,
+                     const gchar    *key,
+                     const gchar    *value,
+                     GError        **error)
+{
+  g_print ("disablign line numbers\n");
+  g_object_set (source_view, "show-line-numbers", FALSE, NULL);
+  return TRUE;
+}
+
+static gboolean
+gb_vim_set_number (GtkSourceView  *source_view,
+                   const gchar    *key,
+                   const gchar    *value,
+                   GError        **error)
+{
+  g_object_set (source_view, "show-line-numbers", TRUE, NULL);
+  return TRUE;
+}
+
+static gboolean
+gb_vim_set_scrolloff (GtkSourceView  *source_view,
+                      const gchar    *key,
+                      const gchar    *value,
+                      GError        **error)
+{
+  gint scroll_offset = 0;
+
+  if (!int32_parse (&scroll_offset, value, 0, G_MAXINT32, "scroll size", error))
+    return FALSE;
+  if (IDE_IS_SOURCE_VIEW (source_view))
+    g_object_set (source_view, "scroll-offset", scroll_offset, NULL);
+  return TRUE;
+}
+
+static gboolean
+gb_vim_set_shiftwidth (GtkSourceView  *source_view,
+                       const gchar    *key,
+                       const gchar    *value,
+                       GError        **error)
+{
+  gint shiftwidth = 0;
+
+  if (!int32_parse (&shiftwidth, value, 0, G_MAXINT32, "shift width", error))
+    return FALSE;
+
+  if (shiftwidth == 0)
+    shiftwidth = -1;
+
+  g_object_set (source_view, "indent-width", shiftwidth, NULL);
+  return TRUE;
+}
+
+static gboolean
+gb_vim_set_tabstop (GtkSourceView  *source_view,
+                    const gchar    *key,
+                    const gchar    *value,
+                    GError        **error)
+{
+  gint tabstop  = 0;
+
+  if (!int32_parse (&tabstop , value, 1, 32, "tab stop", error))
+    return FALSE;
+
+  g_object_set (source_view, "tab-width", tabstop, NULL);
+  return TRUE;
+}
+
+static const GbVimSet vim_sets [] = {
+  { "autoindent",    gb_vim_set_autoindent },
+  { "expandtab",     gb_vim_set_expandtab },
+  { "filetype",      gb_vim_set_filetype },
+  { "noautoindent",  gb_vim_set_noautoindent },
+  { "noexpandtab",   gb_vim_set_noexpandtab },
+  { "nonumber",      gb_vim_set_nonumber },
+  { "number",        gb_vim_set_number },
+  { "scrolloff",     gb_vim_set_scrolloff },
+  { "shiftwidth",    gb_vim_set_shiftwidth },
+  { "tabstop",       gb_vim_set_tabstop },
+  { NULL }
+};
+
+static const GbVimSetAlias vim_set_aliases[] = {
+  { "ai",   "autoindent" },
+  { "et",   "expandtab" },
+  { "ft",   "filetype" },
+  { "noet", "noexpandtab" },
+  { "nu",   "number" },
+  { "nonu", "nonumber" },
+  { "so",   "scrolloff" },
+  { "sw",   "shiftwidth" },
+  { "ts",   "tabstop" },
+  { NULL }
+};
+
+static const GbVimSet *
+lookup_set (const gchar *key)
+{
+  gsize i;
+
+  g_assert (key);
+
+  for (i = 0; vim_set_aliases [i].name; i++)
+    {
+      if (g_str_equal (vim_set_aliases [i].name, key))
+        {
+          key = vim_set_aliases [i].alias;
+          break;
+        }
+    }
+
+  for (i = 0; vim_sets [i].name; i++)
+    {
+      if (g_str_equal (vim_sets [i].name, key))
+        return &vim_sets [i];
+    }
+
+  return NULL;
+}
+
+static gboolean
+gb_vim_command_set (GtkSourceView  *source_view,
+                    const gchar    *command,
+                    const gchar    *options,
+                    GError        **error)
+{
+  gboolean ret = FALSE;
+  gchar **parts;
+  gsize i;
+
+  g_assert (GTK_SOURCE_IS_VIEW (source_view));
+  g_assert (command);
+  g_assert (options);
+
+  parts = g_strsplit (options, " ", 0);
+
+  if (parts [0] == NULL)
+    {
+      ret = TRUE;
+      goto cleanup;
+    }
+
+  for (i = 0; parts [i]; i++)
+    {
+      const GbVimSet *set;
+      const gchar *value = "";
+      gchar *key = parts [i];
+      gchar *tmp;
+
+      for (tmp = key; *tmp; tmp = g_utf8_next_char (tmp))
+        {
+          if (g_utf8_get_char (tmp) == '=')
+            {
+              *tmp = '\0';
+              value = ++tmp;
+              break;
+            }
+        }
+
+      set = lookup_set (key);
+
+      if (set == NULL)
+        {
+          g_set_error (error,
+                       GB_VIM_ERROR,
+                       GB_VIM_ERROR_UNKNOWN_OPTION,
+                       _("Unknown option: %s"),
+                       key);
+          goto cleanup;
+        }
+
+      if (!set->func (source_view, key, value, error))
+        goto cleanup;
+    }
+
+  ret = TRUE;
+
+cleanup:
+  g_strfreev (parts);
+
+  return ret;
+}
+
+static gboolean
+gb_vim_command_colorscheme (GtkSourceView  *source_view,
+                            const gchar    *command,
+                            const gchar    *options,
+                            GError        **error)
+{
+  GtkSourceStyleSchemeManager *manager;
+  GtkSourceStyleScheme *style_scheme;
+  GtkTextBuffer *buffer;
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
+  manager = gtk_source_style_scheme_manager_get_default ();
+  style_scheme = gtk_source_style_scheme_manager_get_scheme (manager, options);
+
+  if (style_scheme == NULL)
+    {
+      g_set_error (error,
+                   GB_VIM_ERROR,
+                   GB_VIM_ERROR_UNKNOWN_OPTION,
+                   _("Cannot find colorscheme '%s'"),
+                   options);
+      return FALSE;
+    }
+
+  g_object_set (buffer, "style-scheme", style_scheme, NULL);
+
+  return TRUE;
+}
+
+static gboolean
+gb_vim_command_edit (GtkSourceView  *source_view,
+                     const gchar    *command,
+                     const gchar    *options,
+                     GError        **error)
+{
+  return TRUE;
+}
+
+static gboolean
+gb_vim_command_quit (GtkSourceView  *source_view,
+                     const gchar    *command,
+                     const gchar    *options,
+                     GError        **error)
+{
+  return TRUE;
+}
+
+static gboolean
+gb_vim_command_split (GtkSourceView  *source_view,
+                      const gchar    *command,
+                      const gchar    *options,
+                      GError        **error)
+{
+  return TRUE;
+}
+
+static gboolean
+gb_vim_command_vsplit (GtkSourceView  *source_view,
+                       const gchar    *command,
+                       const gchar    *options,
+                       GError        **error)
+{
+  return TRUE;
+}
+
+static gboolean
+gb_vim_command_write (GtkSourceView  *source_view,
+                      const gchar    *command,
+                      const gchar    *options,
+                      GError        **error)
+{
+  return TRUE;
+}
+
+static gboolean
+gb_vim_command_wq (GtkSourceView  *source_view,
+                   const gchar    *command,
+                   const gchar    *options,
+                   GError        **error)
+{
+  return (gb_vim_command_write (source_view, command, options, error) &&
+          gb_vim_command_quit (source_view, command, options, error));
+}
+
+static gboolean
+gb_vim_command_syntax (GtkSourceView  *source_view,
+                       const gchar    *command,
+                       const gchar    *options,
+                       GError        **error)
+{
+  if (g_str_equal (options, "enable") || g_str_equal (options, "on"))
+    g_object_set (source_view, "highlight-syntax", TRUE, NULL);
+  else if (g_str_equal (options, "off"))
+    g_object_set (source_view, "highlight-syntax", FALSE, NULL);
+  else
+    {
+      g_set_error (error,
+                   GB_VIM_ERROR,
+                   GB_VIM_ERROR_UNKNOWN_OPTION,
+                   _("Invalid :syntax subcommand : %s"),
+                   options);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static const GbVimCommand vim_commands[] = {
+  { "colorscheme", gb_vim_command_colorscheme },
+  { "edit",        gb_vim_command_edit },
+  { "quit",        gb_vim_command_quit },
+  { "set",         gb_vim_command_set },
+  //{ "sort",        gb_vim_command_sort },
+  { "split",       gb_vim_command_split },
+  { "syntax",      gb_vim_command_syntax },
+  { "vsplit",      gb_vim_command_vsplit },
+  { "w",           gb_vim_command_write },
+  { "wq",          gb_vim_command_wq },
+  { "write",       gb_vim_command_write },
+  { NULL }
+};
+
+static const GbVimCommand *
+lookup_command (const gchar *name)
+{
+  gsize i;
+
+  g_assert (name);
+
+  for (i = 0; vim_commands [i].name; i++)
+    {
+      if (g_str_has_prefix (vim_commands [i].name, name))
+        return &vim_commands [i];
+    }
+
+  return NULL;
+}
+
+gboolean
+gb_vim_execute (GtkSourceView  *source_view,
+                const gchar    *line,
+                GError        **error)
+{
+  GtkTextBuffer *buffer;
+  g_autofree gchar *name_slice = NULL;
+  const GbVimCommand *command;
+  const gchar *command_name = line;
+  const gchar *options;
+
+  g_return_val_if_fail (GTK_SOURCE_IS_VIEW (source_view), FALSE);
+  g_return_val_if_fail (line, FALSE);
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
+
+  if (!GTK_SOURCE_IS_BUFFER (buffer))
+    {
+      g_set_error (error,
+                   GB_VIM_ERROR,
+                   GB_VIM_ERROR_NOT_SOURCE_VIEW,
+                   _("vim mode requires GtkSourceView"));
+      return FALSE;
+    }
+
+  for (options = line; *options; options = g_utf8_next_char (options))
+    {
+      gunichar ch;
+
+      ch = g_utf8_get_char (options);
+
+      if (g_unichar_isspace (ch))
+        break;
+    }
+
+  if (g_unichar_isspace (g_utf8_get_char (options)))
+    {
+      command_name = name_slice = g_strndup (line, options - line);
+      options = g_utf8_next_char (options);
+    }
+
+  command = lookup_command (command_name);
+
+  if (command == NULL)
+    {
+      g_set_error (error,
+                   GB_VIM_ERROR,
+                   GB_VIM_ERROR_NOT_FOUND,
+                   _("Not an editor command: %s"),
+                   command_name);
+      return FALSE;
+    }
+
+  return command->func (source_view, command_name, options, error);
+}
+
+static gchar *
+joinv_and_add (gchar       **parts,
+               gsize         len,
+               const gchar  *delim,
+               const gchar  *str)
+{
+  GString *gstr;
+  gsize i;
+
+  gstr = g_string_new (parts [0]);
+  for (i = 1; i < len; i++)
+    g_string_append_printf (gstr, "%s%s", delim, parts [i]);
+  g_string_append_printf (gstr, "%s%s", delim, str);
+  return g_string_free (gstr, FALSE);
+}
+
+static void
+gb_vim_complete_set (const gchar *line,
+                     GPtrArray   *ar)
+{
+  const gchar *key;
+  gchar **parts;
+  guint len;
+  gsize i;
+
+  parts = g_strsplit (line, " ", 0);
+  len = g_strv_length (parts);
+
+  if (len < 2)
+    {
+      g_strfreev (parts);
+      return;
+    }
+
+  key = parts [len - 1];
+
+  for (i = 0; vim_sets [i].name; i++)
+    {
+      if (g_str_has_prefix (vim_sets [i].name, key))
+        g_ptr_array_add (ar, joinv_and_add (parts, len - 1, " ", vim_sets [i].name));
+    }
+
+  for (i = 0; vim_set_aliases [i].name; i++)
+    {
+      if (g_str_has_prefix (vim_set_aliases [i].name, key))
+        g_ptr_array_add (ar, joinv_and_add (parts, len - 1, " ", vim_set_aliases [i].name));
+    }
+
+  g_strfreev (parts);
+}
+
+static void
+gb_vim_complete_command (const gchar *line,
+                         GPtrArray   *ar)
+{
+  gsize i;
+
+  for (i = 0; vim_commands [i].name; i++)
+    {
+      if (g_str_has_prefix (vim_commands [i].name, line))
+        g_ptr_array_add (ar, g_strdup (vim_commands [i].name));
+    }
+}
+
+gchar **
+gb_vim_complete (const gchar *line)
+{
+  GPtrArray *ar;
+
+  ar = g_ptr_array_new ();
+
+  if (line != NULL)
+    {
+      if (g_str_has_prefix (line, "set "))
+        gb_vim_complete_set (line, ar);
+      else
+        gb_vim_complete_command (line, ar);
+    }
+
+  g_ptr_array_add (ar, NULL);
+
+  return (gchar **)g_ptr_array_free (ar, FALSE);
+}
diff --git a/src/vim/gb-vim.h b/src/vim/gb-vim.h
new file mode 100644
index 0000000..54d4678
--- /dev/null
+++ b/src/vim/gb-vim.h
@@ -0,0 +1,47 @@
+/* gb-vim.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/>.
+ */
+
+#ifndef GB_VIM_H
+#define GB_VIM_H
+
+#include <gtksourceview/gtksource.h>
+
+G_BEGIN_DECLS
+
+#define GB_VIM_ERROR (gb_vim_error_quark())
+
+typedef enum
+{
+  GB_VIM_ERROR_NOT_IMPLEMENTED,
+  GB_VIM_ERROR_NOT_FOUND,
+  GB_VIM_ERROR_NOT_NUMBER,
+  GB_VIM_ERROR_NUMBER_OUT_OF_RANGE,
+  GB_VIM_ERROR_CANNOT_FIND_COLORSCHEME,
+  GB_VIM_ERROR_UNKNOWN_OPTION,
+  GB_VIM_ERROR_NOT_SOURCE_VIEW,
+} IdeVimError;
+
+GQuark     gb_vim_error_quark (void);
+gboolean   gb_vim_execute     (GtkSourceView  *source_view,
+                               const gchar    *line,
+                               GError        **error);
+gchar    **gb_vim_complete    (const gchar    *line);
+
+G_END_DECLS
+
+#endif /* GB_VIM_H */
diff --git a/src/workbench/gb-workbench.c b/src/workbench/gb-workbench.c
index 12fdfec..3a07b22 100644
--- a/src/workbench/gb-workbench.c
+++ b/src/workbench/gb-workbench.c
@@ -22,6 +22,7 @@
 #include <ide.h>
 
 #include "gb-command-gaction-provider.h"
+#include "gb-command-vim-provider.h"
 #include "gb-dnd.h"
 #include "gb-widget.h"
 #include "gb-workbench-actions.h"
@@ -389,6 +390,7 @@ static void
 gb_workbench_init (GbWorkbench *self)
 {
   g_autoptr(GbCommandProvider) gaction_provider = NULL;
+  g_autoptr(GbCommandProvider) vim_provider = NULL;
 
   IDE_ENTRY;
 
@@ -399,8 +401,11 @@ gb_workbench_init (GbWorkbench *self)
   gaction_provider = g_object_new (GB_TYPE_COMMAND_GACTION_PROVIDER,
                                    "workbench", self,
                                    NULL);
+  vim_provider = g_object_new (GB_TYPE_COMMAND_VIM_PROVIDER,
+                               "workbench", self,
+                               NULL);
   gb_command_manager_add_provider (self->command_manager, gaction_provider);
-
+  gb_command_manager_add_provider (self->command_manager, vim_provider);
 
   /* Drag and drop support*/
   gtk_drag_dest_set (GTK_WIDGET (self),


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