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.
Revision: 3457
http://geany.svn.sourceforge.net/geany/?rev=3457&view=rev
Author: eht16
Date: 2009-01-09 18:22:07 +0000 (Fri, 09 Jan 2009)
Log Message:
-----------
Add utils_is_remote_path().
Add private field 'is_remote' to GeanyDocument to indicate whether an opened file is locally accessed or via gvfs-fuse.
Modified Paths:
--------------
trunk/ChangeLog
trunk/src/document.c
trunk/src/documentprivate.h
trunk/src/utils.c
trunk/src/utils.h
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2009-01-09 18:21:44 UTC (rev 3456)
+++ trunk/ChangeLog 2009-01-09 18:22:07 UTC (rev 3457)
@@ -5,6 +5,10 @@
Add checks for GIO (GLib >= 2.16) support.
Allow to specify files on the command line and from remote instances
to be URIs (local and with GIO also remote URIs).
+ * src/document.c, src/documentprivate.h, src/utils.c, src/utils.h:
+ Add utils_is_remote_path().
+ Add private field 'is_remote' to GeanyDocument to indicate whether
+ an opened file is locally accessed or via gvfs-fuse.
2009-01-08 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
Modified: trunk/src/document.c
===================================================================
--- trunk/src/document.c 2009-01-09 18:21:44 UTC (rev 3456)
+++ trunk/src/document.c 2009-01-09 18:22:07 UTC (rev 3457)
@@ -1076,9 +1076,14 @@
return NULL;
}
- if (! reload) doc = document_create(utf8_filename);
- g_return_val_if_fail(doc != NULL, NULL); /* really should not happen */
+ if (! reload)
+ {
+ doc = document_create(utf8_filename);
+ g_return_val_if_fail(doc != NULL, NULL); /* really should not happen */
+ doc->priv->is_remote = utils_is_remote_path(locale_filename);
+ }
+
sci_set_undo_collection(doc->editor->sci, FALSE); /* avoid creation of an undo action */
sci_empty_undo_buffer(doc->editor->sci);
@@ -1114,7 +1119,7 @@
{
/* file exists on disk, set real_path */
g_free(doc->real_path);
- doc->real_path = get_real_path_from_utf8(doc->file_name);
+ doc->real_path = tm_get_real_path(locale_filename);
/* "the" SCI signal (connect after initial setup(i.e. adding text)) */
g_signal_connect(doc->editor->sci, "sci-notify", G_CALLBACK(editor_sci_notify_cb),
@@ -1453,6 +1458,13 @@
err = errno;
fclose(fp);
+
+ /* now the file is on disk, set real_path */
+ if (err == 0 && doc->real_path == NULL)
+ {
+ doc->real_path = tm_get_real_path(locale_filename);
+ doc->priv->is_remote = utils_is_remote_path(locale_filename);
+ }
g_free(locale_filename);
return err;
@@ -1548,12 +1560,6 @@
return FALSE;
}
- /* now the file is on disk, set real_path */
- if (doc->real_path == NULL)
- {
- doc->real_path = get_real_path_from_utf8(doc->file_name);
- }
-
/* store the opened encoding for undo/redo */
store_saved_encoding(doc);
Modified: trunk/src/documentprivate.h
===================================================================
--- trunk/src/documentprivate.h 2009-01-09 18:21:44 UTC (rev 3456)
+++ trunk/src/documentprivate.h 2009-01-09 18:22:07 UTC (rev 3457)
@@ -64,10 +64,12 @@
GTrashStack *redo_actions;
/* Used so Undo/Redo works for encoding changes. */
FileEncoding saved_encoding;
- gboolean colourise_needed; /* use document.c:queue_colourise() instead */
- gint line_count; /* Number of lines in the document. */
- gint symbol_list_sort_mode;
-}
+ gboolean colourise_needed; /* use document.c:queue_colourise() instead */
+ gint line_count; /* Number of lines in the document. */
+ gint symbol_list_sort_mode;
+ /* indicates whether a file is on a remote filesystem, works only with GIO/GVFS */
+ gboolean is_remote;
+ }
GeanyDocumentPrivate;
#endif
Modified: trunk/src/utils.c
===================================================================
--- trunk/src/utils.c 2009-01-09 18:21:44 UTC (rev 3456)
+++ trunk/src/utils.c 2009-01-09 18:22:07 UTC (rev 3457)
@@ -1595,3 +1595,34 @@
return (strstr(uri, "://") != NULL);
}
+
+
+/* path should be in locale encoding */
+gboolean utils_is_remote_path(const gchar *path)
+{
+ g_return_val_if_fail(path != NULL, FALSE);
+
+ /* if path is an URI and it doesn't start "file://", we take it as remote */
+ if (utils_is_uri(path) && strncmp(path, "file:", 5) != 0)
+ return TRUE;
+
+#ifndef G_OS_WIN32
+ {
+ static gchar *fuse_path = NULL;
+ static gsize len = 0;
+ if (fuse_path == NULL)
+ {
+ fuse_path = g_build_filename(g_get_home_dir(), ".gvfs", NULL);
+ len = strlen(fuse_path);
+ }
+ /* Comparing the file path against a hardcoded path is not the most elegant solution
+ * but for now it is better than nothing. Ideally, g_file_new_for_path() should create
+ * proper GFile objects for Fuse paths, but it only does in future GVFS
+ * versions (gvfs 1.1.1). */
+ return (strncmp(path, fuse_path, len) == 0);
+ }
+#endif
+ return FALSE;
+}
+
+
Modified: trunk/src/utils.h
===================================================================
--- trunk/src/utils.h 2009-01-09 18:21:44 UTC (rev 3456)
+++ trunk/src/utils.h 2009-01-09 18:22:07 UTC (rev 3457)
@@ -155,4 +155,6 @@
gboolean utils_is_uri(const gchar *uri);
+gboolean utils_is_remote_path(const gchar *path);
+
#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3456
http://geany.svn.sourceforge.net/geany/?rev=3456&view=rev
Author: eht16
Date: 2009-01-09 18:21:44 +0000 (Fri, 09 Jan 2009)
Log Message:
-----------
Plug a small memleak.
Modified Paths:
--------------
trunk/src/document.c
Modified: trunk/src/document.c
===================================================================
--- trunk/src/document.c 2009-01-09 18:21:30 UTC (rev 3455)
+++ trunk/src/document.c 2009-01-09 18:21:44 UTC (rev 3456)
@@ -1453,6 +1453,7 @@
err = errno;
fclose(fp);
+ g_free(locale_filename);
return err;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.