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.