SF.net SVN: geany:[5729] trunk

ntrel at users.sourceforge.net ntrel at xxxxx
Tue Apr 19 16:04:31 UTC 2011


Revision: 5729
          http://geany.svn.sourceforge.net/geany/?rev=5729&view=rev
Author:   ntrel
Date:     2011-04-19 16:04:31 +0000 (Tue, 19 Apr 2011)

Log Message:
-----------
Fix multiple snippet cursor positions for Tabs + Spaces mode.
Simplify editor_insert_snippet() code now we use cursor marker
strings.

Modified Paths:
--------------
    trunk/ChangeLog
    trunk/src/editor.c

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2011-04-17 13:41:54 UTC (rev 5728)
+++ trunk/ChangeLog	2011-04-19 16:04:31 UTC (rev 5729)
@@ -1,3 +1,11 @@
+2011-04-19  Nick Treleaven  <nick(dot)treleaven(at)btinternet(dot)com>
+
+ * src/editor.c:
+   Fix multiple snippet cursor positions for Tabs + Spaces mode.
+   Simplify editor_insert_snippet() code now we use cursor marker
+   strings.
+
+
 2011-04-17  Enrico Tröger  <enrico(dot)troeger(at)uvena(dot)de>
 
  * src/plugindata.h, src/document.c, src/plugins.c, src/document.h,
@@ -4,7 +12,7 @@
    plugins/geanyfunctions.h:
    Add document_compare_by_tab_order() and
    document_compare_by_tab_order_reverse() to the plugin API.
- * src/ui_uitls.c:
+ * src/ui_utils.c:
    Use document_compare_by_tab_order() as default compare function
    to sort the document list in the document notebook tab menu, this
    fixes the currently broken default ordering.

Modified: trunk/src/editor.c
===================================================================
--- trunk/src/editor.c	2011-04-17 13:41:54 UTC (rev 5728)
+++ trunk/src/editor.c	2011-04-19 16:04:31 UTC (rev 5729)
@@ -117,8 +117,8 @@
 		const gchar *wc, gboolean stem);
 static gsize count_indent_size(GeanyEditor *editor, const gchar *base_indent);
 static const gchar *snippets_find_completion_by_name(const gchar *type, const gchar *name);
-static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
-		gsize indent_size);
+static void snippets_make_replacements(GeanyEditor *editor, GString *pattern);
+static gssize replace_cursor_markers(GeanyEditor *editor, GString *pattern);
 
 
 void editor_snippets_free(void)
@@ -2309,56 +2309,85 @@
 }
 
 
-/* this only works with spaces only indentation on the lines */
-static void fix_line_indents(GeanyEditor *editor, gint line_start, gint line_end)
+static gboolean utils_regex_find(regex_t *regex, const gchar *haystack, gsize start,
+		gsize nmatches, regmatch_t *matches)
 {
-	ScintillaObject *sci = editor->sci;
-	gint line, cur_line, cur_col, pos;
+	gint eflags = 0;
 
-	/* get the line, col position as fixing indentation will move cursor to start of line */
-	pos = sci_get_current_position(sci);
-	cur_col = sci_get_col_from_position(sci, pos);
-	cur_line = sci_get_current_line(sci);
-
-	for (line = line_start; line <= line_end; line++)
+	if (start > 0)
 	{
-		gint size = sci_get_line_indentation(sci, line);
+		gchar c = haystack[start - 1];
 
-		/* set to 0 first to trigger proper indent creation */
-		sci_set_line_indentation(sci, line, 0);
-		sci_set_line_indentation(sci, line, size);
+		if (c == '\n' || c == '\r')
+			eflags = REG_NOTBOL;
 	}
-	pos = scintilla_send_message(sci, SCI_FINDCOLUMN, cur_line, cur_col);
-	sci_set_current_position(sci, pos, FALSE);
+	return regexec(regex, haystack + start, nmatches, matches, eflags) == 0;
 }
 
 
-static void replace_leading_tabs(GString *str, const gchar *whitespace)
+/* match_index: which match to replace, 0 for whole regex.
+ * note: this doesn't support backreferences in replacements */
+static guint utils_string_regex_replace_all(GString *haystack,
+		regex_t *regex, guint match_index, const gchar *replace)
 {
-	regex_t regex;
 	gssize pos;
-	regmatch_t matches[2];
-	gchar *ptr;
+	regmatch_t matches[10];
+	guint ret = 0;
 
-	if (regcomp(&regex, "^ *(\t)", 0) != 0)
+	g_return_val_if_fail(match_index < 10, 0);
+
+	/* ensure haystack->str is not null */
+	if (haystack->len == 0)
+		return 0;
+
+	pos = 0;
+	while (utils_regex_find(regex, haystack->str, pos, G_N_ELEMENTS(matches), matches))
 	{
-		g_return_if_fail(FALSE);
+		regmatch_t *match = &matches[match_index];
+
+		g_return_val_if_fail(match->rm_so >= 0, FALSE);
+		pos += match->rm_so;
+		g_string_erase(haystack, pos, match->rm_eo - match->rm_so);
+		g_string_insert(haystack, pos, replace);
+		pos += strlen(replace);
+		ret++;
 	}
-	ptr = str->str;
-	while (ptr)
+	return ret;
+}
+
+
+static void fix_indentation(GeanyEditor *editor, GString *buf)
+{
+	const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
+	gchar *whitespace;
+	regex_t regex;
+	gint cflags = REG_EXTENDED | REG_NEWLINE;
+
+	/* transform leading tabs into indent widths (in spaces) */
+	whitespace = g_strnfill(iprefs->width, ' ');
+	regcomp(&regex, "^ *(\t)", cflags);
+	while (utils_string_regex_replace_all(buf, &regex, 1, whitespace));
+	regfree(&regex);
+
+	/* remaining tabs are for alignment */
+	if (iprefs->type != GEANY_INDENT_TYPE_TABS)
+		utils_string_replace_all(buf, "\t", whitespace);
+
+	/* use leading tabs */
+	if (iprefs->type != GEANY_INDENT_TYPE_SPACES)
 	{
-		if (regexec(&regex, ptr,
-			G_N_ELEMENTS(matches), matches, 0) != 0)
-			break;
+		gchar *str;
 
-		pos = matches[1].rm_so;
-		g_return_if_fail(pos >= 0);
-		pos += ptr - str->str;
-		g_string_erase(str, pos, 1);
-		g_string_insert(str, pos, whitespace);
-		ptr = str->str + pos + strlen(whitespace);
+		/* for tabs+spaces mode we want the real tab width, not indent width */
+		setptr(whitespace, g_strnfill(sci_get_tab_width(editor->sci), ' '));
+		str = g_strdup_printf("^\t*(%s)", whitespace);
+
+		regcomp(&regex, str, cflags);
+		while (utils_string_regex_replace_all(buf, &regex, 1, "\t"));
+		regfree(&regex);
+		g_free(str);
 	}
-	regfree(&regex);
+	g_free(whitespace);
 }
 
 
@@ -2385,11 +2414,10 @@
 {
 	ScintillaObject *sci = editor->sci;
 	gint line_start = sci_get_line_from_position(sci, insert_pos);
-	gint line_end;
 	gchar *whitespace;
 	GString *buf;
 	const gchar *eol = editor_get_eol_char(editor);
-	const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
+	gint idx;
 
 	g_return_if_fail(text);
 	g_return_if_fail(editor != NULL);
@@ -2405,7 +2433,8 @@
 		/* count indent size up to insert_pos instead of asking sci
 		 * because there may be spaces after it */
 		gchar *tmp = sci_get_line(sci, line_start);
-		gint idx = insert_pos - sci_get_position_from_line(sci, line_start);
+
+		idx = insert_pos - sci_get_position_from_line(sci, line_start);
 		tmp[idx] = '\0';
 		newline_indent_size = count_indent_size(editor, tmp);
 		g_free(tmp);
@@ -2424,32 +2453,19 @@
 	if (replace_newlines)
 		utils_string_replace_all(buf, "\n", eol);
 
-	/* transform leading tabs into indent widths (in spaces) */
-	whitespace = g_strnfill(iprefs->width, ' ');
-	replace_leading_tabs(buf, whitespace);
-	/* remaining tabs are for alignment */
-	if (iprefs->type != GEANY_INDENT_TYPE_TABS)
-		utils_string_replace_all(buf, "\t", whitespace);
-	g_free(whitespace);
+	fix_indentation(editor, buf);
 
-	sci_start_undo_action(sci);
-
-	if (cursor_index >= 0)
+	idx = replace_cursor_markers(editor, buf);
+	if (idx >= 0)
 	{
-		gint idx = utils_string_replace(buf, 0, -1, geany_cursor_marker, NULL);
-
 		sci_insert_text(sci, insert_pos, buf->str);
 		sci_set_current_position(sci, insert_pos + idx, FALSE);
 	}
 	else
 		sci_insert_text(sci, insert_pos, buf->str);
 
-	/* fixup indentation (very useful for Tabs & Spaces indent type) */
-	line_end = sci_get_line_from_position(sci, insert_pos + buf->len);
-	fix_line_indents(editor, line_start, line_end);
 	snippet_cursor_insert_pos = sci_get_current_position(sci);
 
-	sci_end_undo_action(sci);
 	g_string_free(buf, TRUE);
 }
 
@@ -2480,13 +2496,9 @@
 }
 
 
-static gssize replace_cursor_markers(GeanyEditor *editor, GString *pattern, gsize indent_size);
-
-static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern, gsize indent_size)
+static void snippets_make_replacements(GeanyEditor *editor, GString *pattern)
 {
-	gchar *whitespace;
 	GHashTable *specials;
-	const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
 
 	/* replace 'special' completions */
 	specials = g_hash_table_lookup(snippet_hash, "Special");
@@ -2498,20 +2510,9 @@
 	}
 
 	/* now transform other wildcards */
-
 	utils_string_replace_all(pattern, "%newline%", "\n");
+	utils_string_replace_all(pattern, "%ws%", "\t");
 
-	/* if spaces are used, replace tabs with spaces
-	 * otherwise replace all %ws% by \t */
-	if (iprefs->type == GEANY_INDENT_TYPE_SPACES)
-		utils_string_replace_all(pattern, "\t", "%ws%");
-	else
-		utils_string_replace_all(pattern, "%ws%", "\t");
-
-	whitespace = g_strnfill(iprefs->width, ' '); /* use spaces for indentation, will be fixed up */
-	utils_string_replace_all(pattern, "%ws%", whitespace);
-	g_free(whitespace);
-
 	/* replace %cursor% by a very unlikely string marker */
 	utils_string_replace_all(pattern, "%cursor%", geany_cursor_marker);
 
@@ -2520,62 +2521,36 @@
 
 	/* replace any template {foo} wildcards */
 	templates_replace_common(pattern, editor->document->file_name, editor->document->file_type, NULL);
-
-	return replace_cursor_markers(editor, pattern, indent_size);
 }
 
 
-static gssize replace_cursor_markers(GeanyEditor *editor, GString *pattern, gsize indent_size)
+static gssize replace_cursor_markers(GeanyEditor *editor, GString *pattern)
 {
 	gssize cur_index = -1;
-	gint i, idx, nl_count = 0;
+	gint i;
 	GList *temp_list = NULL;
-	gint cursor_steps, old_cursor = 0;
+	gint cursor_steps = 0, old_cursor = 0;
 
 	i = 0;
-	idx = 0;
-	while ((cursor_steps = utils_strpos(pattern->str, geany_cursor_marker)) >= 0)
+	while (1)
 	{
-		/* replace every newline (up to next cursor) with EOL,
-		 * count newlines and update cursor_steps after */
-		while (1)
-		{
-			idx = utils_string_replace(pattern, idx, cursor_steps, "\n", editor_get_eol_char(editor));
-			if (idx == -1)
-				break;
+		cursor_steps = utils_string_replace(pattern, cursor_steps, -1, geany_cursor_marker, NULL);
+		if (cursor_steps == -1)
+			break;
 
-			nl_count++;
-			idx += editor_get_eol_char_len(editor);
-
-			cursor_steps = utils_strpos(pattern->str, geany_cursor_marker);
-		}
-		utils_string_replace_first(pattern, geany_cursor_marker, "");
-		idx = cursor_steps;
-
 		if (i++ > 0)
 		{
 			/* save the relative offset to each cursor position */
-			cursor_steps += (nl_count * indent_size);
 			temp_list = g_list_prepend(temp_list, GINT_TO_POINTER(cursor_steps - old_cursor));
 		}
 		else
 		{
 			/* first cursor already includes newline positions */
-			nl_count = 0;
 			cur_index = cursor_steps;
 		}
 		old_cursor = cursor_steps;
 	}
-	/* replace remaining \n which may occur after the last cursor */
-	while (1)
-	{
-		idx = utils_string_replace(pattern, idx, -1, "\n", editor_get_eol_char(editor));
-		if (idx == -1)
-			break;
 
-		idx += editor_get_eol_char_len(editor);
-	}
-
 	/* put the cursor positions for the most recent
 	 * parsed snippet first, followed by any remaining positions */
 	i = 0;
@@ -5110,12 +5085,10 @@
  */
 void editor_insert_snippet(GeanyEditor *editor, gint pos, const gchar *snippet)
 {
-	gint cursor_pos;
 	GString *pattern;
 
 	pattern = g_string_new(snippet);
-	read_indent(editor, pos);
-	cursor_pos = snippets_make_replacements(editor, pattern, strlen(indent));
-	editor_insert_text_block(editor, pattern->str, pos, cursor_pos, -1, FALSE);
+	snippets_make_replacements(editor, pattern);
+	editor_insert_text_block(editor, pattern->str, pos, -1, -1, FALSE);
 	g_string_free(pattern, TRUE);
 }


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the Commits mailing list