[gnome-builder] libide: import modelines from gedit plugins



commit 12c4804a339bd0e5f78c1ea38ed9b66de5557ab3
Author: Christian Hergert <christian hergert me>
Date:   Wed Mar 18 14:09:13 2015 -0700

    libide: import modelines from gedit plugins

 libide/Makefile.am                    |    3 +
 libide/ide.c                          |    3 +
 libide/modelines/language-mappings    |   14 +
 libide/modelines/modeline-parser.c    |  889 +++++++++++++++++++++++++++++++++
 libide/modelines/modeline-parser.h    |   36 ++
 libide/resources/libide.gresource.xml |    2 +
 6 files changed, 947 insertions(+), 0 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index ee7eec0..7e4fcce 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -241,6 +241,8 @@ libide_1_0_la_SOURCES = \
        libide/ide-source-view-movements.h \
        libide/ide-vim-iter.c \
        libide/ide-vim-iter.h \
+       libide/modelines/modeline-parser.c \
+       libide/modelines/modeline-parser.h \
        libide/tasks/ide-load-directory-task.c \
        libide/tasks/ide-load-directory-task.h \
        libide/theatrics/ide-box-theatric.c \
@@ -272,6 +274,7 @@ libide_1_0_la_includes = \
        -I$(top_srcdir)/libide/gjs \
        -I$(top_srcdir)/libide/gsettings \
        -I$(top_srcdir)/libide/local \
+       -I$(top_srcdir)/libide/modelines \
        -I$(top_srcdir)/libide/pygobject \
        -I$(top_srcdir)/libide/python \
        -I$(top_srcdir)/libide/resources \
diff --git a/libide/ide.c b/libide/ide.c
index faaf04b..453c1b4 100644
--- a/libide/ide.c
+++ b/libide/ide.c
@@ -40,6 +40,8 @@
 #include "ide-search-provider.h"
 #include "ide-xml-language.h"
 
+#include "modeline-parser.h"
+
 static gboolean     gProgramNameRead;
 static const gchar *gProgramName = "libide";
 
@@ -156,5 +158,6 @@ ide_init_ctor (void)
                                   IDE_VCS_EXTENSION_POINT".directory",
                                   -200);
 
+  modeline_parser_init ();
   ggit_init ();
 }
diff --git a/libide/modelines/language-mappings b/libide/modelines/language-mappings
new file mode 100644
index 0000000..47d0029
--- /dev/null
+++ b/libide/modelines/language-mappings
@@ -0,0 +1,14 @@
+[vim]
+cs=c-sharp
+docbk=docbook
+javascript=js
+lhaskell=haskell-literate
+spec=rpmspec
+tex=latex
+xhtml=html
+
+[emacs]
+c++=cpp
+
+[kate]
+
diff --git a/libide/modelines/modeline-parser.c b/libide/modelines/modeline-parser.c
new file mode 100644
index 0000000..ef7f098
--- /dev/null
+++ b/libide/modelines/modeline-parser.c
@@ -0,0 +1,889 @@
+/*
+ * modeline-parser.c
+ * Emacs, Kate and Vim-style modelines support for gedit.
+ *
+ * Copyright (C) 2005-2007 - Steve Frécinaux <code istique net>
+ *
+ * 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 2, 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 "modelines"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <gtksourceview/gtksource.h>
+
+#include "modeline-parser.h"
+
+#define MODELINES_LANGUAGE_MAPPINGS_FILE "/org/gnome/libide/modelines/language-mappings"
+#define gedit_debug_message(ignored,fmt,...) g_debug(fmt,__VA_ARGS__)
+
+/* Mappings: language name -> Gedit language ID */
+static GHashTable *vim_languages = NULL;
+static GHashTable *emacs_languages = NULL;
+static GHashTable *kate_languages = NULL;
+
+typedef enum
+{
+       MODELINE_SET_NONE = 0,
+       MODELINE_SET_TAB_WIDTH = 1 << 0,
+       MODELINE_SET_INDENT_WIDTH = 1 << 1,
+       MODELINE_SET_WRAP_MODE = 1 << 2,
+       MODELINE_SET_SHOW_RIGHT_MARGIN = 1 << 3,
+       MODELINE_SET_RIGHT_MARGIN_POSITION = 1 << 4,
+       MODELINE_SET_LANGUAGE = 1 << 5,
+       MODELINE_SET_INSERT_SPACES = 1 << 6
+} ModelineSet;
+
+typedef struct _ModelineOptions
+{
+       gchar           *language_id;
+
+       /* these options are similar to the GtkSourceView properties of the
+        * same names.
+        */
+       gboolean        insert_spaces;
+       guint           tab_width;
+       guint           indent_width;
+       GtkWrapMode     wrap_mode;
+       gboolean        display_right_margin;
+       guint           right_margin_position;
+
+       ModelineSet     set;
+} ModelineOptions;
+
+#define MODELINE_OPTIONS_DATA_KEY "ModelineOptionsDataKey"
+
+static gboolean
+has_option (ModelineOptions *options,
+            ModelineSet      set)
+{
+       return options->set & set;
+}
+
+void
+modeline_parser_init (void)
+{
+}
+
+void
+modeline_parser_shutdown ()
+{
+       if (vim_languages != NULL)
+               g_hash_table_unref (vim_languages);
+
+       if (emacs_languages != NULL)
+               g_hash_table_unref (emacs_languages);
+
+       if (kate_languages != NULL)
+               g_hash_table_unref (kate_languages);
+
+       vim_languages = NULL;
+       emacs_languages = NULL;
+       kate_languages = NULL;
+}
+
+static GHashTable *
+load_language_mappings_group (GKeyFile *key_file, const gchar *group)
+{
+       GHashTable *table;
+       gchar **keys;
+       gsize length = 0;
+       int i;
+
+       table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+       keys = g_key_file_get_keys (key_file, group, &length, NULL);
+
+       gedit_debug_message (DEBUG_PLUGINS,
+                            "%" G_GSIZE_FORMAT " mappings in group %s",
+                            length, group);
+
+       for (i = 0; i < length; i++)
+       {
+               /* steal the name string */
+               gchar *name = keys[i];
+               gchar *id = g_key_file_get_string (key_file, group, name, NULL);
+               g_hash_table_insert (table, name, id);
+       }
+       g_free (keys);
+
+       return table;
+}
+
+/* lazy loading of language mappings */
+static void
+load_language_mappings (void)
+{
+       g_autoptr(GBytes) bytes = NULL;
+       GKeyFile *mappings;
+       const gchar *data;
+       gsize len = 0;
+       GError *error = NULL;
+
+       bytes = g_resources_lookup_data (MODELINES_LANGUAGE_MAPPINGS_FILE, 0, NULL);
+       g_assert (bytes != NULL);
+
+       data = g_bytes_get_data (bytes, &len);
+       g_assert (data);
+       g_assert_cmpint (len, >, 0);
+
+       mappings = g_key_file_new ();
+
+       if (g_key_file_load_from_data (mappings, data, len, 0, &error))
+       {
+               gedit_debug_message (DEBUG_PLUGINS,
+                                    "Loaded language mappings from %s",
+                                    MODELINES_LANGUAGE_MAPPINGS_FILE);
+
+               vim_languages = load_language_mappings_group (mappings, "vim");
+               emacs_languages = load_language_mappings_group (mappings, "emacs");
+               kate_languages = load_language_mappings_group (mappings, "kate");
+       }
+       else
+       {
+               gedit_debug_message (DEBUG_PLUGINS,
+                                    "Failed to loaded language mappings from %s: %s",
+                                    MODELINES_LANGUAGE_MAPPINGS_FILE, error->message);
+
+               g_error_free (error);
+       }
+
+       g_key_file_free (mappings);
+}
+
+static gchar *
+get_language_id (const gchar *language_name, GHashTable *mapping)
+{
+       gchar *name;
+       gchar *language_id = NULL;
+
+       name = g_ascii_strdown (language_name, -1);
+
+       if (mapping != NULL)
+       {
+               language_id = g_hash_table_lookup (mapping, name);
+
+               if (language_id != NULL)
+               {
+                       g_free (name);
+                       return g_strdup (language_id);
+               }
+       }
+
+       /* by default assume that the gtksourcevuew id is the same */
+       return name;
+}
+
+static gchar *
+get_language_id_vim (const gchar *language_name)
+{
+       if (vim_languages == NULL)
+               load_language_mappings ();
+
+       return get_language_id (language_name, vim_languages);
+}
+
+static gchar *
+get_language_id_emacs (const gchar *language_name)
+{
+       if (emacs_languages == NULL)
+               load_language_mappings ();
+
+       return get_language_id (language_name, emacs_languages);
+}
+
+static gchar *
+get_language_id_kate (const gchar *language_name)
+{
+       if (kate_languages == NULL)
+               load_language_mappings ();
+
+       return get_language_id (language_name, kate_languages);
+}
+
+static gboolean
+skip_whitespaces (gchar **s)
+{
+       while (**s != '\0' && g_ascii_isspace (**s))
+               (*s)++;
+       return **s != '\0';
+}
+
+/* Parse vi(m) modelines.
+ * Vi(m) modelines looks like this:
+ *   - first form:   [text]{white}{vi:|vim:|ex:}[white]{options}
+ *   - second form:  [text]{white}{vi:|vim:|ex:}[white]se[t] {options}:[text]
+ * They can happen on the three first or last lines.
+ */
+static gchar *
+parse_vim_modeline (gchar           *s,
+                   ModelineOptions *options)
+{
+       gboolean in_set = FALSE;
+       gboolean neg;
+       guint intval;
+       GString *key, *value;
+
+       key = g_string_sized_new (8);
+       value = g_string_sized_new (8);
+
+       while (*s != '\0' && !(in_set && *s == ':'))
+       {
+               while (*s != '\0' && (*s == ':' || g_ascii_isspace (*s)))
+                       s++;
+
+               if (*s == '\0')
+                       break;
+
+               if (strncmp (s, "set ", 4) == 0 ||
+                   strncmp (s, "se ", 3) == 0)
+               {
+                       s = strchr(s, ' ') + 1;
+                       in_set = TRUE;
+               }
+
+               neg = FALSE;
+               if (strncmp (s, "no", 2) == 0)
+               {
+                       neg = TRUE;
+                       s += 2;
+               }
+
+               g_string_assign (key, "");
+               g_string_assign (value, "");
+
+               while (*s != '\0' && *s != ':' && *s != '=' &&
+                      !g_ascii_isspace (*s))
+               {
+                       g_string_append_c (key, *s);
+                       s++;
+               }
+
+               if (*s == '=')
+               {
+                       s++;
+                       while (*s != '\0' && *s != ':' &&
+                              !g_ascii_isspace (*s))
+                       {
+                               g_string_append_c (value, *s);
+                               s++;
+                       }
+               }
+
+               if (strcmp (key->str, "ft") == 0 ||
+                   strcmp (key->str, "filetype") == 0)
+               {
+                       g_free (options->language_id);
+                       options->language_id = get_language_id_vim (value->str);
+
+                       options->set |= MODELINE_SET_LANGUAGE;
+               }
+               else if (strcmp (key->str, "et") == 0 ||
+                   strcmp (key->str, "expandtab") == 0)
+               {
+                       options->insert_spaces = !neg;
+                       options->set |= MODELINE_SET_INSERT_SPACES;
+               }
+               else if (strcmp (key->str, "ts") == 0 ||
+                        strcmp (key->str, "tabstop") == 0)
+               {
+                       intval = atoi (value->str);
+
+                       if (intval)
+                       {
+                               options->tab_width = intval;
+                               options->set |= MODELINE_SET_TAB_WIDTH;
+                       }
+               }
+               else if (strcmp (key->str, "sw") == 0 ||
+                        strcmp (key->str, "shiftwidth") == 0)
+               {
+                       intval = atoi (value->str);
+
+                       if (intval)
+                       {
+                               options->indent_width = intval;
+                               options->set |= MODELINE_SET_INDENT_WIDTH;
+                       }
+               }
+               else if (strcmp (key->str, "wrap") == 0)
+               {
+                       options->wrap_mode = neg ? GTK_WRAP_NONE : GTK_WRAP_WORD;
+
+                       options->set |= MODELINE_SET_WRAP_MODE;
+               }
+               else if (strcmp (key->str, "textwidth") == 0 ||
+                        strcmp (key->str, "tw") == 0)
+               {
+                       intval = atoi (value->str);
+
+                       if (intval)
+                       {
+                               options->right_margin_position = intval;
+                               options->display_right_margin = TRUE;
+
+                               options->set |= MODELINE_SET_SHOW_RIGHT_MARGIN |
+                                               MODELINE_SET_RIGHT_MARGIN_POSITION;
+
+                       }
+               }
+       }
+
+       g_string_free (key, TRUE);
+       g_string_free (value, TRUE);
+
+       return s;
+}
+
+/* Parse emacs modelines.
+ * Emacs modelines looks like this: "-*- key1: value1; key2: value2 -*-"
+ * They can happen on the first line, or on the second one if the first line is
+ * a shebang (#!)
+ * See http://www.delorie.com/gnu/docs/emacs/emacs_486.html
+ */
+static gchar *
+parse_emacs_modeline (gchar           *s,
+                     ModelineOptions *options)
+{
+       guint intval;
+       GString *key, *value;
+
+       key = g_string_sized_new (8);
+       value = g_string_sized_new (8);
+
+       while (*s != '\0')
+       {
+               while (*s != '\0' && (*s == ';' || g_ascii_isspace (*s)))
+                       s++;
+               if (*s == '\0' || strncmp (s, "-*-", 3) == 0)
+                       break;
+
+               g_string_assign (key, "");
+               g_string_assign (value, "");
+
+               while (*s != '\0' && *s != ':' && *s != ';' &&
+                      !g_ascii_isspace (*s))
+               {
+                       g_string_append_c (key, *s);
+                       s++;
+               }
+
+               if (!skip_whitespaces (&s))
+                       break;
+
+               if (*s != ':')
+                       continue;
+               s++;
+
+               if (!skip_whitespaces (&s))
+                       break;
+
+               while (*s != '\0' && *s != ';' && !g_ascii_isspace (*s))
+               {
+                       g_string_append_c (value, *s);
+                       s++;
+               }
+
+               gedit_debug_message (DEBUG_PLUGINS,
+                                    "Emacs modeline bit: %s = %s",
+                                    key->str, value->str);
+
+               /* "Mode" key is case insenstive */
+               if (g_ascii_strcasecmp (key->str, "Mode") == 0)
+               {
+                       g_free (options->language_id);
+                       options->language_id = get_language_id_emacs (value->str);
+
+                       options->set |= MODELINE_SET_LANGUAGE;
+               }
+               else if (strcmp (key->str, "tab-width") == 0)
+               {
+                       intval = atoi (value->str);
+
+                       if (intval)
+                       {
+                               options->tab_width = intval;
+                               options->set |= MODELINE_SET_TAB_WIDTH;
+                       }
+               }
+               else if (strcmp (key->str, "indent-offset") == 0 ||
+                        strcmp (key->str, "c-basic-offset") == 0)
+               {
+                       intval = atoi (value->str);
+
+                       if (intval)
+                       {
+                               options->indent_width = intval;
+                               options->set |= MODELINE_SET_INDENT_WIDTH;
+                       }
+               }
+               else if (strcmp (key->str, "indent-tabs-mode") == 0)
+               {
+                       intval = strcmp (value->str, "nil") == 0;
+                       options->insert_spaces = intval;
+
+                       options->set |= MODELINE_SET_INSERT_SPACES;
+               }
+               else if (strcmp (key->str, "autowrap") == 0)
+               {
+                       intval = strcmp (value->str, "nil") != 0;
+                       options->wrap_mode = intval ? GTK_WRAP_WORD : GTK_WRAP_NONE;
+
+                       options->set |= MODELINE_SET_WRAP_MODE;
+               }
+       }
+
+       g_string_free (key, TRUE);
+       g_string_free (value, TRUE);
+
+       return *s == '\0' ? s : s + 2;
+}
+
+/*
+ * Parse kate modelines.
+ * Kate modelines are of the form "kate: key1 value1; key2 value2;"
+ * These can happen on the 10 first or 10 last lines of the buffer.
+ * See http://wiki.kate-editor.org/index.php/Modelines
+ */
+static gchar *
+parse_kate_modeline (gchar           *s,
+                    ModelineOptions *options)
+{
+       guint intval;
+       GString *key, *value;
+
+       key = g_string_sized_new (8);
+       value = g_string_sized_new (8);
+
+       while (*s != '\0')
+       {
+               while (*s != '\0' && (*s == ';' || g_ascii_isspace (*s)))
+                       s++;
+               if (*s == '\0')
+                       break;
+
+               g_string_assign (key, "");
+               g_string_assign (value, "");
+
+               while (*s != '\0' && *s != ';' && !g_ascii_isspace (*s))
+               {
+                       g_string_append_c (key, *s);
+                       s++;
+               }
+
+               if (!skip_whitespaces (&s))
+                       break;
+               if (*s == ';')
+                       continue;
+
+               while (*s != '\0' && *s != ';' &&
+                      !g_ascii_isspace (*s))
+               {
+                       g_string_append_c (value, *s);
+                       s++;
+               }
+
+               gedit_debug_message (DEBUG_PLUGINS,
+                                    "Kate modeline bit: %s = %s",
+                                    key->str, value->str);
+
+               if (strcmp (key->str, "hl") == 0 ||
+                   strcmp (key->str, "syntax") == 0)
+               {
+                       g_free (options->language_id);
+                       options->language_id = get_language_id_kate (value->str);
+
+                       options->set |= MODELINE_SET_LANGUAGE;
+               }
+               else if (strcmp (key->str, "tab-width") == 0)
+               {
+                       intval = atoi (value->str);
+
+                       if (intval)
+                       {
+                               options->tab_width = intval;
+                               options->set |= MODELINE_SET_TAB_WIDTH;
+                       }
+               }
+               else if (strcmp (key->str, "indent-width") == 0)
+               {
+                       intval = atoi (value->str);
+                       if (intval) options->indent_width = intval;
+               }
+               else if (strcmp (key->str, "space-indent") == 0)
+               {
+                       intval = strcmp (value->str, "on") == 0 ||
+                                strcmp (value->str, "true") == 0 ||
+                                strcmp (value->str, "1") == 0;
+
+                       options->insert_spaces = intval;
+                       options->set |= MODELINE_SET_INSERT_SPACES;
+               }
+               else if (strcmp (key->str, "word-wrap") == 0)
+               {
+                       intval = strcmp (value->str, "on") == 0 ||
+                                strcmp (value->str, "true") == 0 ||
+                                strcmp (value->str, "1") == 0;
+
+                       options->wrap_mode = intval ? GTK_WRAP_WORD : GTK_WRAP_NONE;
+
+                       options->set |= MODELINE_SET_WRAP_MODE;
+               }
+               else if (strcmp (key->str, "word-wrap-column") == 0)
+               {
+                       intval = atoi (value->str);
+
+                       if (intval)
+                       {
+                               options->right_margin_position = intval;
+                               options->display_right_margin = TRUE;
+
+                               options->set |= MODELINE_SET_RIGHT_MARGIN_POSITION |
+                                               MODELINE_SET_SHOW_RIGHT_MARGIN;
+                       }
+               }
+       }
+
+       g_string_free (key, TRUE);
+       g_string_free (value, TRUE);
+
+       return s;
+}
+
+/* Scan a line for vi(m)/emacs/kate modelines.
+ * Line numbers are counted starting at one.
+ */
+static void
+parse_modeline (gchar           *s,
+               gint             line_number,
+               gint             line_count,
+               ModelineOptions *options)
+{
+       gchar prev;
+
+       /* look for the beginning of a modeline */
+       for (prev = ' '; (s != NULL) && (*s != '\0'); prev = *(s++))
+       {
+               if (!g_ascii_isspace (prev))
+                       continue;
+
+               if ((line_number <= 3 || line_number > line_count - 3) &&
+                   (strncmp (s, "ex:", 3) == 0 ||
+                    strncmp (s, "vi:", 3) == 0 ||
+                    strncmp (s, "vim:", 4) == 0))
+               {
+                       gedit_debug_message (DEBUG_PLUGINS, "Vim modeline on line %d", line_number);
+
+                       while (*s != ':') s++;
+                       s = parse_vim_modeline (s + 1, options);
+               }
+               else if (line_number <= 2 && strncmp (s, "-*-", 3) == 0)
+               {
+                       gedit_debug_message (DEBUG_PLUGINS, "Emacs modeline on line %d", line_number);
+
+                       s = parse_emacs_modeline (s + 3, options);
+               }
+               else if ((line_number <= 10 || line_number > line_count - 10) &&
+                        strncmp (s, "kate:", 5) == 0)
+               {
+                       gedit_debug_message (DEBUG_PLUGINS, "Kate modeline on line %d", line_number);
+
+                       s = parse_kate_modeline (s + 5, options);
+               }
+       }
+}
+
+static gboolean
+check_previous (GtkSourceView   *view,
+                ModelineOptions *previous,
+                ModelineSet      set)
+{
+       GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
+
+       /* Do not restore default when this is the first time */
+       if (!previous)
+               return FALSE;
+
+       /* Do not restore default when previous was not set */
+       if (!(previous->set & set))
+               return FALSE;
+
+       /* Only restore default when setting has not changed */
+       switch (set)
+       {
+               case MODELINE_SET_INSERT_SPACES:
+                       return gtk_source_view_get_insert_spaces_instead_of_tabs (view) ==
+                              previous->insert_spaces;
+               break;
+               case MODELINE_SET_TAB_WIDTH:
+                       return gtk_source_view_get_tab_width (view) == previous->tab_width;
+               break;
+               case MODELINE_SET_INDENT_WIDTH:
+                       return gtk_source_view_get_indent_width (view) == previous->indent_width;
+               break;
+               case MODELINE_SET_WRAP_MODE:
+                       return gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view)) ==
+                              previous->wrap_mode;
+               break;
+               case MODELINE_SET_RIGHT_MARGIN_POSITION:
+                       return gtk_source_view_get_right_margin_position (view) ==
+                              previous->right_margin_position;
+               break;
+               case MODELINE_SET_SHOW_RIGHT_MARGIN:
+                       return gtk_source_view_get_show_right_margin (view) ==
+                              previous->display_right_margin;
+               break;
+               case MODELINE_SET_LANGUAGE:
+               {
+                       GtkSourceLanguage *language = gtk_source_buffer_get_language (buffer);
+
+                       return (language == NULL && previous->language_id == NULL) ||
+                              (language != NULL && g_strcmp0 (gtk_source_language_get_id (language),
+                                                              previous->language_id) == 0);
+               }
+               break;
+               default:
+                       return FALSE;
+               break;
+       }
+}
+
+static void
+free_modeline_options (ModelineOptions *options)
+{
+       g_free (options->language_id);
+       g_slice_free (ModelineOptions, options);
+}
+
+void
+modeline_parser_apply_modeline (GtkSourceView *view)
+{
+       ModelineOptions options;
+       GtkTextBuffer *buffer;
+       GtkTextIter iter, liter;
+       gint line_count;
+       GSettings *settings;
+
+       options.language_id = NULL;
+       options.set = MODELINE_SET_NONE;
+
+       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+       gtk_text_buffer_get_start_iter (buffer, &iter);
+
+       line_count = gtk_text_buffer_get_line_count (buffer);
+
+       /* Parse the modelines on the 10 first lines... */
+       while ((gtk_text_iter_get_line (&iter) < 10) &&
+              !gtk_text_iter_is_end (&iter))
+       {
+               gchar *line;
+
+               liter = iter;
+               gtk_text_iter_forward_to_line_end (&iter);
+               line = gtk_text_buffer_get_text (buffer, &liter, &iter, TRUE);
+
+               parse_modeline (line,
+                               1 + gtk_text_iter_get_line (&iter),
+                               line_count,
+                               &options);
+
+               gtk_text_iter_forward_line (&iter);
+
+               g_free (line);
+       }
+
+       /* ...and on the 10 last ones (modelines are not allowed in between) */
+       if (!gtk_text_iter_is_end (&iter))
+       {
+               gint cur_line;
+               guint remaining_lines;
+
+               /* we are on the 11th line (count from 0) */
+               cur_line = gtk_text_iter_get_line (&iter);
+               /* g_assert (10 == cur_line); */
+
+               remaining_lines = line_count - cur_line - 1;
+
+               if (remaining_lines > 10)
+               {
+                       gtk_text_buffer_get_end_iter (buffer, &iter);
+                       gtk_text_iter_backward_lines (&iter, 9);
+               }
+       }
+
+       while (!gtk_text_iter_is_end (&iter))
+       {
+               gchar *line;
+
+               liter = iter;
+               gtk_text_iter_forward_to_line_end (&iter);
+               line = gtk_text_buffer_get_text (buffer, &liter, &iter, TRUE);
+
+               parse_modeline (line,
+                               1 + gtk_text_iter_get_line (&iter),
+                               line_count,
+                               &options);
+
+               gtk_text_iter_forward_line (&iter);
+
+               g_free (line);
+       }
+
+       /* Try to set language */
+       if (has_option (&options, MODELINE_SET_LANGUAGE) && options.language_id)
+       {
+               if (g_ascii_strcasecmp (options.language_id, "text") == 0)
+               {
+                       gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), NULL);
+               }
+               else
+               {
+                       GtkSourceLanguageManager *manager;
+                       GtkSourceLanguage *language;
+
+                       manager = gtk_source_language_manager_get_default ();
+
+                       language = gtk_source_language_manager_get_language
+                                       (manager, options.language_id);
+                       if (language != NULL)
+                       {
+                               gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), language);
+                       }
+                       else
+                       {
+                               gedit_debug_message (DEBUG_PLUGINS,
+                                                    "Unknown language `%s'",
+                                                    options.language_id);
+                       }
+               }
+       }
+
+       ModelineOptions *previous = g_object_get_data (G_OBJECT (buffer),
+                                                      MODELINE_OPTIONS_DATA_KEY);
+
+       settings = g_settings_new ("org.gnome.gedit.preferences.editor");
+
+       /* Apply the options we got from modelines and restore defaults if
+          we set them before */
+       if (has_option (&options, MODELINE_SET_INSERT_SPACES))
+       {
+               gtk_source_view_set_insert_spaces_instead_of_tabs
+                                                       (view, options.insert_spaces);
+       }
+       else if (check_previous (view, previous, MODELINE_SET_INSERT_SPACES))
+       {
+#if 0
+               gboolean insert_spaces;
+
+               insert_spaces = g_settings_get_boolean (settings, GEDIT_SETTINGS_INSERT_SPACES);
+
+               gtk_source_view_set_insert_spaces_instead_of_tabs (view, insert_spaces);
+#endif
+       }
+
+       if (has_option (&options, MODELINE_SET_TAB_WIDTH))
+       {
+               gtk_source_view_set_tab_width (view, options.tab_width);
+       }
+       else if (check_previous (view, previous, MODELINE_SET_TAB_WIDTH))
+       {
+#if 0
+               guint tab_width;
+
+               g_settings_get (settings, GEDIT_SETTINGS_TABS_SIZE, "u", &tab_width);
+
+               gtk_source_view_set_tab_width (view, tab_width);
+#endif
+       }
+
+       if (has_option (&options, MODELINE_SET_INDENT_WIDTH))
+       {
+               gtk_source_view_set_indent_width (view, options.indent_width);
+       }
+       else if (check_previous (view, previous, MODELINE_SET_INDENT_WIDTH))
+       {
+               gtk_source_view_set_indent_width (view, -1);
+       }
+
+       if (has_option (&options, MODELINE_SET_WRAP_MODE))
+       {
+               gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), options.wrap_mode);
+       }
+       else if (check_previous (view, previous, MODELINE_SET_WRAP_MODE))
+       {
+#if 0
+               GtkWrapMode mode;
+
+               mode = g_settings_get_enum (settings,
+                                           GEDIT_SETTINGS_WRAP_MODE);
+               gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), mode);
+#endif
+       }
+
+       if (has_option (&options, MODELINE_SET_RIGHT_MARGIN_POSITION))
+       {
+               gtk_source_view_set_right_margin_position (view, options.right_margin_position);
+       }
+       else if (check_previous (view, previous, MODELINE_SET_RIGHT_MARGIN_POSITION))
+       {
+#if 0
+               guint right_margin_pos;
+
+               g_settings_get (settings, GEDIT_SETTINGS_RIGHT_MARGIN_POSITION, "u",
+                               &right_margin_pos);
+               gtk_source_view_set_right_margin_position (view,
+                                                          right_margin_pos);
+#endif
+       }
+
+       if (has_option (&options, MODELINE_SET_SHOW_RIGHT_MARGIN))
+       {
+               gtk_source_view_set_show_right_margin (view, options.display_right_margin);
+       }
+       else if (check_previous (view, previous, MODELINE_SET_SHOW_RIGHT_MARGIN))
+       {
+#if 0
+               gboolean display_right_margin;
+
+               display_right_margin = g_settings_get_boolean (settings,
+                                                              GEDIT_SETTINGS_DISPLAY_RIGHT_MARGIN);
+               gtk_source_view_set_show_right_margin (view, display_right_margin);
+#endif
+       }
+
+       if (previous)
+       {
+               g_free (previous->language_id);
+               *previous = options;
+               previous->language_id = g_strdup (options.language_id);
+       }
+       else
+       {
+               previous = g_slice_new (ModelineOptions);
+               *previous = options;
+               previous->language_id = g_strdup (options.language_id);
+
+               g_object_set_data_full (G_OBJECT (buffer),
+                                       MODELINE_OPTIONS_DATA_KEY,
+                                       previous,
+                                       (GDestroyNotify)free_modeline_options);
+       }
+
+       g_object_unref (settings);
+       g_free (options.language_id);
+}
+
+/* vi:ts=8 */
diff --git a/libide/modelines/modeline-parser.h b/libide/modelines/modeline-parser.h
new file mode 100644
index 0000000..bb55e18
--- /dev/null
+++ b/libide/modelines/modeline-parser.h
@@ -0,0 +1,36 @@
+/*
+ * modelie-parser.h
+ * Emacs, Kate and Vim-style modelines support for gedit.
+ *
+ * Copyright (C) 2005-2007 - Steve Frécinaux <code istique net>
+ *
+ * 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 2, 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 __MODELINE_PARSER_H__
+#define __MODELINE_PARSER_H__
+
+#include <glib.h>
+#include <gtksourceview/gtksource.h>
+
+G_BEGIN_DECLS
+
+void   modeline_parser_init            (void);
+void   modeline_parser_shutdown        (void);
+void   modeline_parser_apply_modeline  (GtkSourceView *view);
+
+G_END_DECLS
+
+#endif /* __MODELINE_PARSER_H__ */
+/* ex:set ts=8 noet: */
diff --git a/libide/resources/libide.gresource.xml b/libide/resources/libide.gresource.xml
index ea33f8a..5b81ce5 100644
--- a/libide/resources/libide.gresource.xml
+++ b/libide/resources/libide.gresource.xml
@@ -13,6 +13,8 @@
     <file alias="snippets/vala.snippets">../../data/snippets/vala.snippets</file>
     <file alias="snippets/xml.snippets">../../data/snippets/xml.snippets</file>
 
+    <file alias="modelines/language-mappings">../modelines/language-mappings</file>
+
     <file alias="file-settings/defaults.ini">../../data/file-settings/defaults.ini</file>
 
     <file alias="keybindings/emacs.css">../../data/keybindings/emacs.css</file>


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