[gnome-builder] auto-indent: add a very minimal python indenter



commit 8eb03cbd50348943a0d12d7a94c2f3f6851a4253
Author: Christian Hergert <christian hergert me>
Date:   Tue Oct 21 17:27:38 2014 -0700

    auto-indent: add a very minimal python indenter

 src/auto-indent/gb-source-auto-indenter-python.c |  246 ++++++++++++++++++++++
 src/auto-indent/gb-source-auto-indenter-python.h |   56 +++++
 src/editor/gb-source-view.c                      |    3 +
 src/gnome-builder.mk                             |    2 +
 4 files changed, 307 insertions(+), 0 deletions(-)
---
diff --git a/src/auto-indent/gb-source-auto-indenter-python.c 
b/src/auto-indent/gb-source-auto-indenter-python.c
new file mode 100644
index 0000000..49ffd9b
--- /dev/null
+++ b/src/auto-indent/gb-source-auto-indenter-python.c
@@ -0,0 +1,246 @@
+/* gb-source-auto-indenter-python.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/>.
+ */
+
+#define G_LOG_DOMAIN "python-indent"
+
+#include "gb-log.h"
+#include "gb-source-auto-indenter-python.h"
+
+/*
+ * TODO:
+ *
+ * This module is very naive. It only checks for a line ending in : to
+ * indent. If you'd like to own this, go for it!
+ *
+ * I suggest adding something like auto indentation to a matching (
+ * for the case when () is used to extend to the next line.
+ */
+
+G_DEFINE_TYPE (GbSourceAutoIndenterPython,
+               gb_source_auto_indenter_python,
+               GB_TYPE_SOURCE_AUTO_INDENTER)
+
+GbSourceAutoIndenter *
+gb_source_auto_indenter_python_new (void)
+{
+  return g_object_new (GB_TYPE_SOURCE_AUTO_INDENTER_PYTHON, NULL);
+}
+
+static gboolean
+in_pydoc (const GtkTextIter *iter)
+{
+  /* TODO: implement this */
+  return FALSE;
+}
+
+static gchar *
+copy_indent (GbSourceAutoIndenterPython *python,
+             GtkTextIter                *begin,
+             GtkTextIter                *end,
+             GtkTextIter                *copy)
+{
+  GString *str;
+
+  str = g_string_new (NULL);
+
+  gtk_text_iter_set_line_offset (copy, 0);
+
+  while (!gtk_text_iter_ends_line (copy))
+    {
+      gunichar ch;
+
+      ch = gtk_text_iter_get_char (copy);
+
+      if (!g_unichar_isspace (ch))
+        break;
+
+      g_string_append_unichar (str, ch);
+
+      if (gtk_text_iter_ends_line (copy) ||
+          !gtk_text_iter_forward_char (copy))
+        break;
+    }
+
+  return g_string_free (str, FALSE);
+}
+
+static gchar *
+copy_indent_minus_tab (GbSourceAutoIndenterPython *python,
+                       GtkTextView                *view,
+                       GtkTextIter                *begin,
+                       GtkTextIter                *end,
+                       GtkTextIter                *copy)
+{
+  GString *str;
+  gchar *copied;
+  guint tab_width = 4;
+
+  copied = copy_indent (python, begin, end, copy);
+  str = g_string_new (copied);
+  g_free (copied);
+
+  if (GTK_SOURCE_IS_VIEW (view))
+    tab_width = gtk_source_view_get_tab_width (GTK_SOURCE_VIEW (view));
+
+  if (tab_width <= str->len)
+    g_string_truncate (str, str->len - tab_width);
+
+  return g_string_free (str, FALSE);
+}
+
+static gchar *
+indent_colon (GbSourceAutoIndenterPython *python,
+              GtkTextView                *view,
+              GtkTextIter                *begin,
+              GtkTextIter                *end,
+              GtkTextIter                *iter)
+{
+  GString *str;
+  gint indent_width = -1;
+  guint tab_width = 4;
+  guint i;
+  gchar *ret;
+
+  /* this is super naive. we don't even walk back to handle multi-line
+   * function parameter lists!
+   */
+
+  ret = copy_indent (python, begin, end, iter);
+  str = g_string_new (ret);
+  g_free (ret);
+  
+  /* force spaces for now, cause anything else is evil in python */
+
+  if (GTK_SOURCE_IS_VIEW (view))
+    indent_width = gtk_source_view_get_indent_width (GTK_SOURCE_VIEW (view));
+
+  if (indent_width == -1)
+    if (GTK_SOURCE_IS_VIEW (view))
+      tab_width = gtk_source_view_get_tab_width (GTK_SOURCE_VIEW (view));
+
+  for (i = 0; i < tab_width; i++)
+    g_string_append (str, " ");
+
+  return g_string_free (str, FALSE);
+}
+
+static gboolean
+is_return_line (const GtkTextIter *line)
+{
+  GtkTextIter iter = *line;
+  GtkTextIter end;
+  gchar *text;
+  gboolean ret;
+
+  gtk_text_iter_set_line_offset (&iter, 0);
+
+  while (!gtk_text_iter_ends_line (&iter))
+    {
+      gunichar ch;
+
+      ch = gtk_text_iter_get_char (&iter);
+      if (!g_unichar_isspace (ch))
+        {
+          if (ch != 'r')
+            return FALSE;
+          break;
+        }
+
+      if (!gtk_text_iter_forward_char (&iter))
+        return FALSE;
+    }
+
+  end = iter;
+
+  if (!gtk_text_iter_forward_chars (&end, 6))
+    return FALSE;
+
+  text = gtk_text_iter_get_slice (&iter, &end);
+  ret = (g_strcmp0 (text, "return") == 0);
+  g_free (text);
+
+  return ret;
+}
+
+static gchar *
+gb_source_auto_indenter_python_format (GbSourceAutoIndenter *indenter,
+                                       GtkTextView          *text_view,
+                                       GtkTextBuffer        *buffer,
+                                       GtkTextIter          *begin,
+                                       GtkTextIter          *end,
+                                       gint                 *cursor_offset,
+                                       GdkEventKey          *event)
+{
+  GbSourceAutoIndenterPython *python = (GbSourceAutoIndenterPython *)indenter;
+  GtkTextIter iter = *begin;
+  gunichar ch;
+
+  /* move to the last character of the last line */
+  if (!gtk_text_iter_backward_char (&iter) ||
+      !gtk_text_iter_backward_char (&iter))
+    return NULL;
+
+  /* get the last character */
+  ch = gtk_text_iter_get_char (&iter);
+
+  switch (ch)
+    {
+    case ':':
+      return indent_colon (python, text_view, begin, end, &iter);
+
+    default:
+      if (in_pydoc (&iter))
+        return copy_indent (python, begin, end, &iter);
+
+      if (is_return_line (&iter))
+        return copy_indent_minus_tab (python, text_view, begin, end, &iter);
+
+      return copy_indent (python, begin, end, &iter);
+    }
+
+  return NULL;
+}
+
+static gboolean
+gb_source_auto_indenter_python_is_trigger (GbSourceAutoIndenter *indenter,
+                                           GdkEventKey          *event)
+{
+  switch (event->keyval)
+    {
+    case GDK_KEY_KP_Enter:
+    case GDK_KEY_Return:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+}
+
+static void
+gb_source_auto_indenter_python_class_init (GbSourceAutoIndenterPythonClass *klass)
+{
+  GbSourceAutoIndenterClass *indent_class = GB_SOURCE_AUTO_INDENTER_CLASS (klass);
+
+  indent_class->is_trigger = gb_source_auto_indenter_python_is_trigger;
+  indent_class->format = gb_source_auto_indenter_python_format;
+}
+
+static void
+gb_source_auto_indenter_python_init (GbSourceAutoIndenterPython *self)
+{
+}
diff --git a/src/auto-indent/gb-source-auto-indenter-python.h 
b/src/auto-indent/gb-source-auto-indenter-python.h
new file mode 100644
index 0000000..c8a4200
--- /dev/null
+++ b/src/auto-indent/gb-source-auto-indenter-python.h
@@ -0,0 +1,56 @@
+/* gb-source-auto-indenter-python.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_SOURCE_AUTO_INDENTER_PYTHON_H
+#define GB_SOURCE_AUTO_INDENTER_PYTHON_H
+
+#include "gb-source-auto-indenter.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_SOURCE_AUTO_INDENTER_PYTHON            (gb_source_auto_indenter_python_get_type())
+#define GB_SOURCE_AUTO_INDENTER_PYTHON(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_SOURCE_AUTO_INDENTER_PYTHON, GbSourceAutoIndenterPython))
+#define GB_SOURCE_AUTO_INDENTER_PYTHON_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_SOURCE_AUTO_INDENTER_PYTHON, GbSourceAutoIndenterPython const))
+#define GB_SOURCE_AUTO_INDENTER_PYTHON_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  
GB_TYPE_SOURCE_AUTO_INDENTER_PYTHON, GbSourceAutoIndenterPythonClass))
+#define GB_IS_SOURCE_AUTO_INDENTER_PYTHON(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GB_TYPE_SOURCE_AUTO_INDENTER_PYTHON))
+#define GB_IS_SOURCE_AUTO_INDENTER_PYTHON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  
GB_TYPE_SOURCE_AUTO_INDENTER_PYTHON))
+#define GB_SOURCE_AUTO_INDENTER_PYTHON_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  
GB_TYPE_SOURCE_AUTO_INDENTER_PYTHON, GbSourceAutoIndenterPythonClass))
+
+typedef struct _GbSourceAutoIndenterPython        GbSourceAutoIndenterPython;
+typedef struct _GbSourceAutoIndenterPythonClass   GbSourceAutoIndenterPythonClass;
+typedef struct _GbSourceAutoIndenterPythonPrivate GbSourceAutoIndenterPythonPrivate;
+
+struct _GbSourceAutoIndenterPython
+{
+  GbSourceAutoIndenter parent;
+
+  /*< private >*/
+  GbSourceAutoIndenterPythonPrivate *priv;
+};
+
+struct _GbSourceAutoIndenterPythonClass
+{
+  GbSourceAutoIndenterClass parent;
+};
+
+GType                 gb_source_auto_indenter_python_get_type (void);
+GbSourceAutoIndenter *gb_source_auto_indenter_python_new      (void);
+
+G_END_DECLS
+
+#endif /* GB_SOURCE_AUTO_INDENTER_PYTHON_H */
diff --git a/src/editor/gb-source-view.c b/src/editor/gb-source-view.c
index 99c1b4b..13849c9 100644
--- a/src/editor/gb-source-view.c
+++ b/src/editor/gb-source-view.c
@@ -24,6 +24,7 @@
 #include "gb-animation.h"
 #include "gb-source-auto-indenter.h"
 #include "gb-source-auto-indenter-c.h"
+#include "gb-source-auto-indenter-python.h"
 #include "gb-source-auto-indenter-xml.h"
 #include "gb-box-theatric.h"
 #include "gb-cairo.h"
@@ -890,6 +891,8 @@ on_language_set (GtkSourceBuffer *buffer,
 
       if (g_str_equal (lang_id, "c") || g_str_equal (lang_id, "chdr"))
         auto_indenter = gb_source_auto_indenter_c_new ();
+      else if (g_str_equal (lang_id, "python"))
+        auto_indenter = gb_source_auto_indenter_python_new ();
       else if (g_str_equal (lang_id, "xml"))
         auto_indenter = gb_source_auto_indenter_xml_new ();
     }
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index c14c415..eb2b730 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -13,6 +13,8 @@ libgnome_builder_la_SOURCES = \
        src/auto-indent/gb-source-auto-indenter.h \
        src/auto-indent/gb-source-auto-indenter-c.c \
        src/auto-indent/gb-source-auto-indenter-c.h \
+       src/auto-indent/gb-source-auto-indenter-python.c \
+       src/auto-indent/gb-source-auto-indenter-python.h \
        src/auto-indent/gb-source-auto-indenter-xml.c \
        src/auto-indent/gb-source-auto-indenter-xml.h \
        src/commands/gb-command.c \


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