[gnome-builder] Add emacs base support
- From: Roberto Majadas <telemaco src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] Add emacs base support
- Date: Fri, 13 Feb 2015 23:40:47 +0000 (UTC)
commit ed3240bc0eb6b51fc68137f12c5f8ab2a06700c4
Author: Roberto Majadas <roberto majadas openshine com>
Date: Sat Feb 7 21:45:57 2015 +0100
Add emacs base support
data/org.gnome.builder.editor.gschema.xml.in | 5 +
src/app/gb-application.c | 35 ++-
src/editor/gb-source-view.c | 22 ++
src/editor/gb-source-view.h | 2 +
src/emacs/gb-source-emacs.c | 454 +++++++++++++++++++++++++
src/emacs/gb-source-emacs.h | 65 ++++
src/gnome-builder.mk | 5 +
src/preferences/gb-preferences-page-emacs.c | 94 +++++
src/preferences/gb-preferences-page-emacs.h | 55 +++
src/preferences/gb-preferences-window.c | 2 +
src/resources/gnome-builder.gresource.xml | 2 +
src/resources/ui/gb-preferences-page-emacs.ui | 83 +++++
src/resources/ui/gb-preferences-window.ui | 9 +
13 files changed, 831 insertions(+), 2 deletions(-)
---
diff --git a/data/org.gnome.builder.editor.gschema.xml.in b/data/org.gnome.builder.editor.gschema.xml.in
index f1069c9..55cdcbc 100644
--- a/data/org.gnome.builder.editor.gschema.xml.in
+++ b/data/org.gnome.builder.editor.gschema.xml.in
@@ -5,6 +5,11 @@
<summary>Enable VIM keybindings</summary>
<description>Whether or not VIM style keybindings should be used in the source code
editor.</description>
</key>
+ <key name="emacs-mode" type="b">
+ <default>false</default>
+ <summary>Enable EMACS keybindings</summary>
+ <description>Whether or not EMACS style keybindings should be used in the source code
editor.</description>
+ </key>
<key name="restore-insert-mark" type="b">
<default>true</default>
<summary>Restore last position</summary>
diff --git a/src/app/gb-application.c b/src/app/gb-application.c
index 266a0b4..d7f6271 100644
--- a/src/app/gb-application.c
+++ b/src/app/gb-application.c
@@ -338,7 +338,27 @@ gb_application_vim_mode_changed (GbApplication *self,
g_return_if_fail (G_IS_SETTINGS (settings));
if (g_settings_get_boolean (settings, "vim-mode"))
- gb_application_load_keybindings (self, "vim");
+ {
+ g_settings_set_boolean (settings, "emacs-mode", FALSE);
+ gb_application_load_keybindings (self, "vim");
+ }
+ else
+ gb_application_load_keybindings (self, "default");
+}
+
+static void
+gb_application_emacs_mode_changed (GbApplication *self,
+ const gchar *key,
+ GSettings *settings)
+{
+ g_return_if_fail (GB_IS_APPLICATION (self));
+ g_return_if_fail (G_IS_SETTINGS (settings));
+
+ if (g_settings_get_boolean (settings, "emacs-mode"))
+ {
+ g_settings_set_boolean (settings, "vim-mode", FALSE);
+ gb_application_load_keybindings (self, "emacs");
+ }
else
gb_application_load_keybindings (self, "default");
}
@@ -355,7 +375,18 @@ gb_application_register_keybindings (GbApplication *self)
G_CALLBACK (gb_application_vim_mode_changed),
self,
G_CONNECT_SWAPPED);
- gb_application_vim_mode_changed (self, NULL, self->priv->editor_settings);
+ g_signal_connect_object (self->priv->editor_settings,
+ "changed::emacs-mode",
+ G_CALLBACK (gb_application_emacs_mode_changed),
+ self,
+ G_CONNECT_SWAPPED);
+ if (g_settings_get_boolean(self->priv->editor_settings, "vim-mode") == TRUE)
+ gb_application_vim_mode_changed (self, NULL, self->priv->editor_settings);
+ else if (g_settings_get_boolean(self->priv->editor_settings, "emacs-mode") == TRUE)
+ gb_application_emacs_mode_changed (self, NULL, self->priv->editor_settings);
+ else
+ gb_application_vim_mode_changed (self, NULL, self->priv->editor_settings);
+
}
static GbWorkbench *
diff --git a/src/editor/gb-source-view.c b/src/editor/gb-source-view.c
index 4268105..47cb7ec 100644
--- a/src/editor/gb-source-view.c
+++ b/src/editor/gb-source-view.c
@@ -44,6 +44,7 @@
#include "gb-source-snippet-private.h"
#include "gb-source-view.h"
#include "gb-source-vim.h"
+#include "gb-source-emacs.h"
#include "gb-widget.h"
enum {
@@ -60,6 +61,7 @@ struct _GbSourceViewPrivate
GtkSourceCompletionProvider *snippets_provider;
GtkSourceCompletionProvider *words_provider;
GbSourceVim *vim;
+ GbSourceEmacs *emacs;
GtkCssProvider *css_provider;
GSettings *language_settings;
@@ -125,6 +127,14 @@ gb_source_view_get_vim (GbSourceView *view)
return view->priv->vim;
}
+GbSourceEmacs *
+gb_source_view_get_emacs (GbSourceView *view)
+{
+ g_return_val_if_fail (GB_IS_SOURCE_VIEW (view), NULL);
+
+ return view->priv->emacs;
+}
+
gboolean
gb_source_view_get_insert_matching_brace (GbSourceView *view)
{
@@ -235,6 +245,7 @@ gb_source_view_disconnect_settings (GbSourceView *view)
g_settings_unbind (view, "tab-width");
g_settings_unbind (view, "font-name");
g_settings_unbind (view->priv->vim, "enabled");
+ g_settings_unbind (view->priv->emacs, "enabled");
g_clear_object (&view->priv->language_settings);
g_clear_object (&view->priv->editor_settings);
@@ -301,6 +312,8 @@ gb_source_view_connect_settings (GbSourceView *view)
buffer, "style-scheme-name", G_SETTINGS_BIND_GET);
g_settings_bind (view->priv->editor_settings, "vim-mode",
view->priv->vim, "enabled", G_SETTINGS_BIND_GET);
+ g_settings_bind (view->priv->editor_settings, "emacs-mode",
+ view->priv->emacs, "enabled", G_SETTINGS_BIND_GET);
g_settings_bind (view->priv->editor_settings, "word-completion",
view, "enable-word-completion", G_SETTINGS_BIND_GET);
g_settings_bind (view->priv->editor_settings, "show-line-numbers",
@@ -2074,6 +2087,7 @@ gb_source_view_finalize (GObject *object)
g_clear_object (&priv->snippets_provider);
g_clear_object (&priv->words_provider);
g_clear_object (&priv->vim);
+ g_clear_object (&priv->emacs);
g_clear_object (&priv->css_provider);
G_OBJECT_CLASS (gb_source_view_parent_class)->finalize (object);
@@ -2431,6 +2445,14 @@ gb_source_view_init (GbSourceView *view)
G_CONNECT_SWAPPED);
/*
+ * Setup Emacs integration.
+ */
+ view->priv->emacs = g_object_new (GB_TYPE_SOURCE_EMACS,
+ "enabled", FALSE,
+ "text-view", view,
+ NULL);
+
+ /*
* We block completion when we are not focused so that two SourceViews
* viewing the same GtkTextBuffer do not both show completion windows.
*/
diff --git a/src/editor/gb-source-view.h b/src/editor/gb-source-view.h
index c4a2869..e1b8bbf 100644
--- a/src/editor/gb-source-view.h
+++ b/src/editor/gb-source-view.h
@@ -24,6 +24,7 @@
#include "gb-source-auto-indenter.h"
#include "gb-source-snippet.h"
#include "gb-source-vim.h"
+#include "gb-source-emacs.h"
G_BEGIN_DECLS
@@ -88,6 +89,7 @@ void gb_source_view_set_overwrite_braces (GbSourceView
void gb_source_view_set_show_shadow (GbSourceView *view,
gboolean show_shadow);
GbSourceVim *gb_source_view_get_vim (GbSourceView *view);
+GbSourceEmacs *gb_source_view_get_emacs (GbSourceView *view);
G_END_DECLS
diff --git a/src/emacs/gb-source-emacs.c b/src/emacs/gb-source-emacs.c
new file mode 100644
index 0000000..a3fd310
--- /dev/null
+++ b/src/emacs/gb-source-emacs.c
@@ -0,0 +1,454 @@
+/* gb-source-emacs.c
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Roberto Majadas <roberto majadas openshine com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "emacs"
+
+#include <errno.h>
+#include <glib/gi18n.h>
+#include <gtksourceview/gtksource.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gb-source-emacs.h"
+#include "gb-string.h"
+
+struct _GbSourceEmacsPrivate
+{
+ GtkTextView *text_view;
+ GString *cmd;
+ guint enabled : 1;
+ guint connected : 1;
+ gulong key_press_event_handler;
+ gulong event_after_handler;
+ gulong key_release_event_handler;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ENABLED,
+ PROP_TEXT_VIEW,
+ LAST_PROP
+};
+
+typedef enum
+{
+ GB_SOURCE_EMACS_COMMAND_FLAG_NONE,
+} GbSourceEmacsCommandFlags;
+
+typedef void (*GbSourceEmacsCommandFunc) (GbSourceEmacs *emacs,
+ GRegex *matcher,
+ GbSourceEmacsCommandFlags flags
+ );
+
+typedef struct
+{
+ GbSourceEmacsCommandFunc func;
+ GRegex *matcher;
+ GbSourceEmacsCommandFlags flags;
+} GbSourceEmacsCommand;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GbSourceEmacs, gb_source_emacs, G_TYPE_OBJECT)
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+static GList *gCommands;
+
+GbSourceEmacs *
+gb_source_emacs_new (GtkTextView *text_view)
+{
+ g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
+
+ return g_object_new (GB_TYPE_SOURCE_EMACS,
+ "text-view", text_view,
+ NULL);
+}
+
+static void
+gb_source_emacs_cmd_exit_from_command_line (GbSourceEmacs *emacs,
+ GRegex *matcher,
+ GbSourceEmacsCommandFlags flags)
+{
+ GbSourceEmacsPrivate *priv = GB_SOURCE_EMACS (emacs)->priv;
+
+ if (priv->cmd != NULL)
+ g_string_free(priv->cmd, TRUE);
+ priv->cmd = g_string_new(NULL);
+}
+
+static void
+gb_source_emacs_cmd_open_file (GbSourceEmacs *emacs,
+ GRegex *matcher,
+ GbSourceEmacsCommandFlags flags)
+{
+ return;
+}
+
+static gboolean
+gb_source_emacs_eval_cmd (GbSourceEmacs *emacs)
+{
+ GbSourceEmacsPrivate *priv = GB_SOURCE_EMACS (emacs)->priv;
+ GMatchInfo *match_info;
+ GList *iter;
+
+ for (iter = gCommands; iter; iter = iter->next)
+ {
+ GbSourceEmacsCommand *cmd = iter->data;
+
+ g_regex_match (cmd->matcher, priv->cmd->str, 0, &match_info);
+ if (g_match_info_matches(match_info))
+ {
+ cmd->func (emacs, cmd->matcher, cmd->flags);
+ g_match_info_free (match_info);
+ if (priv->cmd != NULL)
+ g_string_free(priv->cmd, TRUE);
+ priv->cmd = g_string_new(NULL);
+ break;
+ }
+ g_match_info_free (match_info);
+ }
+
+ g_print(">>> %s\n", priv->cmd->str);
+ return TRUE;
+}
+
+static void
+gb_source_emacs_event_after_cb (GtkTextView *text_view,
+ GdkEventKey *event,
+ GbSourceEmacs *emacs)
+{
+ g_return_if_fail (GB_IS_SOURCE_EMACS (emacs));
+}
+
+static gboolean
+gb_source_emacs_key_press_event_cb (GtkTextView *text_view,
+ GdkEventKey *event,
+ GbSourceEmacs *emacs)
+{
+ GbSourceEmacsPrivate *priv = GB_SOURCE_EMACS (emacs)->priv;
+ gboolean eval_cmd = FALSE;
+
+ g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+ g_return_val_if_fail (event, FALSE);
+ g_return_val_if_fail (GB_IS_SOURCE_EMACS (emacs), FALSE);
+
+ if ((event->keyval >= 0x041 && event->keyval <= 0x05a) || (event->keyval >= 0x061 && event->keyval <=
0x07a))
+ {
+ if (event->state == (GDK_CONTROL_MASK | GDK_MOD1_MASK))
+ {
+ if (priv->cmd->len != 0 )
+ g_string_append_printf(priv->cmd, " ");
+ g_string_append_printf(priv->cmd, "C-M-%s", gdk_keyval_name(event->keyval));
+ eval_cmd = TRUE;
+ }
+ else if ((event->state & GDK_CONTROL_MASK) != 0)
+ {
+ if (priv->cmd->len != 0 )
+ g_string_append_printf(priv->cmd, " ");
+ g_string_append_printf(priv->cmd, "C-%s", gdk_keyval_name(event->keyval));
+ eval_cmd = TRUE;
+ }
+ else if ((event->state & GDK_MOD1_MASK) != 0)
+ {
+ if (priv->cmd->len != 0 )
+ g_string_append_printf(priv->cmd, " ");
+ g_string_append_printf(priv->cmd, "M-%s", gdk_keyval_name(event->keyval));
+ eval_cmd = TRUE;
+ }
+ }
+
+ if (eval_cmd)
+ return gb_source_emacs_eval_cmd(emacs);
+
+ return FALSE;
+}
+
+static gboolean
+gb_source_emacs_key_release_event_cb (GtkTextView *text_view,
+ GdkEventKey *event,
+ GbSourceEmacs *emacs)
+{
+ g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+ g_return_val_if_fail (event, FALSE);
+ g_return_val_if_fail (GB_IS_SOURCE_EMACS (emacs), FALSE);
+
+ return FALSE;
+}
+
+static void
+gb_source_emacs_connect (GbSourceEmacs *emacs)
+{
+ g_return_if_fail (GB_IS_SOURCE_EMACS (emacs));
+ g_return_if_fail (!emacs->priv->connected);
+
+ emacs->priv->key_press_event_handler =
+ g_signal_connect_object (emacs->priv->text_view,
+ "key-press-event",
+ G_CALLBACK (gb_source_emacs_key_press_event_cb),
+ emacs,
+ 0);
+
+ emacs->priv->event_after_handler =
+ g_signal_connect_object (emacs->priv->text_view,
+ "event-after",
+ G_CALLBACK (gb_source_emacs_event_after_cb),
+ emacs,
+ 0);
+
+ emacs->priv->key_release_event_handler =
+ g_signal_connect_object (emacs->priv->text_view,
+ "key-release-event",
+ G_CALLBACK (gb_source_emacs_key_release_event_cb),
+ emacs,
+ 0);
+
+ emacs->priv->connected = TRUE;
+}
+
+static void
+gb_source_emacs_disconnect (GbSourceEmacs *emacs)
+{
+ g_return_if_fail (GB_IS_SOURCE_EMACS (emacs));
+ g_return_if_fail (emacs->priv->connected);
+
+ g_signal_handler_disconnect (emacs->priv->text_view,
+ emacs->priv->key_press_event_handler);
+ emacs->priv->key_press_event_handler = 0;
+
+ g_signal_handler_disconnect (emacs->priv->text_view,
+ emacs->priv->event_after_handler);
+ emacs->priv->event_after_handler = 0;
+
+ g_signal_handler_disconnect (emacs->priv->text_view,
+ emacs->priv->key_release_event_handler);
+ emacs->priv->key_release_event_handler = 0;
+ emacs->priv->connected = FALSE;
+}
+
+gboolean
+gb_source_emacs_get_enabled (GbSourceEmacs *emacs)
+{
+ g_return_val_if_fail (GB_IS_SOURCE_EMACS (emacs), FALSE);
+
+ return emacs->priv->enabled;
+}
+
+void
+gb_source_emacs_set_enabled (GbSourceEmacs *emacs,
+ gboolean enabled)
+{
+ GbSourceEmacsPrivate *priv;
+
+ g_return_if_fail (GB_IS_SOURCE_EMACS (emacs));
+
+ priv = emacs->priv;
+
+ if (priv->enabled == enabled)
+ return;
+
+ if (enabled)
+ {
+
+ gb_source_emacs_connect (emacs);
+ priv->enabled = TRUE;
+ }
+ else
+ {
+ gb_source_emacs_disconnect (emacs);
+ priv->enabled = FALSE;
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (emacs), gParamSpecs [PROP_ENABLED]);
+}
+
+GtkWidget *
+gb_source_emacs_get_text_view (GbSourceEmacs *emacs)
+{
+ g_return_val_if_fail (GB_IS_SOURCE_EMACS (emacs), NULL);
+
+ return (GtkWidget *)emacs->priv->text_view;
+}
+
+static void
+gb_source_emacs_set_text_view (GbSourceEmacs *emacs,
+ GtkTextView *text_view)
+{
+ GbSourceEmacsPrivate *priv;
+
+ g_return_if_fail (GB_IS_SOURCE_EMACS (emacs));
+ g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
+
+ priv = emacs->priv;
+
+ if (priv->text_view == text_view)
+ return;
+
+ if (priv->text_view)
+ {
+ if (priv->enabled)
+ gb_source_emacs_disconnect (emacs);
+ g_object_remove_weak_pointer (G_OBJECT (priv->text_view),
+ (gpointer *)&priv->text_view);
+ priv->text_view = NULL;
+ }
+
+ if (text_view)
+ {
+ priv->text_view = text_view;
+ g_object_add_weak_pointer (G_OBJECT (text_view),
+ (gpointer *)&priv->text_view);
+ if (priv->enabled)
+ gb_source_emacs_connect (emacs);
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (emacs), gParamSpecs [PROP_TEXT_VIEW]);
+}
+
+static void
+gb_source_emacs_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbSourceEmacs *emacs = GB_SOURCE_EMACS (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENABLED:
+ g_value_set_boolean (value, gb_source_emacs_get_enabled (emacs));
+ break;
+
+ case PROP_TEXT_VIEW:
+ g_value_set_object (value, gb_source_emacs_get_text_view (emacs));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gb_source_emacs_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GbSourceEmacs *emacs = GB_SOURCE_EMACS (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENABLED:
+ gb_source_emacs_set_enabled (emacs, g_value_get_boolean (value));
+ break;
+
+ case PROP_TEXT_VIEW:
+ gb_source_emacs_set_text_view (emacs, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gb_source_emacs_finalize (GObject *object)
+{
+ GbSourceEmacsPrivate *priv = GB_SOURCE_EMACS (object)->priv;
+ if (priv->text_view)
+ {
+ gb_source_emacs_disconnect (GB_SOURCE_EMACS (object));
+ g_object_remove_weak_pointer (G_OBJECT (priv->text_view),
+ (gpointer *)&priv->text_view);
+ priv->text_view = NULL;
+ }
+ if (priv->cmd != NULL)
+ g_string_free(priv->cmd, TRUE);
+
+ G_OBJECT_CLASS (gb_source_emacs_parent_class)->finalize (object);
+}
+
+static void
+gb_source_emacs_class_register_command (GbSourceEmacsClass *klass,
+ GRegex *matcher,
+ GbSourceEmacsCommandFlags flags,
+ GbSourceEmacsCommandFunc func)
+{
+ GbSourceEmacsCommand *cmd;
+
+ g_assert (GB_IS_SOURCE_EMACS_CLASS (klass));
+
+ cmd = g_new0 (GbSourceEmacsCommand, 1);
+ cmd->matcher = matcher;
+ cmd->func = func;
+ cmd->flags = flags;
+
+ gCommands = g_list_append(gCommands, cmd);
+}
+
+
+static void
+gb_source_emacs_class_init (GbSourceEmacsClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = gb_source_emacs_finalize;
+ object_class->get_property = gb_source_emacs_get_property;
+ object_class->set_property = gb_source_emacs_set_property;
+
+ gParamSpecs [PROP_ENABLED] =
+ g_param_spec_boolean ("enabled",
+ _("Enabled"),
+ _("If the EMACS engine is enabled."),
+ FALSE,
+ (G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_ENABLED,
+ gParamSpecs [PROP_ENABLED]);
+
+ gParamSpecs [PROP_TEXT_VIEW] =
+ g_param_spec_object ("text-view",
+ _("Text View"),
+ _("The text view the EMACS engine is managing."),
+ GTK_TYPE_TEXT_VIEW,
+ (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_TEXT_VIEW,
+ gParamSpecs [PROP_TEXT_VIEW]);
+
+ /* Register emacs commands */
+ gb_source_emacs_class_register_command (klass,
+ g_regex_new("C-g$", 0, 0, NULL),
+ GB_SOURCE_EMACS_COMMAND_FLAG_NONE,
+ gb_source_emacs_cmd_exit_from_command_line);
+ gb_source_emacs_class_register_command (klass,
+ g_regex_new("^C-x C-s$", 0, 0, NULL),
+ GB_SOURCE_EMACS_COMMAND_FLAG_NONE,
+ gb_source_emacs_cmd_open_file);
+}
+
+static void
+gb_source_emacs_init (GbSourceEmacs *emacs)
+{
+ emacs->priv = gb_source_emacs_get_instance_private (emacs);
+ emacs->priv->enabled = FALSE;
+ emacs->priv->cmd = g_string_new(NULL);
+}
+
+
diff --git a/src/emacs/gb-source-emacs.h b/src/emacs/gb-source-emacs.h
new file mode 100644
index 0000000..ebefa57
--- /dev/null
+++ b/src/emacs/gb-source-emacs.h
@@ -0,0 +1,65 @@
+/* gb-source-emacs.h
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Roberto Majadas <roberto majadas openshine com>
+ *
+ * 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_SOURCE_EMACS_H
+#define GB_SOURCE_EMACS_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_SOURCE_EMACS (gb_source_emacs_get_type())
+#define GB_SOURCE_EMACS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_SOURCE_EMACS,
GbSourceEmacs))
+#define GB_SOURCE_EMACS_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_SOURCE_EMACS,
GbSourceEmacs const))
+#define GB_SOURCE_EMACS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GB_TYPE_SOURCE_EMACS,
GbSourceEmacsClass))
+#define GB_IS_SOURCE_EMACS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_SOURCE_EMACS))
+#define GB_IS_SOURCE_EMACS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GB_TYPE_SOURCE_EMACS))
+#define GB_SOURCE_EMACS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GB_TYPE_SOURCE_EMACS,
GbSourceEmacsClass))
+
+typedef struct _GbSourceEmacs GbSourceEmacs;
+typedef struct _GbSourceEmacsClass GbSourceEmacsClass;
+typedef struct _GbSourceEmacsPrivate GbSourceEmacsPrivate;
+
+struct _GbSourceEmacs
+{
+ GObject parent;
+
+ /*< private >*/
+ GbSourceEmacsPrivate *priv;
+};
+
+struct _GbSourceEmacsClass
+{
+ GObjectClass parent_class;
+
+ gpointer _padding1;
+ gpointer _padding2;
+ gpointer _padding3;
+};
+
+GType gb_source_emacs_get_type (void);
+GbSourceEmacs *gb_source_emacs_new (GtkTextView *text_view);
+gboolean gb_source_emacs_get_enabled (GbSourceEmacs *emacs);
+void gb_source_emacs_set_enabled (GbSourceEmacs *emacs,
+ gboolean enabled);
+
+
+G_END_DECLS
+
+#endif /* GB_SOURCE_EMACS_H */
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index 60d1172..fb6844e 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -97,6 +97,8 @@ libgnome_builder_la_SOURCES = \
src/editor/gb-source-search-highlighter.h \
src/editor/gb-source-view.c \
src/editor/gb-source-view.h \
+ src/emacs/gb-source-emacs.c \
+ src/emacs/gb-source-emacs.h \
src/fuzzy/fuzzy.c \
src/fuzzy/fuzzy.h \
src/gca/gca-diagnostics.c \
@@ -131,6 +133,8 @@ libgnome_builder_la_SOURCES = \
src/navigation/gb-navigation-list.h \
src/preferences/gb-preferences-page-editor.c \
src/preferences/gb-preferences-page-editor.h \
+ src/preferences/gb-preferences-page-emacs.c \
+ src/preferences/gb-preferences-page-emacs.h \
src/preferences/gb-preferences-page-git.c \
src/preferences/gb-preferences-page-git.h \
src/preferences/gb-preferences-page-language.c \
@@ -236,6 +240,7 @@ libgnome_builder_la_CFLAGS = \
-I$(top_srcdir)/src/dialogs \
-I$(top_srcdir)/src/documents \
-I$(top_srcdir)/src/editor \
+ -I$(top_srcdir)/src/emacs \
-I$(top_srcdir)/src/fuzzy \
-I$(top_srcdir)/src/gca \
-I$(top_srcdir)/src/gd \
diff --git a/src/preferences/gb-preferences-page-emacs.c b/src/preferences/gb-preferences-page-emacs.c
new file mode 100644
index 0000000..bc16f1e
--- /dev/null
+++ b/src/preferences/gb-preferences-page-emacs.c
@@ -0,0 +1,94 @@
+/* gb-preferences-page-emacs.c
+ *
+ * Copyright (C) 2015 Roberto Majadas <roberto majadas openshine com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "prefs-page-editor"
+
+#include <glib/gi18n.h>
+
+#include "gb-preferences-page-emacs.h"
+
+struct _GbPreferencesPageEmacsPrivate
+{
+ GSettings *editor_settings;
+
+ /* Widgets owned by Template */
+ GtkSwitch *emacs_mode_switch;
+
+ /* Template widgets used for filtering */
+ GtkWidget *emacs_container;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GbPreferencesPageEmacs, gb_preferences_page_emacs,
+ GB_TYPE_PREFERENCES_PAGE)
+
+static void
+gb_preferences_page_emacs_constructed (GObject *object)
+{
+ GbPreferencesPageEmacsPrivate *priv;
+ GbPreferencesPageEmacs *emacs = (GbPreferencesPageEmacs *)object;
+
+ g_return_if_fail (GB_IS_PREFERENCES_PAGE_EMACS (emacs));
+
+ priv = emacs->priv;
+
+ priv->editor_settings = g_settings_new ("org.gnome.builder.editor");
+
+ g_settings_bind (priv->editor_settings, "emacs-mode",
+ priv->emacs_mode_switch, "active",
+ G_SETTINGS_BIND_DEFAULT);
+}
+
+static void
+gb_preferences_page_emacs_finalize (GObject *object)
+{
+ GbPreferencesPageEmacsPrivate *priv = GB_PREFERENCES_PAGE_EMACS (object)->priv;
+
+ g_clear_object (&priv->editor_settings);
+
+ G_OBJECT_CLASS (gb_preferences_page_emacs_parent_class)->finalize (object);
+}
+
+static void
+gb_preferences_page_emacs_class_init (GbPreferencesPageEmacsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = gb_preferences_page_emacs_finalize;
+ object_class->constructed = gb_preferences_page_emacs_constructed;
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/builder/ui/gb-preferences-page-emacs.ui");
+
+ gtk_widget_class_bind_template_child_private (widget_class, GbPreferencesPageEmacs, emacs_mode_switch);
+ gtk_widget_class_bind_template_child_private (widget_class, GbPreferencesPageEmacs, emacs_container);
+}
+
+static void
+gb_preferences_page_emacs_init (GbPreferencesPageEmacs *self)
+{
+ self->priv = gb_preferences_page_emacs_get_instance_private (self);
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ gb_preferences_page_set_keywords_for_widget (GB_PREFERENCES_PAGE (self),
+ _("emacs modal"),
+ self->priv->emacs_container,
+ self->priv->emacs_mode_switch,
+ NULL);
+}
diff --git a/src/preferences/gb-preferences-page-emacs.h b/src/preferences/gb-preferences-page-emacs.h
new file mode 100644
index 0000000..1153b0e
--- /dev/null
+++ b/src/preferences/gb-preferences-page-emacs.h
@@ -0,0 +1,55 @@
+/* gb-preferences-page-emacs.h
+ *
+ * Copyright (C) 2015 Roberto Majadas <roberto majadas openshine com>
+ *
+ * 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_PREFERENCES_PAGE_EMACS_H
+#define GB_PREFERENCES_PAGE_EMACS_H
+
+#include "gb-preferences-page.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_PREFERENCES_PAGE_EMACS (gb_preferences_page_emacs_get_type())
+#define GB_PREFERENCES_PAGE_EMACS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GB_TYPE_PREFERENCES_PAGE_EMACS, GbPreferencesPageEmacs))
+#define GB_PREFERENCES_PAGE_EMACS_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GB_TYPE_PREFERENCES_PAGE_EMACS, GbPreferencesPageEmacs const))
+#define GB_PREFERENCES_PAGE_EMACS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
GB_TYPE_PREFERENCES_PAGE_EMACS, GbPreferencesPageEmacsClass))
+#define GB_IS_PREFERENCES_PAGE_EMACS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
GB_TYPE_PREFERENCES_PAGE_EMACS))
+#define GB_IS_PREFERENCES_PAGE_EMACS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
GB_TYPE_PREFERENCES_PAGE_EMACS))
+#define GB_PREFERENCES_PAGE_EMACS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GB_TYPE_PREFERENCES_PAGE_EMACS, GbPreferencesPageEmacsClass))
+
+typedef struct _GbPreferencesPageEmacs GbPreferencesPageEmacs;
+typedef struct _GbPreferencesPageEmacsClass GbPreferencesPageEmacsClass;
+typedef struct _GbPreferencesPageEmacsPrivate GbPreferencesPageEmacsPrivate;
+
+struct _GbPreferencesPageEmacs
+{
+ GbPreferencesPage parent;
+
+ /*< private >*/
+ GbPreferencesPageEmacsPrivate *priv;
+};
+
+struct _GbPreferencesPageEmacsClass
+{
+ GbPreferencesPageClass parent;
+};
+
+GType gb_preferences_page_emacs_get_type (void);
+
+G_END_DECLS
+
+#endif /* GB_PREFERENCES_PAGE_EMACS_H */
\ No newline at end of file
diff --git a/src/preferences/gb-preferences-window.c b/src/preferences/gb-preferences-window.c
index 20d8ab6..98f417b 100644
--- a/src/preferences/gb-preferences-window.c
+++ b/src/preferences/gb-preferences-window.c
@@ -25,6 +25,7 @@
#include <glib/gi18n.h>
#include "gb-preferences-page-editor.h"
+#include "gb-preferences-page-emacs.h"
#include "gb-preferences-page-git.h"
#include "gb-preferences-page-language.h"
#include "gb-preferences-page-vim.h"
@@ -337,6 +338,7 @@ gb_preferences_window_class_init (GbPreferencesWindowClass *klass)
g_type_ensure (GB_TYPE_PREFERENCES_PAGE_EDITOR);
g_type_ensure (GB_TYPE_PREFERENCES_PAGE_LANGUAGE);
g_type_ensure (GB_TYPE_PREFERENCES_PAGE_VIM);
+ g_type_ensure (GB_TYPE_PREFERENCES_PAGE_EMACS);
}
static void
diff --git a/src/resources/gnome-builder.gresource.xml b/src/resources/gnome-builder.gresource.xml
index 9b24dee..c6c6c57 100644
--- a/src/resources/gnome-builder.gresource.xml
+++ b/src/resources/gnome-builder.gresource.xml
@@ -15,6 +15,7 @@
<file>js/markdown-view.js</file>
<file>keybindings/default.ini</file>
+ <file>keybindings/emacs.ini</file>
<file>keybindings/vim.ini</file>
<file>language/defaults.ini</file>
@@ -45,6 +46,7 @@
<file>ui/gb-html-view.ui</file>
<file>ui/gb-preferences-window.ui</file>
<file>ui/gb-preferences-page-editor.ui</file>
+ <file>ui/gb-preferences-page-emacs.ui</file>
<file>ui/gb-preferences-page-git.ui</file>
<file>ui/gb-preferences-page-language.ui</file>
<file>ui/gb-preferences-page-vim.ui</file>
diff --git a/src/resources/keybindings/emacs.ini b/src/resources/keybindings/emacs.ini
new file mode 100644
index 0000000..e69de29
diff --git a/src/resources/ui/gb-preferences-page-emacs.ui b/src/resources/ui/gb-preferences-page-emacs.ui
new file mode 100644
index 0000000..90cb6a7
--- /dev/null
+++ b/src/resources/ui/gb-preferences-page-emacs.ui
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.8 -->
+ <template class="GbPreferencesPageEmacs" parent="GbPreferencesPage">
+ <child>
+ <object class="GtkBox">
+ <property name="visible">true</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">12</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkSwitch" id="emacs_mode_switch">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">center</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkBox" id="emacs_container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes"><b>EMACS Modal
Editing</b></property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes">Use EMACS style modal editing in the source
code editor.</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/resources/ui/gb-preferences-window.ui b/src/resources/ui/gb-preferences-window.ui
index 7f11d6d..a9fcdfc 100644
--- a/src/resources/ui/gb-preferences-window.ui
+++ b/src/resources/ui/gb-preferences-window.ui
@@ -141,6 +141,15 @@
<property name="title" translatable="yes">Vim</property>
</packing>
</child>
+ <child>
+ <object class="GbPreferencesPageEmacs" id="emacs_page">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="name">emacs</property>
+ <property name="title" translatable="yes">Emacs</property>
+ </packing>
+ </child>
</object>
</child>
</object>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]