Fix multiple snippet cursor positions for Tabs + Spaces mode.
Simplify editor_insert_snippet() code now we use cursor marker strings. git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@5729 ea778897-0a13-0410-b9d1-a72fbfd435f5
This commit is contained in:
parent
b8f8a36815
commit
06f9d7e068
10
ChangeLog
10
ChangeLog
@ -1,10 +1,18 @@
|
|||||||
|
2011-04-19 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
|
||||||
|
|
||||||
|
* src/editor.c:
|
||||||
|
Fix multiple snippet cursor positions for Tabs + Spaces mode.
|
||||||
|
Simplify editor_insert_snippet() code now we use cursor marker
|
||||||
|
strings.
|
||||||
|
|
||||||
|
|
||||||
2011-04-17 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
|
2011-04-17 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
|
||||||
|
|
||||||
* src/plugindata.h, src/document.c, src/plugins.c, src/document.h,
|
* src/plugindata.h, src/document.c, src/plugins.c, src/document.h,
|
||||||
plugins/geanyfunctions.h:
|
plugins/geanyfunctions.h:
|
||||||
Add document_compare_by_tab_order() and
|
Add document_compare_by_tab_order() and
|
||||||
document_compare_by_tab_order_reverse() to the plugin API.
|
document_compare_by_tab_order_reverse() to the plugin API.
|
||||||
* src/ui_uitls.c:
|
* src/ui_utils.c:
|
||||||
Use document_compare_by_tab_order() as default compare function
|
Use document_compare_by_tab_order() as default compare function
|
||||||
to sort the document list in the document notebook tab menu, this
|
to sort the document list in the document notebook tab menu, this
|
||||||
fixes the currently broken default ordering.
|
fixes the currently broken default ordering.
|
||||||
|
195
src/editor.c
195
src/editor.c
@ -117,8 +117,8 @@ static void read_current_word(GeanyEditor *editor, gint pos, gchar *word, size_t
|
|||||||
const gchar *wc, gboolean stem);
|
const gchar *wc, gboolean stem);
|
||||||
static gsize count_indent_size(GeanyEditor *editor, const gchar *base_indent);
|
static gsize count_indent_size(GeanyEditor *editor, const gchar *base_indent);
|
||||||
static const gchar *snippets_find_completion_by_name(const gchar *type, const gchar *name);
|
static const gchar *snippets_find_completion_by_name(const gchar *type, const gchar *name);
|
||||||
static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
|
static void snippets_make_replacements(GeanyEditor *editor, GString *pattern);
|
||||||
gsize indent_size);
|
static gssize replace_cursor_markers(GeanyEditor *editor, GString *pattern);
|
||||||
|
|
||||||
|
|
||||||
void editor_snippets_free(void)
|
void editor_snippets_free(void)
|
||||||
@ -2309,56 +2309,85 @@ static void snippets_replace_specials(gpointer key, gpointer value, gpointer use
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* this only works with spaces only indentation on the lines */
|
static gboolean utils_regex_find(regex_t *regex, const gchar *haystack, gsize start,
|
||||||
static void fix_line_indents(GeanyEditor *editor, gint line_start, gint line_end)
|
gsize nmatches, regmatch_t *matches)
|
||||||
{
|
{
|
||||||
ScintillaObject *sci = editor->sci;
|
gint eflags = 0;
|
||||||
gint line, cur_line, cur_col, pos;
|
|
||||||
|
|
||||||
/* get the line, col position as fixing indentation will move cursor to start of line */
|
if (start > 0)
|
||||||
pos = sci_get_current_position(sci);
|
|
||||||
cur_col = sci_get_col_from_position(sci, pos);
|
|
||||||
cur_line = sci_get_current_line(sci);
|
|
||||||
|
|
||||||
for (line = line_start; line <= line_end; line++)
|
|
||||||
{
|
{
|
||||||
gint size = sci_get_line_indentation(sci, line);
|
gchar c = haystack[start - 1];
|
||||||
|
|
||||||
/* set to 0 first to trigger proper indent creation */
|
if (c == '\n' || c == '\r')
|
||||||
sci_set_line_indentation(sci, line, 0);
|
eflags = REG_NOTBOL;
|
||||||
sci_set_line_indentation(sci, line, size);
|
|
||||||
}
|
}
|
||||||
pos = scintilla_send_message(sci, SCI_FINDCOLUMN, cur_line, cur_col);
|
return regexec(regex, haystack + start, nmatches, matches, eflags) == 0;
|
||||||
sci_set_current_position(sci, pos, FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void replace_leading_tabs(GString *str, const gchar *whitespace)
|
/* match_index: which match to replace, 0 for whole regex.
|
||||||
|
* note: this doesn't support backreferences in replacements */
|
||||||
|
static guint utils_string_regex_replace_all(GString *haystack,
|
||||||
|
regex_t *regex, guint match_index, const gchar *replace)
|
||||||
{
|
{
|
||||||
regex_t regex;
|
|
||||||
gssize pos;
|
gssize pos;
|
||||||
regmatch_t matches[2];
|
regmatch_t matches[10];
|
||||||
gchar *ptr;
|
guint ret = 0;
|
||||||
|
|
||||||
if (regcomp(®ex, "^ *(\t)", 0) != 0)
|
g_return_val_if_fail(match_index < 10, 0);
|
||||||
{
|
|
||||||
g_return_if_fail(FALSE);
|
|
||||||
}
|
|
||||||
ptr = str->str;
|
|
||||||
while (ptr)
|
|
||||||
{
|
|
||||||
if (regexec(®ex, ptr,
|
|
||||||
G_N_ELEMENTS(matches), matches, 0) != 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
pos = matches[1].rm_so;
|
/* ensure haystack->str is not null */
|
||||||
g_return_if_fail(pos >= 0);
|
if (haystack->len == 0)
|
||||||
pos += ptr - str->str;
|
return 0;
|
||||||
g_string_erase(str, pos, 1);
|
|
||||||
g_string_insert(str, pos, whitespace);
|
pos = 0;
|
||||||
ptr = str->str + pos + strlen(whitespace);
|
while (utils_regex_find(regex, haystack->str, pos, G_N_ELEMENTS(matches), matches))
|
||||||
|
{
|
||||||
|
regmatch_t *match = &matches[match_index];
|
||||||
|
|
||||||
|
g_return_val_if_fail(match->rm_so >= 0, FALSE);
|
||||||
|
pos += match->rm_so;
|
||||||
|
g_string_erase(haystack, pos, match->rm_eo - match->rm_so);
|
||||||
|
g_string_insert(haystack, pos, replace);
|
||||||
|
pos += strlen(replace);
|
||||||
|
ret++;
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void fix_indentation(GeanyEditor *editor, GString *buf)
|
||||||
|
{
|
||||||
|
const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
|
||||||
|
gchar *whitespace;
|
||||||
|
regex_t regex;
|
||||||
|
gint cflags = REG_EXTENDED | REG_NEWLINE;
|
||||||
|
|
||||||
|
/* transform leading tabs into indent widths (in spaces) */
|
||||||
|
whitespace = g_strnfill(iprefs->width, ' ');
|
||||||
|
regcomp(®ex, "^ *(\t)", cflags);
|
||||||
|
while (utils_string_regex_replace_all(buf, ®ex, 1, whitespace));
|
||||||
regfree(®ex);
|
regfree(®ex);
|
||||||
|
|
||||||
|
/* remaining tabs are for alignment */
|
||||||
|
if (iprefs->type != GEANY_INDENT_TYPE_TABS)
|
||||||
|
utils_string_replace_all(buf, "\t", whitespace);
|
||||||
|
|
||||||
|
/* use leading tabs */
|
||||||
|
if (iprefs->type != GEANY_INDENT_TYPE_SPACES)
|
||||||
|
{
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
/* for tabs+spaces mode we want the real tab width, not indent width */
|
||||||
|
setptr(whitespace, g_strnfill(sci_get_tab_width(editor->sci), ' '));
|
||||||
|
str = g_strdup_printf("^\t*(%s)", whitespace);
|
||||||
|
|
||||||
|
regcomp(®ex, str, cflags);
|
||||||
|
while (utils_string_regex_replace_all(buf, ®ex, 1, "\t"));
|
||||||
|
regfree(®ex);
|
||||||
|
g_free(str);
|
||||||
|
}
|
||||||
|
g_free(whitespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2385,11 +2414,10 @@ void editor_insert_text_block(GeanyEditor *editor, const gchar *text, gint inser
|
|||||||
{
|
{
|
||||||
ScintillaObject *sci = editor->sci;
|
ScintillaObject *sci = editor->sci;
|
||||||
gint line_start = sci_get_line_from_position(sci, insert_pos);
|
gint line_start = sci_get_line_from_position(sci, insert_pos);
|
||||||
gint line_end;
|
|
||||||
gchar *whitespace;
|
gchar *whitespace;
|
||||||
GString *buf;
|
GString *buf;
|
||||||
const gchar *eol = editor_get_eol_char(editor);
|
const gchar *eol = editor_get_eol_char(editor);
|
||||||
const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
|
gint idx;
|
||||||
|
|
||||||
g_return_if_fail(text);
|
g_return_if_fail(text);
|
||||||
g_return_if_fail(editor != NULL);
|
g_return_if_fail(editor != NULL);
|
||||||
@ -2405,7 +2433,8 @@ void editor_insert_text_block(GeanyEditor *editor, const gchar *text, gint inser
|
|||||||
/* count indent size up to insert_pos instead of asking sci
|
/* count indent size up to insert_pos instead of asking sci
|
||||||
* because there may be spaces after it */
|
* because there may be spaces after it */
|
||||||
gchar *tmp = sci_get_line(sci, line_start);
|
gchar *tmp = sci_get_line(sci, line_start);
|
||||||
gint idx = insert_pos - sci_get_position_from_line(sci, line_start);
|
|
||||||
|
idx = insert_pos - sci_get_position_from_line(sci, line_start);
|
||||||
tmp[idx] = '\0';
|
tmp[idx] = '\0';
|
||||||
newline_indent_size = count_indent_size(editor, tmp);
|
newline_indent_size = count_indent_size(editor, tmp);
|
||||||
g_free(tmp);
|
g_free(tmp);
|
||||||
@ -2424,32 +2453,19 @@ void editor_insert_text_block(GeanyEditor *editor, const gchar *text, gint inser
|
|||||||
if (replace_newlines)
|
if (replace_newlines)
|
||||||
utils_string_replace_all(buf, "\n", eol);
|
utils_string_replace_all(buf, "\n", eol);
|
||||||
|
|
||||||
/* transform leading tabs into indent widths (in spaces) */
|
fix_indentation(editor, buf);
|
||||||
whitespace = g_strnfill(iprefs->width, ' ');
|
|
||||||
replace_leading_tabs(buf, whitespace);
|
|
||||||
/* remaining tabs are for alignment */
|
|
||||||
if (iprefs->type != GEANY_INDENT_TYPE_TABS)
|
|
||||||
utils_string_replace_all(buf, "\t", whitespace);
|
|
||||||
g_free(whitespace);
|
|
||||||
|
|
||||||
sci_start_undo_action(sci);
|
idx = replace_cursor_markers(editor, buf);
|
||||||
|
if (idx >= 0)
|
||||||
if (cursor_index >= 0)
|
|
||||||
{
|
{
|
||||||
gint idx = utils_string_replace(buf, 0, -1, geany_cursor_marker, NULL);
|
|
||||||
|
|
||||||
sci_insert_text(sci, insert_pos, buf->str);
|
sci_insert_text(sci, insert_pos, buf->str);
|
||||||
sci_set_current_position(sci, insert_pos + idx, FALSE);
|
sci_set_current_position(sci, insert_pos + idx, FALSE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sci_insert_text(sci, insert_pos, buf->str);
|
sci_insert_text(sci, insert_pos, buf->str);
|
||||||
|
|
||||||
/* fixup indentation (very useful for Tabs & Spaces indent type) */
|
|
||||||
line_end = sci_get_line_from_position(sci, insert_pos + buf->len);
|
|
||||||
fix_line_indents(editor, line_start, line_end);
|
|
||||||
snippet_cursor_insert_pos = sci_get_current_position(sci);
|
snippet_cursor_insert_pos = sci_get_current_position(sci);
|
||||||
|
|
||||||
sci_end_undo_action(sci);
|
|
||||||
g_string_free(buf, TRUE);
|
g_string_free(buf, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2480,13 +2496,9 @@ void editor_goto_next_snippet_cursor(GeanyEditor *editor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gssize replace_cursor_markers(GeanyEditor *editor, GString *pattern, gsize indent_size);
|
static void snippets_make_replacements(GeanyEditor *editor, GString *pattern)
|
||||||
|
|
||||||
static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern, gsize indent_size)
|
|
||||||
{
|
{
|
||||||
gchar *whitespace;
|
|
||||||
GHashTable *specials;
|
GHashTable *specials;
|
||||||
const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
|
|
||||||
|
|
||||||
/* replace 'special' completions */
|
/* replace 'special' completions */
|
||||||
specials = g_hash_table_lookup(snippet_hash, "Special");
|
specials = g_hash_table_lookup(snippet_hash, "Special");
|
||||||
@ -2498,19 +2510,8 @@ static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* now transform other wildcards */
|
/* now transform other wildcards */
|
||||||
|
|
||||||
utils_string_replace_all(pattern, "%newline%", "\n");
|
utils_string_replace_all(pattern, "%newline%", "\n");
|
||||||
|
utils_string_replace_all(pattern, "%ws%", "\t");
|
||||||
/* if spaces are used, replace tabs with spaces
|
|
||||||
* otherwise replace all %ws% by \t */
|
|
||||||
if (iprefs->type == GEANY_INDENT_TYPE_SPACES)
|
|
||||||
utils_string_replace_all(pattern, "\t", "%ws%");
|
|
||||||
else
|
|
||||||
utils_string_replace_all(pattern, "%ws%", "\t");
|
|
||||||
|
|
||||||
whitespace = g_strnfill(iprefs->width, ' '); /* use spaces for indentation, will be fixed up */
|
|
||||||
utils_string_replace_all(pattern, "%ws%", whitespace);
|
|
||||||
g_free(whitespace);
|
|
||||||
|
|
||||||
/* replace %cursor% by a very unlikely string marker */
|
/* replace %cursor% by a very unlikely string marker */
|
||||||
utils_string_replace_all(pattern, "%cursor%", geany_cursor_marker);
|
utils_string_replace_all(pattern, "%cursor%", geany_cursor_marker);
|
||||||
@ -2520,61 +2521,35 @@ static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
|
|||||||
|
|
||||||
/* replace any template {foo} wildcards */
|
/* replace any template {foo} wildcards */
|
||||||
templates_replace_common(pattern, editor->document->file_name, editor->document->file_type, NULL);
|
templates_replace_common(pattern, editor->document->file_name, editor->document->file_type, NULL);
|
||||||
|
|
||||||
return replace_cursor_markers(editor, pattern, indent_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gssize replace_cursor_markers(GeanyEditor *editor, GString *pattern, gsize indent_size)
|
static gssize replace_cursor_markers(GeanyEditor *editor, GString *pattern)
|
||||||
{
|
{
|
||||||
gssize cur_index = -1;
|
gssize cur_index = -1;
|
||||||
gint i, idx, nl_count = 0;
|
gint i;
|
||||||
GList *temp_list = NULL;
|
GList *temp_list = NULL;
|
||||||
gint cursor_steps, old_cursor = 0;
|
gint cursor_steps = 0, old_cursor = 0;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
idx = 0;
|
while (1)
|
||||||
while ((cursor_steps = utils_strpos(pattern->str, geany_cursor_marker)) >= 0)
|
|
||||||
{
|
{
|
||||||
/* replace every newline (up to next cursor) with EOL,
|
cursor_steps = utils_string_replace(pattern, cursor_steps, -1, geany_cursor_marker, NULL);
|
||||||
* count newlines and update cursor_steps after */
|
if (cursor_steps == -1)
|
||||||
while (1)
|
break;
|
||||||
{
|
|
||||||
idx = utils_string_replace(pattern, idx, cursor_steps, "\n", editor_get_eol_char(editor));
|
|
||||||
if (idx == -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
nl_count++;
|
|
||||||
idx += editor_get_eol_char_len(editor);
|
|
||||||
|
|
||||||
cursor_steps = utils_strpos(pattern->str, geany_cursor_marker);
|
|
||||||
}
|
|
||||||
utils_string_replace_first(pattern, geany_cursor_marker, "");
|
|
||||||
idx = cursor_steps;
|
|
||||||
|
|
||||||
if (i++ > 0)
|
if (i++ > 0)
|
||||||
{
|
{
|
||||||
/* save the relative offset to each cursor position */
|
/* save the relative offset to each cursor position */
|
||||||
cursor_steps += (nl_count * indent_size);
|
|
||||||
temp_list = g_list_prepend(temp_list, GINT_TO_POINTER(cursor_steps - old_cursor));
|
temp_list = g_list_prepend(temp_list, GINT_TO_POINTER(cursor_steps - old_cursor));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* first cursor already includes newline positions */
|
/* first cursor already includes newline positions */
|
||||||
nl_count = 0;
|
|
||||||
cur_index = cursor_steps;
|
cur_index = cursor_steps;
|
||||||
}
|
}
|
||||||
old_cursor = cursor_steps;
|
old_cursor = cursor_steps;
|
||||||
}
|
}
|
||||||
/* replace remaining \n which may occur after the last cursor */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
idx = utils_string_replace(pattern, idx, -1, "\n", editor_get_eol_char(editor));
|
|
||||||
if (idx == -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
idx += editor_get_eol_char_len(editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* put the cursor positions for the most recent
|
/* put the cursor positions for the most recent
|
||||||
* parsed snippet first, followed by any remaining positions */
|
* parsed snippet first, followed by any remaining positions */
|
||||||
@ -5110,12 +5085,10 @@ const gchar *editor_find_snippet(GeanyEditor *editor, const gchar *snippet_name)
|
|||||||
*/
|
*/
|
||||||
void editor_insert_snippet(GeanyEditor *editor, gint pos, const gchar *snippet)
|
void editor_insert_snippet(GeanyEditor *editor, gint pos, const gchar *snippet)
|
||||||
{
|
{
|
||||||
gint cursor_pos;
|
|
||||||
GString *pattern;
|
GString *pattern;
|
||||||
|
|
||||||
pattern = g_string_new(snippet);
|
pattern = g_string_new(snippet);
|
||||||
read_indent(editor, pos);
|
snippets_make_replacements(editor, pattern);
|
||||||
cursor_pos = snippets_make_replacements(editor, pattern, strlen(indent));
|
editor_insert_text_block(editor, pattern->str, pos, -1, -1, FALSE);
|
||||||
editor_insert_text_block(editor, pattern->str, pos, cursor_pos, -1, FALSE);
|
|
||||||
g_string_free(pattern, TRUE);
|
g_string_free(pattern, TRUE);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user