? folding.patch
? folding2.patch
Index: gtksourceview/gtksourcebuffer-private.h
===================================================================
RCS file: gtksourceview/gtksourcebuffer-private.h
diff -N gtksourceview/gtksourcebuffer-private.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gtksourceview/gtksourcebuffer-private.h	25 Aug 2005 08:30:12 -0000
@@ -0,0 +1,48 @@
+/*  gtksourcebuffer-private.h
+ *
+ *  Copyright (C) 2005 - Jeroen Zwartepoorte <jeroen.zwartepoorte@gmail.com>
+ *
+ *  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_BUFFER_PRIVATE_H__
+#define __GTK_SOURCE_BUFFER_PRIVATE_H__
+
+#include "gtksourcebuffer.h"
+
+G_BEGIN_DECLS
+
+struct _GtkSourceFold
+{
+	GtkTextMark	*start_line;
+	GtkTextMark	*end_line;
+	GSList		*children;
+	gboolean	 folded;
+	gboolean	 prelighted;
+	gboolean	 animated;
+	GtkExpanderStyle expander_style;
+};
+
+GSList		*gtk_source_buffer_get_folds_in_region	(GtkSourceBuffer   *buffer,
+							 const GtkTextIter *begin,
+							 const GtkTextIter *end);
+
+GtkSourceFold	*gtk_source_buffer_get_fold_at_line	(GtkSourceBuffer   *buffer,
+							 gint               line);
+
+G_END_DECLS
+
+#endif  /* __GTK_SOURCE_LANGUAGE_PRIVATE_H__ */
+
Index: gtksourceview/gtksourcebuffer.c
===================================================================
RCS file: /cvs/gnome/gtksourceview/gtksourceview/gtksourcebuffer.c,v
retrieving revision 1.39
diff -u -p -r1.39 gtksourcebuffer.c
--- gtksourceview/gtksourcebuffer.c	21 Jun 2005 17:29:28 -0000	1.39
+++ gtksourceview/gtksourcebuffer.c	25 Aug 2005 08:30:14 -0000
@@ -33,6 +33,7 @@
 
 #include "gtksourceview-i18n.h"
 #include "gtksourcebuffer.h"
+#include "gtksourcebuffer-private.h"
 #include "gtksourcetag.h"
 #include "gtksourcetag-private.h"
 
@@ -72,6 +73,8 @@
 
 #define MAX_CHARS_BEFORE_FINDING_A_MATCH    2000
 
+#define INVISIBLE_LINE			    "GtkSourceBuffer:InvisibleLine"
+
 typedef struct _SyntaxDelimiter      SyntaxDelimiter;
 typedef struct _PatternMatch         PatternMatch;
 
@@ -139,6 +142,8 @@ struct _GtkSourceBufferPrivate 
 	GtkSourceLanguage     *language;
 
 	GtkSourceUndoManager  *undo_manager;
+	
+	GSList                *folds;
 };
 
 
@@ -380,6 +385,7 @@ gtk_source_buffer_init (GtkSourceBuffer 
 	priv->check_brackets = TRUE;
 	priv->bracket_mark = NULL;
 	priv->bracket_found = FALSE;
+	priv->folds = NULL;
 	
 	priv->markers = g_array_new (FALSE, FALSE, sizeof (GtkSourceMarker *));
 
@@ -480,6 +486,10 @@ gtk_source_buffer_constructor (GType    
 
 		gtk_source_tag_style_free (tag_style);
 
+		/* Create invisibility tag for folding lines. */
+		gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (source_buffer),
+					    INVISIBLE_LINE, "invisible", TRUE, NULL);
+
 		if (GTK_IS_SOURCE_TAG_TABLE (GTK_TEXT_BUFFER (source_buffer)->tag_table))
 		{
 			g_signal_connect (GTK_TEXT_BUFFER (source_buffer)->tag_table ,
@@ -3690,3 +3700,456 @@ gtk_source_buffer_get_prev_marker (GtkSo
 	return marker;
 }
 
+static gboolean
+insert_child_fold (GtkSourceBuffer *buffer,
+		   GtkSourceFold   *child,
+		   GtkSourceFold   *parent)
+{
+	GtkTextIter begin, end, pbegin, pend, iter;
+	GSList *folds;
+	GtkSourceFold *child_fold;
+	
+	gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+					  &begin, child->start_line);
+	gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+					  &end, child->end_line);
+
+	gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+					  &pbegin, parent->start_line);
+	gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+					  &pend, parent->end_line);
+
+	g_message ("insert child (%d, %d) into parent (%d, %d)",
+		   gtk_text_iter_get_line (&begin),
+		   gtk_text_iter_get_line (&end),
+		   gtk_text_iter_get_line (&pbegin),
+		   gtk_text_iter_get_line (&pend));
+
+	/* check if the child fold is within the parent fold. */
+	if (gtk_text_iter_compare (&pbegin, &begin) == -1 &&
+	    gtk_text_iter_compare (&pend, &end) == 1)
+	{
+		/* fold already has children; try inserting it into one. */
+		if (parent->children != NULL)
+		{
+			folds = parent->children;
+			
+			/* try inserting the child fold recursively. */
+			while (folds != NULL)
+			{
+				child_fold = folds->data;
+			
+				gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+								  &iter, child_fold->start_line);
+				/* check if the current fold is past the new fold. */
+				if (gtk_text_iter_compare (&iter, &end) == 1)
+				{
+					g_message ("adding fold before child @ %d", gtk_text_iter_get_line (&iter));
+					parent->children = g_slist_insert_before (parent->children,
+										  folds, child);
+					return TRUE;
+				}
+
+				if (insert_child_fold (buffer, child, parent))
+					return TRUE;
+				
+				folds = g_slist_next (folds);
+			}
+		}
+
+		/* fold is inside parent, but not a child of parent. */		
+		g_message ("adding fold to parent fold @ %d", gtk_text_iter_get_line (&pbegin));
+		parent->children = g_slist_append (parent->children, child);
+		return TRUE;
+	}
+	else if (gtk_text_iter_in_range (&pbegin, &begin, &end) ||
+	         gtk_text_iter_in_range (&pend, &begin, &end))
+	{
+		g_warning ("Cannot add child fold: fold overlapses with an existing fold.");
+	}
+	
+	return FALSE;
+}
+
+GtkSourceFold *
+gtk_source_buffer_add_fold (GtkSourceBuffer   *buffer,
+			    const GtkTextIter *begin,
+			    const GtkTextIter *end)
+{
+	GSList *folds;
+	GtkSourceFold *fold, *parent;
+	GtkTextIter iter;
+
+	g_return_val_if_fail (GTK_IS_SOURCE_BUFFER (buffer), NULL);
+	g_return_val_if_fail (begin != NULL, NULL);
+	g_return_val_if_fail (end != NULL, NULL);
+
+	g_message ("add fold @ %d, %d", gtk_text_iter_get_line (begin), gtk_text_iter_get_line (end));
+
+	fold = g_new0 (GtkSourceFold, 1);
+	fold->children = NULL;
+	fold->folded = FALSE;
+	fold->prelighted = FALSE;
+	fold->animated = FALSE;
+	fold->expander_style = GTK_EXPANDER_EXPANDED;
+	
+	fold->start_line = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (buffer),
+							NULL, begin, FALSE);
+	fold->end_line = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (buffer),
+						      NULL, end, FALSE);
+	
+	/* Insert the fold either at the root level or as a child of an existing fold. */
+	folds = buffer->priv->folds;
+	while (folds != NULL) {
+		parent = folds->data;
+
+		/* check if the current fold is past the new fold. */
+		gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+						  &iter, parent->start_line);
+		if (gtk_text_iter_compare (&iter, end) == 1)
+		{
+			g_message ("adding fold before root %d", gtk_text_iter_get_line (&iter)); 
+			buffer->priv->folds = g_slist_insert_before (buffer->priv->folds,
+								     folds, fold);
+			break;
+		}
+
+		/* try adding the child to all folds in the region. */
+		if (insert_child_fold (buffer, fold, parent))
+			break;
+	
+		folds = g_slist_next (folds);
+	}
+	
+	/* add the fold at the end of the list. */
+	if (folds == NULL) {
+		g_message ("adding fold at end of root");
+		buffer->priv->folds = g_slist_append (buffer->priv->folds, fold);
+	}
+	
+	return fold;
+}
+
+static void
+foreach_fold_region (gpointer data, gpointer user_data)
+{
+	gtk_source_buffer_remove_fold (GTK_SOURCE_BUFFER (user_data), data);
+}
+
+void
+gtk_source_buffer_remove_fold (GtkSourceBuffer *buffer,
+			       GtkSourceFold   *fold)
+{
+	g_return_if_fail (GTK_IS_SOURCE_BUFFER (buffer));
+	g_return_if_fail (fold != NULL);
+	g_return_if_fail (g_slist_index (buffer->priv->folds, fold) != -1);
+	
+	if (fold->folded) {
+		/* FIXME */
+	}
+	
+	gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer), fold->start_line);
+	gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer), fold->end_line);
+	
+	buffer->priv->folds = g_slist_remove (buffer->priv->folds, fold);
+	
+	g_slist_foreach (buffer->priv->folds, foreach_fold_region, buffer);
+	
+	g_free (fold);
+}
+
+gboolean
+gtk_source_buffer_get_folded (GtkSourceBuffer *buffer,
+			      GtkSourceFold   *fold)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_BUFFER (buffer), FALSE);
+	g_return_val_if_fail (fold != NULL, FALSE);
+
+	return fold->folded;
+}
+
+static void
+reapply_invisibleline_tag (GtkTextBuffer *buffer,
+			   GSList        *folds)
+{
+	GtkSourceFold *fold;
+	GtkTextIter begin, end;
+	
+	while (folds != NULL) {
+		fold = folds->data;
+		
+		if (fold->folded) {
+			gtk_text_buffer_get_iter_at_mark (buffer, &begin,
+							  fold->start_line);	
+			gtk_text_buffer_get_iter_at_mark (buffer, &end,
+							  fold->end_line);
+			gtk_text_buffer_apply_tag_by_name (buffer, INVISIBLE_LINE,
+							   &begin, &end);
+		} else if (fold->children != NULL) {
+			reapply_invisibleline_tag (buffer, fold->children);
+		}
+	
+		folds = g_slist_next (folds);
+	}
+}
+
+void
+gtk_source_buffer_set_folded (GtkSourceBuffer *buffer,
+			      GtkSourceFold   *fold,
+			      gboolean         folded)
+{
+	GtkTextIter begin, end, insert;
+
+	g_return_if_fail (GTK_IS_SOURCE_BUFFER (buffer));
+	g_return_if_fail (fold != NULL);
+
+	folded = (folded != FALSE);
+	
+	if (fold->folded == folded)
+		return;
+	
+	fold->folded = folded;
+
+	gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+					  &begin, fold->start_line);	
+	gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+					  &end, fold->end_line);
+	
+	if (folded) {
+		gtk_text_buffer_apply_tag_by_name (GTK_TEXT_BUFFER (buffer),
+						   INVISIBLE_LINE,
+						   &begin, &end);
+
+		gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+						  &insert,
+						  gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (buffer)));
+		
+		/* make the cursor visible again if it was inside the fold. */
+		if (gtk_text_iter_in_range (&insert, &begin, &end)) {
+			if (!gtk_text_iter_forward_visible_cursor_position (&insert))
+				gtk_text_iter_backward_visible_cursor_position (&insert);
+		
+			gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (buffer), &insert);
+		}
+	
+		if (!fold->animated)
+			fold->expander_style = GTK_EXPANDER_COLLAPSED;
+	} else {
+		gtk_text_buffer_remove_tag_by_name (GTK_TEXT_BUFFER (buffer),
+						    INVISIBLE_LINE,
+						    &begin, &end);
+		
+		/* reapply the invisibleline tag to collapsed children. */
+		if (fold->children != NULL)
+			reapply_invisibleline_tag (GTK_TEXT_BUFFER (buffer),
+						   fold->children);
+		
+		if (!fold->animated)
+			fold->expander_style = GTK_EXPANDER_EXPANDED;
+	}
+}
+
+void
+gtk_source_buffer_get_fold_bounds (GtkSourceBuffer *buffer,
+				   GtkSourceFold   *fold,
+				   GtkTextIter     *begin,
+				   GtkTextIter     *end)
+{
+	g_return_if_fail (GTK_IS_SOURCE_BUFFER (buffer));
+	g_return_if_fail (fold != NULL && begin != NULL && end != NULL);
+	
+	gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+					  begin, fold->start_line);
+	gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+					  end, fold->end_line);
+}
+
+static void
+get_folds_in_region (GtkTextBuffer     *buffer,
+		     const GtkTextIter *begin,
+		     const GtkTextIter *end,
+		     GtkSourceFold     *fold,
+		     GSList           **list)
+{
+	GtkTextIter fbegin, fend;
+	GSList *children;
+
+	gtk_text_buffer_get_iter_at_mark (buffer, &fbegin, fold->start_line);
+	gtk_text_buffer_get_iter_at_mark (buffer, &fend, fold->end_line);
+
+	/* the region lies in the fold, so add any children in the region. */
+	if (gtk_text_iter_compare (&fbegin, begin) == -1 &&
+	    gtk_text_iter_compare (&fend, end) >= 0)
+	{
+		children = fold->children;
+		while (children != NULL) {
+			get_folds_in_region (buffer, begin, end, children->data, list);
+			children = g_slist_next (children);
+		}
+	}
+	/* the entire fold lies in the region, so add the fold + children. */
+	else if (gtk_text_iter_compare (&fbegin, begin) >= 0 &&
+	         gtk_text_iter_compare (&fend, end) <= 0)
+	{
+		*list = g_slist_append (*list, fold);
+		children = fold->children;
+		while (children != NULL) {
+			get_folds_in_region (buffer, begin, end, children->data, list);
+			children = g_slist_next (children);
+		}
+	}
+	/* start iter is in the region, so add the fold first. */
+	else if (gtk_text_iter_compare (&fbegin, begin) >= 0 &&
+	         gtk_text_iter_compare (&fbegin, end) <= 0)
+	{
+		*list = g_slist_append (*list, fold);
+		children = fold->children;
+		while (children != NULL) {
+			get_folds_in_region (buffer, begin, end, children->data, list);
+			children = g_slist_next (children);
+		}
+	}
+}
+
+/**
+ * gtk_source_buffer_get_folds_in_region:
+ * @buffer: a #GtkSourceBuffer.
+ * @begin: the begin point of the region.
+ * @end: the end point of the region>
+ * 
+ * Return a list of all folds in the specified region. This is a flattened list
+ * of the parent->child fold hierarchy. This function is mainly used in 
+ * gtk_source_view_get_lines to determine which folds to draw.
+ * 
+ * Return value: a #GSList of the #GtkSourceFold's in the region, or %NULL if
+ * there are no folds in the region.
+ **/
+GSList *
+gtk_source_buffer_get_folds_in_region (GtkSourceBuffer   *buffer,
+				       const GtkTextIter *begin,
+				       const GtkTextIter *end)
+{
+	GSList *result, *folds;
+	GtkSourceFold *fold;
+
+	g_return_val_if_fail (GTK_IS_SOURCE_BUFFER (buffer), NULL);
+	g_return_val_if_fail (begin != NULL && end != NULL, NULL);
+
+	result = NULL;
+	folds = buffer->priv->folds;
+	while (folds != NULL)
+	{
+		fold = folds->data;
+
+		get_folds_in_region (GTK_TEXT_BUFFER (buffer), begin, end, fold, &result);
+
+		folds = g_slist_next (folds);
+	}
+
+	return result;
+}
+
+static GtkSourceFold *
+find_fold_at_line (GtkTextBuffer *buffer,
+		   GSList        *folds,
+		   gint           line)
+{
+	GtkSourceFold *fold;
+	GtkTextIter iter;
+	gint start_line, end_line;
+			
+	while (folds != NULL)
+	{
+		fold = folds->data;
+		
+		gtk_text_buffer_get_iter_at_mark (buffer, &iter, fold->start_line);
+		start_line = gtk_text_iter_get_line (&iter);
+		gtk_text_buffer_get_iter_at_mark (buffer, &iter, fold->end_line);
+		end_line = gtk_text_iter_get_line (&iter);
+		
+		if (line >= start_line && line <= end_line) {
+			GtkSourceFold *child;
+		
+			if (!fold->children)
+				return fold;
+			
+			child = find_fold_at_line (buffer, fold->children, line);
+			if (child)
+				return child;
+			else
+				return fold;
+		}
+	
+		folds = g_slist_next (folds);
+	}
+	
+	return NULL;
+}
+
+GtkSourceFold *
+gtk_source_buffer_get_fold_at_line (GtkSourceBuffer *buffer,
+				    gint             line)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_BUFFER (buffer), NULL);
+	g_return_val_if_fail (line >= 0, NULL);
+
+	return find_fold_at_line (GTK_TEXT_BUFFER (buffer),
+				  buffer->priv->folds,
+				  line);
+}
+
+static GtkSourceFold *
+find_fold_at_iter (GtkTextBuffer     *buffer,
+		   GSList            *folds,
+		   const GtkTextIter *iter)
+{
+	GtkSourceFold *fold;
+	GtkTextIter start_iter, end_iter;
+	
+	while (folds != NULL)
+	{
+		fold = folds->data;
+		
+		gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, fold->start_line);
+		gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, fold->end_line);
+		
+		if (gtk_text_iter_compare (&start_iter, iter) <= 0 &&
+		    gtk_text_iter_compare (&end_iter, iter) >= 0)
+		{
+			GtkSourceFold *child;
+		
+			if (!fold->children)
+				return fold;
+			
+			child = find_fold_at_iter (buffer, fold->children, iter);
+			if (child)
+				return child;
+			else
+				return fold;
+		}
+	
+		folds = g_slist_next (folds);
+	}
+	
+	return NULL;
+}
+
+GtkSourceFold *
+gtk_source_buffer_get_fold_at_iter (GtkSourceBuffer   *buffer,
+				    const GtkTextIter *iter)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_BUFFER (buffer), NULL);
+	g_return_val_if_fail (iter != NULL, NULL);
+
+	return find_fold_at_iter (GTK_TEXT_BUFFER (buffer),
+				  buffer->priv->folds,
+				  iter);
+}
+
+const GSList *
+gtk_source_buffer_get_root_folds (GtkSourceBuffer *buffer)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_BUFFER (buffer), NULL);
+	
+	return buffer->priv->folds;
+}
Index: gtksourceview/gtksourcebuffer.h
===================================================================
RCS file: /cvs/gnome/gtksourceview/gtksourceview/gtksourcebuffer.h,v
retrieving revision 1.18
diff -u -p -r1.18 gtksourcebuffer.h
--- gtksourceview/gtksourcebuffer.h	6 Jun 2003 08:54:36 -0000	1.18
+++ gtksourceview/gtksourcebuffer.h	25 Aug 2005 08:30:14 -0000
@@ -42,6 +42,7 @@ G_BEGIN_DECLS
 typedef struct _GtkSourceBuffer			GtkSourceBuffer;
 typedef struct _GtkSourceBufferClass		GtkSourceBufferClass;
 typedef struct _GtkSourceBufferPrivate		GtkSourceBufferPrivate;
+typedef struct _GtkSourceFold			GtkSourceFold;
 
 struct _GtkSourceBuffer 
 {
@@ -68,7 +69,6 @@ struct _GtkSourceBufferClass 
 	void (*_gtk_source_reserved1) 	(void);
 	void (*_gtk_source_reserved2) 	(void);
 	void (*_gtk_source_reserved3) 	(void);
-
 };
 
 #include <gtksourceview/gtksourcemarker.h>
@@ -140,6 +140,29 @@ GtkSourceMarker         *gtk_source_buff
 								 GtkTextIter            *iter);
 GtkSourceMarker         *gtk_source_buffer_get_prev_marker      (GtkSourceBuffer        *buffer,
 								 GtkTextIter            *iter);
+
+/* fold methods. */
+GtkSourceFold		*gtk_source_buffer_add_fold		(GtkSourceBuffer        *buffer,
+								 const GtkTextIter      *begin,
+								 const GtkTextIter      *end);
+void			 gtk_source_buffer_remove_fold		(GtkSourceBuffer        *buffer,
+								 GtkSourceFold          *fold);
+
+gboolean		 gtk_source_buffer_get_folded		(GtkSourceBuffer        *buffer,
+								 GtkSourceFold          *fold);
+void			 gtk_source_buffer_set_folded		(GtkSourceBuffer        *buffer,
+								 GtkSourceFold          *fold,
+								 gboolean                folded);
+
+void                     gtk_source_buffer_get_fold_bounds	(GtkSourceBuffer        *buffer,
+								 GtkSourceFold          *fold,
+								 GtkTextIter            *begin,
+								 GtkTextIter            *end);
+
+GtkSourceFold		*gtk_source_buffer_get_fold_at_iter	(GtkSourceBuffer        *buffer,
+								 const GtkTextIter      *iter);
+
+const GSList		*gtk_source_buffer_get_root_folds	(GtkSourceBuffer        *buffer);
 
 /* INTERNAL private stuff - not even exported from the library on
  * many platforms
Index: gtksourceview/gtksourceview.c
===================================================================
RCS file: /cvs/gnome/gtksourceview/gtksourceview/gtksourceview.c,v
retrieving revision 1.39
diff -u -p -r1.39 gtksourceview.c
--- gtksourceview/gtksourceview.c	3 Aug 2005 16:52:10 -0000	1.39
+++ gtksourceview/gtksourceview.c	25 Aug 2005 08:30:16 -0000
@@ -36,6 +36,7 @@
 #include "gtksourceview-i18n.h"
 #include "gtksourceview-marshal.h"
 #include "gtksourceview.h"
+#include "gtksourcebuffer-private.h"
 
 /*
 #define ENABLE_DEBUG
@@ -58,6 +59,11 @@
 #define DEFAULT_MARGIN			80
 #define MAX_MARGIN			200
 
+#define DEFAULT_EXPANDER_SIZE		12
+#define EXPANDER_EXTRA_PADDING		4
+
+typedef struct _MarginLine MarginLine;
+
 /* Signals */
 enum {
 	UNDO,
@@ -76,7 +82,8 @@ enum {
 	PROP_SHOW_MARGIN,
 	PROP_MARGIN,
 	PROP_SMART_HOME_END,
-	PROP_HIGHLIGHT_CURRENT_LINE
+	PROP_HIGHLIGHT_CURRENT_LINE,
+	PROP_SHOW_FOLD_REGIONS
 };
 
 struct _GtkSourceViewPrivate
@@ -96,6 +103,13 @@ struct _GtkSourceViewPrivate
 
 	GtkSourceBuffer *source_buffer;
 	gint		 old_lines;
+	
+	gboolean	 show_fold_regions;
+	gint		 expander_size;
+	gint		 prelight_fold_line;
+	gboolean	 fold_button_down;
+	guint		 animation_timeout;
+	gint		 animate_fold_line;
 };
 
 /* Implement DnD for application/x-color drops */
@@ -127,6 +141,14 @@ static void 	set_source_buffer 			(GtkSo
 static void	gtk_source_view_populate_popup 		(GtkTextView        *view,
 					    		 GtkMenu            *menu);
 
+static gboolean gtk_source_view_motion			(GtkWidget          *widget,
+							 GdkEventMotion     *event);
+
+static gboolean gtk_source_view_button_press		(GtkWidget          *widget,
+							 GdkEventButton     *event);
+static gboolean gtk_source_view_button_release		(GtkWidget          *widget,
+							 GdkEventButton     *event);
+
 static void	gtk_source_view_move_cursor		(GtkTextView        *text_view,
 							 GtkMovementStep     step,
 							 gint                count,
@@ -140,6 +162,7 @@ static void 	gtk_source_view_get_lines 	
 				       			 gint               last_y,
 				       			 GArray            *buffer_coords,
 				       			 GArray            *numbers,
+				       			 GHashTable        *folds,
 				       			 gint              *countp);
 static gint     gtk_source_view_expose 			(GtkWidget         *widget,
 							 GdkEventExpose    *event);
@@ -189,8 +212,11 @@ gtk_source_view_class_init (GtkSourceVie
 	object_class->get_property = gtk_source_view_get_property;
 	object_class->set_property = gtk_source_view_set_property;
 
+	widget_class->button_press_event = gtk_source_view_button_press;
+	widget_class->button_release_event = gtk_source_view_button_release;
 	widget_class->key_press_event = key_press_event;
 	widget_class->expose_event = gtk_source_view_expose;
+	widget_class->motion_notify_event = gtk_source_view_motion;
 	widget_class->style_set = gtk_source_view_style_set;
 
 	textview_class->populate_popup = gtk_source_view_populate_popup;
@@ -216,6 +242,14 @@ gtk_source_view_class_init (GtkSourceVie
 							       G_PARAM_READWRITE));
 
 	g_object_class_install_property (object_class,
+					 PROP_SHOW_FOLD_REGIONS,
+					 g_param_spec_boolean ("show_fold_regions",
+							       _("Show Fold Regions"),
+							       _("Whether to display fold regions"),
+							       FALSE,
+							       G_PARAM_READWRITE));
+
+	g_object_class_install_property (object_class,
 					 PROP_TABS_WIDTH,
 					 g_param_spec_uint ("tabs_width",
 							    _("Tabs Width"),
@@ -276,6 +310,15 @@ gtk_source_view_class_init (GtkSourceVie
 							       FALSE,
 							       G_PARAM_READWRITE));
 
+	gtk_widget_class_install_style_property (widget_class,
+						 g_param_spec_int ("expander-size",
+								   _("Expander Size"),
+								   _("Size of the expander arrow"),
+								   0,
+								   G_MAXINT,
+								   DEFAULT_EXPANDER_SIZE,
+								   G_PARAM_READABLE));
+
 	signals [UNDO] =
 		g_signal_new ("undo",
 			      G_TYPE_FROM_CLASS (klass),
@@ -337,6 +380,11 @@ gtk_source_view_set_property (GObject   
 							       g_value_get_boolean (value));
 			break;
 			
+		case PROP_SHOW_FOLD_REGIONS:
+			gtk_source_view_set_show_fold_regions (view,
+							       g_value_get_boolean (value));
+			break;
+			
 		case PROP_TABS_WIDTH:
 			gtk_source_view_set_tabs_width (view, 
 							g_value_get_uint (value));
@@ -406,6 +454,12 @@ gtk_source_view_get_property (GObject   
 
 			break;
 			
+		case PROP_SHOW_FOLD_REGIONS:
+			g_value_set_boolean (value,
+					     gtk_source_view_get_show_fold_regions (view));
+
+			break;
+			
 		case PROP_TABS_WIDTH:
 			g_value_set_uint (value,
 					  gtk_source_view_get_tabs_width (view));
@@ -460,6 +514,8 @@ gtk_source_view_init (GtkSourceView *vie
 	view->priv->margin = DEFAULT_MARGIN;
 	view->priv->cached_margin_width = -1;
 	view->priv->smart_home_end = TRUE;
+	view->priv->prelight_fold_line = -1;
+	view->priv->fold_button_down = FALSE;
 	
 	view->priv->pixmap_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
 							  (GDestroyNotify) g_free,
@@ -703,6 +759,259 @@ gtk_source_view_populate_popup (GtkTextV
 
 }
 
+static gboolean
+gtk_source_view_motion (GtkWidget *widget, GdkEventMotion *event)
+{
+	GtkSourceView *view;
+	int x, y, y_buf;
+	GtkTextIter line_start;
+	GtkSourceFold *fold;
+	
+	view = GTK_SOURCE_VIEW (widget);
+	
+	if (view->priv->show_fold_regions && event->is_hint &&
+	    event->window == gtk_text_view_get_window (GTK_TEXT_VIEW (view),
+						       GTK_TEXT_WINDOW_LEFT))
+	{
+		gboolean redraw = FALSE;
+	
+		/* disable prelight on previous fold */
+		if (view->priv->prelight_fold_line != -1) {
+			fold = gtk_source_buffer_get_fold_at_line (view->priv->source_buffer,
+								   view->priv->prelight_fold_line);
+			
+			if (fold != NULL) {
+				fold->prelighted = FALSE;
+				redraw = TRUE;
+			}
+			
+			view->priv->prelight_fold_line = -1;
+		}
+			
+		/* Calling get_pointer will generate a new motion event the
+		   next time we move the pointer. */
+		gdk_window_get_pointer (event->window, &x, &y, NULL);
+		
+		gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view),
+						       GTK_TEXT_WINDOW_LEFT,
+						       x, y, NULL, &y_buf);
+		
+		gtk_text_view_get_line_at_y (GTK_TEXT_VIEW (view),
+					     &line_start,
+					     y_buf,
+					     NULL);
+
+		//g_message ("motion at line %d", gtk_text_iter_get_line (&line_start));
+
+		fold = gtk_source_buffer_get_fold_at_line (view->priv->source_buffer,
+							   gtk_text_iter_get_line (&line_start));
+		
+		/* check if the starting fold is on the same line as the cursor */	  
+		if (fold != NULL) {
+			GtkTextIter fold_start;
+			
+			gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (view->priv->source_buffer),
+							  &fold_start, fold->start_line);
+
+			//g_message ("fold present @ %d", gtk_text_iter_get_line (&fold_start));
+
+			if (gtk_text_iter_get_line (&line_start) ==
+			    gtk_text_iter_get_line (&fold_start))
+			{
+				fold->prelighted = TRUE;
+				redraw = TRUE;
+				view->priv->prelight_fold_line = gtk_text_iter_get_line (&line_start);
+			}
+		}
+		
+		if (redraw)
+			gtk_widget_queue_draw (widget);
+		
+		return TRUE;
+	}
+	else if (view->priv->show_fold_regions && event->is_hint &&
+	         view->priv->prelight_fold_line != -1)
+	{
+		fold = gtk_source_buffer_get_fold_at_line (view->priv->source_buffer,
+							   view->priv->prelight_fold_line);
+							  
+		/* disable prelight on previous fold */
+		if (fold != NULL) {
+			fold->prelighted = FALSE;
+			gtk_widget_queue_draw (widget);
+		}
+		
+		view->priv->prelight_fold_line = -1;
+
+		return GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
+	}
+	else
+	{
+		return GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
+	}
+}
+
+static gboolean
+gtk_source_view_button_press (GtkWidget *widget, GdkEventButton *event)
+{
+	GtkSourceView *view;
+	int y_buf;
+	GtkTextIter line_start;
+	GtkSourceFold *fold;
+	
+	view = GTK_SOURCE_VIEW (widget);
+	
+	if (view->priv->show_fold_regions && event->button == 1 &&
+	    event->window == gtk_text_view_get_window (GTK_TEXT_VIEW (view),
+						       GTK_TEXT_WINDOW_LEFT))
+	{
+		gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view),
+						       GTK_TEXT_WINDOW_LEFT,
+						       event->x, event->y,
+						       NULL, &y_buf);
+		
+		gtk_text_view_get_line_at_y (GTK_TEXT_VIEW (view),
+					     &line_start,
+					     y_buf,
+					     NULL);
+
+		fold = gtk_source_buffer_get_fold_at_line (view->priv->source_buffer,
+							   gtk_text_iter_get_line (&line_start));
+		
+		if (fold != NULL)
+		{
+			GtkTextIter fold_start;
+			
+			gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (view->priv->source_buffer),
+							  &fold_start, fold->start_line);
+
+			if (gtk_text_iter_get_line (&line_start) ==
+			    gtk_text_iter_get_line (&fold_start))
+			{
+				view->priv->fold_button_down = TRUE;
+			}
+		}
+
+		return TRUE;
+	}
+	else
+	{
+		return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
+	}
+}
+
+static gboolean
+fold_animation_timeout (GtkSourceView *view)
+{
+	gboolean finish = FALSE;
+	GtkSourceFold *fold;
+
+
+	fold = gtk_source_buffer_get_fold_at_line (view->priv->source_buffer,
+						   view->priv->animate_fold_line);
+	
+	if (fold == NULL)
+	{
+		view->priv->animation_timeout = 0;
+		return FALSE;
+	}
+
+	GDK_THREADS_ENTER ();
+
+	if (fold->folded)
+	{
+		if (fold->expander_style == GTK_EXPANDER_EXPANDED)
+		{
+			fold->expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
+		}
+		else
+		{
+			fold->expander_style = GTK_EXPANDER_COLLAPSED;
+			finish = TRUE;
+		}
+	}
+	else
+	{
+		if (fold->expander_style == GTK_EXPANDER_COLLAPSED)
+		{
+			fold->expander_style = GTK_EXPANDER_SEMI_EXPANDED;
+		}
+		else
+		{
+			fold->expander_style = GTK_EXPANDER_EXPANDED;
+			finish = TRUE;
+		}
+	}
+
+	if (finish)
+	{
+		view->priv->animation_timeout = 0;
+		view->priv->animate_fold_line = -1;
+		fold->animated = FALSE;
+	}
+
+	gtk_widget_queue_draw (GTK_WIDGET (view));
+
+	GDK_THREADS_LEAVE ();
+
+	return !finish;
+}
+
+static void
+start_fold_animation (GtkSourceView *view)
+{
+	if (view->priv->animation_timeout)
+		g_source_remove (view->priv->animation_timeout);
+
+	view->priv->animation_timeout =
+		g_timeout_add (50, (GSourceFunc) fold_animation_timeout, view);
+}
+
+static gboolean
+gtk_source_view_button_release (GtkWidget *widget, GdkEventButton *event)
+{
+	GtkSourceView *view;
+	int y_buf;
+	GtkTextIter line_start;
+	GtkSourceFold *fold;
+	
+	view = GTK_SOURCE_VIEW (widget);
+	
+	if (view->priv->show_fold_regions && event->button == 1 &&
+	    view->priv->fold_button_down &&
+	    event->window == gtk_text_view_get_window (GTK_TEXT_VIEW (view),
+						       GTK_TEXT_WINDOW_LEFT))
+	{
+		gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view),
+						       GTK_TEXT_WINDOW_LEFT,
+						       event->x, event->y,
+						       NULL, &y_buf);
+		
+		gtk_text_view_get_line_at_y (GTK_TEXT_VIEW (view),
+					     &line_start,
+					     y_buf,
+					     NULL);
+
+		fold = gtk_source_buffer_get_fold_at_line (view->priv->source_buffer,
+							   gtk_text_iter_get_line (&line_start));
+		
+		if (fold != NULL) {
+			fold->animated = TRUE;
+			gtk_source_buffer_set_folded (view->priv->source_buffer,
+						      fold, !fold->folded);
+			view->priv->animate_fold_line = gtk_text_iter_get_line (&line_start);
+			start_fold_animation (view);
+			view->priv->fold_button_down = FALSE;
+		}
+
+		return TRUE;
+	}
+	else
+	{
+		return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
+	}
+}
+
 static void
 move_cursor (GtkTextView       *text_view,
 	     const GtkTextIter *new_location,
@@ -815,18 +1124,32 @@ gtk_source_view_get_lines (GtkTextView  
 			   gint          last_y,
 			   GArray       *buffer_coords,
 			   GArray       *numbers,
+			   GHashTable   *fold_hash,
 			   gint         *countp)
 {
-	GtkTextIter iter;
+	GtkTextIter iter, iter2, start_fold, end_fold;
+	GSList *folds, *l;
+	GtkSourceFold *fold = NULL;
 	gint count;
 	gint size;
-      	gint last_line_num = -1;	
+      	gint last_line_num = -1;
 
 	g_array_set_size (buffer_coords, 0);
 	g_array_set_size (numbers, 0);
   
-	/* Get iter at first y */
+	/* get iter at first and last y */
 	gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
+	gtk_text_view_get_line_at_y (text_view, &iter2, last_y, NULL);
+	
+	//g_message ("from %d to %d", gtk_text_iter_get_line (&iter), gtk_text_iter_get_line (&iter2));
+
+	/* forward to line end so we match all folds on the line. */
+	gtk_text_iter_forward_to_line_end (&iter2);
+	
+	/* get a flattened list of all folds in the area */
+	folds = gtk_source_buffer_get_folds_in_region (GTK_SOURCE_VIEW (text_view)->priv->source_buffer,
+						       &iter, &iter2);
+	l = folds;
 
 	/* For each iter, get its location and add it to the arrays.
 	 * Stop when we pass last_y
@@ -834,22 +1157,79 @@ gtk_source_view_get_lines (GtkTextView  
 	count = 0;
   	size = 0;
 
-  	while (!gtk_text_iter_is_end (&iter))
+	/* start with the first fold in the region */
+	if (g_slist_length (folds) > 0) {
+		fold = folds->data;
+
+		gtk_text_buffer_get_iter_at_mark (text_view->buffer,
+						  &start_fold,
+						  fold->start_line);
+		
+	}
+
+	last_line_num = gtk_text_iter_get_line (&iter);
+	
+  	while (TRUE)
     	{
 		gint y, height;
-      
-		gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
 
+		/* add line coordinates */
+		gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
 		g_array_append_val (buffer_coords, y);
-		last_line_num = gtk_text_iter_get_line (&iter);
+
+		//g_message ("at line %d, %d", last_line_num, gtk_text_iter_get_line (&iter));
+
+		/* add line number */		
 		g_array_append_val (numbers, last_line_num);
+		
+		/* increase line number depending on whether there's a
+		 * collapsed fold on the line */
+		if (fold != NULL && gtk_text_iter_get_line (&iter) ==
+		    gtk_text_iter_get_line (&start_fold))
+		{
+			//g_message ("fold @ %d", last_line_num);
+			g_hash_table_insert (fold_hash,
+					     GINT_TO_POINTER (last_line_num),
+					     fold);
+
+			if (fold->folded)
+			{
+				gtk_text_buffer_get_iter_at_mark (text_view->buffer,
+								  &end_fold,
+								  fold->end_line);
+			
+				last_line_num += gtk_text_iter_get_line (&end_fold) -
+						 gtk_text_iter_get_line (&start_fold);
+			}
+			else
+			{
+				last_line_num++;
+			}
+			
+			/* advance to the next fold (if it exists) */
+			folds = g_slist_next (folds);
+			if (folds != NULL)
+			{
+				fold = folds->data;
+
+				gtk_text_buffer_get_iter_at_mark (text_view->buffer,
+								  &start_fold,
+								  fold->start_line);
+			}
+			else
+			{
+				fold = NULL;
+			}
+		} else {
+			last_line_num++;
+		}
       	
 		++count;
 
-		if ((y + height) >= last_y)
+		if (gtk_text_iter_is_end (&iter) || (y + height) >= last_y)
 			break;
-      
-		gtk_text_iter_forward_line (&iter);
+
+		gtk_text_iter_forward_visible_line (&iter);
 	}
 
 	if (gtk_text_iter_is_end (&iter))
@@ -869,6 +1249,9 @@ gtk_source_view_get_lines (GtkTextView  
 		}
 	}
 
+	if (l != NULL)
+		g_slist_free (l);
+
 	*countp = count;
 }
 
@@ -972,14 +1355,18 @@ gtk_source_view_paint_margin (GtkSourceV
 	gint y1, y2;
 	gint count;
 	gint margin_width;
-	gint text_width, x_pixmap;
+	gint text_width, text_height, x_pixmap;
 	gint i;
 	GtkTextIter cur;
 	gint cur_line;
+	GHashTable *folds;
+	GtkSourceFold *fold;
 
 	text_view = GTK_TEXT_VIEW (view);
 
-	if (!view->priv->show_line_numbers && !view->priv->show_line_markers)
+	if (!view->priv->show_line_numbers &&
+	    !view->priv->show_line_markers &&
+	    !view->priv->show_fold_regions)
 	{
 		gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (text_view),
 						      GTK_TEXT_WINDOW_LEFT,
@@ -1011,6 +1398,7 @@ gtk_source_view_paint_margin (GtkSourceV
 
 	numbers = g_array_new (FALSE, FALSE, sizeof (gint));
 	pixels = g_array_new (FALSE, FALSE, sizeof (gint));
+	folds = g_hash_table_new (g_direct_hash, g_direct_equal);
 
 	/* get the line numbers and y coordinates. */
 	gtk_source_view_get_lines (text_view,
@@ -1018,8 +1406,9 @@ gtk_source_view_paint_margin (GtkSourceV
 				   y2,
 				   pixels,
 				   numbers,
+				   folds,
 				   &count);
-
+	
 	/* A zero-lined document should display a "1"; we don't need to worry about
 	scrolling effects of the text widget in this special case */
 	
@@ -1043,7 +1432,7 @@ gtk_source_view_paint_margin (GtkSourceV
 		    "%d", MAX (99, gtk_text_buffer_get_line_count (text_view->buffer)));
 	layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), str);
 
-	pango_layout_get_pixel_size (layout, &text_width, NULL);
+	pango_layout_get_pixel_size (layout, &text_width, &text_height);
 	
 	pango_layout_set_width (layout, text_width);
 	pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
@@ -1059,6 +1448,9 @@ gtk_source_view_paint_margin (GtkSourceV
 	if (view->priv->show_line_markers)
 		margin_width += GUTTER_PIXMAP;
 
+	if (view->priv->show_fold_regions)
+		margin_width += view->priv->expander_size;
+
 	g_return_if_fail (margin_width != 0);
 	
 	gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (text_view),
@@ -1097,7 +1489,6 @@ gtk_source_view_paint_margin (GtkSourceV
 		marker_line = gtk_source_marker_get_line (
 			GTK_SOURCE_MARKER (current_marker->data));
 	
-	
 	gtk_text_buffer_get_iter_at_mark (text_view->buffer, 
 					  &cur, 
 					  gtk_text_buffer_get_insert (text_view->buffer));
@@ -1147,6 +1538,30 @@ gtk_source_view_paint_margin (GtkSourceV
 					  pos,
 					  layout);
 		}
+		
+		if (view->priv->show_fold_regions && g_hash_table_size (folds) > 0)
+		{
+			gint line_to_paint = g_array_index (numbers, gint, i);
+			fold = g_hash_table_lookup (folds, GINT_TO_POINTER (line_to_paint));
+			
+			if (fold != NULL)
+			{
+				GtkStateType state = GTK_WIDGET_STATE (view);
+			
+				if (fold->prelighted)
+					state = GTK_STATE_PRELIGHT;
+			
+				gtk_paint_expander (GTK_WIDGET (view)->style,
+						    win,
+						    state,
+						    NULL,
+						    GTK_WIDGET (view),
+						    NULL,
+						    text_width + 4 + (view->priv->expander_size / 2),
+						    pos + (text_height / 2),
+						    fold->expander_style);
+			}
+		}
 
 		if (view->priv->show_line_markers && current_marker) 
 		{
@@ -1170,6 +1585,7 @@ gtk_source_view_paint_margin (GtkSourceV
 	g_slist_free (markers);
 	g_array_free (pixels, TRUE);
 	g_array_free (numbers, TRUE);
+	g_hash_table_destroy (folds);
 
 	g_object_unref (G_OBJECT (layout));
 }
@@ -1195,7 +1611,7 @@ gtk_source_view_expose (GtkWidget      *
 	}
 	
 	/* check if the expose event is for the text window first, and
-	 * make sure the visible region is highlighted */
+	 * make sure the visible region is prelighted */
 	if (event->window == gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT) &&
 	    view->priv->source_buffer != NULL) 
 	{
@@ -2173,6 +2589,12 @@ gtk_source_view_style_set (GtkWidget *wi
 		(* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
 
 	view = GTK_SOURCE_VIEW (widget);
+	
+	gtk_widget_style_get (widget,
+			      "expander-size", &view->priv->expander_size,
+			      NULL);
+	//view->priv->expander_size += EXPANDER_EXTRA_PADDING;
+  
 	if (previous_style)
 	{
 		/* If previous_style is NULL this is the initial
@@ -2186,3 +2608,54 @@ gtk_source_view_style_set (GtkWidget *wi
 	}
 }
 
+static void
+expand_folds (GtkSourceBuffer *buffer, GSList *folds)
+{
+	GtkSourceFold *fold;
+	GSList *children;
+
+	while (folds != NULL) {
+		fold = folds->data;
+		children = fold->children;
+		
+		expand_folds (buffer, children);
+		
+		gtk_source_buffer_set_folded (buffer, fold, FALSE);
+	
+		folds = g_slist_next (folds);
+	}
+}
+
+void
+gtk_source_view_set_show_fold_regions (GtkSourceView *view,
+				       gboolean       enable)
+{
+	GSList *folds;
+
+	g_return_if_fail (GTK_IS_SOURCE_VIEW (view));
+
+	enable = (enable != FALSE);
+
+	if (view->priv->show_fold_regions == enable)
+		return;
+
+	view->priv->show_fold_regions = enable;
+
+	/* expand all folds when hiding the fold gutter. */
+	if (!enable) {
+		folds = gtk_source_buffer_get_root_folds (view->priv->source_buffer);
+		expand_folds (view->priv->source_buffer, folds);
+	}
+
+	gtk_widget_queue_draw (GTK_WIDGET (view));
+
+	g_object_notify (G_OBJECT (view), "show_fold_regions");
+}
+
+gboolean
+gtk_source_view_get_show_fold_regions (GtkSourceView *view)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_VIEW (view), FALSE);
+
+	return view->priv->show_fold_regions;
+}
Index: gtksourceview/gtksourceview.h
===================================================================
RCS file: /cvs/gnome/gtksourceview/gtksourceview/gtksourceview.h,v
retrieving revision 1.10
diff -u -p -r1.10 gtksourceview.h
--- gtksourceview/gtksourceview.h	8 Jan 2005 22:02:30 -0000	1.10
+++ gtksourceview/gtksourceview.h	25 Aug 2005 08:30:16 -0000
@@ -39,7 +39,6 @@ G_BEGIN_DECLS
 #define GTK_IS_SOURCE_VIEW_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_VIEW))
 #define GTK_SOURCE_VIEW_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_VIEW, GtkSourceViewClass))
 
-
 typedef struct _GtkSourceView GtkSourceView;
 typedef struct _GtkSourceViewClass GtkSourceViewClass;
 
@@ -69,7 +68,7 @@ GType		 gtk_source_view_get_type 		(void
 
 /* Constructors */
 GtkWidget 	*gtk_source_view_new 			(void);
-GtkWidget 	*gtk_source_view_new_with_buffer	(GtkSourceBuffer *buffer);
+GtkWidget 	*gtk_source_view_new_with_buffer		(GtkSourceBuffer *buffer);
 
 /* Properties */
 void 		 gtk_source_view_set_show_line_numbers 	(GtkSourceView   *view,
@@ -80,7 +79,7 @@ void 		 gtk_source_view_set_show_line_ma
 							 gboolean         show);
 gboolean	 gtk_source_view_get_show_line_markers  (GtkSourceView   *view);
 
-void 		 gtk_source_view_set_tabs_width 	(GtkSourceView   *view, 
+void 		 gtk_source_view_set_tabs_width		(GtkSourceView   *view, 
 							 guint            width);
 guint            gtk_source_view_get_tabs_width         (GtkSourceView   *view);
 
@@ -117,6 +116,10 @@ GdkPixbuf	*gtk_source_view_get_marker_pi
 void		 gtk_source_view_set_smart_home_end	(GtkSourceView   *view,
 							 gboolean         enable);
 gboolean	 gtk_source_view_get_smart_home_end	(GtkSourceView   *view);
+
+void		 gtk_source_view_set_show_fold_regions	(GtkSourceView   *view,
+							 gboolean         enable);
+gboolean	 gtk_source_view_get_show_fold_regions	(GtkSourceView   *view);
 
 G_END_DECLS
 #endif				/* end of SOURCE_VIEW_H__ */
Index: tests/test-widget.c
===================================================================
RCS file: /cvs/gnome/gtksourceview/tests/test-widget.c,v
retrieving revision 1.11
diff -u -p -r1.11 test-widget.c
--- tests/test-widget.c	8 Jan 2005 22:02:30 -0000	1.11
+++ tests/test-widget.c	25 Aug 2005 08:30:16 -0000
@@ -413,7 +413,7 @@ static void
 markers_toggled_cb (GtkAction *action, gpointer user_data)
 {
 	g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
-	gtk_source_view_set_show_line_markers (
+	gtk_source_view_set_show_fold_regions (
 		GTK_SOURCE_VIEW (user_data),
 		gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
 }
@@ -767,6 +767,7 @@ create_view_window (GtkSourceBuffer *buf
 
 	/* view */
 	view = gtk_source_view_new_with_buffer (buffer);
+	g_object_set_data (G_OBJECT (window), "view", view);
 	
 	g_signal_connect (buffer, "mark_set", G_CALLBACK (move_cursor_cb), view);
 	g_signal_connect (buffer, "changed", G_CALLBACK (update_cursor_position), view);
@@ -805,6 +806,9 @@ create_view_window (GtkSourceBuffer *buf
 	/* misc widgets */
 	vbox = gtk_vbox_new (0, FALSE);
 	sw = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+					GTK_POLICY_AUTOMATIC,
+					GTK_POLICY_AUTOMATIC);
 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
                                              GTK_SHADOW_IN);
 	pos_label = gtk_label_new ("Position");
@@ -819,7 +823,7 @@ create_view_window (GtkSourceBuffer *buf
 	gtk_box_pack_start (GTK_BOX (vbox), pos_label, FALSE, FALSE, 0);
 
 	/* setup view */
-	font_desc = pango_font_description_from_string ("monospace 10");
+	font_desc = pango_font_description_from_string ("Courier New 9");
 	if (font_desc != NULL)
 	{
 		gtk_widget_modify_font (view, font_desc);
@@ -977,6 +981,8 @@ main (int argc, char *argv[])
 	GtkWidget *window;
 	GtkSourceLanguagesManager *lm;
 	GtkSourceBuffer *buffer;
+	GtkSourceView *view;
+	GtkTextIter begin, end;
 	
 	/* initialization */
 	gtk_init (&argc, &argv);
@@ -987,13 +993,40 @@ main (int argc, char *argv[])
 	buffer = create_source_buffer (lm);
 	g_object_unref (lm);
 
-	if (argc > 1)
-		open_file (buffer, argv [1]);
-	else
-		open_file (buffer, "../gtksourceview/gtksourcebuffer.c");
-
 	/* create first window */
 	window = create_main_window (buffer);
+	view = GTK_SOURCE_VIEW (g_object_get_data (G_OBJECT (window), "view"));
+
+	if (argc > 1) {
+		open_file (buffer, argv [1]);
+	} else {
+		open_file (buffer, "test.c");
+
+		/* main() fold. */		
+		gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (buffer), &begin, 33);
+		gtk_text_iter_forward_to_line_end (&begin);
+		gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (buffer), &end, 65);
+		gtk_source_buffer_add_fold (buffer, &begin, &end);
+
+		/* doit() fold. */		
+		gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (buffer), &begin, 18);
+		gtk_text_iter_forward_to_line_end (&begin);
+		gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (buffer), &end, 22);
+		gtk_source_buffer_add_fold (buffer, &begin, &end);
+
+		/* nested while (...) fold. */
+		gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (buffer), &begin, 57);
+		gtk_text_iter_forward_to_line_end (&begin);
+		gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (buffer), &end, 60);
+		gtk_source_buffer_add_fold (buffer, &begin, &end);
+		
+		/* nested if (...) fold. */
+		gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (buffer), &begin, 50);
+		gtk_text_iter_forward_to_line_end (&begin);
+		gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (buffer), &end, 53);
+		gtk_source_buffer_add_fold (buffer, &begin, &end);
+	}
+
 	gtk_window_set_default_size (GTK_WINDOW (window), 500, 500);
 	gtk_widget_show (window);
 
Index: tests/test.c
===================================================================
RCS file: tests/test.c
diff -N tests/test.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/test.c	25 Aug 2005 08:30:17 -0000
@@ -0,0 +1,65 @@
+/*
+ * This is a test of gtksourceview's capabilities. Notice the new highlighting
+ * engine that supports sub-languages like GTK+-like @ comments.
+ */
+
+#include <gtk/gtk.h>
+
+#if 0
+
+#if GTK_SOURCE_VIEW_IS_SMART_ABOUT_NESTED_IFDEFS
+#define HOORAY
+#else
+#define GET_A_REAL_EDITOR
+#endif
+
+#endif /* #if 0 */
+
+static void
+doit (void)
+{
+	g_message ("Just do it!");
+}
+
+/**
+ * main:
+ * @argc: the number of command-line arguments given to the program + 1.
+ * @argv: the arguments specified on the command-line.
+ *
+ * Displays a basic #GtkWindow.
+ *
+ * Return value: 0 if the program completed succesfully.
+ **/
+int
+main (int argc, char *argv[])
+{
+	GtkWidget *window;
+	gchar *title;
+	
+	gtk_init (&argc, &argv);
+	
+	title = "GtkSourceView test";
+	
+	/* There should be a breakpoint on the next line. */
+	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	
+	/* Try hovering over "title" to see it's value (tooltip). */
+	gtk_window_set_title (GTK_WINDOW (window), title);
+	
+	gtk_window_set_default_size (GTK_WINDOW (window), 500, 500);
+	
+	if (argc > 1) {
+		g_message ("%d arguments where given at startup", argc - 1);
+	}
+	
+	/* The next line is bookmarked. */
+	gtk_widget_show_all (window);
+
+	while (gtk_events_pending ()) {
+		gtk_main_iteration ();
+	}
+
+	gtk_main ();
+	
+	return 0;
+}
