gtksourceview r2190 - in branches/indenters: . gtksourceview tests



Author: icq
Date: Sat Feb 28 17:01:13 2009
New Revision: 2190
URL: http://svn.gnome.org/viewvc/gtksourceview?rev=2190&view=rev

Log:
2009-02-28  Ignacio Casal Quinteiro  <nacho resa gmail com>

        * gtksourceview/gtksourcelanguage.c:
        * gtksourceview/gtksourcelanguage.h:
        * gtksourceview/c-indenter.c:
        * gtksourceview/gtksourceindentermanager.c:
        * gtksourceview/c-indenter.h:
        * gtksourceview/gtksourceindenter-utils.c:
        * gtksourceview/simple-indenter.c:
        * gtksourceview/gtksourceview-utils.c:
        * gtksourceview/gtksourceindentermanager.h:
        * gtksourceview/gtksourceindenter.c:
        * gtksourceview/gtksourceview.c:
        * gtksourceview/gtksourceindenter-utils.h:
        * gtksourceview/gtksourceview-utils.h:
        * gtksourceview/simple-indenter.h:
        * gtksourceview/gtksourceindenter.h:
        * gtksourceview/gtksourceview.h:
        * gtksourceview/Makefile.am:
        * tests/test-widget.c:
        Added initial framework files.
        Added a simple indenter that makes the same functionaly
        that gsv had before, and added the c-indenter that tries
        to be an smart indenter for c files.



Added:
   branches/indenters/gtksourceview/c-indenter.c   (contents, props changed)
   branches/indenters/gtksourceview/c-indenter.h   (contents, props changed)
   branches/indenters/gtksourceview/gtksourceindenter-utils.c   (contents, props changed)
   branches/indenters/gtksourceview/gtksourceindenter-utils.h   (contents, props changed)
   branches/indenters/gtksourceview/gtksourceindenter.c   (contents, props changed)
   branches/indenters/gtksourceview/gtksourceindenter.h   (contents, props changed)
   branches/indenters/gtksourceview/gtksourceindentermanager.c   (contents, props changed)
   branches/indenters/gtksourceview/gtksourceindentermanager.h   (contents, props changed)
   branches/indenters/gtksourceview/simple-indenter.c   (contents, props changed)
   branches/indenters/gtksourceview/simple-indenter.h   (contents, props changed)
Modified:
   branches/indenters/ChangeLog
   branches/indenters/gtksourceview/Makefile.am
   branches/indenters/gtksourceview/gtksourcelanguage.c
   branches/indenters/gtksourceview/gtksourcelanguage.h
   branches/indenters/gtksourceview/gtksourceview-utils.c
   branches/indenters/gtksourceview/gtksourceview-utils.h
   branches/indenters/gtksourceview/gtksourceview.c
   branches/indenters/gtksourceview/gtksourceview.h
   branches/indenters/tests/test-widget.c

Modified: branches/indenters/gtksourceview/Makefile.am
==============================================================================
--- branches/indenters/gtksourceview/Makefile.am	(original)
+++ branches/indenters/gtksourceview/Makefile.am	Sat Feb 28 17:01:13 2009
@@ -27,7 +27,8 @@
 	gtksourcestyleschememanager.h		\
 	gtksourcestylescheme.h			\
 	gtksourcemark.h				\
-	gtksourceprintcompositor.h
+	gtksourceprintcompositor.h		\
+	gtksourceindenter.h
 
 libgtksourceview_2_0_la_SOURCES = 	\
 	gtksourcebuffer.c 		\
@@ -56,6 +57,15 @@
 	gtksourcecontextengine.c	\
 	gtksourcemark.c			\
 	gtksourceprintcompositor.c      \
+	gtksourceindenter.c		\
+	gtksourceindentermanager.c	\
+	gtksourceindentermanager.h	\
+	c-indenter.c			\
+	c-indenter.h			\
+	simple-indenter.c		\
+	simple-indenter.h		\
+	gtksourceindenter-utils.c	\
+	gtksourceindenter-utils.h	\
 	$(libgtksourceview_headers)
 
 # do not distribute generated files

Added: branches/indenters/gtksourceview/c-indenter.c
==============================================================================
--- (empty file)
+++ branches/indenters/gtksourceview/c-indenter.c	Sat Feb 28 17:01:13 2009
@@ -0,0 +1,371 @@
+/*
+ * c-indenter.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2009 - Ignacio Casal Quinteiro
+ *
+ * gedit 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 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "c-indenter.h"
+#include "gtksourceindenter.h"
+#include "gtksourceview.h"
+#include "gtksourceindenter-utils.h"
+
+#define C_INDENTER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object),\
+				       C_TYPE_INDENTER, CIndenterPrivate))
+
+struct _CIndenterPrivate
+{
+};
+
+G_DEFINE_TYPE (CIndenter, c_indenter, GTK_TYPE_SOURCE_INDENTER)
+
+static const gchar * regexes[] =
+{
+	"^\\s*(if|while|else if|for|switch)\\s*\\(.*\\)\\s*$",
+	"^\\s*(else|do)\\s*$",
+	NULL
+};
+
+static gboolean
+match_regexes (GtkTextIter *iter)
+{
+	gint i = 0;
+	gboolean match = FALSE;
+	gchar *string;
+	GtkTextIter start;
+	
+	start = *iter;
+	
+	gtk_source_indenter_find_open_char (&start, '(', ')', FALSE);
+	
+	gtk_text_iter_set_line_offset (&start, 0);
+	gtk_text_iter_forward_char (iter);
+	
+	string = gtk_text_iter_get_text (&start, iter);
+	gtk_text_iter_backward_char (iter);
+	g_warning (string);
+	
+	while (regexes[i] != NULL)
+	{
+		GRegex *regex;
+		GMatchInfo *match_info;
+		
+		regex = g_regex_new (regexes[i], G_REGEX_DOTALL, 0, NULL);
+		g_regex_match (regex, string, 0, &match_info);
+		
+		if (g_match_info_matches (match_info))
+			match = TRUE;
+		
+		g_match_info_free (match_info);
+		g_regex_unref (regex);
+		
+		if (match)
+		{
+			break;
+		}
+		i++;
+	}
+	
+	g_free (string);
+	
+	return match;
+}
+
+static gboolean
+is_caselabel (const gchar *label)
+{
+	const gchar *case_label = "case";
+	gchar *p;
+	gunichar c;
+	gint i = 0;
+	gboolean is_case = TRUE;
+	
+	p = (gchar *)label;
+	c = g_utf8_get_char (p);
+	
+	while (case_label[i] != '\0')
+	{
+		g_warning ("%c|%c", c, case_label[i]);
+		
+		if (case_label[i] != c)
+		{
+			is_case = FALSE;
+			break;
+		}
+		
+		p = g_utf8_next_char (p);
+		c = g_utf8_get_char (p);
+		i++;
+	}
+	
+	return is_case;
+}
+
+static gfloat
+c_indenter_get_indentation_level (GtkSourceIndenter *indenter,
+				  GtkTextView *view,
+				  GtkTextIter *cur,
+				  gboolean relocating)
+{
+	/*
+	 * The idea of this algorithm is just move the iter to the right position
+	 * and manage the iter to get a context to get the right amount of indents
+	 */
+	GtkTextIter iter;
+	gunichar c;
+	gfloat amount = 0.;
+	
+	iter = *cur;
+	
+	if (!gtk_source_indenter_move_to_no_space (&iter, -1))
+		return 0.;
+
+	/*
+	 * Check for comments
+	 */
+	if (!gtk_source_indenter_move_to_no_comments (&iter))
+		return 0.;
+
+	c = gtk_text_iter_get_char (&iter);
+	g_warning ("char %c", c);
+	
+	if (c == '*')
+	{
+		gunichar ch;
+		
+		/*
+		 * We are in a comment
+		 */
+		amount = gtk_source_indenter_get_amount_indents (view,
+								 &iter);
+		
+		/* We are in the case "/ *" so we have to add an space */
+		gtk_text_iter_backward_char (&iter);
+		ch = gtk_text_iter_get_char (&iter);
+		
+		if (ch == '/')
+		{
+			amount = gtk_source_indenter_add_space (view, amount);
+		}
+	}
+	else if (c == ';')
+	{
+		gfloat current_indent;
+		
+		current_indent = gtk_source_indenter_get_amount_indents (view,
+									 &iter);
+
+		/*
+		 * We have to check that we are not in something like:
+		 * hello (eoeo,
+		 *        eoeo);
+		 */
+		gtk_text_iter_backward_char (&iter);
+		c = gtk_text_iter_get_char (&iter);
+		if (c == ')' && gtk_source_indenter_find_open_char (&iter, '(', ')', FALSE))
+		{
+			amount = gtk_source_indenter_get_amount_indents (view,
+									 &iter);
+		}
+		else
+		{
+			/*
+			 * We have to check if we are in just one line block
+			 */
+			while (!gtk_text_iter_ends_line (&iter) &&
+			       gtk_text_iter_backward_char (&iter))
+				continue;
+			
+			gtk_text_iter_backward_char (&iter);
+			
+			if (match_regexes (&iter))
+			{
+				gtk_source_indenter_find_open_char (&iter, '(', ')', FALSE);
+				
+				amount = gtk_source_indenter_get_amount_indents (view,
+										 &iter);
+			}
+			else
+			{
+				amount = current_indent;
+			}
+		}
+	}
+	else if (c == '}')
+	{
+		amount = gtk_source_indenter_get_amount_indents (view,
+								 &iter);
+		
+		/*
+		 * We need to look backward for {.
+		 * FIXME: We need to set a number of lines to look backward.
+		 */
+		if (relocating && gtk_source_indenter_find_open_char (&iter, '{', '}', FALSE))
+		{
+			amount = gtk_source_indenter_get_amount_indents (view,
+									 &iter);
+		}
+	}
+	else if (c == '{')
+	{
+		amount = gtk_source_indenter_get_amount_indents (view,
+								 &iter);
+		
+		/*
+		 * Check that the previous line match regexes
+		 */
+		while (gtk_text_iter_backward_char (&iter) &&
+		       !gtk_text_iter_ends_line (&iter))
+			continue;
+		
+		gtk_text_iter_backward_char (&iter);
+		
+		if (relocating)
+		{
+			if (match_regexes (&iter))
+			{
+				gtk_source_indenter_find_open_char (&iter, '(', ')', FALSE);
+			
+				amount = gtk_source_indenter_get_amount_indents (view,
+										 &iter);
+			}
+		}
+		else
+		{
+			amount++;
+		}
+	}
+	else if (c == ',' || c == '&' || c == '|')
+	{
+		GtkTextIter s;
+		
+		amount = gtk_source_indenter_get_amount_indents (view,
+								 &iter);
+		
+		s = iter;
+		if (gtk_source_indenter_find_open_char (&s, '(', ')', TRUE))
+		{
+			amount = gtk_source_indenter_get_amount_indents_from_position (view, &s);
+			amount = gtk_source_indenter_add_space (view, amount);
+		}
+	}
+	else if (c == ')' && relocating)
+	{
+		amount = gtk_source_indenter_get_amount_indents (view,
+								 &iter);
+		
+		if (gtk_source_indenter_find_open_char (&iter, '(', ')', FALSE))
+		{
+			amount = gtk_source_indenter_get_amount_indents_from_position (view, &iter);
+		}
+	}
+	else if (c == ':')
+	{
+		if (relocating)
+		{
+			GtkTextIter start;
+			gchar *label;
+			
+			start = iter;
+			gtk_text_iter_set_line_offset (&start, 0);
+			gtk_source_indenter_move_to_no_space (&start, 1);
+			
+			label = gtk_text_iter_get_text (&start, &iter);
+			
+			if (!is_caselabel (label))
+			{
+				amount = 0.;
+			}
+			else
+			{
+				amount = gtk_source_indenter_get_amount_indents (view, &iter);
+			}
+			
+			g_free (label);
+		}
+		else
+		{
+			amount = 1.;
+		}
+	}
+	else if (c == '=')
+	{
+		amount = gtk_source_indenter_get_amount_indents (view, &iter) + 1;
+	}
+	else if (match_regexes (&iter))
+	{
+		gtk_source_indenter_find_open_char (&iter, '(', ')', FALSE);
+		
+		amount = gtk_source_indenter_get_amount_indents (view,
+								 &iter) + 1;
+	}
+	else
+	{
+		GtkTextIter copy;
+		gunichar ch;
+		
+		amount = gtk_source_indenter_get_amount_indents (view, &iter);
+		
+		/*
+		 * Now we have to check for the start of the line
+		 */
+		copy = iter;
+		
+		gtk_source_indenter_move_to_no_space (&copy, 1);
+		ch = gtk_text_iter_get_char (&copy);
+		
+		/* # is always indent 0. Example: #ifdef */
+		if (relocating && ch == '#')
+		{
+			amount = 0;
+		}
+	}
+	
+	return amount;
+}
+
+static void
+c_indenter_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (c_indenter_parent_class)->finalize (object);
+}
+
+static void
+c_indenter_class_init (CIndenterClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtkSourceIndenterClass *indenter_class = GTK_SOURCE_INDENTER_CLASS (klass);
+	
+	object_class->finalize = c_indenter_finalize;
+	
+	indenter_class->get_indentation_level = c_indenter_get_indentation_level;
+
+	//g_type_class_add_private (object_class, sizeof (CIndenterPrivate));
+}
+
+static void
+c_indenter_init (CIndenter *self)
+{
+	//self->priv = C_INDENTER_GET_PRIVATE (self);
+}
+
+CIndenter *
+c_indenter_new ()
+{
+	return g_object_new (C_TYPE_INDENTER, NULL);
+}

Added: branches/indenters/gtksourceview/c-indenter.h
==============================================================================
--- (empty file)
+++ branches/indenters/gtksourceview/c-indenter.h	Sat Feb 28 17:01:13 2009
@@ -0,0 +1,61 @@
+/*
+ * c-indenter.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2009 - Ignacio Casal Quinteiro
+ *
+ * gedit 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 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __C_INDENTER_H__
+#define __C_INDENTER_H__
+
+#include <glib-object.h>
+#include "gtksourceindenter.h"
+
+G_BEGIN_DECLS
+
+#define C_TYPE_INDENTER			(c_indenter_get_type ())
+#define C_INDENTER(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), C_TYPE_INDENTER, CIndenter))
+#define C_INDENTER_CONST(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), C_TYPE_INDENTER, CIndenter const))
+#define C_INDENTER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST ((klass), C_TYPE_INDENTER, CIndenterClass))
+#define C_IS_INDENTER(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), C_TYPE_INDENTER))
+#define C_IS_INDENTER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), C_TYPE_INDENTER))
+#define C_INDENTER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), C_TYPE_INDENTER, CIndenterClass))
+
+typedef struct _CIndenter		CIndenter;
+typedef struct _CIndenterClass		CIndenterClass;
+typedef struct _CIndenterPrivate	CIndenterPrivate;
+
+struct _CIndenter
+{
+	GtkSourceIndenter parent;
+	
+	CIndenterPrivate *priv;
+};
+
+struct _CIndenterClass
+{
+	GtkSourceIndenterClass parent_class;
+};
+
+GType c_indenter_get_type (void) G_GNUC_CONST;
+CIndenter *c_indenter_new (void);
+
+
+G_END_DECLS
+
+#endif /* __C_INDENTER_H__ */

Added: branches/indenters/gtksourceview/gtksourceindenter-utils.c
==============================================================================
--- (empty file)
+++ branches/indenters/gtksourceview/gtksourceindenter-utils.c	Sat Feb 28 17:01:13 2009
@@ -0,0 +1,272 @@
+/*
+ * gtksourceindenter-utils.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2009 - Ignacio Casal Quinteiro
+ *
+ * gedit 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 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gtksourceindenter-utils.h"
+#include "gtksourceview-utils.h"
+#include "gtksourceview.h"
+
+
+gfloat
+gtk_source_indenter_get_amount_indents (GtkTextView *view,
+					GtkTextIter *cur)
+{
+	gint indent_width;
+	GtkTextIter start;
+	gunichar c;
+	gint amount = 0;
+	gint rest = 0;
+	
+	start = *cur;
+	gtk_text_iter_set_line_offset (&start, 0);
+	
+	c = gtk_text_iter_get_char (&start);
+	if (!g_unichar_isspace (c))
+		return 0;
+	
+	indent_width = _gtk_source_view_get_real_indent_width (GTK_SOURCE_VIEW (view));
+	
+	while (g_unichar_isspace (c) &&
+	       c != '\n' &&
+	       c != '\r' &&
+	       gtk_text_iter_compare (&start, cur) < 0)
+	{
+		if (c == '\t')
+		{
+			if (rest != 0)
+				rest = 0;
+			amount++;
+		}
+		else
+		{
+			rest++;
+		}
+		
+		if (rest == indent_width)
+		{
+			amount++;
+			rest = 0;
+		}
+		
+		if (!gtk_text_iter_forward_char (&start))
+			break;
+		
+		c = gtk_text_iter_get_char (&start);
+	}
+
+	return (gfloat)amount + (gfloat)(0.1 * rest);
+}
+
+gfloat
+gtk_source_indenter_get_amount_indents_from_position (GtkTextView *view,
+						      GtkTextIter *cur)
+{
+	gint indent_width;
+	GtkTextIter start;
+	gunichar c;
+	gint amount = 0;
+	gint rest = 0;
+	
+	indent_width = _gtk_source_view_get_real_indent_width (GTK_SOURCE_VIEW (view));
+	
+	start = *cur;
+	gtk_text_iter_set_line_offset (&start, 0);
+	
+	c = gtk_text_iter_get_char (&start);
+	
+	while (gtk_text_iter_compare (&start, cur) < 0)
+	{
+		if (c == '\t')
+		{
+			if (rest != 0)
+				rest = 0;
+			amount++;
+		}
+		else
+		{
+			rest++;
+		}
+		
+		if (rest == indent_width)
+		{
+			amount++;
+			rest = 0;
+		}
+		
+		if (!gtk_text_iter_forward_char (&start))
+			break;
+		
+		c = gtk_text_iter_get_char (&start);
+	}
+	
+	return (gfloat)amount + (gfloat)(0.1 * rest);
+}
+
+gboolean
+gtk_source_indenter_move_to_no_space (GtkTextIter *iter,
+				      gint direction)
+{
+	gunichar c;
+	gboolean moved = TRUE;
+	
+	c = gtk_text_iter_get_char (iter);
+	
+	while (g_unichar_isspace (c))
+	{
+		if (!gtk_text_iter_forward_chars (iter, direction))
+		{
+			moved = FALSE;
+			break;
+		}
+		c = gtk_text_iter_get_char (iter);
+	}
+	
+	return moved;
+}
+
+gboolean
+gtk_source_indenter_move_to_no_comments (GtkTextIter *iter)
+{
+	gunichar c;
+	
+	c = gtk_text_iter_get_char (iter);
+	
+	if (c == '/' && gtk_text_iter_backward_char (iter))
+	{
+		c = gtk_text_iter_get_char (iter);
+		
+		if (c == '*')
+		{
+			/*
+			 * We look backward for '*' '/'
+			 */
+			for (;;)
+			{
+				if (!gtk_text_iter_backward_char (iter))
+					return FALSE;
+				c = gtk_text_iter_get_char (iter);
+				
+				if (c == '*')
+				{
+					if (!gtk_text_iter_backward_char (iter))
+						return FALSE;
+					c = gtk_text_iter_get_char (iter);
+					
+					if (c == '/')
+					{
+						/*
+						 * We reached to the beggining of the comment,
+						 * now we have to look backward for non spaces
+						 */
+						if (!gtk_text_iter_backward_char (iter))
+							return FALSE;
+						c = gtk_text_iter_get_char (iter);
+						
+						while (g_unichar_isspace (c) && gtk_text_iter_backward_char (iter))
+						{
+							c = gtk_text_iter_get_char (iter);
+						}
+						
+						break;
+					}
+				}
+			}
+		}
+	}
+	
+	return TRUE;
+}
+
+gboolean
+gtk_source_indenter_find_open_char (GtkTextIter *iter,
+				    gchar open,
+				    gchar close,
+				    gboolean skip_first)
+{
+	GtkTextIter copy;
+	gunichar c;
+	gboolean moved = FALSE;
+	gint counter = 0;
+	
+	copy = *iter;
+	
+	/*
+	 * FIXME: We have to take care of number of lines to go back
+	 */
+	c = gtk_text_iter_get_char (&copy);
+	do
+	{
+		/*
+		 * This algorithm has to work even if we have if (xxx, xx(),
+		 */
+		if (c == close || skip_first)
+		{
+			counter--;
+			skip_first = FALSE;
+		}
+		
+		if (c == open && counter != 0)
+		{
+			counter++;
+		}
+		
+		if (counter == 0)
+		{
+			*iter = copy;
+			moved = TRUE;
+			break;
+		}
+	}
+	while (gtk_text_iter_backward_char (&copy) &&
+	       (c = gtk_text_iter_get_char (&copy)));
+	
+	return moved;
+}
+
+gfloat
+gtk_source_indenter_add_space (GtkTextView *view,
+			       gfloat current_level)
+{
+	gint indent_width;
+	gint spaces;
+	gint tabs;
+	
+	indent_width = _gtk_source_view_get_real_indent_width (GTK_SOURCE_VIEW (view));
+	tabs = (gint)current_level;
+	spaces = round (10 * (gfloat)(current_level - tabs));
+	
+	/*
+	 * We add the new space
+	 */
+	spaces++;
+	
+	if (spaces == indent_width)
+	{
+		spaces = 0;
+		tabs++;
+	}
+	
+	return (gfloat)tabs + (gfloat)(0.1 * spaces);
+}

Added: branches/indenters/gtksourceview/gtksourceindenter-utils.h
==============================================================================
--- (empty file)
+++ branches/indenters/gtksourceview/gtksourceindenter-utils.h	Sat Feb 28 17:01:13 2009
@@ -0,0 +1,53 @@
+/*
+ * gtksourceindenter-utils.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2009 - Ignacio Casal Quinteiro
+ *
+ * gedit 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 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GTK_SOURCE_VIEW_UTILS_H__
+#define __GTK_SOURCE_VIEW_UTILS_H__
+
+#include <glib.h>
+#include "gtksourceview.h"
+
+G_BEGIN_DECLS
+
+gfloat		 gtk_source_indenter_get_amount_indents		(GtkTextView *view,
+								 GtkTextIter *cur);
+
+gfloat		 gtk_source_indenter_get_amount_indents_from_position
+								(GtkTextView *view,
+								 GtkTextIter *cur);
+
+gboolean	 gtk_source_indenter_move_to_no_space		(GtkTextIter *iter,
+								 gint direction);
+
+gboolean	 gtk_source_indenter_move_to_no_comments	(GtkTextIter *iter);
+
+gboolean	 gtk_source_indenter_find_open_char		(GtkTextIter *iter,
+								 gchar open,
+								 gchar close,
+								 gboolean skip_first);
+
+gfloat		 gtk_source_indenter_add_space			(GtkTextView *view,
+								 gfloat current_level);
+
+G_END_DECLS
+
+#endif

Added: branches/indenters/gtksourceview/gtksourceindenter.c
==============================================================================
--- (empty file)
+++ branches/indenters/gtksourceview/gtksourceindenter.c	Sat Feb 28 17:01:13 2009
@@ -0,0 +1,159 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ *  gtksourceindenter.c
+ *
+ *  Copyright (C) 2009 - Ignacio Casal Quinteiro <icq gnome org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Library General Public License as published by
+ *  the Free Software Foundation; either version 2 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 Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "gtksourceindenter.h"
+#include "gtksourceview.h"
+#include "gtksourceview-utils.h"
+
+
+G_DEFINE_TYPE(GtkSourceIndenter, gtk_source_indenter, G_TYPE_OBJECT)
+
+static const gchar * relocatables[] =
+{
+	"0{",
+	"0}",
+	"0)",
+	"0#",
+	":",
+	NULL
+};
+
+static const gchar * extra_indent_words[] =
+{
+	"if",
+	"else",
+	"while",
+	"do",
+	"for",
+	"switch",
+	NULL
+};
+
+/* Default implementation */
+static const gchar * const *
+gtk_source_indenter_get_relocatables_default (GtkSourceIndenter *self)
+{
+	return relocatables;
+}
+
+/* Default implementation */
+static const gchar * const *
+gtk_source_indenter_get_extra_indent_words_default (GtkSourceIndenter *self)
+{
+	return extra_indent_words;
+}
+
+/* Default implementation */
+static gfloat
+gtk_source_indenter_get_indentation_level_default (GtkSourceIndenter *self,
+						   GtkTextView       *view,
+						   GtkTextIter       *iter,
+						   gboolean           relocating)
+{
+	g_return_val_if_reached (0);
+}
+
+static void
+gtk_source_indenter_finalize (GObject *object)
+{
+	/* Empty */
+}
+
+static void 
+gtk_source_indenter_class_init (GtkSourceIndenterClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	klass->get_relocatables = gtk_source_indenter_get_relocatables_default;
+	klass->get_extra_indent_words = gtk_source_indenter_get_extra_indent_words_default;
+	klass->get_indentation_level = gtk_source_indenter_get_indentation_level_default;
+
+	object_class->finalize = gtk_source_indenter_finalize;
+}
+
+static void 
+gtk_source_indenter_init (GtkSourceIndenter *self)
+{
+	/* Empty */
+}
+
+/**
+ * gtk_source_indenter_get_indentation_level:
+ * @self: a #GtkSourceIndenter
+ * @view: a #GtkTextView
+ * @iter: a #GtkTextIter
+ *
+ * Gets the indentation level for a line determined by @iter.
+ * This func is expensive so it must be called only when it is neccessary,
+ * for example when is tiped a trigger, or when the user moves to a determined
+ * line.
+ * Always this func is called the indenter is going to search for a context
+ * to know the indentation level.
+ *
+ * Returns: the indentation level for a line determined by @iter.
+ */
+gfloat
+gtk_source_indenter_get_indentation_level (GtkSourceIndenter *self,
+					   GtkTextView       *view,
+					   GtkTextIter       *iter,
+					   gboolean           relocating)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_INDENTER (self), 0);
+	
+	return GTK_SOURCE_INDENTER_GET_CLASS (self)->get_indentation_level (self, view, iter, relocating);
+}
+
+/**
+ * gtk_source_indenter_get_extra_indent_words:
+ * @self: a #GtkSourceIndenter
+ *
+ * Gets the words that start an extra indent in the next line.
+ * This will not change the indentation level.
+ *
+ * Returns: the words that start an extra indent in the next line.
+ */
+const gchar * const *
+gtk_source_indenter_get_extra_indent_words (GtkSourceIndenter *self)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_INDENTER (self), NULL);
+	
+	return GTK_SOURCE_INDENTER_GET_CLASS (self)->get_extra_indent_words (self);
+}
+
+/**
+ * gtk_source_indenter_get_relocatables:
+ * @self: a #GtkSourceIndenter
+ *
+ * Gets the words that should be relocated on indentation. For example: {,}...
+ * This will trigger a gtk_source_indenter_get_indentation_level() to know
+ * where must be relocated.
+ * This is going to be detected only when a extra indent is added,
+ * see gtk_source_indenter_get_extra_indent_words(), and in case you add a \t
+ * or a \n the detection is finished.
+ *
+ * Returns: the words that should be relocated on indentation.
+ */
+const gchar * const *
+gtk_source_indenter_get_relocatables (GtkSourceIndenter *self)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_INDENTER (self), NULL);
+	
+	return GTK_SOURCE_INDENTER_GET_CLASS (self)->get_relocatables (self);
+}

Added: branches/indenters/gtksourceview/gtksourceindenter.h
==============================================================================
--- (empty file)
+++ branches/indenters/gtksourceview/gtksourceindenter.h	Sat Feb 28 17:01:13 2009
@@ -0,0 +1,92 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ *  gtksourceindenter.h
+ *
+ *  Copyright (C) 2009 - Ignacio Casal Quinteiro <icq gnome org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Library General Public License as published by
+ *  the Free Software Foundation; either version 2 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 Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_SOURCE_INDENTER_H__
+#define __GTK_SOURCE_INDENTER_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define GTK_TYPE_SOURCE_INDENTER              (gtk_source_indenter_get_type())
+#define GTK_SOURCE_INDENTER(obj)              (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_SOURCE_INDENTER, GtkSourceIndenter))
+#define GTK_SOURCE_INDENTER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_SOURCE_INDENTER, GtkSourceIndenterClass))
+#define GTK_IS_SOURCE_INDENTER(obj)           (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_SOURCE_INDENTER))
+#define GTK_IS_SOURCE_INDENTER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_INDENTER))
+#define GTK_SOURCE_INDENTER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_SOURCE_INDENTER, GtkSourceIndenterClass))
+
+typedef struct _GtkSourceIndenter GtkSourceIndenter;
+
+struct _GtkSourceIndenter
+{
+	GObject parent;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _GtkSourceIndenterClass GtkSourceIndenterClass;
+
+struct _GtkSourceIndenterClass
+{
+	GObjectClass parent_class;
+	
+	const gchar * const * (*get_relocatables)         (GtkSourceIndenter *self);
+	
+	const gchar * const * (*get_extra_indent_words)   (GtkSourceIndenter *self);
+	
+	gfloat		      (*get_indentation_level)    (GtkSourceIndenter *self,
+							   GtkTextView       *view,
+							   GtkTextIter       *iter,
+							   gboolean           relocating);
+};
+
+GType		 gtk_source_indenter_get_type		(void);
+
+const gchar * const *
+		 gtk_source_indenter_get_relocatables	(GtkSourceIndenter *self);
+
+const gchar * const *
+		 gtk_source_indenter_get_extra_indent_words
+		 					(GtkSourceIndenter *self);
+
+gfloat		 gtk_source_indenter_get_indentation_level
+							(GtkSourceIndenter *self,
+							 GtkTextView       *buf,
+							 GtkTextIter       *iter,
+							 gboolean           relocating);
+
+gfloat		 gtk_source_indenter_get_amount_indents (GtkTextView *view,
+							 GtkTextIter *cur);
+
+gfloat		 gtk_source_indenter_get_amount_indents_from_position
+							(GtkTextView *view,
+							 GtkTextIter *cur);
+
+G_END_DECLS
+
+#endif
+

Added: branches/indenters/gtksourceview/gtksourceindentermanager.c
==============================================================================
--- (empty file)
+++ branches/indenters/gtksourceview/gtksourceindentermanager.c	Sat Feb 28 17:01:13 2009
@@ -0,0 +1,85 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ *  gtksourceindentermanager.c
+ *
+ *  Copyright (C) 2009 - Ignacio Casal Quinteiro <icq gnome org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Library General Public License as published by
+ *  the Free Software Foundation; either version 2 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 Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "gtksourceindentermanager.h"
+#include "c-indenter.h"
+#include "simple-indenter.h"
+
+
+#define GTK_SOURCE_INDENTER_MANAGER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GTK_TYPE_SOURCE_INDENTER_MANAGER, GtkSourceIndenterManagerPrivate))
+
+struct _GtkSourceIndenterManagerPrivate
+{
+};
+
+G_DEFINE_TYPE (GtkSourceIndenterManager, gtk_source_indenter_manager, G_TYPE_OBJECT)
+
+static void
+gtk_source_indenter_manager_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (gtk_source_indenter_manager_parent_class)->finalize (object);
+}
+
+static void
+gtk_source_indenter_manager_class_init (GtkSourceIndenterManagerClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	
+	object_class->finalize = gtk_source_indenter_manager_finalize;
+
+	//g_type_class_add_private (object_class, sizeof(GtkSourceIndenterManagerPrivate));
+}
+
+static void
+gtk_source_indenter_manager_init (GtkSourceIndenterManager *self)
+{
+	//self->priv = GTK_SOURCE_INDENTER_MANAGER_GET_PRIVATE (self);
+}
+
+GtkSourceIndenterManager *
+gtk_source_indenter_manager_get_default ()
+{
+	static GtkSourceIndenterManager *manager = NULL;
+
+	if (manager == NULL)
+	{
+		manager = g_object_new (GTK_TYPE_SOURCE_INDENTER_MANAGER, NULL);
+	}
+
+	return manager;
+}
+
+GtkSourceIndenter *
+gtk_source_indenter_manager_get_indenter_by_id (GtkSourceIndenterManager *manager,
+						const gchar *id)
+{
+	GtkSourceIndenter *indenter;
+
+	if (id != NULL && strcmp (id, "c") == 0)
+	{
+		indenter = GTK_SOURCE_INDENTER (c_indenter_new ());
+	}
+	else
+	{
+		indenter = GTK_SOURCE_INDENTER (simple_indenter_new ());
+	}
+
+	return indenter;
+}

Added: branches/indenters/gtksourceview/gtksourceindentermanager.h
==============================================================================
--- (empty file)
+++ branches/indenters/gtksourceview/gtksourceindentermanager.h	Sat Feb 28 17:01:13 2009
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ *  gtksourceindentermanager.h
+ *
+ *  Copyright (C) 2009 - Ignacio Casal Quinteiro <icq gnome org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Library General Public License as published by
+ *  the Free Software Foundation; either version 2 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 Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_SOURCE_INDENTER_MANAGER_H__
+#define __GTK_SOURCE_INDENTER_MANAGER_H__
+
+#include <glib-object.h>
+
+#include "gtksourceindenter.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SOURCE_INDENTER_MANAGER		(gtk_source_indenter_manager_get_type ())
+#define GTK_SOURCE_INDENTER_MANAGER(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_INDENTER_MANAGER, GtkSourceIndenterManager))
+#define GTK_SOURCE_INDENTER_MANAGER_CONST(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_INDENTER_MANAGER, GtkSourceIndenterManager const))
+#define GTK_SOURCE_INDENTER_MANAGER_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SOURCE_INDENTER_MANAGER, GtkSourceIndenterManagerClass))
+#define GTK_IS_SOURCE_INDENTER_MANAGER(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SOURCE_INDENTER_MANAGER))
+#define GTK_IS_SOURCE_INDENTER_MANAGER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_INDENTER_MANAGER))
+#define GTK_SOURCE_INDENTER_MANAGER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_INDENTER_MANAGER, GtkSourceIndenterManagerClass))
+
+typedef struct _GtkSourceIndenterManager	GtkSourceIndenterManager;
+typedef struct _GtkSourceIndenterManagerClass	GtkSourceIndenterManagerClass;
+typedef struct _GtkSourceIndenterManagerPrivate	GtkSourceIndenterManagerPrivate;
+
+struct _GtkSourceIndenterManager
+{
+	GObject parent;
+	
+	GtkSourceIndenterManagerPrivate *priv;
+};
+
+struct _GtkSourceIndenterManagerClass
+{
+	GObjectClass parent_class;
+};
+
+GType				 gtk_source_indenter_manager_get_type	(void) G_GNUC_CONST;
+
+GtkSourceIndenterManager	*gtk_source_indenter_manager_get_default(void);
+
+GtkSourceIndenter		*gtk_source_indenter_manager_get_indenter_by_id
+									(GtkSourceIndenterManager *manager,
+									 const gchar *id);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_INDENTER_MANAGER_H__ */

Modified: branches/indenters/gtksourceview/gtksourcelanguage.c
==============================================================================
--- branches/indenters/gtksourceview/gtksourcelanguage.c	(original)
+++ branches/indenters/gtksourceview/gtksourcelanguage.c	Sat Feb 28 17:01:13 2009
@@ -38,6 +38,7 @@
 #include "gtksourcelanguage-private.h"
 #include "gtksourcelanguage.h"
 #include "gtksourceview-marshal.h"
+#include "gtksourceindentermanager.h"
 
 #define DEFAULT_SECTION _("Others")
 
@@ -879,6 +880,24 @@
 	return info->name;
 }
 
+GtkSourceIndenter *
+_gtk_source_language_get_indenter (GtkSourceLanguage *language)
+{
+	GtkSourceIndenterManager *manager;
+	GtkSourceIndenter *indenter;
+	
+	manager = gtk_source_indenter_manager_get_default ();
+
+	if (GTK_IS_SOURCE_LANGUAGE (language))
+		indenter = gtk_source_indenter_manager_get_indenter_by_id (manager,
+									   language->priv->id);
+	else
+		indenter = gtk_source_indenter_manager_get_indenter_by_id (manager,
+									   NULL);
+	
+	return indenter;
+}
+
 /* Utility functions for GtkSourceStyleInfo */
 
 GtkSourceStyleInfo *

Modified: branches/indenters/gtksourceview/gtksourcelanguage.h
==============================================================================
--- branches/indenters/gtksourceview/gtksourcelanguage.h	(original)
+++ branches/indenters/gtksourceview/gtksourcelanguage.h	Sat Feb 28 17:01:13 2009
@@ -24,6 +24,7 @@
 #include <glib.h>
 #include <glib-object.h>
 #include <gtk/gtk.h>
+#include "gtksourceindenter.h"
 
 G_BEGIN_DECLS
 
@@ -77,6 +78,9 @@
 const char       *gtk_source_language_get_style_name	(GtkSourceLanguage *language,
 							 const char        *style_id);
 
+GtkSourceIndenter *
+		 _gtk_source_language_get_indenter	(GtkSourceLanguage *language);
+
 G_END_DECLS
 
 #endif /* __GTK_SOURCE_LANGUAGE_H__ */

Modified: branches/indenters/gtksourceview/gtksourceview-utils.c
==============================================================================
--- branches/indenters/gtksourceview/gtksourceview-utils.c	(original)
+++ branches/indenters/gtksourceview/gtksourceview-utils.c	Sat Feb 28 17:01:13 2009
@@ -23,6 +23,7 @@
 #endif
 
 #include "gtksourceview-utils.h"
+#include "gtksourceview.h"
 
 #define SOURCEVIEW_DIR "gtksourceview-2.0"
 
@@ -123,3 +124,14 @@
 
 	return g_slist_reverse (files);
 }
+
+/*********************** Indenter utils functions ****************************/
+
+gint
+_gtk_source_view_get_real_indent_width (GtkSourceView *view)
+{
+	gint indent_width = gtk_source_view_get_indent_width (view);
+	guint tab_width = gtk_source_view_get_tab_width (view);
+
+	return indent_width < 0 ? tab_width : indent_width;
+}

Modified: branches/indenters/gtksourceview/gtksourceview-utils.h
==============================================================================
--- branches/indenters/gtksourceview/gtksourceview-utils.h	(original)
+++ branches/indenters/gtksourceview/gtksourceview-utils.h	Sat Feb 28 17:01:13 2009
@@ -22,6 +22,8 @@
 #define __GTK_SOURCE_VIEW_UTILS_H__
 
 #include <glib.h>
+#include "gtksourceview.h"
+#include <gtk/gtk.h>
 
 G_BEGIN_DECLS
 
@@ -32,6 +34,8 @@
 					     const gchar  *suffix,
 					     gboolean      only_dirs);
 
+gint	 _gtk_source_view_get_real_indent_width (GtkSourceView *view);
+
 G_END_DECLS
 
 #endif /* __GTK_SOURCE_VIEW_UTILS_H__ */

Modified: branches/indenters/gtksourceview/gtksourceview.c
==============================================================================
--- branches/indenters/gtksourceview/gtksourceview.c	(original)
+++ branches/indenters/gtksourceview/gtksourceview.c	Sat Feb 28 17:01:13 2009
@@ -39,6 +39,7 @@
 #include "gtksourceview-typebuiltins.h"
 #include "gtksourcemark.h"
 #include "gtksourceview.h"
+#include "gtksourceview-utils.h"
 
 /*
 #define ENABLE_DEBUG
@@ -188,6 +189,9 @@
 				       			 gint              *countp);
 static gint     gtk_source_view_expose 			(GtkWidget         *widget,
 							 GdkEventExpose    *event);
+static void	gtk_source_view_event_after		(GtkWidget         *widget,
+							 GdkEvent          *event,
+							 gpointer           useless);
 static gboolean	gtk_source_view_key_press_event		(GtkWidget         *widget,
 							 GdkEventKey       *event);
 static gboolean	gtk_source_view_button_press_event	(GtkWidget         *widget,
@@ -737,6 +741,11 @@
 			  "notify::buffer",
 			  G_CALLBACK (notify_buffer),
 			  NULL);
+	
+	g_signal_connect (view,
+			  "event-after",
+			  G_CALLBACK (gtk_source_view_event_after),
+			  NULL);
 }
 
 static GObject *
@@ -2757,51 +2766,6 @@
 }
 
 static gchar *
-compute_indentation (GtkSourceView *view,
-		     GtkTextIter   *cur)
-{
-	GtkTextIter start;
-	GtkTextIter end;
-
-	gunichar ch;
-	gint line;
-
-	line = gtk_text_iter_get_line (cur);
-
-	gtk_text_buffer_get_iter_at_line (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)),
-					  &start,
-					  line);
-
-	end = start;
-
-	ch = gtk_text_iter_get_char (&end);
-
-	while (g_unichar_isspace (ch) &&
-	       (ch != '\n') &&
-	       (ch != '\r') &&
-	       (gtk_text_iter_compare (&end, cur) < 0))
-	{
-		if (!gtk_text_iter_forward_char (&end))
-			break;
-
-		ch = gtk_text_iter_get_char (&end);
-	}
-
-	if (gtk_text_iter_equal (&start, &end))
-		return NULL;
-
-	return gtk_text_iter_get_slice (&start, &end);
-}
-
-static gint
-get_real_indent_width (GtkSourceView *view)
-{
-	return view->priv->indent_width < 0 ?
-	       view->priv->tab_width :
-	       view->priv->indent_width;
-}
-
-static gchar *
 get_indent_string (gint tabs, gint spaces)
 {
 	gchar *str;
@@ -2816,6 +2780,31 @@
 	return str;
 }
 
+static gchar *
+get_indent_string_from_indent_level (GtkSourceView *view,
+				     gfloat level)
+{
+	gint tabs;
+	gint spaces;
+	gchar *indent = NULL;
+	gint indent_width;
+	
+	tabs = (gint)level;
+	spaces = round (10 * (gfloat)(level - tabs));
+	indent_width = _gtk_source_view_get_real_indent_width (view);
+	
+	if (view->priv->insert_spaces)
+	{
+		indent = g_strnfill (indent_width * tabs + spaces, ' ');
+	}
+	else
+	{
+		indent = get_indent_string (tabs, spaces);
+	}
+
+	return indent;
+}
+
 static void
 indent_lines (GtkSourceView *view, GtkTextIter *start, GtkTextIter *end)
 {
@@ -2839,7 +2828,7 @@
 
 	if (view->priv->insert_spaces)
 	{
-		spaces = get_real_indent_width (view);
+		spaces = _gtk_source_view_get_real_indent_width (view);
 
 		tab_buffer = g_strnfill (spaces, ' ');
 	}
@@ -2847,7 +2836,7 @@
 	{
 		gint indent_width;
 
-		indent_width = get_real_indent_width (view);
+		indent_width = _gtk_source_view_get_real_indent_width (view);
 		spaces = indent_width % view->priv->tab_width;
 		tabs = indent_width / view->priv->tab_width;
 
@@ -2941,7 +2930,7 @@
 	}
 
 	tab_width = view->priv->tab_width;
-	indent_width = get_real_indent_width (view);
+	indent_width = _gtk_source_view_get_real_indent_width (view);
 
 	gtk_text_buffer_begin_user_action (buf);
 
@@ -3036,7 +3025,7 @@
 		gint pos;
 		gint spaces;
 
-		indent_width = get_real_indent_width (view);
+		indent_width = _gtk_source_view_get_real_indent_width (view);
 
 		/* CHECK: is this a performance problem? */
 		pos = get_line_offset_in_equivalent_spaces (view, start);
@@ -3059,7 +3048,7 @@
 		gint spaces;
 
 		tab_width = view->priv->tab_width;
-		indent_width = get_real_indent_width (view);
+		indent_width = _gtk_source_view_get_real_indent_width (view);
 
 		/* CHECK: is this a performance problem? */
 		from = get_line_offset_in_equivalent_spaces (view, start);
@@ -3183,11 +3172,192 @@
 }
 
 static gboolean
+check_whitespaces (GtkTextIter *cur)
+{
+	GtkTextIter start;
+	gunichar c;
+	gboolean check = FALSE;
+	
+	start = *cur;
+	
+	gtk_text_iter_set_line_offset (&start, 0);
+	c = gtk_text_iter_get_char (&start);
+	
+	while (gtk_text_iter_compare (&start, cur) < 0)
+	{
+		if (!g_unichar_isspace (c))
+		{
+			check = FALSE;
+			break;
+		}
+		else
+			check = TRUE;
+		
+		gtk_text_iter_forward_char (&start);
+		c = gtk_text_iter_get_char (&start);
+	}
+	
+	return check;
+}
+
+static gchar *
+get_current_token (GtkTextBuffer *buf,
+		   GtkTextIter *cur)
+{
+	GtkTextIter start;
+	gchar *word = NULL;
+	gunichar w;
+	
+	start = *cur;
+	
+	if (gtk_text_iter_ends_word (cur) ||
+	    (gtk_text_iter_inside_word (cur) && gtk_text_iter_starts_word (cur)))
+	{
+		gtk_text_iter_backward_word_start (&start);
+		word = gtk_text_buffer_get_text (buf, &start, cur, FALSE);
+	}
+	
+	if (word == NULL && gtk_text_iter_backward_char (&start))
+	{
+		w = gtk_text_iter_get_char (&start);
+		if (!g_unichar_isspace (w))
+			word = g_strdup_printf ("%c", w);
+	}
+	
+	*cur = start;
+	
+	return word;
+}
+
+static void
+gtk_source_view_event_after (GtkWidget *widget,
+			     GdkEvent  *event,
+			     gpointer   useless)
+{
+	GtkSourceView *view;
+	GtkTextBuffer *buf;
+	GtkTextIter cur;
+	GtkTextMark *mark;
+	GtkSourceLanguage *lang;
+	GtkSourceIndenter *indenter;
+	GtkTextIter copy;
+	const gchar * const *relocatables;
+	gfloat level;
+	gint m = 0;
+	
+	if (event->type != GDK_KEY_PRESS || 
+	    event->key.state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))
+		return;
+	
+	view = GTK_SOURCE_VIEW (widget);
+	buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
+	
+	mark = gtk_text_buffer_get_insert (buf);
+	gtk_text_buffer_get_iter_at_mark (buf, &cur, mark);
+	
+	lang = gtk_source_buffer_get_language (view->priv->source_buffer);
+	indenter = _gtk_source_language_get_indenter (lang);
+	
+	/*
+	 * Relocations
+	 */
+	relocatables = gtk_source_indenter_get_relocatables (indenter);
+	while (relocatables != NULL && relocatables[m] != NULL)
+	{
+		const gchar *reloc = relocatables[m];
+		GtkTextIter start;
+		gchar *word;
+		gchar *word2;
+		gchar *indent = NULL;
+		guint keyval;
+		
+		/*
+		 * Check that the key entered is the same as the last character
+		 * in reloc
+		 */
+		keyval = gdk_unicode_to_keyval (reloc[strlen (reloc) - 1]);
+		if (event->key.keyval != keyval)
+		{
+			m++;
+			continue;
+		}
+		
+		start = copy = cur;
+		gtk_text_iter_set_line_offset (&start, 0);
+		
+		/*
+		 * First check the word
+		 */
+		word = get_current_token (buf, &copy);
+		
+		if (word != NULL)
+		{
+			switch (reloc[0])
+			{
+				case '0': if (check_whitespaces (&copy))
+					  {
+						word2 = g_strndup (reloc + 1, strlen (reloc) - 1);
+						
+						if (strcmp (word, word2) == 0)
+						{
+							level = gtk_source_indenter_get_indentation_level (indenter,
+													   GTK_TEXT_VIEW (view),
+													   &copy,
+													   TRUE);
+							indent = get_indent_string_from_indent_level (view, level);
+						}
+						g_free (word2);
+					  }
+					  break;
+				default: if (strcmp (word, reloc) == 0)
+					 {
+						level = gtk_source_indenter_get_indentation_level (indenter,
+												   GTK_TEXT_VIEW (view),
+												   &copy,
+												   TRUE);
+						indent = get_indent_string_from_indent_level (view, level);
+					 }
+					 break;
+			}
+			g_free (word);
+		}
+		
+		if (indent != NULL)
+		{
+			GtkTextIter end;
+			gunichar c;
+			
+			gtk_text_iter_set_line_offset (&start, 0);
+			end = start;
+			
+			c = gtk_text_iter_get_char (&end);
+			while (g_unichar_isspace (c))
+			{
+				gtk_text_iter_forward_char (&end);
+				c = gtk_text_iter_get_char (&end);
+			}
+			
+			gtk_text_buffer_begin_user_action (buf);
+			gtk_text_buffer_delete (buf, &start, &end);
+			
+			gtk_text_buffer_insert (buf, &start, indent, -1);
+			gtk_text_buffer_end_user_action (buf);
+
+			g_free (indent);
+			break;
+		}
+		m++;
+	}
+}
+
+static gboolean
 gtk_source_view_key_press_event (GtkWidget   *widget,
 				 GdkEventKey *event)
 {
 	GtkSourceView *view;
 	GtkTextBuffer *buf;
+	GtkSourceLanguage *lang;
+	GtkSourceIndenter *indenter;
 	GtkTextIter cur;
 	GtkTextMark *mark;
 	guint modifiers;
@@ -3207,7 +3377,10 @@
 
 	mark = gtk_text_buffer_get_insert (buf);
 	gtk_text_buffer_get_iter_at_mark (buf, &cur, mark);
-
+	
+	lang = gtk_source_buffer_get_language (view->priv->source_buffer);
+	indenter = _gtk_source_language_get_indenter (lang);
+	
 	if ((key == GDK_Return || key == GDK_KP_Enter) &&
 	    !(event->state & GDK_SHIFT_MASK) &&
 	    view->priv->auto_indent)
@@ -3217,11 +3390,17 @@
 		 * level as the previous line.
 		 * SHIFT+ENTER allows to avoid autoindentation.
 		 */
+		gfloat indent_level;
 		gchar *indent = NULL;
 
 		/* Calculate line indentation and create indent string. */
-		indent = compute_indentation (view, &cur);
-
+		indent_level = gtk_source_indenter_get_indentation_level (indenter,
+									  GTK_TEXT_VIEW (view),
+									  &cur, FALSE);
+		indent = get_indent_string_from_indent_level (view, indent_level);
+		
+		g_warning ("%f", indent_level);
+		
 		if (indent != NULL)
 		{
 			/* Allow input methods to internally handle a key press event.
@@ -3235,6 +3414,7 @@
 			gtk_text_buffer_get_iter_at_mark (buf, &cur, mark);
 
 			/* Insert new line and auto-indent. */
+			//FIXME: Remove current indentation before insert the new one
 			gtk_text_buffer_begin_user_action (buf);
 			gtk_text_buffer_insert (buf, &cur, "\n", 1);
 			gtk_text_buffer_insert (buf, &cur, indent, strlen (indent));
@@ -3787,6 +3967,87 @@
 	return view->priv->draw_spaces;
 }
 
+/**
+ * gtk_source_view_reindent_lines:
+ * @view: a #GtkSourceView
+ * @start: iterator to initilize with selection start
+ * @end: iterator to initialize with selection end
+ *
+ * FIXME: Add a real doc.
+ * Reindent the lines from @start to @end
+ */
+void
+gtk_source_view_reindent_lines (GtkSourceView *view,
+				GtkTextIter *start,
+				GtkTextIter *end)
+{
+	GtkSourceLanguage *lang;
+	GtkSourceIndenter *indenter;
+	GtkTextBuffer *buf;
+	GtkTextMark *end_mark;
+	
+	g_return_if_fail (GTK_IS_SOURCE_VIEW (view));
+	g_return_if_fail (start != NULL && end != NULL);
+	
+	buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+	lang = gtk_source_buffer_get_language (view->priv->source_buffer);
+	indenter = _gtk_source_language_get_indenter (lang);
+	
+	end_mark = gtk_text_buffer_create_mark (buf, NULL, end, FALSE);
+	gtk_text_buffer_get_iter_at_mark (buf, end, end_mark);
+	
+	while (gtk_text_iter_get_line (start) <=
+	       gtk_text_iter_get_line (end))
+	{
+		gfloat level;
+		gchar *str;
+		
+		/*
+		 * Put start in the end of the previous line
+		 */
+		gtk_text_iter_set_line_offset (start, 0);
+		//gtk_text_iter_backward_char (start);
+		
+		level = gtk_source_indenter_get_indentation_level (indenter,
+								   GTK_TEXT_VIEW (view),
+								   start,
+								   FALSE);
+		g_warning ("reindent level: %f", level);
+		str = get_indent_string_from_indent_level (view, level);
+		if (str != NULL)
+		{
+			GtkTextIter iter;
+			gunichar c;
+			
+			iter = *start;
+			
+			c = gtk_text_iter_get_char (&iter);
+			while (g_unichar_isspace (c) &&
+			       c != '\n' &&
+			       c != '\r')
+			{
+				gtk_text_iter_forward_char (&iter);
+				c = gtk_text_iter_get_char (&iter);
+			}
+			
+			gtk_text_buffer_begin_user_action (buf);
+			gtk_text_buffer_delete (buf, start, &iter);
+			
+			gtk_text_buffer_insert (buf, start, str, -1);
+			gtk_text_buffer_end_user_action (buf);
+			
+			g_free (str);
+		}
+		
+		gtk_text_buffer_get_iter_at_mark (buf, end, end_mark);
+		gtk_text_iter_forward_line (start);
+		//gtk_text_iter_forward_line (start);
+	}
+	
+	gtk_text_buffer_delete_mark (buf, end_mark);
+}
+
+
 static void
 gtk_source_view_style_set (GtkWidget *widget, GtkStyle *previous_style)
 {

Modified: branches/indenters/gtksourceview/gtksourceview.h
==============================================================================
--- branches/indenters/gtksourceview/gtksourceview.h	(original)
+++ branches/indenters/gtksourceview/gtksourceview.h	Sat Feb 28 17:01:13 2009
@@ -198,5 +198,9 @@
 GtkSourceDrawSpacesFlags
 		gtk_source_view_get_draw_spaces		(GtkSourceView   *view);
 
+void		gtk_source_view_reindent_lines		(GtkSourceView *view,
+							 GtkTextIter *start,
+							 GtkTextIter *end);
+
 G_END_DECLS
 #endif				/* end of SOURCE_VIEW_H__ */

Added: branches/indenters/gtksourceview/simple-indenter.c
==============================================================================
--- (empty file)
+++ branches/indenters/gtksourceview/simple-indenter.c	Sat Feb 28 17:01:13 2009
@@ -0,0 +1,81 @@
+/*
+ * c-indenter.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2009 - Ignacio Casal Quinteiro
+ *
+ * gedit 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 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "simple-indenter.h"
+#include "gtksourceindenter.h"
+#include "gtksourceview-utils.h"
+
+#define SIMPLE_INDENTER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object),\
+					    SIMPLE_TYPE_INDENTER, SimpleIndenterPrivate))
+
+struct _SimpleIndenterPrivate
+{
+};
+
+G_DEFINE_TYPE (SimpleIndenter, simple_indenter, GTK_TYPE_SOURCE_INDENTER)
+
+static gfloat
+simple_indenter_get_indentation_level (GtkSourceIndenter *indenter,
+				       GtkTextView *view,
+				       GtkTextIter *iter,
+				       gboolean relocating)
+{
+	return gtk_source_indenter_get_amount_indents (view, iter);
+}
+
+static const gchar * const *
+simple_indenter_get_relocatables (GtkSourceIndenter *self)
+{
+	return NULL;
+}
+
+static void
+simple_indenter_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (simple_indenter_parent_class)->finalize (object);
+}
+
+static void
+simple_indenter_class_init (SimpleIndenterClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtkSourceIndenterClass *indenter_class = GTK_SOURCE_INDENTER_CLASS (klass);
+	
+	object_class->finalize = simple_indenter_finalize;
+	
+	indenter_class->get_indentation_level = simple_indenter_get_indentation_level;
+	indenter_class->get_relocatables = simple_indenter_get_relocatables;
+
+	//g_type_class_add_private (object_class, sizeof (SimpleIndenterPrivate));
+}
+
+static void
+simple_indenter_init (SimpleIndenter *self)
+{
+	//self->priv = SIMPLE_INDENTER_GET_PRIVATE (self);
+}
+
+SimpleIndenter *
+simple_indenter_new ()
+{
+	return g_object_new (SIMPLE_TYPE_INDENTER, NULL);
+}

Added: branches/indenters/gtksourceview/simple-indenter.h
==============================================================================
--- (empty file)
+++ branches/indenters/gtksourceview/simple-indenter.h	Sat Feb 28 17:01:13 2009
@@ -0,0 +1,61 @@
+/*
+ * c-indenter.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2009 - Ignacio Casal Quinteiro
+ *
+ * gedit 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 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __SIMPLE_INDENTER_H__
+#define __SIMPLE_INDENTER_H__
+
+#include <glib-object.h>
+#include "gtksourceindenter.h"
+
+G_BEGIN_DECLS
+
+#define SIMPLE_TYPE_INDENTER			(simple_indenter_get_type ())
+#define SIMPLE_INDENTER(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), SIMPLE_TYPE_INDENTER, SimpleIndenter))
+#define SIMPLE_INDENTER_CONST(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), SIMPLE_TYPE_INDENTER, SimpleIndenter const))
+#define SIMPLE_INDENTER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST ((klass), SIMPLE_TYPE_INDENTER, SimpleIndenterClass))
+#define SIMPLE_IS_INDENTER(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), SIMPLE_TYPE_INDENTER))
+#define SIMPLE_IS_INDENTER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), SIMPLE_TYPE_INDENTER))
+#define SIMPLE_INDENTER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), SIMPLE_TYPE_INDENTER, SimpleIndenterClass))
+
+typedef struct _SimpleIndenter		SimpleIndenter;
+typedef struct _SimpleIndenterClass	SimpleIndenterClass;
+typedef struct _SimpleIndenterPrivate	SimpleIndenterPrivate;
+
+struct _SimpleIndenter
+{
+	GtkSourceIndenter parent;
+	
+	SimpleIndenterPrivate *priv;
+};
+
+struct _SimpleIndenterClass
+{
+	GtkSourceIndenterClass parent_class;
+};
+
+GType simple_indenter_get_type (void) G_GNUC_CONST;
+SimpleIndenter *simple_indenter_new (void);
+
+
+G_END_DECLS
+
+#endif /* __SIMPLE_INDENTER_H__ */

Modified: branches/indenters/tests/test-widget.c
==============================================================================
--- branches/indenters/tests/test-widget.c	(original)
+++ branches/indenters/tests/test-widget.c	Sat Feb 28 17:01:13 2009
@@ -94,7 +94,8 @@
 
 static GtkWidget *create_view_window             (GtkSourceBuffer *buffer,
 						  GtkSourceView   *from);
-
+static void       reindent_cb			 (GtkAction       *action,
+						  gpointer         user_data);
 
 /* Actions & UI definition ---------------------------------------------------- */
 
@@ -119,6 +120,8 @@
 	  "Find", G_CALLBACK (find_cb) },
 	{ "Replace", GTK_STOCK_FIND_AND_REPLACE, "Search and _Replace", "<control>R",
 	  "Search and Replace", G_CALLBACK (replace_cb) },
+	{ "SmartIndent", GTK_STOCK_ADD, "Rein_dent", "<control>I",
+	  "Reindent code", G_CALLBACK (reindent_cb) },
 };
 
 static GtkToggleActionEntry toggle_entries[] = {
@@ -223,6 +226,8 @@
 "        <menuitem action=\"SmartHomeEndAfter\"/>"
 "        <menuitem action=\"SmartHomeEndAlways\"/>"
 "      </menu>"
+"      <separator/>"
+"      <menuitem action=\"SmartIndent\"/>"
 "    </menu>"
 "  </menubar>"
 "</ui>";
@@ -619,6 +624,30 @@
 	gtk_widget_show (window);
 }
 
+static void
+reindent_cb (GtkAction *action, gpointer user_data)
+{
+	GtkSourceView *view;
+	GtkTextBuffer *buf;
+	GtkTextIter start, end;
+	
+	g_return_if_fail (GTK_IS_SOURCE_VIEW (user_data));
+	
+	view = GTK_SOURCE_VIEW (user_data);
+	buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+	
+	if (!gtk_text_buffer_get_selection_bounds (buf, &start, &end))
+	{
+		GtkTextMark *insert;
+		
+		insert = gtk_text_buffer_get_insert (buf);
+		gtk_text_buffer_get_iter_at_mark (buf, &start, insert);
+		end = start;
+	}
+	
+	gtk_source_view_reindent_lines (view, &start, &end);
+}
+
 
 /* Buffer action callbacks ------------------------------------------------------------ */
 



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