[anjuta] python: Moved indentation to its own file an implemented IAnjutaIndenter



commit e9e5aec4e3e818478d42d63d786753498794118c
Author: Johannes Schmid <jhs gnome org>
Date:   Sun Feb 13 20:54:45 2011 +0100

    python: Moved indentation to its own file an implemented IAnjutaIndenter

 plugins/language-support-python/Makefile.am        |    2 +-
 plugins/language-support-python/plugin.c           |  940 +-------------------
 .../language-support-python/python-indentation.c   |  914 +++++++++++++++++++
 .../language-support-python/python-indentation.h   |   39 +
 4 files changed, 992 insertions(+), 903 deletions(-)
---
diff --git a/plugins/language-support-python/Makefile.am b/plugins/language-support-python/Makefile.am
index 65631c9..b5824bd 100644
--- a/plugins/language-support-python/Makefile.am
+++ b/plugins/language-support-python/Makefile.am
@@ -34,7 +34,7 @@ plugindir = $(anjuta_plugin_dir)
 plugin_LTLIBRARIES = libpython_plugin.la
 
 # Plugin sources
-libpython_plugin_la_SOURCES = plugin.c plugin.h python-assist.c python-assist.h python-utils.c python-utils.h
+libpython_plugin_la_SOURCES = plugin.c plugin.h python-assist.c python-assist.h python-utils.c python-utils.h python-indentation.c python-indentation.h
 
 libpython_plugin_la_LDFLAGS = $(ANJUTA_PLUGIN_LDFLAGS)
 
diff --git a/plugins/language-support-python/plugin.c b/plugins/language-support-python/plugin.c
index 7a61696..60d8cc9 100644
--- a/plugins/language-support-python/plugin.c
+++ b/plugins/language-support-python/plugin.c
@@ -42,12 +42,12 @@
 #include <libanjuta/interfaces/ianjuta-preferences.h>
 #include <libanjuta/interfaces/ianjuta-symbol.h>
 #include <libanjuta/interfaces/ianjuta-language.h>
-
-//REMOVE GLADE #include <glade/glade.h>
+#include <libanjuta/interfaces/ianjuta-indenter.h>
 
 #include "plugin.h"
 #include "python-utils.h"
 #include "python-assist.h"
+#include "python-indentation.h"
 
 /* Pixmaps */
 #define ANJUTA_PIXMAP_COMPLETE			  "anjuta-complete"
@@ -65,839 +65,13 @@
 /* Preferences keys */
 
 #define PREF_SCHEMA "org.gnome.anjuta.python"
-#define PREF_INDENT_AUTOMATIC "python-indent-automatic"
-#define PREF_INDENT_ADAPTIVE "python-indent-adaptive"
-#define PREF_INDENT_TAB_INDENTS "python-indent-tab-indents"
-#define PREF_INDENT_STATEMENT_SIZE "python-indent-statement-size"
-#define PREF_INDENT_BRACE_SIZE "python-indent-brace-size"
+
 
 #define PREF_NO_ROPE_WARNING "python-no-rope-warning"
 #define PREF_INTERPRETER_PATH "python-interpreter-path"
 
-#define TAB_SIZE (ianjuta_editor_get_tabsize (editor, NULL))
-
-#define USE_SPACES_FOR_INDENTATION (ianjuta_editor_get_use_spaces (editor, NULL))
-
-#define INDENT_SIZE \
-	(plugin->param_statement_indentation >= 0? \
-		plugin->param_statement_indentation : \
-		g_settings_get_int (plugin->settings, PREF_INDENT_STATEMENT_SIZE))
-
-#define BRACE_INDENT \
-	(plugin->param_brace_indentation >= 0? \
-		plugin->param_brace_indentation : \
-		g_settings_get_int (plugin->settings, PREF_INDENT_BRACE_SIZE))
-
-#define CASE_INDENT (INDENT_SIZE)
-#define LABEL_INDENT (INDENT_SIZE)
-
 static gpointer parent_class;
 
-static gboolean
-iter_is_newline (IAnjutaIterable *iter, gchar ch)
-{
-	if (ch == '\n' || ch == '\r')
-		return TRUE;
-	return FALSE;
-}
-
-/* Returns TRUE if iter was moved */
-static gboolean
-skip_iter_to_newline_head (IAnjutaIterable *iter, gchar ch)
-{
-	gboolean ret_val = FALSE;
-	
-	if (ch == '\n')
-	{
-		/* Possibly at tail */
-		if (ianjuta_iterable_previous (iter, NULL))
-		{
-			ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
-											0, NULL);
-			if (ch != '\r')
-				/* Already at head, undo iter */
-				ianjuta_iterable_next (iter, NULL);
-			else
-				/* Correctly at head */
-				ret_val = TRUE;
-		}
-	}
-	return ret_val;
-}
-
-/* Returns TRUE if iter was moved */
-static gboolean
-skip_iter_to_newline_tail (IAnjutaIterable *iter, gchar ch)
-{
-	gboolean ret_val = FALSE;
-	
-	if (ch == '\r')
-	{
-		/* Possibly at head */
-		if (ianjuta_iterable_previous (iter, NULL))
-		{
-			ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
-											0, NULL);
-			if (ch != '\n')
-				/* Already at tail, undo iter */
-				ianjuta_iterable_next (iter, NULL);
-			else
-				/* Correctly at tail */
-				ret_val = TRUE;
-		}
-	}
-	return ret_val;
-}
-
-/* Jumps to the reverse matching brace of the given brace character */
-
-static gint
-get_line_indentation (IAnjutaEditor *editor, gint line_num)
-{
-	IAnjutaIterable *line_begin, *line_end;
-	gchar *line_string, *idx;
-	gint line_indent = 0;
-	
-	line_begin = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
-	line_end = ianjuta_editor_get_line_end_position (editor, line_num, NULL);
-	/*
-	DEBUG_PRINT ("%s: line begin = %d, line end = %d", __FUNCTION__,
-				 line_begin, line_end);
-	*/
-	if (ianjuta_iterable_compare (line_begin, line_end, NULL) == 0)
-	{
-		g_object_unref (line_begin);
-		g_object_unref (line_end);
-		return 0;
-	}
-	
-	line_string = ianjuta_editor_get_text (editor, line_begin, line_end,
-												NULL);
-	g_object_unref (line_begin);
-	g_object_unref (line_end);
-	
-	/* DEBUG_PRINT ("line_string = '%s'", line_string); */
-	
-	if (!line_string)
-		return 0;
-	
-	idx = line_string;
-	
-	/* Find first non-white space */
-	while (*idx != '\0' && isspace (*idx))
-	{
-		if (*idx == '\t')
-			line_indent += TAB_SIZE;
-		else
-			line_indent++;
-		idx++; /* Since we are looking for first non-space char, simple
-				* increment of the utf8 chars would do */
-	}
-	g_free (line_string);
-	return line_indent;
-}
-
-static gchar *
-get_line_indentation_string (IAnjutaEditor *editor, gint spaces, gint line_indent_spaces)
-{
-	gint i;
-	gchar *indent_string;
-		
-	if ((spaces + line_indent_spaces) <= 0)
-		return NULL;
-	
-	if (USE_SPACES_FOR_INDENTATION)
-	{
-		indent_string = g_new0 (gchar, spaces + line_indent_spaces + 1);
-		for (i = 0; i < (spaces + line_indent_spaces); i++)
-			indent_string[i] = ' ';
-	}
-	else
-	{
-		gint num_tabs = spaces / TAB_SIZE;
-		gint num_spaces = spaces % TAB_SIZE;
-		indent_string = g_new0 (gchar, num_tabs + num_spaces + line_indent_spaces + 1);
-		
-		for (i = 0; i < num_tabs; i++)
-			indent_string[i] = '\t';
-		for (; i < num_tabs + (num_spaces + line_indent_spaces); i++)
-			indent_string[i] = ' ';
-	}
-	return indent_string;
-}
-
-static void
-set_indentation_param_emacs (PythonPlugin* plugin, const gchar *param,
-					   const gchar *value)
-{
-	//DEBUG_PRINT ("Setting indent param: %s = %s", param, value);
-	if (strcasecmp (param, "indent-tabs-mode") == 0)
-	{
-		if (strcasecmp (value, "t") == 0)
-		{
-			plugin->param_use_spaces = 0;
-			ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
-										   FALSE, NULL);
-		}
-		else if (strcasecmp (value, "nil") == 0)
-		{
-			plugin->param_use_spaces = 1;
-			ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
-										   TRUE, NULL);
-		}
-	}
-	else if (strcasecmp (param, "c-basic-offset") == 0)
-	{
-		plugin->param_statement_indentation = atoi (value);
-	}
-	else if (strcasecmp (param, "tab-width") == 0)
-	{
-		plugin->param_tab_size = atoi (value);
-		ianjuta_editor_set_tabsize (IANJUTA_EDITOR (plugin->current_editor),
-									plugin->param_tab_size, NULL);
-	}
-}
-
-static void
-set_indentation_param_vim (PythonPlugin* plugin, const gchar *param,
-					   const gchar *value)
-{
-	//DEBUG_PRINT ("Setting indent param: %s = %s", param, value);
-	if (g_str_equal (param, "expandtab") ||
-		g_str_equal (param, "et"))
-	{
-			plugin->param_use_spaces = 1;
-			ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
-										   TRUE, NULL);
-	}
-	else if (g_str_equal (param, "noexpandtabs") ||
-			 g_str_equal (param, "noet"))
-	{
-	  	plugin->param_use_spaces = 0;
-			ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
-										   FALSE, NULL);
-	}
-	if (!value)
-		return;
-	else if (g_str_equal (param, "shiftwidth") ||
-			 g_str_equal (param, "sw"))
-	{
-		plugin->param_statement_indentation = atoi (value);
-	}
-	else if (g_str_equal (param, "softtabstop") ||
-			 g_str_equal (param, "sts") ||
-			 g_str_equal (param, "tabstop") ||
-			 g_str_equal (param, "ts"))
-	{
-		plugin->param_tab_size = atoi (value);
-		ianjuta_editor_set_tabsize (IANJUTA_EDITOR (plugin->current_editor),
-									plugin->param_tab_size, NULL);
-	}
-}
-
-static void
-parse_mode_line_emacs (PythonPlugin *plugin, const gchar *modeline)
-{
-	gchar **strv, **ptr;
-	
-	strv = g_strsplit (modeline, ";", -1);
-	ptr = strv;
-	while (*ptr)
-	{
-		gchar **keyval;
-		keyval = g_strsplit (*ptr, ":", 2);
-		if (keyval[0] && keyval[1])
-		{
-			g_strstrip (keyval[0]);
-			g_strstrip (keyval[1]);
-			set_indentation_param_emacs (plugin, g_strchug (keyval[0]),
-                                   g_strchug (keyval[1]));
-		}
-		g_strfreev (keyval);
-		ptr++;
-	}
-	g_strfreev (strv);
-}
-
-static void
-parse_mode_line_vim (PythonPlugin *plugin, const gchar *modeline)
-{
-	gchar **strv, **ptr;
-	
-	strv = g_strsplit (modeline, " ", -1);
-	ptr = strv;
-	while (*ptr)
-	{
-		gchar **keyval;
-		keyval = g_strsplit (*ptr, "=", 2);
-		if (keyval[0])
-		{
-			g_strstrip (keyval[0]);
-      if (keyval[1])
-      {
-			  g_strstrip (keyval[1]);
-			  set_indentation_param_vim (plugin, g_strchug (keyval[0]),
-                                     g_strchug (keyval[1]));
-      }
-      else
-			  set_indentation_param_vim (plugin, g_strchug (keyval[0]),
-                                     NULL);        
-		}
-		g_strfreev (keyval);
-		ptr++;
-	}
-	g_strfreev (strv);
-}
-
-static gchar *
-extract_mode_line (const gchar *comment_text, gboolean* vim)
-{
-	/* Search for emacs-like modelines */
-	gchar *begin_modeline, *end_modeline;
-	begin_modeline = strstr (comment_text, "-*-");
-	if (begin_modeline)
-	{
-		begin_modeline += 3;
-		end_modeline = strstr (begin_modeline, "-*-");
-		if (end_modeline)
-		{
-		  *vim = FALSE;
-				return g_strndup (begin_modeline, end_modeline - begin_modeline);
-		}
-	}
-	/* Search for vim-like modelines */
-	begin_modeline = strstr (comment_text, "vim:set");
-	if (begin_modeline)
-	{
-		begin_modeline += 7;
-		end_modeline = strstr (begin_modeline, ":");
-		/* Check for escape characters */
-		while (end_modeline)
-		{
-			 if (!g_str_equal ((end_modeline - 1), "\\"))
-				break;
-			end_modeline++;
-			end_modeline = strstr (end_modeline, ":");
-		}
-		if (end_modeline)
-		{
-			gchar* vim_modeline = g_strndup (begin_modeline, end_modeline - begin_modeline);
-			*vim = TRUE;
-			return vim_modeline;
-		}
-	}
-	return NULL;
-}
-
-#define MINI_BUFFER_SIZE 3
-
-static void
-initialize_indentation_params (PythonPlugin *plugin)
-{
-	IAnjutaIterable *iter;
-	GString *comment_text;
-	gboolean comment_begun = FALSE;
-	gboolean line_comment = FALSE;
-	gchar mini_buffer[MINI_BUFFER_SIZE] = {0};
-	
-	/* Initialize indentation parameters */
-	plugin->param_tab_size = -1;
-	plugin->param_statement_indentation = -1;
-	plugin->param_brace_indentation = -1;
-	plugin->param_case_indentation = -1;
-	plugin->param_label_indentation = -1;
-	plugin->param_use_spaces = -1;
-	
-	/* Find the first comment text in the buffer */
-	comment_text = g_string_new (NULL);
-	iter = ianjuta_editor_get_start_position (IANJUTA_EDITOR (plugin->current_editor),
-											  NULL);
-	do
-	{
-		gboolean shift_buffer = TRUE;
-		gint i;
-		gchar ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
-												 0, NULL);
-		
-		for (i = 0; i < MINI_BUFFER_SIZE - 1; i++)
-		{
-			if (mini_buffer[i] == '\0')
-			{
-				mini_buffer[i] = ch;
-				shift_buffer = FALSE;
-				break;
-			}
-		}
-		if (shift_buffer == TRUE)
-		{
-			/* Shift buffer and add */
-			for (i = 0; i < MINI_BUFFER_SIZE - 1; i++)
-				mini_buffer [i] = mini_buffer[i+1];
-			mini_buffer[i] = ch;
-		}
-		
-		if (!comment_begun && strncmp (mini_buffer, "/*", 2) == 0)
-		{
-			comment_begun = TRUE;
-			/* Reset buffer */
-			mini_buffer[0] = mini_buffer[1] = '\0';
-		}
-		else if (!comment_begun && strncmp (mini_buffer, "//", 2) == 0)
-		{
-			comment_begun = TRUE;
-			line_comment = TRUE;
-		}
-		else if (!comment_begun && mini_buffer[1] != '\0')
-		{
-			/* The buffer doesn't begin with a comment */
-			break;
-		}
-		else if (comment_begun)
-		{
-			if ((line_comment && ch == '\n') ||
-				(!line_comment && strncmp (mini_buffer, "*/", 2) == 0))
-			{
-				break;
-			}
-		}
-		
-		if (comment_begun)
-			g_string_append_c (comment_text, ch);
-		
-	}
-	while (ianjuta_iterable_next (iter, NULL));
-	
-	/* DEBUG_PRINT ("Comment text: %s", comment_text->str);*/
-	if (comment_text->len > 0)
-	{
-		
-		/* First comment found */
-    gboolean vim;
-		gchar *modeline = extract_mode_line (comment_text->str, &vim);
-		if (modeline)
-		{
-      if (!vim)
-			  parse_mode_line_emacs (plugin, modeline);
-      else
-        parse_mode_line_vim (plugin, modeline);
-			g_free (modeline);
-		}
-	}
-	g_string_free (comment_text, TRUE);
-	g_object_unref (iter);
-}
-
-static gint
-set_line_indentation (IAnjutaEditor *editor, gint line_num, gint indentation, gint line_indent_spaces)
-{
-	IAnjutaIterable *line_begin, *line_end, *indent_position;
-	IAnjutaIterable *current_pos;
-	gint carat_offset, nchars = 0, nchars_removed = 0;
-	gchar *old_indent_string = NULL, *indent_string = NULL;
-	
-	/* DEBUG_PRINT ("In %s()", __FUNCTION__); */
-	line_begin = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
-	line_end = ianjuta_editor_get_line_end_position (editor, line_num, NULL);
-	
-	/*
-	DEBUG_PRINT ("line begin = %d, line end = %d, current_pos = %d",
-				 line_begin, line_end, current_pos);
-	*/
-	indent_position = ianjuta_iterable_clone (line_begin, NULL);
-	
-	if (ianjuta_iterable_compare (line_end, line_begin, NULL) > 0)
-	{
-		gchar *idx;
-		gchar *line_string = ianjuta_editor_get_text (editor, line_begin,
-														   line_end, NULL);
-		
-		//DEBUG_PRINT ("line_string = '%s'", line_string);
-		if (line_string)
-		{
-			idx = line_string;
-			
-			/* Find first non-white space */
-			while (*idx != '\0' && isspace (*idx))
-			{
-				idx = g_utf8_find_next_char (idx, NULL);
-				ianjuta_iterable_next (indent_position, NULL);
-			}
-			g_free (line_string);
-		}
-	}
-	/* Indent iter defined at this point, Identify how much is current
-	 * position is beyound this point. We need to restore it later after
-	 * indentation
-	*/
-	current_pos = ianjuta_editor_get_position (editor, NULL);
-	carat_offset = ianjuta_iterable_diff (indent_position, current_pos, NULL);
-	//DEBUG_PRINT ("carat offset is = %d", carat_offset);
-	
-	/* Set new indentation */
-	if ((indentation + line_indent_spaces) > 0)
-	{
-		indent_string = get_line_indentation_string (editor, indentation, line_indent_spaces);
-		nchars = indent_string ? g_utf8_strlen (indent_string, -1) : 0;
-		
-		/* Only indent if there is something to indent with */
-		if (indent_string)
-		{
-			/* Get existing indentation */
-			if (ianjuta_iterable_compare (indent_position, line_begin, NULL) > 0)
-			{
-				old_indent_string =
-					ianjuta_editor_get_text (editor, line_begin,
-												  indent_position, NULL);
-				
-				//DEBUG_PRINT ("old_indent_string = '%s'", old_indent_string);
-				nchars_removed = g_utf8_strlen (old_indent_string, -1);
-			}
-			
-			/* Only indent if there was no indentation before or old
-			 * indentation string was different from the new indent string
-			 */
-			if (old_indent_string == NULL ||
-				strcmp (old_indent_string, indent_string) != 0)
-			{
-				/* Remove the old indentation string, if there is any */
-				if (old_indent_string)
-					ianjuta_editor_erase (editor, line_begin,
-										  indent_position, NULL);
-				
-				/* Insert the new indentation string */
-				ianjuta_editor_insert (editor, line_begin,
-									   indent_string, -1, NULL);
-			}
-		}
-	}
-	
-	/* If indentation == 0, we really didn't enter the previous code block,
-	 * but we may need to clear existing indentation.
-	 */
-	if ((indentation + line_indent_spaces) == 0)
-	{
-		/* Get existing indentation */
-		if (ianjuta_iterable_compare (indent_position, line_begin, NULL) > 0)
-		{
-			old_indent_string =
-				ianjuta_editor_get_text (editor, line_begin,
-											  indent_position, NULL);
-			nchars_removed = g_utf8_strlen (old_indent_string, -1);
-		}
-		if (old_indent_string)
-			ianjuta_editor_erase (editor, line_begin, indent_position, NULL);
-	}
-	
-	/* Restore current position */
-	if (carat_offset >= 0)
-	{
-		/* If the cursor was not before the first non-space character in
-		 * the line, restore it's position after indentation.
-		 */
-		gint i;
-		IAnjutaIterable *pos = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
-		for (i = 0; i < nchars + carat_offset; i++)
-			ianjuta_iterable_next (pos, NULL);
-		ianjuta_editor_goto_position (editor, pos, NULL);
-		g_object_unref (pos);
-	}
-	else /* cursor_offset < 0 */
-	{
-		/* If the cursor was somewhere in the old indentation spaces,
-		 * home the cursor to first non-space character in the line (or
-		 * end of line if there is no non-space characters in the line.
-		 */
-		gint i;
-		IAnjutaIterable *pos = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
-		for (i = 0; i < nchars; i++)
-			ianjuta_iterable_next (pos, NULL);
-		ianjuta_editor_goto_position (editor, pos, NULL);
-		g_object_unref (pos);
-	}
-
-	g_object_unref (current_pos);
-	g_object_unref (indent_position);
-	g_object_unref (line_begin);
-	g_object_unref (line_end);
-	
-	g_free (old_indent_string);
-	g_free (indent_string);
-	return nchars;
-}
-
-/*  incomplete_statement:
- *  1 == COMPLETE STATEMENT
- *  0 == INCOMPLETE STATEMENT
- * -1 == UNKNOWN
- */
-
-static gchar*
-get_current_statement (IAnjutaEditor *editor, gint line_num, gint *found_line_num)
-{
-	gchar point_ch;
-	IAnjutaIterable *iter = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
-	gchar statement[1024];
-	gint counter=0;
-
-	do
-	{
-		point_ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0, NULL);
-
-		if (!ianjuta_iterable_next (iter, NULL) )
-			break;
-	} while (point_ch == ' ' || point_ch == '\t'); // Whitespace
-
-	if (!ianjuta_iterable_previous (iter, NULL))
-		return "";
-	
-	do
-	{
-		point_ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0, NULL);
-		statement[counter++] = point_ch;
-		
-		if (!ianjuta_iterable_next (iter, NULL) )
-			break;
-	} while (isalpha(point_ch) || isdigit(point_ch)); // FIXME: Is this UTF-8 compatible?
-	statement[counter-1] = '\0';
-
-	g_object_unref (iter);
-	return g_strdup_printf("%s", statement);
-}
-
-static gchar 
-get_last_char (IAnjutaEditor *editor, gint line_num, gint *found_line_num)
-{
-	gchar point_ch;
-	IAnjutaIterable *iter = ianjuta_editor_get_line_end_position (editor, line_num, NULL);
-
-	do
-	{
-		if (ianjuta_iterable_previous (iter, NULL) )
-		{
-			point_ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0,
-												 NULL); 
-		}
-		else
-			break;
-	} 
-	while (point_ch == ' ' || point_ch == '\n' || point_ch == '\r' || point_ch == '\t'); // Whitespace
-
-	*found_line_num = ianjuta_editor_get_line_from_position (editor, iter, NULL);
-	return point_ch;
-}
-
-static gboolean
-spaces_only (IAnjutaEditor* editor, IAnjutaIterable* begin, IAnjutaIterable* end);
-
-static gboolean
-is_spaces_only (IAnjutaEditor *editor, gint line_num)
-{
-		IAnjutaIterable* begin = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
-		IAnjutaIterable* end = ianjuta_editor_get_line_end_position (editor, line_num , NULL);
-
-		if (spaces_only (editor, begin, end))
-		{
-			return TRUE;
-		}
-
-	return FALSE;
-}
-
-static gint
-get_line_indentation_base (PythonPlugin *plugin,
-						   IAnjutaEditor *editor,
-						   gint line_num,
-						   gint *incomplete_statement,
-						   gint *line_indent_spaces,
-						   gboolean *colon_indent)
-{
-	IAnjutaIterable *iter;
-	gchar point_ch;
-	gint line_indent = 0;
-	gint currentline = line_num - 1;
-	gchar *last_line_statement;
-	
-	*incomplete_statement = 0;
-	*line_indent_spaces = 0;
-	
-	if (currentline <= 1)
-		return 0;
-	
-	iter = ianjuta_editor_get_line_end_position (editor, line_num, NULL);
-
-	point_ch = get_last_char (editor, currentline, &currentline);
-	last_line_statement = get_current_statement (editor, currentline, &currentline);
-
-	if (!g_strcmp0(last_line_statement, "return") || 
-	    !g_strcmp0(last_line_statement, "break") ||
-	    !g_strcmp0(last_line_statement, "pass") || 
-	    !g_strcmp0(last_line_statement, "raise") || 	    
-	    !g_strcmp0(last_line_statement, "continue") )
-	{					
-		if (get_line_indentation (editor, currentline)>= INDENT_SIZE)
-			line_indent = get_line_indentation (editor, currentline) - INDENT_SIZE;
-	}
-	else if (point_ch == ':')
-	{
-        line_indent = get_line_indentation (editor, currentline) + INDENT_SIZE;
-	}
-	else
-	{
-		gint line = currentline;
-		while (is_spaces_only(editor, line) && line >= 0)
-			line--;
-		line_indent = get_line_indentation (editor, line);
-	}
-
-	return line_indent;
-}
-
-static gboolean
-spaces_only (IAnjutaEditor* editor, IAnjutaIterable* begin, IAnjutaIterable* end)
-{
-	gboolean empty = TRUE;
-	gchar* idx;
-	gchar* text = ianjuta_editor_get_text (editor, begin, end, NULL);
-
-	if (text == NULL)
-		return TRUE;
-	
-
-	for (idx = text; *idx != '\0'; idx++)
-	{
-		if (!isspace(*idx))
-		{
-			empty = FALSE;
-			break;
-		}
-	}
-	g_free(text);
-	return empty;
-}
-
-static gint
-get_line_auto_indentation (PythonPlugin *plugin, IAnjutaEditor *editor,
-						   gint line, gint *line_indent_spaces)
-{
-	IAnjutaIterable *iter;
-	gint line_indent = 0;
-	gint incomplete_statement = -1;
-	gboolean colon_indent = FALSE;
-	
-	g_return_val_if_fail (line > 0, 0);
-
-	if (line == 1) /* First line */
-	{
-		return 0;
-	}
-	else
-	{
-		IAnjutaIterable* begin = ianjuta_editor_get_line_begin_position (editor, line -1 , NULL);
-		IAnjutaIterable* end = ianjuta_editor_get_line_end_position (editor, line -1 , NULL);
-
-		if (spaces_only (editor, begin, end))
-		{
-			set_line_indentation (editor, line -1, 0, 0);
-		}
-		g_object_unref (begin);
-		g_object_unref (end);
-	}
-	
-	iter = ianjuta_editor_get_line_begin_position (editor, line, NULL);
-
-/*	if (is_iter_inside_string (iter))
-	{
-		line_indent = get_line_indentation (editor, line - 1);
-	}
-	else
-	{*/
-		line_indent = get_line_indentation_base (plugin, editor, line,
-												 &incomplete_statement, 
-												 line_indent_spaces,
-												 &colon_indent);
-	/*}*/
-
-	/* Determine what the first non-white char in the line is */
-	do
-	{
-		gchar ch;
-		/* Check if we are *inside* comment or string. Begining of comment
-		 * or string does not count as inside. If inside, just align with
-		 * previous indentation.
-		 */
-		/*if (is_iter_inside_string (iter))
-		{
-			line_indent = get_line_indentation (editor, line - 1);
-			break;
-		}*/
-		ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
-										   0, NULL);
-		if (iter_is_newline (iter, ch))
-		{
-			skip_iter_to_newline_tail (iter, ch);
-			
-			/* First levels are excused from incomplete statement indent */
-			if (incomplete_statement == 1 && line_indent > 0)
-				line_indent += INDENT_SIZE;
-			break;
-		}
-		
-		else if (!isspace (ch))
-		{
-			/* First levels are excused from incomplete statement indent */
-			if (incomplete_statement == 1 && line_indent > 0)
-				line_indent += INDENT_SIZE;
-			break;
-		}
-
-	}
-	while (ianjuta_iterable_next (iter, NULL));
-	g_object_unref (iter);
-	
-	return line_indent;
-}
-
-static void
-on_editor_char_inserted_cpp (IAnjutaEditor *editor,
-							 IAnjutaIterable *insert_pos,
-							 gchar ch,
-							 PythonPlugin *plugin)
-{
-	IAnjutaIterable *iter;
-	gboolean should_auto_indent = FALSE;
-
-	iter = ianjuta_iterable_clone (insert_pos, NULL);
-
-	/* If autoindent is enabled*/
-	if (g_settings_get_boolean (plugin->settings, PREF_INDENT_AUTOMATIC))
-	{
-		if (iter_is_newline (iter, ch))
-		{
-			skip_iter_to_newline_head (iter, ch);
-			/* All newline entries means enable indenting */
-			should_auto_indent = TRUE;
-		}
-
-		if (should_auto_indent)
-		{
-			gint insert_line;
-			gint line_indent;
-			gint line_indent_spaces;
-		
-			ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT(editor), NULL);
-			initialize_indentation_params (plugin);
-			
-			insert_line = ianjuta_editor_get_lineno (editor, NULL);
-			line_indent = get_line_auto_indentation (plugin, editor, insert_line, &line_indent_spaces);
-			set_line_indentation (editor, insert_line, line_indent, line_indent_spaces);
-			ianjuta_document_end_undo_action (IANJUTA_DOCUMENT(editor), NULL);
-		}
-	}
-	
-
-	g_object_unref (iter);
-}
-
 static void
 on_check_finished (AnjutaLauncher* launcher,
                    int child_pid, int exit_status,
@@ -956,9 +130,18 @@ check_support (PythonPlugin *python_plugin)
 		g_free (command);
 	}
 }
-	                                            
 
 static void
+on_editor_char_inserted_python (IAnjutaEditor *editor,
+                         IAnjutaIterable *insert_pos,
+                         gchar ch,
+                         PythonPlugin *plugin)
+{
+	python_indent (plugin, editor, insert_pos, ch);
+}
+
+                         
+static void
 install_support (PythonPlugin *lang_plugin)
 {	
 	IAnjutaLanguage* lang_manager =
@@ -991,7 +174,7 @@ install_support (PythonPlugin *lang_plugin)
 	{
 		g_signal_connect (lang_plugin->current_editor,
 						  "char-added",
-						  G_CALLBACK (on_editor_char_inserted_cpp),
+						  G_CALLBACK (on_editor_char_inserted_python),
 						  lang_plugin);
 	}
 	else
@@ -999,7 +182,7 @@ install_support (PythonPlugin *lang_plugin)
 		return;
 	}
 	
-	initialize_indentation_params (lang_plugin);
+	python_indent_init (lang_plugin);
 	/* Disable editor intern auto-indent */
 	ianjuta_editor_set_auto_indent (IANJUTA_EDITOR(lang_plugin->current_editor),
 								    FALSE, NULL);
@@ -1048,7 +231,7 @@ uninstall_support (PythonPlugin *lang_plugin)
 		(g_str_equal (lang_plugin->current_language, "Python")))
 	{
 		g_signal_handlers_disconnect_by_func (lang_plugin->current_editor,
-									G_CALLBACK (on_editor_char_inserted_cpp),
+									G_CALLBACK (on_editor_char_inserted_python),
 									lang_plugin);
 	}
 	
@@ -1128,49 +311,10 @@ on_value_removed_current_editor (AnjutaPlugin *plugin, const gchar *name,
 
 static void
 on_auto_indent (GtkAction *action, gpointer data)
-{
-	gint line_start, line_end;
-	gint insert_line;
-	gint line_indent;
-	gboolean has_selection;
-	
-	PythonPlugin *lang_plugin;
-	IAnjutaEditor *editor;
-	lang_plugin = (PythonPlugin*) (data);
-	editor = IANJUTA_EDITOR (lang_plugin->current_editor);
-	
-	has_selection = ianjuta_editor_selection_has_selection
-						(IANJUTA_EDITOR_SELECTION (editor), NULL);
-	if (has_selection)
-	{
-		IAnjutaIterable *sel_start, *sel_end;
-		sel_start = ianjuta_editor_selection_get_start (IANJUTA_EDITOR_SELECTION (editor),
-														NULL);
-		sel_end = ianjuta_editor_selection_get_end (IANJUTA_EDITOR_SELECTION (editor),
-													NULL);
-		line_start = ianjuta_editor_get_line_from_position (editor, sel_start, NULL);
-		line_end = ianjuta_editor_get_line_from_position (editor, sel_end, NULL);
-		g_object_unref (sel_start);
-		g_object_unref (sel_end);
-	}
-	else
-	{
-		line_start = ianjuta_editor_get_lineno (IANJUTA_EDITOR(editor), NULL);
-		line_end = line_start;
-	}
-	ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT(editor), NULL);
-	initialize_indentation_params (lang_plugin);
-	
-	for (insert_line = line_start; insert_line <= line_end; insert_line++)
-	{
-		gint line_indent_spaces = 0;
-		line_indent = get_line_auto_indentation (lang_plugin, editor,
-												 insert_line,
-												 &line_indent_spaces);
-		/* DEBUG_PRINT ("Line indent for line %d = %d", insert_line, line_indent); */
-		set_line_indentation (editor, insert_line, line_indent, line_indent_spaces);
-	}
-	ianjuta_document_end_undo_action (IANJUTA_DOCUMENT(editor), NULL);
+{	
+	PythonPlugin *lang_plugin = ANJUTA_PLUGIN_PYTHON (data);
+
+	python_indent_auto (lang_plugin, NULL, NULL);
 }
 
 static GtkActionEntry actions[] = {
@@ -1189,25 +333,6 @@ static GtkActionEntry actions[] = {
 };
 
 static void
-register_stock_icons (AnjutaPlugin *plugin)
-{
-	static gboolean registered = FALSE;
-
-	if (registered)
-		return;
-	registered = TRUE;
-	
-	/* Register stock icons */
-	BEGIN_REGISTER_ICON (plugin);
-//	REGISTER_ICON_FULL (ANJUTA_PIXMAP_SWAP, ANJUTA_STOCK_SWAP);
-//	REGISTER_ICON_FULL (ANJUTA_PIXMAP_COMPLETE, ANJUTA_STOCK_COMPLETE);	
-//	REGISTER_ICON_FULL (ANJUTA_PIXMAP_AUTOCOMPLETE, ANJUTA_STOCK_AUTOCOMPLETE);
-//	REGISTER_ICON_FULL (ANJUTA_PIXMAP_AUTOINDENT, ANJUTA_STOCK_AUTOINDENT);
-	END_REGISTER_ICON;
-}
-
-// CODE from git PLUGIN
-static void
 on_project_root_added (AnjutaPlugin *plugin, const gchar *name, 
 					   const GValue *value, gpointer user_data)
 {
@@ -1249,12 +374,6 @@ python_plugin_activate (AnjutaPlugin *plugin)
 	static gboolean initialized = FALSE;
 
 	python_plugin = (PythonPlugin*) plugin;
-
-	if (!initialized)
-	{
-		register_stock_icons (plugin);
-	}
-
 	
 	python_plugin->prefs = anjuta_shell_get_preferences (plugin->shell, NULL);
 	
@@ -1393,10 +512,27 @@ ipreferences_iface_init (IAnjutaPreferencesIface* iface)
 	iface->unmerge = ipreferences_unmerge;	
 }
 
-//ANJUTA_PLUGIN_BOILERPLATE (PythonPlugin, python_plugin);
+static void
+iindenter_indent (IAnjutaIndenter* indenter,
+                  IAnjutaIterable* start,
+                  IAnjutaIterable* end,
+                  GError** e)
+{
+	PythonPlugin* plugin = ANJUTA_PLUGIN_PYTHON (indenter);
+
+	python_indent_auto (plugin,
+	                    start, end);
+}
+
+static void
+iindenter_iface_init (IAnjutaIndenterIface* iface)
+{
+	iface->indent = iindenter_indent;
+}
 
 ANJUTA_PLUGIN_BEGIN (PythonPlugin, python_plugin);
 ANJUTA_PLUGIN_ADD_INTERFACE(ipreferences, IANJUTA_TYPE_PREFERENCES);
+ANJUTA_PLUGIN_ADD_INTERFACE(iindenter, IANJUTA_TYPE_INDENTER);
 ANJUTA_PLUGIN_END;
 
 
diff --git a/plugins/language-support-python/python-indentation.c b/plugins/language-support-python/python-indentation.c
new file mode 100644
index 0000000..11b3083
--- /dev/null
+++ b/plugins/language-support-python/python-indentation.c
@@ -0,0 +1,914 @@
+/*
+ * python-indentation.c
+ *
+ * Copyright (C) 2011 - Johannes Schmid
+	 *
+ * 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 of the License, or
+ * (at your option) any later version.
+	 *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <libanjuta/anjuta-shell.h>
+#include <libanjuta/anjuta-debug.h>
+#include <libanjuta/anjuta-launcher.h>
+#include <libanjuta/anjuta-preferences.h>
+#include <libanjuta/interfaces/ianjuta-iterable.h>
+#include <libanjuta/interfaces/ianjuta-document.h>
+#include <libanjuta/interfaces/ianjuta-document-manager.h>
+#include <libanjuta/interfaces/ianjuta-editor.h>
+#include <libanjuta/interfaces/ianjuta-file.h>
+#include <libanjuta/interfaces/ianjuta-editor-cell.h>
+#include <libanjuta/interfaces/ianjuta-editor-language.h>
+#include <libanjuta/interfaces/ianjuta-editor-selection.h>
+#include <libanjuta/interfaces/ianjuta-editor-assist.h>
+#include <libanjuta/interfaces/ianjuta-preferences.h>
+#include <libanjuta/interfaces/ianjuta-symbol.h>
+#include <libanjuta/interfaces/ianjuta-language.h>
+
+#include "python-indentation.h"
+
+#define PREF_INDENT_AUTOMATIC "python-indent-automatic"
+#define PREF_INDENT_ADAPTIVE "python-indent-adaptive"
+#define PREF_INDENT_TAB_INDENTS "python-indent-tab-indents"
+#define PREF_INDENT_STATEMENT_SIZE "python-indent-statement-size"
+#define PREF_INDENT_BRACE_SIZE "python-indent-brace-size"
+
+#define TAB_SIZE (ianjuta_editor_get_tabsize (editor, NULL))
+
+#define USE_SPACES_FOR_INDENTATION (ianjuta_editor_get_use_spaces (editor, NULL))
+
+#define INDENT_SIZE \
+(plugin->param_statement_indentation >= 0? \
+plugin->param_statement_indentation : \
+g_settings_get_int (plugin->settings, PREF_INDENT_STATEMENT_SIZE))
+
+#define BRACE_INDENT \
+(plugin->param_brace_indentation >= 0? \
+plugin->param_brace_indentation : \
+g_settings_get_int (plugin->settings, PREF_INDENT_BRACE_SIZE))
+
+#define CASE_INDENT (INDENT_SIZE)
+#define LABEL_INDENT (INDENT_SIZE)
+
+static gboolean
+iter_is_newline (IAnjutaIterable *iter, gchar ch)
+{
+	if (ch == '\n' || ch == '\r')
+		return TRUE;
+	return FALSE;
+}
+
+/* Returns TRUE if iter was moved */
+static gboolean
+skip_iter_to_newline_head (IAnjutaIterable *iter, gchar ch)
+{
+	gboolean ret_val = FALSE;
+
+	if (ch == '\n')
+	{
+		/* Possibly at tail */
+		if (ianjuta_iterable_previous (iter, NULL))
+		{
+			ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
+			                                   0, NULL);
+			if (ch != '\r')
+				/* Already at head, undo iter */
+				ianjuta_iterable_next (iter, NULL);
+			else
+				/* Correctly at head */
+				ret_val = TRUE;
+		}
+	}
+	return ret_val;
+}
+
+/* Returns TRUE if iter was moved */
+static gboolean
+skip_iter_to_newline_tail (IAnjutaIterable *iter, gchar ch)
+{
+	gboolean ret_val = FALSE;
+
+	if (ch == '\r')
+	{
+		/* Possibly at head */
+		if (ianjuta_iterable_previous (iter, NULL))
+		{
+			ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
+			                                   0, NULL);
+			if (ch != '\n')
+				/* Already at tail, undo iter */
+				ianjuta_iterable_next (iter, NULL);
+			else
+				/* Correctly at tail */
+				ret_val = TRUE;
+		}
+	}
+	return ret_val;
+}
+
+/* Jumps to the reverse matching brace of the given brace character */
+
+static gint
+get_line_indentation (IAnjutaEditor *editor, gint line_num)
+{
+	IAnjutaIterable *line_begin, *line_end;
+	gchar *line_string, *idx;
+	gint line_indent = 0;
+
+	line_begin = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
+	line_end = ianjuta_editor_get_line_end_position (editor, line_num, NULL);
+	/*
+	 DEBUG_PRINT ("%s: line begin = %d, line end = %d", __FUNCTION__,
+	              line_begin, line_end);
+				  */
+	if (ianjuta_iterable_compare (line_begin, line_end, NULL) == 0)
+	{
+		g_object_unref (line_begin);
+		g_object_unref (line_end);
+		return 0;
+	}
+
+	line_string = ianjuta_editor_get_text (editor, line_begin, line_end,
+	                                       NULL);
+	g_object_unref (line_begin);
+	g_object_unref (line_end);
+
+	/* DEBUG_PRINT ("line_string = '%s'", line_string); */
+
+	if (!line_string)
+		return 0;
+
+	idx = line_string;
+
+	/* Find first non-white space */
+	while (*idx != '\0' && isspace (*idx))
+	{
+		if (*idx == '\t')
+			line_indent += TAB_SIZE;
+		else
+			line_indent++;
+		idx++; /* Since we are looking for first non-space char, simple
+		 * increment of the utf8 chars would do */
+	}
+	g_free (line_string);
+	return line_indent;
+}
+
+static gchar *
+get_line_indentation_string (IAnjutaEditor *editor, gint spaces, gint line_indent_spaces)
+{
+	gint i;
+	gchar *indent_string;
+
+	if ((spaces + line_indent_spaces) <= 0)
+		return NULL;
+
+	if (USE_SPACES_FOR_INDENTATION)
+	{
+		indent_string = g_new0 (gchar, spaces + line_indent_spaces + 1);
+		for (i = 0; i < (spaces + line_indent_spaces); i++)
+			indent_string[i] = ' ';
+	}
+	else
+	{
+		gint num_tabs = spaces / TAB_SIZE;
+		gint num_spaces = spaces % TAB_SIZE;
+		indent_string = g_new0 (gchar, num_tabs + num_spaces + line_indent_spaces + 1);
+
+		for (i = 0; i < num_tabs; i++)
+			indent_string[i] = '\t';
+		for (; i < num_tabs + (num_spaces + line_indent_spaces); i++)
+			indent_string[i] = ' ';
+	}
+	return indent_string;
+}
+
+static void
+set_indentation_param_emacs (PythonPlugin* plugin, const gchar *param,
+                             const gchar *value)
+{
+	//DEBUG_PRINT ("Setting indent param: %s = %s", param, value);
+	if (strcasecmp (param, "indent-tabs-mode") == 0)
+	{
+		if (strcasecmp (value, "t") == 0)
+		{
+			plugin->param_use_spaces = 0;
+			ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
+			                               FALSE, NULL);
+		}
+		else if (strcasecmp (value, "nil") == 0)
+		{
+			plugin->param_use_spaces = 1;
+			ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
+			                               TRUE, NULL);
+		}
+	}
+	else if (strcasecmp (param, "c-basic-offset") == 0)
+	{
+		plugin->param_statement_indentation = atoi (value);
+	}
+	else if (strcasecmp (param, "tab-width") == 0)
+	{
+		plugin->param_tab_size = atoi (value);
+		ianjuta_editor_set_tabsize (IANJUTA_EDITOR (plugin->current_editor),
+		                            plugin->param_tab_size, NULL);
+	}
+}
+
+static void
+set_indentation_param_vim (PythonPlugin* plugin, const gchar *param,
+                           const gchar *value)
+{
+	//DEBUG_PRINT ("Setting indent param: %s = %s", param, value);
+	if (g_str_equal (param, "expandtab") ||
+	    g_str_equal (param, "et"))
+	{
+		plugin->param_use_spaces = 1;
+		ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
+		                               TRUE, NULL);
+	}
+	else if (g_str_equal (param, "noexpandtabs") ||
+	         g_str_equal (param, "noet"))
+	{
+		plugin->param_use_spaces = 0;
+		ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
+		                               FALSE, NULL);
+	}
+	if (!value)
+		return;
+	else if (g_str_equal (param, "shiftwidth") ||
+	         g_str_equal (param, "sw"))
+	{
+		plugin->param_statement_indentation = atoi (value);
+	}
+	else if (g_str_equal (param, "softtabstop") ||
+	         g_str_equal (param, "sts") ||
+	         g_str_equal (param, "tabstop") ||
+	         g_str_equal (param, "ts"))
+	{
+		plugin->param_tab_size = atoi (value);
+		ianjuta_editor_set_tabsize (IANJUTA_EDITOR (plugin->current_editor),
+		                            plugin->param_tab_size, NULL);
+	}
+}
+
+static void
+parse_mode_line_emacs (PythonPlugin *plugin, const gchar *modeline)
+{
+	gchar **strv, **ptr;
+
+	strv = g_strsplit (modeline, ";", -1);
+	ptr = strv;
+	while (*ptr)
+	{
+		gchar **keyval;
+		keyval = g_strsplit (*ptr, ":", 2);
+		if (keyval[0] && keyval[1])
+		{
+			g_strstrip (keyval[0]);
+			g_strstrip (keyval[1]);
+			set_indentation_param_emacs (plugin, g_strchug (keyval[0]),
+			                             g_strchug (keyval[1]));
+		}
+		g_strfreev (keyval);
+		ptr++;
+	}
+	g_strfreev (strv);
+}
+
+static void
+parse_mode_line_vim (PythonPlugin *plugin, const gchar *modeline)
+{
+	gchar **strv, **ptr;
+
+	strv = g_strsplit (modeline, " ", -1);
+	ptr = strv;
+	while (*ptr)
+	{
+		gchar **keyval;
+		keyval = g_strsplit (*ptr, "=", 2);
+		if (keyval[0])
+		{
+			g_strstrip (keyval[0]);
+			if (keyval[1])
+			{
+				g_strstrip (keyval[1]);
+				set_indentation_param_vim (plugin, g_strchug (keyval[0]),
+				                           g_strchug (keyval[1]));
+			}
+			else
+				set_indentation_param_vim (plugin, g_strchug (keyval[0]),
+				                           NULL);        
+		}
+		g_strfreev (keyval);
+		ptr++;
+	}
+	g_strfreev (strv);
+}
+
+static gchar *
+extract_mode_line (const gchar *comment_text, gboolean* vim)
+{
+	/* Search for emacs-like modelines */
+	gchar *begin_modeline, *end_modeline;
+	begin_modeline = strstr (comment_text, "-*-");
+	if (begin_modeline)
+	{
+		begin_modeline += 3;
+		end_modeline = strstr (begin_modeline, "-*-");
+		if (end_modeline)
+		{
+			*vim = FALSE;
+			return g_strndup (begin_modeline, end_modeline - begin_modeline);
+		}
+	}
+	/* Search for vim-like modelines */
+	begin_modeline = strstr (comment_text, "vim:set");
+	if (begin_modeline)
+	{
+		begin_modeline += 7;
+		end_modeline = strstr (begin_modeline, ":");
+		/* Check for escape characters */
+		while (end_modeline)
+		{
+			if (!g_str_equal ((end_modeline - 1), "\\"))
+				break;
+			end_modeline++;
+			end_modeline = strstr (end_modeline, ":");
+		}
+		if (end_modeline)
+		{
+			gchar* vim_modeline = g_strndup (begin_modeline, end_modeline - begin_modeline);
+			*vim = TRUE;
+			return vim_modeline;
+		}
+	}
+	return NULL;
+}
+
+#define MINI_BUFFER_SIZE 3
+
+void
+python_indent_init (PythonPlugin* plugin)
+{
+	IAnjutaIterable *iter;
+	GString *comment_text;
+	gboolean comment_begun = FALSE;
+	gboolean line_comment = FALSE;
+	gchar mini_buffer[MINI_BUFFER_SIZE] = {0};
+
+	/* Initialize indentation parameters */
+	plugin->param_tab_size = -1;
+	plugin->param_statement_indentation = -1;
+	plugin->param_brace_indentation = -1;
+	plugin->param_case_indentation = -1;
+	plugin->param_label_indentation = -1;
+	plugin->param_use_spaces = -1;
+
+	/* Find the first comment text in the buffer */
+	comment_text = g_string_new (NULL);
+	iter = ianjuta_editor_get_start_position (IANJUTA_EDITOR (plugin->current_editor),
+	                                          NULL);
+	do
+	{
+		gboolean shift_buffer = TRUE;
+		gint i;
+		gchar ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
+		                                         0, NULL);
+
+		for (i = 0; i < MINI_BUFFER_SIZE - 1; i++)
+		{
+			if (mini_buffer[i] == '\0')
+			{
+				mini_buffer[i] = ch;
+				shift_buffer = FALSE;
+				break;
+			}
+		}
+		if (shift_buffer == TRUE)
+		{
+			/* Shift buffer and add */
+			for (i = 0; i < MINI_BUFFER_SIZE - 1; i++)
+				mini_buffer [i] = mini_buffer[i+1];
+			mini_buffer[i] = ch;
+		}
+
+		if (!comment_begun && strncmp (mini_buffer, "/*", 2) == 0)
+		{
+			comment_begun = TRUE;
+			/* Reset buffer */
+			mini_buffer[0] = mini_buffer[1] = '\0';
+		}
+		else if (!comment_begun && strncmp (mini_buffer, "//", 2) == 0)
+		                                    {
+												comment_begun = TRUE;
+												line_comment = TRUE;
+											}
+		                                    else if (!comment_begun && mini_buffer[1] != '\0')
+		                                    {
+												/* The buffer doesn't begin with a comment */
+												break;
+											}
+		                                    else if (comment_begun)
+		                                    {
+												if ((line_comment && ch == '\n') ||
+												    (!line_comment && strncmp (mini_buffer, "*/", 2) == 0))
+												{
+													break;
+												}
+											}
+
+		                                    if (comment_begun)
+		                                    g_string_append_c (comment_text, ch);
+
+	                                    }
+	while (ianjuta_iterable_next (iter, NULL));
+
+	/* DEBUG_PRINT ("Comment text: %s", comment_text->str);*/
+	if (comment_text->len > 0)
+	{
+
+		/* First comment found */
+		gboolean vim;
+		gchar *modeline = extract_mode_line (comment_text->str, &vim);
+		if (modeline)
+		{
+			if (!vim)
+				parse_mode_line_emacs (plugin, modeline);
+			else
+				parse_mode_line_vim (plugin, modeline);
+			g_free (modeline);
+		}
+	}
+	g_string_free (comment_text, TRUE);
+	g_object_unref (iter);
+}
+
+static gint
+set_line_indentation (IAnjutaEditor *editor, gint line_num, gint indentation, gint line_indent_spaces)
+{
+	IAnjutaIterable *line_begin, *line_end, *indent_position;
+	IAnjutaIterable *current_pos;
+	gint carat_offset, nchars = 0, nchars_removed = 0;
+	gchar *old_indent_string = NULL, *indent_string = NULL;
+
+	/* DEBUG_PRINT ("In %s()", __FUNCTION__); */
+	line_begin = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
+	line_end = ianjuta_editor_get_line_end_position (editor, line_num, NULL);
+
+	/*
+	 DEBUG_PRINT ("line begin = %d, line end = %d, current_pos = %d",
+	              line_begin, line_end, current_pos);
+				  */
+	indent_position = ianjuta_iterable_clone (line_begin, NULL);
+
+	if (ianjuta_iterable_compare (line_end, line_begin, NULL) > 0)
+	{
+		gchar *idx;
+		gchar *line_string = ianjuta_editor_get_text (editor, line_begin,
+		                                              line_end, NULL);
+
+		//DEBUG_PRINT ("line_string = '%s'", line_string);
+		if (line_string)
+		{
+			idx = line_string;
+
+			/* Find first non-white space */
+			while (*idx != '\0' && isspace (*idx))
+			{
+				idx = g_utf8_find_next_char (idx, NULL);
+				ianjuta_iterable_next (indent_position, NULL);
+			}
+			g_free (line_string);
+		}
+	}
+	/* Indent iter defined at this point, Identify how much is current
+	 * position is beyound this point. We need to restore it later after
+	 * indentation
+	 */
+	current_pos = ianjuta_editor_get_position (editor, NULL);
+	carat_offset = ianjuta_iterable_diff (indent_position, current_pos, NULL);
+	//DEBUG_PRINT ("carat offset is = %d", carat_offset);
+
+	/* Set new indentation */
+	if ((indentation + line_indent_spaces) > 0)
+	{
+		indent_string = get_line_indentation_string (editor, indentation, line_indent_spaces);
+		nchars = indent_string ? g_utf8_strlen (indent_string, -1) : 0;
+
+		/* Only indent if there is something to indent with */
+		if (indent_string)
+		{
+			/* Get existing indentation */
+			if (ianjuta_iterable_compare (indent_position, line_begin, NULL) > 0)
+			{
+				old_indent_string =
+					ianjuta_editor_get_text (editor, line_begin,
+					                         indent_position, NULL);
+
+				//DEBUG_PRINT ("old_indent_string = '%s'", old_indent_string);
+				nchars_removed = g_utf8_strlen (old_indent_string, -1);
+			}
+
+			/* Only indent if there was no indentation before or old
+			 * indentation string was different from the new indent string
+			 */
+			if (old_indent_string == NULL ||
+			    strcmp (old_indent_string, indent_string) != 0)
+			{
+				/* Remove the old indentation string, if there is any */
+				if (old_indent_string)
+					ianjuta_editor_erase (editor, line_begin,
+					                      indent_position, NULL);
+
+				/* Insert the new indentation string */
+				ianjuta_editor_insert (editor, line_begin,
+				                       indent_string, -1, NULL);
+			}
+		}
+	}
+
+	/* If indentation == 0, we really didn't enter the previous code block,
+	 * but we may need to clear existing indentation.
+	 */
+	if ((indentation + line_indent_spaces) == 0)
+	{
+		/* Get existing indentation */
+		if (ianjuta_iterable_compare (indent_position, line_begin, NULL) > 0)
+		{
+			old_indent_string =
+				ianjuta_editor_get_text (editor, line_begin,
+				                         indent_position, NULL);
+			nchars_removed = g_utf8_strlen (old_indent_string, -1);
+		}
+		if (old_indent_string)
+			ianjuta_editor_erase (editor, line_begin, indent_position, NULL);
+	}
+
+	/* Restore current position */
+	if (carat_offset >= 0)
+	{
+		/* If the cursor was not before the first non-space character in
+		 * the line, restore it's position after indentation.
+		 */
+		gint i;
+		IAnjutaIterable *pos = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
+		for (i = 0; i < nchars + carat_offset; i++)
+			ianjuta_iterable_next (pos, NULL);
+		ianjuta_editor_goto_position (editor, pos, NULL);
+		g_object_unref (pos);
+	}
+	else /* cursor_offset < 0 */
+	{
+		/* If the cursor was somewhere in the old indentation spaces,
+		 * home the cursor to first non-space character in the line (or
+		                                                             * end of line if there is no non-space characters in the line.
+		 */
+		gint i;
+		IAnjutaIterable *pos = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
+		for (i = 0; i < nchars; i++)
+			ianjuta_iterable_next (pos, NULL);
+		ianjuta_editor_goto_position (editor, pos, NULL);
+		g_object_unref (pos);
+	}
+
+	g_object_unref (current_pos);
+	g_object_unref (indent_position);
+	g_object_unref (line_begin);
+	g_object_unref (line_end);
+
+	g_free (old_indent_string);
+	g_free (indent_string);
+	return nchars;
+}
+
+/*  incomplete_statement:
+ *  1 == COMPLETE STATEMENT
+ *  0 == INCOMPLETE STATEMENT
+ * -1 == UNKNOWN
+ */
+
+static gchar*
+get_current_statement (IAnjutaEditor *editor, gint line_num, gint *found_line_num)
+{
+	gchar point_ch;
+	IAnjutaIterable *iter = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
+	gchar statement[1024];
+	gint counter=0;
+
+	do
+	{
+		point_ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0, NULL);
+
+		if (!ianjuta_iterable_next (iter, NULL) )
+			break;
+	} while (point_ch == ' ' || point_ch == '\t'); // Whitespace
+
+	if (!ianjuta_iterable_previous (iter, NULL))
+		return "";
+
+	do
+	{
+		point_ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0, NULL);
+		statement[counter++] = point_ch;
+
+		if (!ianjuta_iterable_next (iter, NULL) )
+			break;
+	} while (isalpha(point_ch) || isdigit(point_ch)); // FIXME: Is this UTF-8 compatible?
+	statement[counter-1] = '\0';
+
+	g_object_unref (iter);
+	return g_strdup_printf("%s", statement);
+}
+
+static gchar 
+get_last_char (IAnjutaEditor *editor, gint line_num, gint *found_line_num)
+{
+	gchar point_ch;
+	IAnjutaIterable *iter = ianjuta_editor_get_line_end_position (editor, line_num, NULL);
+
+	do
+	{
+		if (ianjuta_iterable_previous (iter, NULL) )
+		{
+			point_ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0,
+			                                         NULL); 
+		}
+		else
+			break;
+	} 
+	while (point_ch == ' ' || point_ch == '\n' || point_ch == '\r' || point_ch == '\t'); // Whitespace
+
+	*found_line_num = ianjuta_editor_get_line_from_position (editor, iter, NULL);
+	return point_ch;
+}
+
+static gboolean
+spaces_only (IAnjutaEditor* editor, IAnjutaIterable* begin, IAnjutaIterable* end);
+
+static gboolean
+is_spaces_only (IAnjutaEditor *editor, gint line_num)
+{
+	IAnjutaIterable* begin = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
+	IAnjutaIterable* end = ianjuta_editor_get_line_end_position (editor, line_num , NULL);
+
+	if (spaces_only (editor, begin, end))
+	{
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gint
+get_line_indentation_base (PythonPlugin *plugin,
+                           IAnjutaEditor *editor,
+                           gint line_num,
+                           gint *incomplete_statement,
+                           gint *line_indent_spaces,
+                           gboolean *colon_indent)
+{
+	IAnjutaIterable *iter;
+	gchar point_ch;
+	gint line_indent = 0;
+	gint currentline = line_num - 1;
+	gchar *last_line_statement;
+
+	*incomplete_statement = 0;
+	*line_indent_spaces = 0;
+
+	if (currentline <= 1)
+		return 0;
+
+	iter = ianjuta_editor_get_line_end_position (editor, line_num, NULL);
+
+	point_ch = get_last_char (editor, currentline, &currentline);
+	last_line_statement = get_current_statement (editor, currentline, &currentline);
+
+	if (!g_strcmp0(last_line_statement, "return") || 
+	    !g_strcmp0(last_line_statement, "break") ||
+	    !g_strcmp0(last_line_statement, "pass") || 
+	    !g_strcmp0(last_line_statement, "raise") || 	    
+	    !g_strcmp0(last_line_statement, "continue") )
+	{					
+		if (get_line_indentation (editor, currentline)>= INDENT_SIZE)
+			line_indent = get_line_indentation (editor, currentline) - INDENT_SIZE;
+	}
+	else if (point_ch == ':')
+	{
+		line_indent = get_line_indentation (editor, currentline) + INDENT_SIZE;
+	}
+	else
+	{
+		gint line = currentline;
+		while (is_spaces_only(editor, line) && line >= 0)
+			line--;
+		line_indent = get_line_indentation (editor, line);
+	}
+
+	return line_indent;
+}
+
+static gboolean
+spaces_only (IAnjutaEditor* editor, IAnjutaIterable* begin, IAnjutaIterable* end)
+{
+	gboolean empty = TRUE;
+	gchar* idx;
+	gchar* text = ianjuta_editor_get_text (editor, begin, end, NULL);
+
+	if (text == NULL)
+		return TRUE;
+
+
+	for (idx = text; *idx != '\0'; idx++)
+	{
+		if (!isspace(*idx))
+		{
+			empty = FALSE;
+			break;
+		}
+	}
+	g_free(text);
+	return empty;
+}
+
+static gint
+get_line_auto_indentation (PythonPlugin *plugin, IAnjutaEditor *editor,
+                           gint line, gint *line_indent_spaces)
+{
+	IAnjutaIterable *iter;
+	gint line_indent = 0;
+	gint incomplete_statement = -1;
+	gboolean colon_indent = FALSE;
+
+	g_return_val_if_fail (line > 0, 0);
+
+	if (line == 1) /* First line */
+	{
+		return 0;
+	}
+	else
+	{
+		IAnjutaIterable* begin = ianjuta_editor_get_line_begin_position (editor, line -1 , NULL);
+		IAnjutaIterable* end = ianjuta_editor_get_line_end_position (editor, line -1 , NULL);
+
+		if (spaces_only (editor, begin, end))
+		{
+			set_line_indentation (editor, line -1, 0, 0);
+		}
+		g_object_unref (begin);
+		g_object_unref (end);
+	}
+
+	iter = ianjuta_editor_get_line_begin_position (editor, line, NULL);
+
+	/*	if (is_iter_inside_string (iter))
+	{
+		line_indent = get_line_indentation (editor, line - 1);
+}
+else
+{*/
+	line_indent = get_line_indentation_base (plugin, editor, line,
+	                                         &incomplete_statement, 
+	                                         line_indent_spaces,
+	                                         &colon_indent);
+	/*}*/
+
+	/* Determine what the first non-white char in the line is */
+	do
+	{
+		gchar ch;
+		/* Check if we are *inside* comment or string. Begining of comment
+		 * or string does not count as inside. If inside, just align with
+		 * previous indentation.
+		 */
+		/*if (is_iter_inside_string (iter))
+		{
+			line_indent = get_line_indentation (editor, line - 1);
+			break;
+	}*/
+		ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
+		                                   0, NULL);
+		if (iter_is_newline (iter, ch))
+		{
+			skip_iter_to_newline_tail (iter, ch);
+
+			/* First levels are excused from incomplete statement indent */
+			if (incomplete_statement == 1 && line_indent > 0)
+				line_indent += INDENT_SIZE;
+			break;
+		}
+
+		else if (!isspace (ch))
+		{
+			/* First levels are excused from incomplete statement indent */
+			if (incomplete_statement == 1 && line_indent > 0)
+				line_indent += INDENT_SIZE;
+			break;
+		}
+
+	}
+	while (ianjuta_iterable_next (iter, NULL));
+	g_object_unref (iter);
+
+	return line_indent;
+}
+
+void
+python_indent (PythonPlugin *plugin,
+               IAnjutaEditor *editor,
+               IAnjutaIterable *insert_pos,
+               gchar ch)
+{
+	IAnjutaIterable *iter;
+	gboolean should_auto_indent = FALSE;
+
+	iter = ianjuta_iterable_clone (insert_pos, NULL);
+
+	/* If autoindent is enabled*/
+	if (g_settings_get_boolean (plugin->settings, PREF_INDENT_AUTOMATIC))
+	{
+		if (iter_is_newline (iter, ch))
+		{
+			skip_iter_to_newline_head (iter, ch);
+			/* All newline entries means enable indenting */
+			should_auto_indent = TRUE;
+		}
+
+		if (should_auto_indent)
+		{
+			gint insert_line;
+			gint line_indent;
+			gint line_indent_spaces;
+
+			ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT(editor), NULL);
+			python_indent_init (plugin);
+
+			insert_line = ianjuta_editor_get_lineno (editor, NULL);
+			line_indent = get_line_auto_indentation (plugin, editor, insert_line, &line_indent_spaces);
+			set_line_indentation (editor, insert_line, line_indent, line_indent_spaces);
+			ianjuta_document_end_undo_action (IANJUTA_DOCUMENT(editor), NULL);
+		}
+	}
+
+
+	g_object_unref (iter);
+}
+
+void
+python_indent_auto (PythonPlugin* lang_plugin,
+                    IAnjutaIterable* start,
+                    IAnjutaIterable* end)
+{
+	gint line_start, line_end;
+	gint insert_line;
+	gint line_indent;
+	gboolean has_selection;
+
+	IAnjutaEditor *editor;
+	editor = IANJUTA_EDITOR (lang_plugin->current_editor);
+
+	has_selection = ianjuta_editor_selection_has_selection
+		(IANJUTA_EDITOR_SELECTION (editor), NULL);
+	if (has_selection)
+	{
+		IAnjutaIterable *sel_start, *sel_end;
+		sel_start = ianjuta_editor_selection_get_start (IANJUTA_EDITOR_SELECTION (editor),
+		                                                NULL);
+		sel_end = ianjuta_editor_selection_get_end (IANJUTA_EDITOR_SELECTION (editor),
+		                                            NULL);
+		line_start = ianjuta_editor_get_line_from_position (editor, sel_start, NULL);
+		line_end = ianjuta_editor_get_line_from_position (editor, sel_end, NULL);
+		g_object_unref (sel_start);
+		g_object_unref (sel_end);
+	}
+	else
+	{
+		line_start = ianjuta_editor_get_lineno (IANJUTA_EDITOR(editor), NULL);
+		line_end = line_start;
+	}
+	ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT(editor), NULL);
+	python_indent_init (lang_plugin);
+
+	for (insert_line = line_start; insert_line <= line_end; insert_line++)
+	{
+		gint line_indent_spaces = 0;
+		line_indent = get_line_auto_indentation (lang_plugin, editor,
+		                                         insert_line,
+		                                         &line_indent_spaces);
+		set_line_indentation (editor, insert_line, line_indent, line_indent_spaces);
+	}
+	ianjuta_document_end_undo_action (IANJUTA_DOCUMENT(editor), NULL);
+}
diff --git a/plugins/language-support-python/python-indentation.h b/plugins/language-support-python/python-indentation.h
new file mode 100644
index 0000000..899eff5
--- /dev/null
+++ b/plugins/language-support-python/python-indentation.h
@@ -0,0 +1,39 @@
+/*
+ * python-indentation.h
+ *
+ * Copyright (C) 2011 - Johannes Schmid
+ *
+ * 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 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 PYTHON_INDENTATION_H
+#define PYTHON_INDENTATION_H
+
+#include "plugin.h"
+
+#include <libanjuta/interfaces/ianjuta-iterable.h>
+#include <libanjuta/interfaces/ianjuta-editor.h>
+
+void python_indent_init (PythonPlugin* lang_plugin);
+
+void python_indent (PythonPlugin* lang_plugin, 
+                    IAnjutaEditor* editor, 
+                    IAnjutaIterable* insert_pos,
+                    gchar ch);
+
+void python_indent_auto (PythonPlugin* lang_plugin,
+                         IAnjutaIterable* start,
+                         IAnjutaIterable* end);
+
+#endif
\ No newline at end of file



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