On Wed, 17 Nov 2010 14:48:49 +0000%
Nick Treleaven <[email protected]> wrote:
> On Tue, 16 Nov 2010 19:06:59 +0300
> Eugene Arshinov <[email protected]> wrote:
>
> > > > > In [HTML] section I have a snippet
> > > > >
> > > > > lia=<li><a href="%cursor%">%cursor%</a></li>
> > > > >
> > > > > It begins with a tag, so the plugin will insert it after I
> > > > > type <lia> (it will result in <lia><li><a ...>...</a></li>
> > > > > which isn't useful).
> > > >
> > > > Why would <lia> be kept? That should be removed, otherwise
> > > > <table> would result in <table><table>...</table>
> > >
> > > Yes, removing the tag is a good idea, especially if we account
> > > that it's how "ordinary" snippets work now. I had an idea that
> > > for snippets for the plugin snippet body should contain only the
> > > part that's inserted (i.e., shouldn't contain the first open tag)
> > > because it easily allows to save attributes user may have
> > > specified in the open tag that gets autocompleted. If we remove
> > > this tag, we'll have to copy the attributes to the first tag
> > > within snippet body, but I think it's easy to implement.
>
> I would implement it to not autocomplete tags with attributes, only
> match '<' + snippet_name + '>'. The user could add any attributes
> after snippet insertion.
>
Yes, but moving cursor back and forth for that, I think, would be too
annoying. User can insert %cursor% when he might want to insert
attributes, but I think it isn't convenient too. Moreover, this will
be a regression against the HTML table template which was built-in
previously (of course, a minor regression, but still).
For me as a user an acceptable solution would be copy "input
attributes" to the first tag of snippet body (we already search for the
first tag, by the way), if the latter does not already contain
attributes (which will be true most of the time). And
implementing copying appeared not so hard for me, so I
implemented it. The code got larger than I expected, but I still
thing it is normal for the benefit it gives.
I need to copy attributes before editor.c:snippets_make_replacements
runs to get correct cursor positions, so I have to escape the
attributes string. But, in order the string got "unescaped" properly,
I had to fix the bug with {ob} and {cb} templates. This is the first
patch.
The previous version of the patch incorrectly left the typed tag
intact. To remove it I had to get open_xml_tag_pos instead of
open_xml_tag. I added the corresponding function and exported it.
This is the second patch.
If you have some free time, please review and commit. (I start to
think geany-devel would be the proper place for this discussion :-))
BTW, here is the current code of the plugin:
<http://nopaste.geany.org/p/m5d408564>. It looks a bit scary because
of not-so-useful structs, but it's the way I chose to group pointers
by what they point to (input or snippet), otherwise I got confused
quickly. My little C experience suggests me nothing less ugly.
Best regards,
Eugene.diff --git a/ChangeLog b/ChangeLog
index f66ec60..3aa7e91 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2010-11-21 Eugene Arshinov <earshinov(at)gmail(dot)com>
+
+ * src/editor.c, src/templates.c, src/templates.h:
+ Fix a bug in editor.c:snippets_make_replacements() with handling of
+ {ob} and {cb}. Function template_replace_common() now takes an
+ argument that controls if {ob} and {cb} should be replaced.
+
+
2010-11-18 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
* src/build.c, src/dialogs.c, src/dialogs.h, src/callbacks.c:
diff --git a/src/editor.c b/src/editor.c
index 46a0666..bbb73f7 100644
--- a/src/editor.c
+++ b/src/editor.c
@@ -2402,12 +2402,13 @@ static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
gsize indent_size)
{
gssize cur_index = -1;
- gchar *whitespace;
- gint i, tmp_pos, whitespace_len, nl_count = 0;
+ gchar *whitespace, *ptr;
+ gint i, pos, whitespace_len, nl_count = 0, offset;
GHashTable *specials;
- GList *temp_list = NULL;
+ GList *temp_list = NULL, *node;
const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
gint cursor_steps, old_cursor = 0;
+ gboolean cur_index_handled;
/* replace 'special' completions */
specials = g_hash_table_lookup(snippet_hash, "Special");
@@ -2418,8 +2419,8 @@ static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
g_hash_table_foreach(specials, snippets_replace_specials, NULL);
}
- /* replace any template {foo} wildcards */
- templates_replace_common(pattern, editor->document->file_name, editor->document->file_type, NULL);
+ /* replace any template {foo} wildcards except braces {ob} and {cb} */
+ templates_replace_common(pattern, editor->document->file_name, editor->document->file_type, NULL, FALSE);
/* transform other wildcards */
/* convert to %newlines%, else we get endless loops */
@@ -2442,7 +2443,7 @@ static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
{
/* 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)
+ while ((pos = utils_strpos(pattern->str, "%newline%")) < cursor_steps && pos != -1)
{
nl_count++;
utils_string_replace_first(pattern, "%newline%", editor_get_eol_char(editor));
@@ -2450,7 +2451,7 @@ static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
}
/* 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)
+ while ((pos = utils_strpos(pattern->str, "%ws%")) < cursor_steps && pos != -1)
{
utils_string_replace_first(pattern, "%ws%", whitespace);
cursor_steps = utils_strpos(pattern->str, "%cursor%");
@@ -2480,16 +2481,61 @@ static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
g_free(whitespace);
/* escape % last */
- /* Bug: {ob}pc{cb} will be replaced by % too */
- templates_replace_valist(pattern, "{pc}", "%", NULL);
+ pos = 0;
+ offset = 0;
+ node = temp_list;
+ cur_index_handled = FALSE;
+ while ((ptr = strchr(pattern->str + pos, '{')) != NULL)
+ {
+ pos = ptr - pattern->str;
+
+ /* synchronously iterate the list of cursor positions, applying current offset
+ * remember to handle cur_index separately */
+ if (!cur_index_handled && cur_index + offset <= pos)
+ {
+ cur_index += offset;
+ cur_index_handled = TRUE;
+ }
+ while (node && GPOINTER_TO_INT(node->data) + offset <= pos)
+ {
+ node->data += offset;
+ node = node->next;
+ }
+
+ if (strncmp(pattern->str + pos + 1, "pc}", 3) == 0)
+ {
+ g_string_erase(pattern, pos + 1, 3);
+ pattern->str[pos] = '%';
+ pos++; /* one char inserted */
+ offset -= 3; /* pattern became 3 chars shorter */
+ }
+ else if (strncmp(pattern->str + pos + 1, "ob}", 3) == 0)
+ {
+ g_string_erase(pattern, pos + 1, 3);
+ pattern->str[pos] = '{';
+ pos++; /* one char inserted */
+ offset -= 3; /* pattern became 3 chars shorter */
+ }
+ else if (strncmp(pattern->str + pos + 1, "cb}", 3) == 0)
+ {
+ g_string_erase(pattern, pos + 1, 3);
+ pattern->str[pos] = '}';
+ pos++; /* one char inserted */
+ offset -= 3; /* pattern became 3 chars shorter */
+ }
+ else
+ pos++; /* skip the brace */
+ }
+ if (!cur_index_handled)
+ cur_index += offset;
+ for (; node; node = node->next)
+ node->data += offset;
/* We put the cursor positions for the most recent
* parsed snippet first, followed by any remaining positions */
i = 0;
if (temp_list)
{
- GList *node;
-
foreach_list(node, temp_list)
g_queue_push_nth(snippet_offsets, node->data, i++);
diff --git a/src/templates.c b/src/templates.c
index ad37b2c..eda66c8 100644
--- a/src/templates.c
+++ b/src/templates.c
@@ -220,7 +220,7 @@ static gboolean create_new_filetype_items(void)
void templates_replace_common(GString *template, const gchar *fname,
- GeanyFiletype *ft, const gchar *func_name)
+ GeanyFiletype *ft, const gchar *func_name, gboolean replace_braces)
{
gchar *shortname;
@@ -244,11 +244,15 @@ void templates_replace_common(GString *template, const gchar *fname,
templates_replace_default_dates(template);
templates_replace_command(template, fname, ft->name, func_name);
/* Bug: command results could have {ob} {cb} strings in! */
- /* replace braces last */
- templates_replace_valist(template,
- "{ob}", "{",
- "{cb}", "}",
- NULL);
+
+ if (replace_braces)
+ {
+ /* replace braces last */
+ templates_replace_valist(template,
+ "{ob}", "{",
+ "{cb}", "}",
+ NULL);
+ }
}
@@ -270,7 +274,7 @@ static gchar *get_template_from_file(const gchar *locale_fname, const gchar *doc
templates_replace_valist(template,
"{fileheader}", file_header,
NULL);
- templates_replace_common(template, doc_filename, ft, NULL);
+ templates_replace_common(template, doc_filename, ft, NULL, TRUE);
utils_free_pointers(2, file_header, content, NULL);
return g_string_free(template, FALSE);
@@ -578,7 +582,7 @@ gchar *templates_get_template_fileheader(gint filetype_idx, const gchar *fname)
GString *template = g_string_new(str);
g_free(str);
- templates_replace_common(template, fname, ft, NULL);
+ templates_replace_common(template, fname, ft, NULL, TRUE);
convert_eol_characters(template, NULL);
return g_string_free(template, FALSE);
}
@@ -603,7 +607,7 @@ gchar *templates_get_template_new_file(GeanyFiletype *ft)
file_header = get_template_fileheader(ft);
templates_replace_valist(ft_template, "{fileheader}", file_header, NULL);
}
- templates_replace_common(ft_template, NULL, ft, NULL);
+ templates_replace_common(ft_template, NULL, ft, NULL, TRUE);
convert_eol_characters(ft_template, NULL);
g_free(file_header);
diff --git a/src/templates.h b/src/templates.h
index 74a1555..069069c 100644
--- a/src/templates.h
+++ b/src/templates.h
@@ -73,7 +73,7 @@ gchar *templates_get_template_function(GeanyDocument *doc, const gchar *func_nam
gchar *templates_get_template_licence(GeanyDocument *doc, gint licence_type);
void templates_replace_common(GString *template, const gchar *fname,
- GeanyFiletype *ft, const gchar *func_name);
+ GeanyFiletype *ft, const gchar *func_name, gboolean replace_braces);
void templates_replace_valist(GString *text,
const gchar *first_wildcard, ...) G_GNUC_NULL_TERMINATED;
diff --git a/ChangeLog b/ChangeLog
index 3aa7e91..826bd4e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,10 @@
Fix a bug in editor.c:snippets_make_replacements() with handling of
{ob} and {cb}. Function template_replace_common() now takes an
argument that controls if {ob} and {cb} should be replaced.
+ * plugins/geanyfunctions.h, src/plugindata.h, src/plugins.c,
+ src/utils.c, src/utils.h:
+ Add utils_find_open_xml_tag_pos() function which was previously a
+ part of utils_find_open_xml_tag(). Add the new function to API.
2010-11-18 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
diff --git a/plugins/geanyfunctions.h b/plugins/geanyfunctions.h
index ab12bbf..e5ee73f 100644
--- a/plugins/geanyfunctions.h
+++ b/plugins/geanyfunctions.h
@@ -250,6 +250,8 @@
geany_functions->p_utils->utils_copy_environment
#define utils_find_open_xml_tag \
geany_functions->p_utils->utils_find_open_xml_tag
+#define utils_find_open_xml_tag_pos \
+ geany_functions->p_utils->utils_find_open_xml_tag_pos
#define ui_dialog_vbox_new \
geany_functions->p_ui->ui_dialog_vbox_new
#define ui_frame_new_with_alignment \
diff --git a/src/plugindata.h b/src/plugindata.h
index 72c84d5..67f5cb4 100644
--- a/src/plugindata.h
+++ b/src/plugindata.h
@@ -50,7 +50,7 @@
enum {
/** The Application Programming Interface (API) version, incremented
* whenever any plugin data types are modified or appended to. */
- GEANY_API_VERSION = 199,
+ GEANY_API_VERSION = 200,
/** The Application Binary Interface (ABI) version, incremented whenever
* existing fields in the plugin data types have to be changed or reordered. */
@@ -432,6 +432,7 @@ typedef struct UtilsFuncs
GError **error);
gchar** (*utils_copy_environment)(const gchar **exclude_vars, const gchar *first_varname, ...);
gchar* (*utils_find_open_xml_tag) (const gchar sel[], gint size);
+ const gchar* (*utils_find_open_xml_tag_pos) (const gchar sel[], gint size);
}
UtilsFuncs;
@@ -621,6 +622,8 @@ typedef struct EditorFuncs
const gchar* (*editor_find_snippet) (struct GeanyEditor *editor, const gchar *snippet_name);
void (*editor_insert_snippet) (struct GeanyEditor *editor, gint pos, const gchar *snippet);
+ gssize (*editor_snippets_make_replacements)(GeanyEditor *editor, GString *pattern,
+ gsize indent_size);
}
EditorFuncs;
diff --git a/src/plugins.c b/src/plugins.c
index 745e414..859fd10 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -219,7 +219,8 @@ static UtilsFuncs utils_funcs = {
&utils_str_remove_chars,
&utils_get_file_list_full,
&utils_copy_environment,
- &utils_find_open_xml_tag
+ &utils_find_open_xml_tag,
+ &utils_find_open_xml_tag_pos
};
static UIUtilsFuncs uiutils_funcs = {
diff --git a/src/utils.c b/src/utils.c
index 46e9207..e7e5655 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -276,13 +276,34 @@ gint utils_write_file(const gchar *filename, const gchar *text)
}
-/** Searches backward through @a size bytes looking for a '<', then returns the tag, if any.
+/** Searches backward through @a size bytes looking for a '<'
* @param sel .
* @param size .
- * @return The tag name.
+ * @return The tag name (newly allocated) or @c NULL if no opening tag was found
*/
gchar *utils_find_open_xml_tag(const gchar sel[], gint size)
{
+ const gchar *cur, *begin;
+
+ cur = utils_find_open_xml_tag_pos(sel, size);
+ if (cur == NULL)
+ return NULL;
+
+ cur++; /* skip the bracket */
+ begin = cur;
+ while (strchr(":_-.", *cur) || isalnum(*cur))
+ cur++;
+ return g_strndup(begin, cur-begin);
+}
+
+
+/** Searches backward through @a size bytes looking for a '<'
+ * @param sel .
+ * @param size .
+ * @return pointer to '<' of the found opening tag within @a sel, or @c NULL if no opening tag was found
+ */
+const gchar *utils_find_open_xml_tag_pos(const gchar sel[], gint size)
+{
/* stolen from anjuta and modified */
const gchar *begin, *cur;
@@ -310,27 +331,15 @@ gchar *utils_find_open_xml_tag(const gchar sel[], gint size)
{
if (*cur == '<')
break;
+ /* exit immediately if such non-valid XML/HTML is detected, e.g. "<script>if a >" */
else if (*cur == '>')
break;
--cur;
}
- if (*cur == '<')
- {
- GString *result;
-
- cur++;
- if (*cur == '/')
- return NULL; /* we found a closing tag */
-
- result = g_string_sized_new(64);
- while (strchr(":_-.", *cur) || isalnum(*cur))
- {
- g_string_append_c(result, *cur);
- cur++;
- }
- return g_string_free(result, FALSE);
- }
+ if (*cur == '<' && *(cur+1) != '/')
+ /* if the found tag is an opening, not a closing tag */
+ return cur;
return NULL;
}
diff --git a/src/utils.h b/src/utils.h
index 7d92751..bccf8c2 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -142,6 +142,8 @@ gint utils_write_file(const gchar *filename, const gchar *text);
gchar *utils_find_open_xml_tag(const gchar sel[], gint size);
+const gchar *utils_find_open_xml_tag_pos(const gchar sel[], gint size);
+
gboolean utils_is_short_html_tag(const gchar *tag_name);
void utils_ensure_same_eol_characters(GString *string, gint target_eol_mode);
_______________________________________________
Geany mailing list
[email protected]
http://lists.uvena.de/cgi-bin/mailman/listinfo/geany