[gnome-builder/wip/commands] commands: plumb sort command into generic command bar



commit 48eee03fb3deb1133dd3aa9759a68468aa3bd9f0
Author: Christian Hergert <christian hergert me>
Date:   Tue Oct 7 03:44:14 2014 -0700

    commands: plumb sort command into generic command bar
    
    The goal for this is to lose the per-editor command bar and move to a
    global command bar at the bottom. The commands will determine the active
    editor tab with workbench.get_active_workspace().get_active_tab().

 src/app/gb-application.c            |    2 +
 src/commands/gb-command-bar.c       |   40 ++++++++-
 src/commands/gb-command-manager.c   |   56 +++++++++++-
 src/commands/gb-command-manager.h   |    9 ++-
 src/commands/gb-command.c           |   22 ++++-
 src/commands/gb-command.h           |    9 ++-
 src/commands/gb-commands-internal.c |  173 +++++++++++++++++++++++++++++++++++
 src/commands/gb-commands-internal.h |   24 +++++
 src/editor/gb-editor-workspace.c    |   15 +++
 src/editor/gb-editor-workspace.h    |    8 +-
 src/gnome-builder.mk                |    2 +
 11 files changed, 345 insertions(+), 15 deletions(-)
---
diff --git a/src/app/gb-application.c b/src/app/gb-application.c
index 83548dd..7f249fb 100644
--- a/src/app/gb-application.c
+++ b/src/app/gb-application.c
@@ -26,6 +26,7 @@
 #include <glib/gi18n.h>
 
 #include "gb-application.h"
+#include "gb-commands-internal.h"
 #include "gb-editor-workspace.h"
 #include "gb-log.h"
 #include "gb-keybindings.h"
@@ -372,6 +373,7 @@ gb_application_startup (GApplication *app)
   gb_application_register_actions (self);
   gb_application_register_keybindings (self);
   gb_application_register_theme_overrides (self);
+  gb_commands_internal_init ();
 
   EXIT;
 }
diff --git a/src/commands/gb-command-bar.c b/src/commands/gb-command-bar.c
index 598e6d2..2d25d1d 100644
--- a/src/commands/gb-command-bar.c
+++ b/src/commands/gb-command-bar.c
@@ -16,7 +16,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "gb-command.h"
 #include "gb-command-bar.h"
+#include "gb-command-manager.h"
 #include "gb-string.h"
 
 struct _GbCommandBarPrivate
@@ -65,9 +67,19 @@ gb_command_bar_show (GbCommandBar *bar)
 }
 
 static void
+gb_command_bar_push_task (GbCommandBar  *bar,
+                          GbCommandTask *task)
+{
+  g_return_if_fail (GB_IS_COMMAND_BAR (bar));
+  g_return_if_fail (GB_IS_COMMAND_TASK (task));
+}
+
+static void
 gb_command_bar_on_entry_activate (GbCommandBar *bar,
                                   GtkEntry     *entry)
 {
+  GbWorkbench *workbench = NULL;
+  GtkWidget *parent;
   const gchar *text;
 
   g_return_if_fail (GB_IS_COMMAND_BAR (bar));
@@ -75,11 +87,33 @@ gb_command_bar_on_entry_activate (GbCommandBar *bar,
 
   text = gtk_entry_get_text (entry);
 
-  if (gb_str_empty0 (text))
+  parent = gtk_widget_get_toplevel (GTK_WIDGET (bar));
+  if (GB_IS_WORKBENCH (parent))
+    workbench = GB_WORKBENCH (parent);
+
+  if (!gb_str_empty0 (text))
     {
-      gb_command_bar_hide (bar);
-      return;
+      GbCommandManager *manager;
+      GbCommandTask *task = NULL;
+      GbCommand *command = NULL;
+      GVariant *parameters = NULL;
+
+      manager = gb_command_manager_get_default ();
+      command = gb_command_manager_lookup (manager, text, &parameters);
+
+      if (command)
+        {
+          task = gb_command_execute (command, parameters, workbench);
+          if (task)
+            gb_command_bar_push_task (bar, task);
+        }
+
+      g_clear_object (&task);
+      g_clear_object (&command);
+      g_clear_pointer (&parameters, g_variant_unref);
     }
+
+  gb_command_bar_hide (bar);
 }
 
 static gboolean
diff --git a/src/commands/gb-command-manager.c b/src/commands/gb-command-manager.c
index 83c6fe8..ba36b89 100644
--- a/src/commands/gb-command-manager.c
+++ b/src/commands/gb-command-manager.c
@@ -16,6 +16,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <string.h>
+
 #include "gb-command-manager.h"
 
 /**
@@ -55,7 +57,7 @@ gb_command_manager_get_default (void)
 
   if (!instance)
     instance = gb_command_manager_new ();
-  
+
   return instance;
 }
 
@@ -76,6 +78,58 @@ gb_command_manager_register (GbCommandManager *manager,
   g_hash_table_replace (manager->priv->commands, name, g_object_ref (command));
 }
 
+static gchar *
+gb_command_manager_parse (GbCommandManager  *manager,
+                          const gchar       *command_text,
+                          GVariant         **parameters)
+{
+  GVariant *variant = NULL;
+  gchar *ret = NULL;
+
+  g_return_val_if_fail (GB_IS_COMMAND_MANAGER (manager), NULL);
+  g_return_val_if_fail (command_text, NULL);
+
+  /* shortcut for no parameters. */
+  if (strchr (command_text, '(') == NULL)
+    return g_strstrip (g_strdup (command_text));
+
+  /* TODO: parse parameters */
+
+  if (parameters)
+    *parameters = variant ? g_variant_ref (variant) : NULL;
+
+  g_clear_pointer (&variant, g_variant_unref);
+
+  return ret;
+}
+
+GbCommand *
+gb_command_manager_lookup (GbCommandManager  *manager,
+                           const gchar       *command_text,
+                           GVariant         **parameters)
+{
+  GbCommandManagerPrivate *priv;
+  GbCommand *command;
+  GVariant *variant = NULL;
+  gchar *name;
+
+  g_return_val_if_fail (GB_IS_COMMAND_MANAGER (manager), NULL);
+  g_return_val_if_fail (command_text, NULL);
+
+  priv = manager->priv;
+
+  name = gb_command_manager_parse (manager, command_text, &variant);
+  command = g_hash_table_lookup (priv->commands, name);
+
+  if (command && parameters)
+    *parameters = variant ? g_variant_ref (variant) : NULL;
+
+  g_clear_pointer (&name, g_free);
+  g_clear_pointer (&variant, g_variant_unref);
+
+  return command;
+}
+
 static void
 gb_command_manager_finalize (GObject *object)
 {
diff --git a/src/commands/gb-command-manager.h b/src/commands/gb-command-manager.h
index fff6da3..ac7f357 100644
--- a/src/commands/gb-command-manager.h
+++ b/src/commands/gb-command-manager.h
@@ -19,6 +19,8 @@
 #ifndef GB_COMMAND_MANAGER_H
 #define GB_COMMAND_MANAGER_H
 
+#include <gio/gio.h>
+
 #include "gb-command.h"
 
 G_BEGIN_DECLS
@@ -51,8 +53,11 @@ struct _GbCommandManagerClass
 GType             gb_command_manager_get_type    (void) G_GNUC_CONST;
 GbCommandManager *gb_command_manager_new         (void);
 GbCommandManager *gb_command_manager_get_default (void);
-void              gb_command_manager_register    (GbCommandManager *manager,
-                                                  GbCommand        *command);
+void              gb_command_manager_register    (GbCommandManager  *manager,
+                                                  GbCommand         *command);
+GbCommand        *gb_command_manager_lookup      (GbCommandManager  *manager,
+                                                  const gchar       *command_text,
+                                                  GVariant         **parameters);
 
 G_END_DECLS
 
diff --git a/src/commands/gb-command.c b/src/commands/gb-command.c
index 827e508..2057c55 100644
--- a/src/commands/gb-command.c
+++ b/src/commands/gb-command.c
@@ -71,6 +71,14 @@ gb_command_set_name (GbCommand   *command,
     }
 }
 
+const gchar *
+gb_command_get_description (GbCommand *command)
+{
+  g_return_val_if_fail (GB_IS_COMMAND (command), NULL);
+
+  return command->priv->description;
+}
+
 void
 gb_command_set_description (GbCommand   *command,
                             const gchar *description)
@@ -87,13 +95,17 @@ gb_command_set_description (GbCommand   *command,
 }
 
 GbCommandTask *
-gb_command_execute (GbCommand *command)
+gb_command_execute (GbCommand   *command,
+                    GVariant    *parameters,
+                    GbWorkbench *workbench)
 {
   GbCommandTask *task = NULL;
 
   g_return_val_if_fail (GB_IS_COMMAND (command), NULL);
 
-  g_signal_emit (command, gSignals [EXECUTE], 0, &task);
+  g_signal_emit (command, gSignals [EXECUTE], 0,
+                 parameters, workbench,
+                 &task);
 
   return task;
 }
@@ -192,9 +204,11 @@ gb_command_class_init (GbCommandClass *klass)
                   G_STRUCT_OFFSET (GbCommandClass, execute),
                   g_signal_accumulator_first_wins,
                   NULL,
-                  g_cclosure_marshal_VOID__VOID,
+                  NULL,
                   GB_TYPE_COMMAND_TASK,
-                  0);
+                  2,
+                  G_TYPE_VARIANT,
+                  GB_TYPE_WORKBENCH);
 }
 
 static void
diff --git a/src/commands/gb-command.h b/src/commands/gb-command.h
index 96b7fcc..b88a6ae 100644
--- a/src/commands/gb-command.h
+++ b/src/commands/gb-command.h
@@ -22,6 +22,7 @@
 #include <gio/gio.h>
 
 #include "gb-command-task.h"
+#include "gb-workbench.h"
 
 G_BEGIN_DECLS
 
@@ -49,7 +50,9 @@ struct _GbCommandClass
 {
   GObjectClass parent;
 
-  GbCommandTask *(*execute) (GbCommand *command);
+  GbCommandTask *(*execute) (GbCommand   *command,
+                             GVariant    *parameters,
+                             GbWorkbench *workbench);
 
   gpointer _padding1;
   gpointer _padding2;
@@ -68,7 +71,9 @@ void            gb_command_set_name        (GbCommand   *command,
 const gchar    *gb_command_get_description (GbCommand   *command);
 void            gb_command_set_description (GbCommand   *command,
                                             const gchar *description);
-GbCommandTask  *gb_command_execute         (GbCommand   *command);
+GbCommandTask  *gb_command_execute         (GbCommand   *command,
+                                            GVariant    *parameters,
+                                            GbWorkbench *workbench);
 
 G_END_DECLS
 
diff --git a/src/commands/gb-commands-internal.c b/src/commands/gb-commands-internal.c
new file mode 100644
index 0000000..5b3c70b
--- /dev/null
+++ b/src/commands/gb-commands-internal.c
@@ -0,0 +1,173 @@
+/* gb-commands-internal.c
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gtksourceview/gtksource.h>
+#include <stdlib.h>
+
+#include "gb-command.h"
+#include "gb-command-manager.h"
+#include "gb-commands-internal.h"
+#include "gb-editor-tab.h"
+#include "gb-editor-workspace.h"
+
+typedef void (*TextCommandFunc) (GbCommand        *command,
+                                 GVariant         *parameters,
+                                 GbEditorTab      *tab,
+                                 GbEditorDocument *document);
+
+typedef struct
+{
+  const gchar     *name;
+  const gchar     *description;
+  TextCommandFunc  command;
+} TextCommand;
+
+static void
+text_iter_swap (GtkTextIter *a,
+                GtkTextIter *b)
+{
+  GtkTextIter tmp;
+
+  gtk_text_iter_assign (&tmp, a);
+  gtk_text_iter_assign (a, b);
+  gtk_text_iter_assign (b, &tmp);
+}
+
+static int
+str_compare_qsort (const void *aptr,
+                   const void *bptr)
+{
+  const gchar * const *a = aptr;
+  const gchar * const *b = bptr;
+
+  return g_strcmp0 (*a, *b);
+}
+
+static void
+text_command_sort (GbCommand        *command,
+                   GVariant         *parameters,
+                   GbEditorTab      *tab,
+                   GbEditorDocument *document)
+{
+  GtkTextBuffer *buffer = (GtkTextBuffer *)document;
+  GtkTextMark *insert;
+  GtkTextIter begin;
+  GtkTextIter cursor;
+  GtkTextIter end;
+  gchar **parts;
+  gchar *text;
+  guint cursor_offset;
+
+  g_return_val_if_fail (GB_IS_COMMAND (command), NULL);
+  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+
+  gtk_text_buffer_get_selection_bounds (buffer, &begin, &end);
+
+  if (gtk_text_iter_equal (&begin, &end))
+    return;
+
+  insert = gtk_text_buffer_get_insert (buffer);
+  gtk_text_buffer_get_iter_at_mark (buffer, &cursor, insert);
+  cursor_offset = gtk_text_iter_get_offset (&cursor);
+
+  if (gtk_text_iter_compare (&begin, &end) > 0)
+    text_iter_swap (&begin, &end);
+
+  if (gtk_text_iter_starts_line (&end))
+    gtk_text_iter_backward_char (&end);
+
+  text = gtk_text_iter_get_slice (&begin, &end);
+  parts = g_strsplit (text, "\n", 0);
+  g_free (text);
+
+  qsort (parts, g_strv_length (parts), sizeof (gchar *),
+         str_compare_qsort);
+
+  text = g_strjoinv ("\n", parts);
+  gtk_text_buffer_delete (buffer, &begin, &end);
+  gtk_text_buffer_insert (buffer, &begin, text, -1);
+  g_free (text);
+  g_strfreev (parts);
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &begin, cursor_offset);
+  gtk_text_buffer_select_range (buffer, &begin, &begin);
+}
+
+static GbCommandTask *
+text_command_execute (GbCommand   *command,
+                      GVariant    *parameters,
+                      GbWorkbench *workbench,
+                      TextCommand *text_command)
+{
+  GbEditorDocument *document;
+  GbWorkspace *workspace;
+  GbEditorTab *tab;
+
+  g_return_val_if_fail (GB_IS_COMMAND (command), NULL);
+  g_return_val_if_fail (GB_IS_WORKBENCH (workbench), NULL);
+  g_return_val_if_fail (text_command, NULL);
+
+  workspace = gb_workbench_get_active_workspace (workbench);
+  if (!GB_IS_EDITOR_WORKSPACE (workspace))
+    return NULL;
+
+  tab = gb_editor_workspace_get_active_tab (GB_EDITOR_WORKSPACE (workspace));
+  if (!tab)
+    return NULL;
+
+  document = gb_editor_tab_get_document (tab);
+  if (!document)
+    return NULL;
+
+  text_command->command (command, parameters, tab, document);
+
+  return NULL;
+}
+
+static TextCommand gTextCommands[] = {
+  { "sort",
+    N_("Sort the selected text in the editor."),
+    text_command_sort },
+};
+
+void
+gb_commands_internal_init (void)
+{
+  GbCommandManager *manager;
+  guint i;
+  
+  manager = gb_command_manager_get_default ();
+
+  for (i = 0; i < G_N_ELEMENTS (gTextCommands); i++)
+    {
+      GbCommand *command;
+
+      command = g_object_new (GB_TYPE_COMMAND,
+                              "name", gTextCommands [i].name,
+                              "description", gTextCommands [i].description,
+                              NULL);
+      g_signal_connect (command,
+                        "execute",
+                        G_CALLBACK (text_command_execute),
+                        &gTextCommands [i]);
+      gb_command_manager_register (manager, command);
+      g_object_unref (command);
+    }
+}
diff --git a/src/commands/gb-commands-internal.h b/src/commands/gb-commands-internal.h
new file mode 100644
index 0000000..aab3763
--- /dev/null
+++ b/src/commands/gb-commands-internal.h
@@ -0,0 +1,24 @@
+/* gb-commands-internal.h
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_COMMANDS_INTERNAL_H
+#define GB_COMMANDS_INTERNAL_H
+
+void gb_commands_internal_init (void);
+
+#endif /* GB_COMMANDS_INTERNAL_H */
diff --git a/src/editor/gb-editor-workspace.c b/src/editor/gb-editor-workspace.c
index 57dee44..73be30a 100644
--- a/src/editor/gb-editor-workspace.c
+++ b/src/editor/gb-editor-workspace.c
@@ -29,6 +29,21 @@ enum {
 
 G_DEFINE_TYPE_WITH_PRIVATE (GbEditorWorkspace, gb_editor_workspace, GB_TYPE_WORKSPACE)
 
+GbEditorTab *
+gb_editor_workspace_get_active_tab (GbEditorWorkspace *workspace)
+{
+  GbTab *tab;
+
+  g_return_val_if_fail (GB_IS_EDITOR_WORKSPACE (workspace), NULL);
+
+  tab = gb_multi_notebook_get_active_tab (workspace->priv->multi_notebook);
+
+  if (GB_IS_EDITOR_TAB (tab))
+    return GB_EDITOR_TAB (tab);
+
+  return NULL;
+}
+
 void
 gb_editor_workspace_open (GbEditorWorkspace *workspace,
                           GFile             *file)
diff --git a/src/editor/gb-editor-workspace.h b/src/editor/gb-editor-workspace.h
index 719fe66..c0bbd5c 100644
--- a/src/editor/gb-editor-workspace.h
+++ b/src/editor/gb-editor-workspace.h
@@ -19,6 +19,7 @@
 #ifndef GB_EDITOR_WORKSPACE_H
 #define GB_EDITOR_WORKSPACE_H
 
+#include "gb-editor-tab.h"
 #include "gb-workspace.h"
 
 G_BEGIN_DECLS
@@ -48,9 +49,10 @@ struct _GbEditorWorkspaceClass
   GbWorkspaceClass parent_class;
 };
 
-GType gb_editor_workspace_get_type (void) G_GNUC_CONST;
-void  gb_editor_workspace_open     (GbEditorWorkspace *workspace,
-                                    GFile             *file);
+GType        gb_editor_workspace_get_type       (void) G_GNUC_CONST;
+void         gb_editor_workspace_open           (GbEditorWorkspace *workspace,
+                                                 GFile             *file);
+GbEditorTab *gb_editor_workspace_get_active_tab (GbEditorWorkspace *workspace);
 
 G_END_DECLS
 
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index f56701f..58919c5 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -17,6 +17,8 @@ libgnome_builder_la_SOURCES = \
        src/commands/gb-command-manager.h \
        src/commands/gb-command-task.c \
        src/commands/gb-command-task.h \
+       src/commands/gb-commands-internal.c \
+       src/commands/gb-commands-internal.h \
        src/devhelp/gb-devhelp-navigation-item.c \
        src/devhelp/gb-devhelp-navigation-item.h \
        src/devhelp/gb-devhelp-tab.c \


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