SF.net SVN: geany:[3461] trunk

eht16 at users.sourceforge.net eht16 at xxxxx
Sun Jan 11 21:05:03 UTC 2009


Revision: 3461
          http://geany.svn.sourceforge.net/geany/?rev=3461&view=rev
Author:   eht16
Date:     2009-01-11 21:05:03 +0000 (Sun, 11 Jan 2009)

Log Message:
-----------
Support multiple %cursor% wildcards in Snippets. To switch between %cursor% wildcards, use the new keybinding 'Move cursor in snippet' (patch by Thomas Martitz, thanks).

Modified Paths:
--------------
    trunk/ChangeLog
    trunk/THANKS
    trunk/data/snippets.conf
    trunk/doc/geany.html
    trunk/doc/geany.txt
    trunk/po/POTFILES.in
    trunk/src/Makefile.am
    trunk/src/about.c
    trunk/src/editor.c
    trunk/src/editor.h
    trunk/src/keybindings.c
    trunk/src/keybindings.h
    trunk/src/makefile.win32
    trunk/src/plugindata.h
    trunk/src/utils.c
    trunk/src/utils.h
    trunk/wscript

Added Paths:
-----------
    trunk/src/queue.c
    trunk/src/queue.h

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/ChangeLog	2009-01-11 21:05:03 UTC (rev 3461)
@@ -9,6 +9,13 @@
    src/symbols.c, tagmanager/read.h:
    Fix several compiler warnings and build errors
    (patch by Daniel Richard G., thanks).
+ * data/snippets.conf, doc/geany.html, doc/geany.txt, src/editor.c,
+   src/editor.h, src/keybindings.c, src/keybindings.h, src/Makefile.am,
+   src/makefile.win32, src/plugindata.h, src/utils.c, src/utils.h,
+   src/about.c, src/queue.c, src/queue.h, THANKS, wscript:
+   Support multiple %cursor% wildcards in Snippets. To switch between
+   %cursor% wildcards, use the new keybinding 'Move cursor in snippet'
+   (patch by Thomas Martitz, thanks).
 
 
 2009-01-09  Enrico Tröger  <enrico(dot)troeger(at)uvena(dot)de>

Modified: trunk/THANKS
===================================================================
--- trunk/THANKS	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/THANKS	2009-01-11 21:05:03 UTC (rev 3461)
@@ -59,6 +59,7 @@
 Guillaume de Rorthais <ioguix(at)free(dot)fr> - Auto-close brackets/braces/quotes patch
 Tyler Mulligan <tyler(at)doknowevil(dot)net> - Close All toolbar icon
 Philipp Gildein <philipp(at)gildein(dot)com> - Ada filetype patch
+Thomas Martitz <thomas47(at)arcor(dot)de> - Multiple %cursor% wildcards in Snippets patch
 
 Translators:
 ------------

Modified: trunk/data/snippets.conf
===================================================================
--- trunk/data/snippets.conf	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/data/snippets.conf	2009-01-11 21:05:03 UTC (rev 3461)
@@ -3,9 +3,11 @@
 # use \n or %newline% for a new line (it will be replaced by the used EOL char(s) - LF, CR/LF, CR).
 # use \t or %ws% for an indentation step, it will be replaced according to the current document's indent mode.
 # use \s to force whitespace at beginning or end of a value ('key= value' won't work, use 'key=\svalue').
-# use %cursor% to define where the cursor should be placed after completion.
 # use %key% for all keys defined in the [Special] section.
-# you can define a section for each supported filetype to overwrite default settings, the section
+# use %cursor% to define where the cursor should be placed after completion. You can define multiple
+#     %cursor% wildcards and use the "Move cursor in snippet" to jump to the next defined cursor
+#     position in the completed snippet.
+# You can define a section for each supported filetype to overwrite default settings, the section
 # name must match exactly the internal filetype name, run 'geany --ft-names' for a full list.
 #
 # Additionally, you can use most of the template wildcards like {developer} or {date} in the snippets.
@@ -18,13 +20,13 @@
 
 # Default is used for all filetypes and keys can be overwritten by [filetype] sections
 [Default]
-if=if (%cursor%)%brace_open%\n%brace_close%
-else=else%brace_open%%cursor%\n%brace_close%
-for=for (i = 0; i < %cursor%; i++)%brace_open%\n%brace_close%
-while=while (%cursor%)%brace_open%\n%brace_close%
-do=do%brace_open%%cursor%\n%brace_close% while ()
-switch=switch (%cursor%)%brace_open%case : break;\n%ws%default: \n%brace_close%
-try=try%block_cursor%catch ()%block%
+if=if (%cursor%)%block_cursor%
+else=else%block_cursor%
+for=for (i = 0; i < %cursor%; i++)%block_cursor%
+while=while (%cursor%)%block_cursor%
+do=do\n{%n%%cursor%\n} while(%cursor%)\n%cursor%
+switch=switch (%cursor%)%brace_open%case %cursor%:%n%\t%cursor%%n%break;\n%ws%default:%n%\t%cursor%\n%brace_close%%cursor%
+try=try%block%\ncatch (%cursor%)%block_cursor%
 
 # special keys to be used in other snippets, cannot be used "standalone"
 # can be used by %key%, e.g. %brace_open%
@@ -34,8 +36,8 @@
 [Special]
 brace_open=\n{\n\t
 brace_close=}\n
-block=\n{\n\t\n}\n
-block_cursor=\n{\n\t%cursor%\n}\n
+block=\n{\n\t%cursor%\n}
+block_cursor=\n{\n\t%cursor%\n}\n%cursor%
 #wordchars=_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
 
 [C++]

Modified: trunk/doc/geany.html
===================================================================
--- trunk/doc/geany.html	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/doc/geany.html	2009-01-11 21:05:03 UTC (rev 3461)
@@ -6,7 +6,7 @@
 <meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
 <title>Geany</title>
 <meta name="authors" content="Enrico Tröger  Nick Treleaven  Frank Lanitz" />
-<meta name="date" content="$Date$" />
+<meta name="date" content="2009-01-04" />
 <style type="text/css">
 
 /*
@@ -139,7 +139,7 @@
 <br />Nick Treleaven
 <br />Frank Lanitz</td></tr>
 <tr><th class="docinfo-name">Date:</th>
-<td>$Date$</td></tr>
+<td>2009-01-04</td></tr>
 <tr><th class="docinfo-name">Version:</th>
 <td>0.16</td></tr>
 </tbody>
@@ -1131,7 +1131,10 @@
 </tr>
 <tr><td>%cursor%</td>
 <td>Place the cursor at this position after completion has
-been done.</td>
+been done. You can define multiple %cursor% wildcards
+and use the keybinding <tt class="docutils literal"><span class="pre">Move</span> <span class="pre">cursor</span> <span class="pre">in</span> <span class="pre">snippet</span></tt> to jump
+to the next defined cursor position in the completed
+snippet.</td>
 </tr>
 <tr><td>%...%</td>
 <td>"..." means the name of a key in the "Special" section.
@@ -1152,7 +1155,8 @@
 </pre>
 <p>Every time you write <tt class="docutils literal"><span class="pre">myname</span></tt> <TAB> in Geany, it will replace "myname"
 with "Enrico Tröger". The key to start auto completion can be changed
-in the preferences dialog, by default it is TAB.</p>
+in the preferences dialog, by default it is TAB. The corresponding keybinding
+is called <tt class="docutils literal"><span class="pre">Complete</span> <span class="pre">snippet</span></tt>.</p>
 <p>Since Geany 0.15 you can also use most of the available templates wildcards
 listed in <a class="reference internal" href="#template-wildcards">Template wildcards</a>. All wildcards which are listed as
 <cite>available in snippets</cite> can be used. For instance to improve the above example:</p>
@@ -2588,6 +2592,12 @@
 argument. See the section called <a class="reference internal" href="#context-actions">Context
 actions</a>.</td>
 </tr>
+<tr><td>Move cursor in snippet</td>
+<td> </td>
+<td>Jumps to the next defined cursor positions in a
+completed snippets if multiple cursor positions
+where defined.</td>
+</tr>
 <tr><td><strong>Clipboard</strong></td>
 <td> </td>
 <td> </td>
@@ -4559,7 +4569,7 @@
 <div class="footer">
 <hr class="footer" />
 <a class="reference external" href="geany.txt">View document source</a>.
-Generated on: 2009-01-04 18:12 UTC.
+Generated on: 2009-01-11 20:50 UTC.
 Generated by <a class="reference external" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source.
 
 </div>

Modified: trunk/doc/geany.txt
===================================================================
--- trunk/doc/geany.txt	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/doc/geany.txt	2009-01-11 21:05:03 UTC (rev 3461)
@@ -806,7 +806,10 @@
                   ('key= value' won't work, use 'key=\\svalue')
 
 %cursor%          Place the cursor at this position after completion has
-                  been done.
+                  been done. You can define multiple %cursor% wildcards
+                  and use the keybinding ``Move cursor in snippet`` to jump
+                  to the next defined cursor position in the completed
+                  snippet.
 
 %...%             "..." means the name of a key in the "Special" section.
                   If you have defined a key "brace_open" in the "Special"
@@ -826,7 +829,8 @@
 
 Every time you write ``myname`` <TAB> in Geany, it will replace "myname"
 with "Enrico Tröger". The key to start auto completion can be changed
-in the preferences dialog, by default it is TAB.
+in the preferences dialog, by default it is TAB. The corresponding keybinding
+is called ``Complete snippet``.
 
 Since Geany 0.15 you can also use most of the available templates wildcards
 listed in `Template wildcards`_. All wildcards which are listed as
@@ -2377,6 +2381,10 @@
                                                           argument. See the section called `Context
                                                           actions`_.
 
+Move cursor in snippet                                    Jumps to the next defined cursor positions in a
+                                                          completed snippets if multiple cursor positions
+                                                          where defined.
+
 **Clipboard**
 
 Cut                             Ctrl-X                    Cut the current selection to the clipboard.

Modified: trunk/po/POTFILES.in
===================================================================
--- trunk/po/POTFILES.in	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/po/POTFILES.in	2009-01-11 21:05:03 UTC (rev 3461)
@@ -26,6 +26,7 @@
 src/prefs.c
 src/printing.c
 src/project.c
+src/queue.c
 src/sciwrappers.c
 src/search.c
 src/socket.c

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/src/Makefile.am	2009-01-11 21:05:03 UTC (rev 3461)
@@ -34,6 +34,7 @@
 	prefs.c prefs.h \
 	printing.c printing.h \
 	project.c project.h \
+	queue.c queue.h \
 	sciwrappers.c sciwrappers.h \
 	search.c search.h \
 	socket.c socket.h \

Modified: trunk/src/about.c
===================================================================
--- trunk/src/about.c	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/src/about.c	2009-01-11 21:05:03 UTC (rev 3461)
@@ -83,8 +83,8 @@
 "Giuseppe Torelli, Guillaume de Rorthais, Guillaume Hoffmann, Herbert Voss, Jason Oster, Jean-François Wauthy, Jeff Pohlmeyer, "
 "John Gabriele, Josef Whiter, Kevin Ellwood, Kristoffer A. Tjernås, Marko Peric, Matti Mårds, Moritz Barsnick, "
 "Peter Strand, Philipp Gildein, Pierre Joye, Rob van der Linde, Robert McGinley, Roland Baudin, S Jagannathan, Saleem Abdulrasool, "
-"Sebastian Kraft, Shiv, Slava Semushin, Stefan Oltmanns, Tamim, Tomás Vírseda, Tyler Mulligan, Walery Studennikov, "
-"Yura Siamashka";
+"Sebastian Kraft, Shiv, Slava Semushin, Stefan Oltmanns, Tamim, Thomas Martitz, Tomás Vírseda, "
+"Tyler Mulligan, Walery Studennikov, Yura Siamashka";
 
 
 static void header_eventbox_style_set(GtkWidget *widget);

Modified: trunk/src/editor.c
===================================================================
--- trunk/src/editor.c	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/src/editor.c	2009-01-11 21:05:03 UTC (rev 3461)
@@ -58,12 +58,16 @@
 #include "keybindings.h"
 #include "project.h"
 #include "projectprivate.h"
+#include "queue.h"
 
 
 /* Note: Avoid using SSM in files not related to scintilla, use sciwrappers.h instead. */
 #define SSM(s, m, w, l) scintilla_send_message(s, m, w, l)
 
 
+static GeanyQueue *snippet_queue = NULL;
+static gint snippet_cursor_insert_pos;
+
 /* holds word under the mouse or keyboard cursor */
 static gchar current_word[GEANY_MAX_WORD_LENGTH];
 
@@ -96,9 +100,10 @@
 static void close_block(GeanyEditor *editor, gint pos);
 
 
-void editor_snippets_free()
+void editor_snippets_free(void)
 {
 	g_hash_table_destroy(editor_prefs.snippets);
+	queue_destroy(snippet_queue);
 }
 
 
@@ -113,6 +118,8 @@
 	GKeyFile *userconfig = g_key_file_new();
 	GHashTable *tmp;
 
+	snippet_queue = queue_init();
+
 	sysconfigfile = g_strconcat(app->datadir, G_DIR_SEPARATOR_S, "snippets.conf", NULL);
 	userconfigfile = g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "snippets.conf", NULL);
 
@@ -1800,12 +1807,15 @@
  * @param cursor_index If >= 0, the index into @a text to place the cursor.
  * @param newline_indent_size Indentation size (in spaces) to insert for each newline; use
  * -1 to read the indent size from the line with @a insert_pos on it.
+ * @param replace_newlines Whether to replace newlines in text or not. If
+ * newlines have been replaced before, this should be false, to avoid multiple
+ * replacements of newlines, which is error prone on Windows.
  * @warning Make sure all \t tab chars in @a text are intended as indent widths,
  * NOT any hard tabs (you get those when copying document text with the Tabs
  * & Spaces indent mode set).
  * @note This doesn't scroll the cursor in view afterwards. */
 static void editor_insert_text_block(GeanyEditor *editor, const gchar *text, gint insert_pos,
-		gint cursor_index, gint newline_indent_size)
+		gint cursor_index, gint newline_indent_size, gboolean replace_newlines)
 {
 	ScintillaObject *sci = editor->sci;
 	gint line_start = sci_get_line_from_position(sci, insert_pos);
@@ -1835,7 +1845,8 @@
 	}
 
 	/* transform line endings */
-	utils_string_replace_all(buf, "\n", editor_get_eol_char(editor));
+	if (replace_newlines)
+		utils_string_replace_all(buf, "\n", editor_get_eol_char(editor));
 
 	/* transform tabs into indent widths (in spaces) */
 	whitespace = g_strnfill(editor_get_indent_prefs(editor)->width, ' ');
@@ -1857,24 +1868,47 @@
 	/* 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);
 
 	g_string_free(buf, TRUE);
 }
 
 
+/* Move the cursor to the next specified cursor position in an inserted snippet.
+ * Can, and should, be optimized to give better results */
+void snippet_goto_next_cursor(ScintillaObject *sci, gint current_pos)
+{
+	if (snippet_queue)
+	{
+		gpointer offset;
+
+		snippet_queue = queue_delete(snippet_queue, &offset, FALSE);
+		if (current_pos > snippet_cursor_insert_pos)
+			snippet_cursor_insert_pos = GPOINTER_TO_INT(offset) + current_pos;
+		else
+			snippet_cursor_insert_pos += GPOINTER_TO_INT(offset);
+
+		sci_set_current_position(sci, snippet_cursor_insert_pos, FALSE);
+	}
+}
+
+
 static gboolean snippets_complete_constructs(GeanyEditor *editor, gint pos, const gchar *word)
 {
+	ScintillaObject *sci = editor->sci;
 	gchar *str, *whitespace;
 	GString *pattern;
-	gint step, str_len;
-	gsize cur_index;
+	gint i, str_len, tmp_pos, whitespace_len, nl_count = 0;
+	gssize cur_index = -1;
 	gint ft_id = FILETYPE_ID(editor->document->file_type);
 	GHashTable *specials;
-	ScintillaObject *sci = editor->sci;
+	GeanyQueue *temp_list;
+	const GeanyIndentPrefs *iprefs;
+	gsize indent_size;
+	gint cursor_steps, old_cursor = 0;
 
 	str = g_strdup(word);
 	g_strstrip(str);
-
 	pattern = g_string_new(snippets_find_completion_by_name(filetypes[ft_id]->name, str));
 	if (pattern == NULL || pattern->len == 0)
 	{
@@ -1883,6 +1917,11 @@
 		return FALSE;
 	}
 
+	temp_list = queue_init();
+	iprefs = editor_get_indent_prefs(editor);
+	read_indent(editor, pos);
+	indent_size = strlen(indent);
+
 	/* remove the typed word, it will be added again by the used auto completion
 	 * (not really necessary but this makes the auto completion more flexible,
 	 *  e.g. with a completion like hi=hello, so typing "hi<TAB>" will result in "hello") */
@@ -1905,25 +1944,71 @@
 	snippets_replace_wildcards(editor, pattern);
 
 	/* transform other wildcards */
-	utils_string_replace_all(pattern, "%newline%", editor_get_eol_char(editor));
+	/* convert to %newlines%, else we get endless loops */
+	utils_string_replace_all(pattern, "\n", "%newline%");
 
-	/* use spaces for indentation, will be fixed up */
-	whitespace = g_strnfill(editor_get_indent_prefs(editor)->width, ' ');
-	utils_string_replace_all(pattern, "%ws%", whitespace);
-	g_free(whitespace);
+	/* if spaces are used, replaces all tabs with %ws%, which is later replaced
+	 * by real whitespace characters
+	 * otherwise replace all %ws% by \t, which will be replaced later by tab
+	 * characters,
+	 * this makes seperating between tab and spaces intentation pretty easy */
+	if (iprefs->type == GEANY_INDENT_TYPE_SPACES)
+		utils_string_replace_all(pattern, "\t", "%ws%");
+	else
+		utils_string_replace_all(pattern, "%ws%", "\t");
 
-	/* find the %cursor% pos (has to be done after all other operations) */
-	step = utils_strpos(pattern->str, "%cursor%");
-	if (step != -1)
-		utils_string_replace_all(pattern, "%cursor%", "");
+	whitespace = g_strnfill(iprefs->width, ' '); /* use spaces for indentation, will be fixed up */
+	whitespace_len = strlen(whitespace);
+	i = 0;
+	while ((cursor_steps = utils_strpos(pattern->str, "%cursor%")) >= 0)
+	{
+		/* replace every %newline% (up to next %cursor%) with EOL,
+		 * and update cursor_steps after */
+		while ((tmp_pos = utils_strpos(pattern->str, "%newline%")) < cursor_steps && tmp_pos != -1)
+		{
+			nl_count++;
+			utils_string_replace_first(pattern, "%newline%", editor_get_eol_char(editor));
+			cursor_steps = utils_strpos(pattern->str, "%cursor%");
+		}
+		/* replace every %ws% (up to next %cursor%) with whitespaces,
+		 * and update cursor_steps after */
+		while ((tmp_pos = utils_strpos(pattern->str, "%ws%")) < cursor_steps && tmp_pos != -1)
+		{
+			utils_string_replace_first(pattern, "%ws%", whitespace);
+			cursor_steps = utils_strpos(pattern->str, "%cursor%");
+		}
+		/* finally replace the next %cursor% */
+		utils_string_replace_first(pattern, "%cursor%", "");
 
-	/* finally insert the text and set the cursor */
-	if (step != -1)
-		cur_index = step;
-	else
+		/* modify cursor_steps to take indentation count and type into account */
+
+		/* We're saving the relative offset to each cursor position in a simple
+		 * linked list, including intendations between them. */
+		if (i++ > 0)
+		{
+			cursor_steps += (nl_count * indent_size);
+			queue_append(temp_list, GINT_TO_POINTER(cursor_steps - old_cursor));
+		}
+		else
+		{
+			nl_count = 0;
+			cur_index = cursor_steps;
+		}
+		old_cursor = cursor_steps;
+	}
+	/* replace remaining %ws% and %newline% which may occur after the last %cursor% */
+	utils_string_replace_all(pattern, "%newline%", editor_get_eol_char(editor));
+	utils_string_replace_all(pattern, "%ws", whitespace);
+	g_free(whitespace);
+	/* We create a new list, where the cursor positions for the most recent
+	 * parsed snipped come first, followed by the remaining positions */
+	if (temp_list->data)
+		snippet_queue = queue_concat_copy(temp_list, snippet_queue);
+	if (cur_index < 0)
 		cur_index = pattern->len;
 
-	editor_insert_text_block(editor, pattern->str, pos, cur_index, -1);
+	/* finally insert the text and set the cursor */
+	editor_insert_text_block(editor, pattern->str, pos, cur_index, -1, FALSE);
 	sci_scroll_caret(sci);
 
 	g_free(str);
@@ -2169,7 +2254,7 @@
 						indent_str, "</tr>\n",
 						NULL);
 	editor_insert_text_block(editor, table, pos, -1,
-		count_indent_size(editor, indent));
+		count_indent_size(editor, indent), TRUE);
 	g_free(table);
 }
 

Modified: trunk/src/editor.h
===================================================================
--- trunk/src/editor.h	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/src/editor.h	2009-01-11 21:05:03 UTC (rev 3461)
@@ -167,6 +167,8 @@
 
 gboolean editor_start_auto_complete(GeanyEditor *editor, gint pos, gboolean force);
 
+void snippet_goto_next_cursor(ScintillaObject *sci, gint current_pos);
+
 gboolean editor_complete_snippet(GeanyEditor *editor, gint pos);
 
 void editor_auto_latex(GeanyEditor *editor, gint pos);

Modified: trunk/src/keybindings.c
===================================================================
--- trunk/src/keybindings.c	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/src/keybindings.c	2009-01-11 21:05:03 UTC (rev 3461)
@@ -242,6 +242,8 @@
 		GDK_Down, GDK_MOD1_MASK, "edit_scrolllinedown", _("Scroll down the view by one line"), NULL);
 	keybindings_set_item(group, GEANY_KEYS_EDITOR_COMPLETESNIPPET, NULL,	/* handled specially in check_snippet_completion() */
 		GDK_Tab, 0, "edit_completesnippet", _("Complete snippet"), NULL);
+	keybindings_set_item(group, GEANY_KEYS_EDITOR_SNIPPET_NEXT_CURSOR, cb_func_editor_action,
+		0, 0, "move_snippetnextcursor", _("Move cursor in snippet"), NULL);
 	keybindings_set_item(group, GEANY_KEYS_EDITOR_SUPPRESSSNIPPETCOMPLETION, cb_func_editor_action,
 		0, 0, "edit_suppresssnippetcompletion", _("Suppress snippet completion"), NULL);
 	keybindings_set_item(group, GEANY_KEYS_EDITOR_CONTEXTACTION, cb_func_editor_action,
@@ -1725,6 +1727,10 @@
 		case GEANY_KEYS_EDITOR_DUPLICATELINE:
 			duplicate_lines(doc->editor);
 			break;
+		case GEANY_KEYS_EDITOR_SNIPPET_NEXT_CURSOR:
+			snippet_goto_next_cursor(doc->editor->sci,
+					sci_get_current_position(doc->editor->sci));
+			break;
 		case GEANY_KEYS_EDITOR_DELETELINE:
 			delete_lines(doc->editor);
 			break;

Modified: trunk/src/keybindings.h
===================================================================
--- trunk/src/keybindings.h	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/src/keybindings.h	2009-01-11 21:05:03 UTC (rev 3461)
@@ -139,6 +139,7 @@
 	GEANY_KEYS_EDITOR_AUTOCOMPLETE,
 	GEANY_KEYS_EDITOR_CALLTIP,
 	GEANY_KEYS_EDITOR_MACROLIST,
+	GEANY_KEYS_EDITOR_SNIPPET_NEXT_CURSOR,
 	GEANY_KEYS_EDITOR_COUNT
 };
 

Modified: trunk/src/makefile.win32
===================================================================
--- trunk/src/makefile.win32	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/src/makefile.win32	2009-01-11 21:05:03 UTC (rev 3461)
@@ -64,7 +64,7 @@
 		geanyentryaction.o geanymenubuttonaction.o geanyobject.o geanywraplabel.o highlighting.o \
 		interface.o keybindings.o keyfile.o \
 		log.o main.o msgwindow.o navqueue.o notebook.o plugins.o prefs.o printing.o project.o \
-		sciwrappers.o search.o socket.o stash.o \
+		queue.o sciwrappers.o search.o socket.o stash.o \
 		symbols.o templates.o toolbar.o tools.o treeviews.o \
 		ui_utils.o utils.o win32.o
 

Modified: trunk/src/plugindata.h
===================================================================
--- trunk/src/plugindata.h	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/src/plugindata.h	2009-01-11 21:05:03 UTC (rev 3461)
@@ -45,7 +45,7 @@
 enum {
 	/** The Application Programming Interface (API) version, incremented
 	 * whenever any plugin data types are modified or appended to. */
-	GEANY_API_VERSION = 123,
+	GEANY_API_VERSION = 124,
 
 	/** The Application Binary Interface (ABI) version, incremented whenever
 	 * existing fields in the plugin data types have to be changed or reordered. */
@@ -329,7 +329,7 @@
 typedef struct UtilsFuncs
 {
 	gboolean	(*str_equal) (const gchar *a, const gchar *b);
-	gboolean	(*string_replace_all) (GString *haystack, const gchar *needle,
+	guint		(*string_replace_all) (GString *haystack, const gchar *needle,
 				 const gchar *replacement);
 	GSList*		(*get_file_list) (const gchar *path, guint *length, GError **error);
 	gint		(*write_file) (const gchar *filename, const gchar *text);

Added: trunk/src/queue.c
===================================================================
--- trunk/src/queue.c	                        (rev 0)
+++ trunk/src/queue.c	2009-01-11 21:05:03 UTC (rev 3461)
@@ -0,0 +1,141 @@
+/*
+ *      queue.c - this file is part of Geany, a fast and lightweight IDE
+ *
+ *      Copyright 2009 kugel. aka Thomas Martitz <thomas47(at)arcor(dot)de>
+ *
+ *      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, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * This provides a simple single linked list, with some functons to modify it.
+ * Being a queue, you can append data only to the end of the list, end retrieve
+ * data from the beginning. Only the first node is directly visible, but with the several foreach
+ * functions you can iterate through the entire list.
+ */
+
+
+#include "geany.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "queue.h"
+
+
+/* Allocates memory for queue_start, and sets next and data members to NULL */
+GeanyQueue *queue_init(void)
+{
+	return g_new0(GeanyQueue, 1);
+}
+
+
+/* Returns true if q_node is the last node in a queue */
+static gboolean queue_is_last_node(const GeanyQueue *q_node)
+{
+    return (q_node->next == NULL);
+}
+
+
+/* Appends a data in a new node at the end of the lst */
+void queue_append(GeanyQueue *queue_start, gpointer data)
+{
+	GeanyQueue *temp, *next;
+
+	if (queue_start == NULL || data == NULL)
+		return;
+
+	if (queue_start->data == NULL)
+	{
+		queue_start->data = data;
+		return;
+	}
+
+	temp = g_new0(GeanyQueue, 1);
+	temp->data = data;
+	temp->next = NULL;
+
+	next = queue_start;
+	while (! queue_is_last_node(next))
+		next = next->next;
+	next->next = temp;
+}
+
+
+/* Removes and frees the first node in queue_start, and writes the data of the
+ * removed node into data.
+ * Returns a pointer to the new first item */
+GeanyQueue *queue_delete(GeanyQueue *queue_start, gpointer *data, const gboolean free_data)
+{
+	GeanyQueue *ret;
+
+	if (NULL == queue_start)
+		return NULL;
+
+	if (data != NULL)
+		*data = queue_start->data;
+
+	if (free_data)
+		g_free(queue_start->data);
+
+	ret = queue_start->next;
+	g_free(queue_start);
+
+	return ret;
+}
+
+
+/* Removes and frees the entire queue staring at queue_start */
+void queue_destroy(GeanyQueue *queue_start)
+{
+	while ((queue_start = queue_delete(queue_start, NULL, FALSE)));
+}
+
+typedef void (*ForeachFunc) (GeanyQueue *queue_start, gpointer data);
+
+/* Iterates through param, and calls func with the node queue_start and each node in param */
+static void queue_foreach_data_2(GeanyQueue *queue_start, ForeachFunc func, GeanyQueue *param)
+{
+	GeanyQueue *temp = param;
+
+	if (!queue_start || !param)
+		return;
+
+	do
+	{
+		(*func) (queue_start, (temp->data));
+	}
+	while ((temp = temp->next));
+}
+
+
+/* Copies the data of each node in q1, then the data of each node in q2 to a newly
+ * created queue, using queue_append. Frees q1 and q2.
+ * Returns a pointer to the created queue. */
+GeanyQueue *queue_concat_copy(GeanyQueue *q1, GeanyQueue *q2)
+{
+	/*		q1 +	q2		=	q3			*
+	 *  ->1->2 + ->4->5->6  = 4->5->6->1->2 */
+	GeanyQueue *ret = queue_init();
+
+	queue_foreach_data_2(ret, queue_append, q1);
+	queue_foreach_data_2(ret, queue_append, q2);
+
+	queue_destroy(q1);
+	queue_destroy(q2);
+
+	return ret;
+}
+


Property changes on: trunk/src/queue.c
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision
Added: svn:eol-style
   + native

Added: trunk/src/queue.h
===================================================================
--- trunk/src/queue.h	                        (rev 0)
+++ trunk/src/queue.h	2009-01-11 21:05:03 UTC (rev 3461)
@@ -0,0 +1,45 @@
+/*
+ *      queue.h - this file is part of Geany, a fast and lightweight IDE
+ *
+ *      Copyright 2009 kugel. aka Thomas Martitz <thomas47(at)arcor(dot)de>
+ *
+ *      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, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __QUEUE_H__
+#define __QUEUE_H__
+
+
+typedef struct _GeanyQueue
+{
+	gpointer data;
+	struct _GeanyQueue *next;
+} GeanyQueue;
+
+
+GeanyQueue *queue_init(void);
+
+void queue_append(GeanyQueue *queue_start, gpointer data);
+
+GeanyQueue *queue_delete(GeanyQueue *queue_start, gpointer *data, const gboolean free_data);
+
+GeanyQueue *queue_concat_copy(GeanyQueue *q1, GeanyQueue *q2);
+
+void queue_destroy(GeanyQueue *queue_start);
+
+
+#endif /* __QUEUE_H__ */


Property changes on: trunk/src/queue.h
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision
Added: svn:eol-style
   + native

Modified: trunk/src/utils.c
===================================================================
--- trunk/src/utils.c	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/src/utils.c	2009-01-11 21:05:03 UTC (rev 3461)
@@ -1355,6 +1355,41 @@
 }
 
 
+static guint utils_string_replace_helper(GString *haystack, const gchar *needle,
+										 const gchar *replace, const guint max_replaces)
+{
+	const gchar *stack, *match;
+	guint ret = 0;
+	gssize pos;
+
+	if (haystack->len == 0)
+		return FALSE;
+	g_return_val_if_fail(NZV(needle), 0);
+
+	stack = haystack->str;
+	if (! (match = strstr(stack, needle)))
+		return 0;
+	do
+	{
+		pos = match - haystack->str;
+		g_string_erase(haystack, pos, strlen(needle));
+
+		/* make next search after removed matching text.
+		 * (we have to be careful to only use haystack->str as its address may change) */
+		stack = haystack->str + pos;
+
+		if (replace)
+		{
+			g_string_insert(haystack, pos, replace);
+			stack = haystack->str + pos + strlen(replace);	/* skip past replacement */
+		}
+	}
+	while (++ret != max_replaces && (match = strstr(stack, needle)));
+
+	return ret;
+}
+
+
 /**
  * Replaces all occurrences of @c needle in @c haystack with @c replace.
  * As of Geany 0.16, @a replace can match @a needle, so the following will work:
@@ -1364,40 +1399,28 @@
  * @param needle The string which should be replaced.
  * @param replace The replacement for @c needle.
  *
- * @return @a TRUE if @c needle was found, else @a FALSE.
+ * @return @a amount of replacements done
  **/
-gboolean utils_string_replace_all(GString *haystack, const gchar *needle, const gchar *replace)
+guint utils_string_replace_all(GString *haystack, const gchar *needle, const gchar *replace)
 {
-	const gchar *stack, *match;
-	gssize pos = -1;
+	return utils_string_replace_helper(haystack, needle, replace, 0);
+}
 
-	if (haystack->len == 0)
-		return FALSE;
-	g_return_val_if_fail(NZV(needle), FALSE);
 
-	stack = haystack->str;
-	while (1)
-	{
-		match = strstr(stack, needle);
-		if (match == NULL)
-			break;
-		else
-		{
-			pos = match - haystack->str;
-			g_string_erase(haystack, pos, strlen(needle));
-
-			/* make next search after removed matching text.
-			 * (we have to be careful to only use haystack->str as its address may change) */
-			stack = haystack->str + pos;
-
-			if (replace)
-			{
-				g_string_insert(haystack, pos, replace);
-				stack = haystack->str + pos + strlen(replace);	/* skip past replacement */
-			}
-		}
-	}
-	return (pos != -1);
+/*
+ * Replaces the first occurrence of @c needle in @c haystack with @c replace.
+ * As of Geany 0.16, @a replace can match @a needle, so the following will work:
+ * @code utils_string_replace_all(text, "\n", "\r\n"); @endcode
+ *
+ * @param haystack The input string to operate on. This string is modified in place.
+ * @param needle The string which should be replaced.
+ * @param replace The replacement for @c needle.
+ *
+ * @return @a amount of replacements done
+ */
+guint utils_string_replace_first(GString *haystack, const gchar *needle, const gchar *replace)
+{
+	return utils_string_replace_helper(haystack, needle, replace, 1);
 }
 
 

Modified: trunk/src/utils.h
===================================================================
--- trunk/src/utils.h	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/src/utils.h	2009-01-11 21:05:03 UTC (rev 3461)
@@ -82,8 +82,10 @@
 
 gchar *utils_get_hostname(void);
 
-gboolean utils_string_replace_all(GString *str, const gchar *needle, const gchar *replace);
+guint utils_string_replace_all(GString *haystack, const gchar *needle, const gchar *replace);
 
+guint utils_string_replace_first(GString *haystack, const gchar *needle, const gchar *replace);
+
 gchar *utils_str_replace(gchar *haystack, const gchar *needle, const gchar *replacement);
 
 gint utils_strpos(const gchar* haystack, const gchar *needle);

Modified: trunk/wscript
===================================================================
--- trunk/wscript	2009-01-11 18:29:39 UTC (rev 3460)
+++ trunk/wscript	2009-01-11 21:05:03 UTC (rev 3461)
@@ -94,7 +94,7 @@
 	'src/highlighting.c', 'src/interface.c', 'src/keybindings.c',
 	'src/keyfile.c', 'src/log.c', 'src/main.c', 'src/msgwindow.c', 'src/navqueue.c', 'src/notebook.c',
 	'src/plugins.c', 'src/prefix.c', 'src/prefs.c', 'src/printing.c', 'src/project.c',
-	'src/sciwrappers.c', 'src/search.c', 'src/socket.c', 'src/stash.c',
+	'src/queue.c', 'src/sciwrappers.c', 'src/search.c', 'src/socket.c', 'src/stash.c',
 	'src/symbols.c',
 	'src/templates.c', 'src/toolbar.c', 'src/tools.c', 'src/treeviews.c',
 	'src/ui_utils.c', 'src/utils.c' ]


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