~ubuntu-branches/ubuntu/wily/geany/wily

« back to all changes in this revision

Viewing changes to src/editor.c

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2011-12-10 07:43:26 UTC
  • mfrom: (3.3.7 sid)
  • Revision ID: package-import@ubuntu.com-20111210074326-s8yqbew5i20h33tf
Tags: 0.21-1ubuntu1
* Merge from Debian Unstable, remaining changes:
  - debian/patches/20_use_evince_viewer.patch:
     + use evince as viewer for pdf and dvi files
  - debian/patches/20_use_x_terminal_emulator.patch:
     + use x-terminal-emulator as terminal
  - debian/control
     + Add breaks on geany-plugins-common << 0.20
* Also fixes bugs:
  - Filter for MATLAB/Octave files filters everythign (LP: 885505)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 *      editor.c - this file is part of Geany, a fast and lightweight IDE
3
3
 *
4
 
 *      Copyright 2005-2010 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5
 
 *      Copyright 2006-2010 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
6
 
 *      Copyright 2009-2010 Frank Lanitz <frank(at)frank(dot)uvena(dot)de>
 
4
 *      Copyright 2005-2011 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
 
5
 *      Copyright 2006-2011 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
 
6
 *      Copyright 2009-2011 Frank Lanitz <frank(at)frank(dot)uvena(dot)de>
7
7
 *
8
8
 *      This program is free software; you can redistribute it and/or modify
9
9
 *      it under the terms of the GNU General Public License as published by
19
19
 *      along with this program; if not, write to the Free Software
20
20
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
21
 *
22
 
 * $Id: editor.c 5495 2010-12-22 13:44:41Z ntrel $
 
22
 * $Id: editor.c 5959 2011-09-26 16:31:32Z ntrel $
23
23
 */
24
24
 
25
25
/**
80
80
static gint snippet_cursor_insert_pos;
81
81
static GtkAccelGroup *snippet_accel_group = NULL;
82
82
 
 
83
static const gchar geany_cursor_marker[] = "__GEANY_CURSOR_MARKER__";
 
84
 
83
85
/* holds word under the mouse or keyboard cursor */
84
86
static gchar current_word[GEANY_MAX_WORD_LENGTH];
85
87
 
108
110
static void auto_close_chars(ScintillaObject *sci, gint pos, gchar c);
109
111
static void close_block(GeanyEditor *editor, gint pos);
110
112
static void editor_highlight_braces(GeanyEditor *editor, gint cur_pos);
111
 
static void read_current_word(GeanyEditor *editor, gint pos, gchar *word, size_t wordlen,
 
113
static void read_current_word(GeanyEditor *editor, gint pos, gchar *word, gsize wordlen,
112
114
                const gchar *wc, gboolean stem);
113
115
static gsize count_indent_size(GeanyEditor *editor, const gchar *base_indent);
114
116
static const gchar *snippets_find_completion_by_name(const gchar *type, const gchar *name);
115
 
static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
116
 
                gsize indent_size);
 
117
static void snippets_make_replacements(GeanyEditor *editor, GString *pattern);
 
118
static gssize replace_cursor_markers(GeanyEditor *editor, GString *pattern);
117
119
 
118
120
 
119
121
void editor_snippets_free(void)
341
343
        {
342
344
                gboolean can_goto;
343
345
 
 
346
                /* ensure the editor widget has the focus after this operation */
 
347
                gtk_widget_grab_focus(widget);
 
348
 
344
349
                editor_find_current_word(editor, editor_info.click_pos,
345
350
                        current_word, sizeof current_word, NULL);
346
351
 
509
514
        ScintillaObject *sci = editor->sci;
510
515
        gint pos = sci_get_current_position(sci);
511
516
 
 
517
        /* since Scintilla 2.24, SCN_UPDATEUI is also sent on scrolling though we don't need to handle
 
518
         * this and so ignore every SCN_UPDATEUI events except for content and selection changes */
 
519
        if (! (nt->updated & SC_UPDATE_CONTENT) && ! (nt->updated & SC_UPDATE_SELECTION))
 
520
                return;
 
521
 
512
522
        /* undo / redo menu update */
513
523
        ui_update_popup_reundo_items(editor->document);
514
524
 
811
821
        (*line)++;
812
822
        while (*line <= lineMaxSubord)
813
823
        {
814
 
                if (G_UNLIKELY(force))
 
824
                if (force)
815
825
                {
816
826
                        if (visLevels > 0)
817
827
                                SSM(sci, SCI_SHOWLINES, *line, *line);
827
837
                        levelLine = SSM(sci, SCI_GETFOLDLEVEL, *line, 0);
828
838
                if (levelLine & SC_FOLDLEVELHEADERFLAG)
829
839
                {
830
 
                        if (G_UNLIKELY(force))
 
840
                        if (force)
831
841
                        {
832
842
                                if (visLevels > 1)
833
843
                                        SSM(sci, SCI_SETFOLDEXPANDED, *line, 1);
1049
1059
                                /* handle special fold cases, e.g. #1923350 */
1050
1060
                                fold_changed(sci, nt->line, nt->foldLevelNow, nt->foldLevelPrev);
1051
1061
                        }
 
1062
                        if (nt->modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT))
 
1063
                        {
 
1064
                                document_update_tag_list_in_idle(doc);
 
1065
                        }
1052
1066
                        break;
1053
1067
 
1054
1068
                case SCN_CHARADDED:
1088
1102
                case SCN_URIDROPPED:
1089
1103
                        if (nt->text != NULL)
1090
1104
                        {
1091
 
                                document_open_file_list(nt->text, -1);
 
1105
                                document_open_file_list(nt->text, strlen(nt->text));
1092
1106
                        }
1093
1107
                        break;
1094
1108
 
1484
1498
        gint depth = 1;
1485
1499
        gint styAtPos;
1486
1500
 
 
1501
        /* Hack: we need the style at @p pos but it isn't computed yet, so force styling
 
1502
         * of this very position */
 
1503
        sci_colourise(sci, pos, pos + 1);
 
1504
 
1487
1505
        styBrace = sci_get_style_at(sci, pos);
1488
1506
 
1489
1507
        if (utils_is_opening_brace(chBrace, editor_prefs.brace_match_ltgt))
1490
1508
                direction = 1;
1491
1509
 
1492
 
        pos = pos + direction;
 
1510
        pos += direction;
1493
1511
        while ((pos >= 0) && (pos < sci_get_length(sci)))
1494
1512
        {
1495
 
                chAtPos = sci_get_char_at(sci, pos - 1);
 
1513
                chAtPos = sci_get_char_at(sci, pos);
1496
1514
                styAtPos = sci_get_style_at(sci, pos);
1497
1515
 
1498
1516
                if ((pos > sci_get_end_styled(sci)) || (styAtPos == styBrace))
1504
1522
                        if (depth == 0)
1505
1523
                                return pos;
1506
1524
                }
1507
 
                pos = pos + direction;
 
1525
                pos += direction;
1508
1526
        }
1509
1527
        return -1;
1510
1528
}
1513
1531
/* Called after typing '}'. */
1514
1532
static void close_block(GeanyEditor *editor, gint pos)
1515
1533
{
1516
 
        GeanyDocument *doc;
1517
1534
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
1518
1535
        gint x = 0, cnt = 0;
1519
1536
        gint line, line_len, eol_char_len;
1526
1543
        g_return_if_fail(editor != NULL && editor->document->file_type != NULL);
1527
1544
 
1528
1545
        sci = editor->sci;
1529
 
        doc = editor->document;
1530
1546
 
1531
1547
        if (! lexer_has_braces(sci))
1532
1548
                return;
1585
1601
}
1586
1602
 
1587
1603
 
 
1604
/* checks whether @p c is an ASCII character (e.g. < 0x80) */
 
1605
#define IS_ASCII(c) (((unsigned char)(c)) < 0x80)
 
1606
 
 
1607
 
1588
1608
/* Reads the word at given cursor position and writes it into the given buffer. The buffer will be
1589
1609
 * NULL terminated in any case, even when the word is truncated because wordlen is too small.
1590
1610
 * position can be -1, then the current position is used.
1591
1611
 * wc are the wordchars to use, if NULL, GEANY_WORDCHARS will be used */
1592
 
static void read_current_word(GeanyEditor *editor, gint pos, gchar *word, size_t wordlen,
 
1612
static void read_current_word(GeanyEditor *editor, gint pos, gchar *word, gsize wordlen,
1593
1613
                const gchar *wc, gboolean stem)
1594
1614
{
1595
1615
        gint line, line_start, startword, endword;
1616
1636
        /* the checks for "c < 0" are to allow any Unicode character which should make the code
1617
1637
         * a little bit more Unicode safe, anyway, this allows also any Unicode punctuation,
1618
1638
         * TODO: improve this code */
1619
 
        while (startword > 0 && (strchr(wc, chunk[startword - 1]) || chunk[startword - 1] < 0))
 
1639
        while (startword > 0 && (strchr(wc, chunk[startword - 1]) || ! IS_ASCII(chunk[startword - 1])))
1620
1640
                startword--;
1621
1641
        if (!stem)
1622
1642
        {
1623
 
                while (chunk[endword] != 0 && (strchr(wc, chunk[endword]) || chunk[endword] < 0))
 
1643
                while (chunk[endword] != 0 && (strchr(wc, chunk[endword]) || ! IS_ASCII(chunk[endword])))
1624
1644
                        endword++;
1625
1645
        }
1626
1646
 
1641
1661
 * NULL terminated in any case, even when the word is truncated because wordlen is too small.
1642
1662
 * position can be -1, then the current position is used.
1643
1663
 * wc are the wordchars to use, if NULL, GEANY_WORDCHARS will be used */
1644
 
void editor_find_current_word(GeanyEditor *editor, gint pos, gchar *word, size_t wordlen,
 
1664
void editor_find_current_word(GeanyEditor *editor, gint pos, gchar *word, gsize wordlen,
1645
1665
                                                          const gchar *wc)
1646
1666
{
1647
1667
        read_current_word(editor, pos, word, wordlen, wc, FALSE);
1648
1668
}
1649
1669
 
1650
1670
 
 
1671
/* Same as editor_find_current_word() but uses editor's word boundaries to decide what the word
 
1672
 * is.  This should be used e.g. to get the word to search for */
 
1673
void editor_find_current_word_sciwc(GeanyEditor *editor, gint pos, gchar *word, gsize wordlen)
 
1674
{
 
1675
        gint start;
 
1676
        gint end;
 
1677
 
 
1678
        g_return_if_fail(editor != NULL);
 
1679
 
 
1680
        if (pos == -1)
 
1681
                pos = sci_get_current_position(editor->sci);
 
1682
 
 
1683
        start = SSM(editor->sci, SCI_WORDSTARTPOSITION, pos, TRUE);
 
1684
        end = SSM(editor->sci, SCI_WORDENDPOSITION, pos, TRUE);
 
1685
 
 
1686
        if (start == end) /* caret in whitespaces sequence */
 
1687
                *word = 0;
 
1688
        else
 
1689
        {
 
1690
                if ((guint)(end - start) >= wordlen)
 
1691
                        end = start + (wordlen - 1);
 
1692
                sci_get_text_range(editor->sci, start, end, word);
 
1693
        }
 
1694
}
 
1695
 
 
1696
 
1651
1697
/**
1652
1698
 *  Finds the word at the position specified by @a pos. If any word is found, it is returned.
1653
1699
 *  Otherwise NULL is returned.
1935
1981
        GString *words;
1936
1982
        const gchar **entities = symbols_get_html_entities();
1937
1983
 
1938
 
        if (*root != '&' || G_UNLIKELY(entities == NULL))
 
1984
        if (*root != '&' || entities == NULL)
1939
1985
                return FALSE;
1940
1986
 
1941
1987
        words = g_string_sized_new(500);
2005
2051
}
2006
2052
 
2007
2053
 
2008
 
/* Algorithm based on based on Scite's StartAutoCompleteWord() */
2009
 
static GString *get_doc_words(ScintillaObject *sci, gchar *root, gsize rootlen)
 
2054
/* Algorithm based on based on Scite's StartAutoCompleteWord()
 
2055
 * @returns a sorted list of words matching @p root */
 
2056
static GSList *get_doc_words(ScintillaObject *sci, gchar *root, gsize rootlen)
2010
2057
{
2011
2058
        gchar *word;
2012
2059
        gint len, current, word_end;
2013
2060
        gint pos_find, flags;
2014
2061
        guint word_length;
2015
2062
        gsize nmatches = 0;
2016
 
        GString *words;
 
2063
        GSList *words = NULL;
2017
2064
        struct Sci_TextToFind ttf;
2018
2065
 
2019
2066
        len = sci_get_length(sci);
2026
2073
        ttf.chrgText.cpMax = 0;
2027
2074
        flags = SCFIND_WORDSTART | SCFIND_MATCHCASE;
2028
2075
 
2029
 
        words = g_string_sized_new(256);
2030
 
        /* put space before first entry to make searching with strstr easy */
2031
 
        g_string_append_c(words, ' ');
2032
 
 
2033
2076
        /* search the whole document for the word root and collect results */
2034
2077
        pos_find = scintilla_send_message(sci, SCI_FINDTEXT, flags, (uptr_t) &ttf);
2035
2078
        while (pos_find >= 0 && pos_find < len)
2037
2080
                word_end = pos_find + rootlen;
2038
2081
                if (pos_find != current)
2039
2082
                {
2040
 
                        while (word_end < len && strchr(GEANY_WORDCHARS, sci_get_char_at(sci, word_end)) != NULL)
2041
 
                                word_end++;
 
2083
                        word_end = SSM(sci, SCI_WORDENDPOSITION, word_end, TRUE);
2042
2084
 
2043
2085
                        word_length = word_end - pos_find;
2044
2086
                        if (word_length > rootlen)
2045
2087
                        {
2046
 
                                word = g_malloc0(word_length + 3);
2047
 
                                sci_get_text_range(sci, pos_find, word_end, word + 1);
2048
 
                                word[0] = ' ';
2049
 
                                word[word_length + 1] = ' ';
2050
 
                                /* search the words string whether we already have the word in, otherwise add it */
2051
 
                                if (strstr(words->str, word) == NULL)
 
2088
                                word = sci_get_contents_range(sci, pos_find, word_end);
 
2089
                                /* search whether we already have the word in, otherwise add it */
 
2090
                                if (g_slist_find_custom(words, word, (GCompareFunc)utils_str_casecmp) != NULL)
 
2091
                                        g_free(word);
 
2092
                                else
2052
2093
                                {
2053
 
                                        g_string_append(words, word + 1);
 
2094
                                        words = g_slist_prepend(words, word);
2054
2095
                                        nmatches++;
2055
2096
                                }
2056
 
                                g_free(word);
2057
2097
 
2058
2098
                                if (nmatches == editor_prefs.autocompletion_max_entries)
2059
2099
                                        break;
2063
2103
                pos_find = scintilla_send_message(sci, SCI_FINDTEXT, flags, (uptr_t) &ttf);
2064
2104
        }
2065
2105
 
2066
 
        if (words->len > 1)
2067
 
        {
2068
 
                g_strdelimit(words->str, " ", '\n');
2069
 
                words->str[words->len - 1] = '\0'; /* remove the trailing '\n' */
2070
 
                return words;
2071
 
        }
2072
 
        g_string_free(words, TRUE);
2073
 
        return NULL;
 
2106
        return g_slist_sort(words, (GCompareFunc)utils_str_casecmp);
2074
2107
}
2075
2108
 
2076
2109
 
2077
2110
static gboolean autocomplete_doc_word(GeanyEditor *editor, gchar *root, gsize rootlen)
2078
2111
{
2079
2112
        ScintillaObject *sci = editor->sci;
2080
 
        GString *words;
 
2113
        GSList *words, *node;
2081
2114
        GString *str;
2082
 
        gchar *ptr;
2083
 
        GSList *node, *list = NULL;
 
2115
        guint n_words = 0;
2084
2116
 
2085
2117
        words = get_doc_words(sci, root, rootlen);
2086
2118
        if (!words)
2089
2121
                return FALSE;
2090
2122
        }
2091
2123
 
2092
 
        /* words are unsorted, make list of words */
2093
 
        foreach_str(ptr, words->str)
2094
 
        {
2095
 
                if (*ptr == '\n')
2096
 
                {
2097
 
                        list = g_slist_prepend(list, ptr + 1);
2098
 
                        /* terminate previous string in list */
2099
 
                        ptr[0] = 0x0;
2100
 
                        ptr++;
2101
 
                }
2102
 
        }
2103
 
        list = g_slist_sort(list, (GCompareFunc)utils_str_casecmp);
2104
 
 
2105
 
        str = g_string_sized_new(words->len);
2106
 
        foreach_slist(node, list)
 
2124
        str = g_string_sized_new(editor_prefs.autocompletion_max_entries * (rootlen + 1));
 
2125
        foreach_slist(node, words)
2107
2126
        {
2108
2127
                g_string_append(str, node->data);
 
2128
                g_free(node->data);
2109
2129
                if (node->next)
2110
2130
                        g_string_append_c(str, '\n');
 
2131
                n_words++;
2111
2132
        }
2112
 
        if (g_slist_length(list) >= editor_prefs.autocompletion_max_entries)
 
2133
        if (n_words >= editor_prefs.autocompletion_max_entries)
2113
2134
                g_string_append(str, "\n...");
2114
2135
 
2115
 
        g_slist_free(list);
2116
 
        g_string_free(words, TRUE);
 
2136
        g_slist_free(words);
2117
2137
 
2118
2138
        show_autocomplete(sci, rootlen, str->str);
2119
2139
        g_string_free(str, TRUE);
2123
2143
 
2124
2144
gboolean editor_start_auto_complete(GeanyEditor *editor, gint pos, gboolean force)
2125
2145
{
2126
 
        gint line, line_start, line_len, line_pos, current, rootlen, startword, lexer, style;
2127
 
        gchar *linebuf, *root;
 
2146
        gint rootlen, lexer, style;
 
2147
        gchar *root;
 
2148
        gchar cword[GEANY_MAX_WORD_LENGTH];
2128
2149
        ScintillaObject *sci;
2129
2150
        gboolean ret = FALSE;
2130
2151
        const gchar *wordchars;
2131
2152
        GeanyFiletype *ft;
2132
2153
 
 
2154
        g_return_val_if_fail(editor != NULL, FALSE);
 
2155
 
2133
2156
        if (! editor_prefs.auto_complete_symbols && ! force)
2134
2157
                return FALSE;
2135
2158
 
2136
 
        g_return_val_if_fail(editor != NULL, FALSE);
2137
 
 
2138
2159
        /* If we are at the beginning of the document, we skip autocompletion as we can't determine the
2139
2160
         * necessary styling information */
2140
2161
        if (G_UNLIKELY(pos < 2))
2143
2164
        sci = editor->sci;
2144
2165
        ft = editor->document->file_type;
2145
2166
 
2146
 
        line = sci_get_line_from_position(sci, pos);
2147
 
        line_start = sci_get_position_from_line(sci, line);
2148
 
        line_len = sci_get_line_length(sci, line);
2149
 
        line_pos = pos - line_start - 1;
2150
 
        current = pos - line_start;
2151
 
        startword = current;
2152
2167
        lexer = sci_get_lexer(sci);
2153
2168
        style = sci_get_style_at(sci, pos - 2);
2154
2169
 
2158
2173
 
2159
2174
        autocomplete_scope(editor);
2160
2175
 
2161
 
        linebuf = sci_get_line(sci, line);
2162
 
 
2163
2176
        if (ft->id == GEANY_FILETYPES_LATEX)
2164
2177
                wordchars = GEANY_WORDCHARS"\\"; /* add \ to word chars if we are in a LaTeX file */
2165
2178
        else if (ft->id == GEANY_FILETYPES_HTML || ft->id == GEANY_FILETYPES_PHP)
2167
2180
        else
2168
2181
                wordchars = GEANY_WORDCHARS;
2169
2182
 
2170
 
        /* find the start of the current word */
2171
 
        while ((startword > 0) && (strchr(wordchars, linebuf[startword - 1])))
2172
 
                startword--;
2173
 
        linebuf[current] = '\0';
2174
 
        root = linebuf + startword;
2175
 
        rootlen = current - startword;
 
2183
        read_current_word(editor, pos, cword, sizeof(cword), wordchars, TRUE);
 
2184
        root = cword;
 
2185
        rootlen = strlen(root);
2176
2186
 
2177
2187
        if (rootlen > 0)
2178
2188
        {
2189
2199
                        }
2190
2200
                        ret = autocomplete_html(sci, root, rootlen);
2191
2201
                }
 
2202
                else if (ft->id == GEANY_FILETYPES_PHP && style == SCE_HPHP_DEFAULT &&
 
2203
                                 rootlen == 3 && strcmp(root, "php") == 0 && pos >= 5 &&
 
2204
                                 sci_get_char_at(sci, pos - 5) == '<' && sci_get_char_at(sci, pos - 4) == '?')
 
2205
                {
 
2206
                        /* nothing, don't complete PHP open tags */
 
2207
                }
2192
2208
                else
2193
2209
                {
2194
2210
                        /* force is set when called by keyboard shortcut, otherwise start at the
2208
2224
        if (!ret && force)
2209
2225
                utils_beep();
2210
2226
 
2211
 
        g_free(linebuf);
2212
2227
        return ret;
2213
2228
}
2214
2229
 
2242
2257
}
2243
2258
 
2244
2259
 
2245
 
/* This is very ugly but passing the pattern to ac_replace_specials() doesn't work because it is
2246
 
 * modified when replacing a completion but the foreach function still passes the old pointer
2247
 
 * to ac_replace_specials, so we use a global pointer outside of ac_replace_specials and
2248
 
 * ac_complete_constructs. Any hints to improve this are welcome. */
2249
 
static GString *snippets_global_pattern = NULL;
2250
 
 
2251
2260
static void snippets_replace_specials(gpointer key, gpointer value, gpointer user_data)
2252
2261
{
2253
2262
        gchar *needle;
 
2263
        GString *pattern = user_data;
2254
2264
 
2255
2265
        g_return_if_fail(key != NULL);
2256
2266
        g_return_if_fail(value != NULL);
2257
2267
 
2258
2268
        needle = g_strconcat("%", (gchar*) key, "%", NULL);
2259
2269
 
2260
 
        utils_string_replace_all(snippets_global_pattern, needle, (gchar*) value);
 
2270
        utils_string_replace_all(pattern, needle, (gchar*) value);
2261
2271
        g_free(needle);
2262
2272
}
2263
2273
 
2264
2274
 
2265
 
/* this only works with spaces only indentation on the lines */
2266
 
static void fix_line_indents(GeanyEditor *editor, gint line_start, gint line_end)
2267
 
{
2268
 
        ScintillaObject *sci = editor->sci;
2269
 
        gint line, cur_line, cur_col, pos;
2270
 
 
2271
 
        /* get the line, col position as fixing indentation will move cursor to start of line */
2272
 
        pos = sci_get_current_position(sci);
2273
 
        cur_col = sci_get_col_from_position(sci, pos);
2274
 
        cur_line = sci_get_current_line(sci);
2275
 
 
2276
 
        for (line = line_start; line <= line_end; line++)
2277
 
        {
2278
 
                gint size = sci_get_line_indentation(sci, line);
2279
 
 
2280
 
                /* set to 0 first to trigger proper indent creation */
2281
 
                sci_set_line_indentation(sci, line, 0);
2282
 
                sci_set_line_indentation(sci, line, size);
2283
 
        }
2284
 
        pos = scintilla_send_message(sci, SCI_FINDCOLUMN, cur_line, cur_col);
2285
 
        sci_set_current_position(sci, pos, FALSE);
2286
 
}
2287
 
 
2288
 
 
2289
 
static void replace_leading_tabs(GString *str, const gchar *whitespace)
2290
 
{
 
2275
static gboolean utils_regex_find(regex_t *regex, const gchar *haystack, gsize start,
 
2276
                gsize nmatches, regmatch_t *matches)
 
2277
{
 
2278
        gint eflags = 0;
 
2279
 
 
2280
        if (start > 0)
 
2281
        {
 
2282
                gchar c = haystack[start - 1];
 
2283
 
 
2284
                if (c == '\n' || c == '\r')
 
2285
                        eflags = REG_NOTBOL;
 
2286
        }
 
2287
        return regexec(regex, haystack + start, nmatches, matches, eflags) == 0;
 
2288
}
 
2289
 
 
2290
 
 
2291
/* match_index: which match to replace, 0 for whole regex.
 
2292
 * note: this doesn't support backreferences in replacements */
 
2293
static guint utils_string_regex_replace_all(GString *haystack,
 
2294
                regex_t *regex, guint match_index, const gchar *replace)
 
2295
{
 
2296
        gssize pos;
 
2297
        regmatch_t matches[10];
 
2298
        guint ret = 0;
 
2299
 
 
2300
        g_return_val_if_fail(match_index < 10, 0);
 
2301
 
 
2302
        /* ensure haystack->str is not null */
 
2303
        if (haystack->len == 0)
 
2304
                return 0;
 
2305
 
 
2306
        pos = 0;
 
2307
        while (utils_regex_find(regex, haystack->str, pos, G_N_ELEMENTS(matches), matches))
 
2308
        {
 
2309
                regmatch_t *match = &matches[match_index];
 
2310
 
 
2311
                g_return_val_if_fail(match->rm_so >= 0, FALSE);
 
2312
                pos += match->rm_so;
 
2313
                pos = utils_string_replace(haystack, pos, match->rm_eo - match->rm_so, replace);
 
2314
                ret++;
 
2315
        }
 
2316
        return ret;
 
2317
}
 
2318
 
 
2319
 
 
2320
static void fix_indentation(GeanyEditor *editor, GString *buf)
 
2321
{
 
2322
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
 
2323
        gchar *whitespace;
2291
2324
        regex_t regex;
2292
 
        gssize pos;
2293
 
        regmatch_t matches[2];
2294
 
        gchar *ptr;
2295
 
 
2296
 
        if (regcomp(&regex, "^ *(\t)", 0) != 0)
2297
 
        {
2298
 
                g_return_if_fail(FALSE);
2299
 
        }
2300
 
        ptr = str->str;
2301
 
        while (ptr)
2302
 
        {
2303
 
                if (regexec(&regex, ptr,
2304
 
                        G_N_ELEMENTS(matches), matches, 0) != 0)
2305
 
                        break;
2306
 
 
2307
 
                pos = matches[1].rm_so;
2308
 
                g_return_if_fail(pos >= 0);
2309
 
                pos += ptr - str->str;
2310
 
                g_string_erase(str, pos, 1);
2311
 
                g_string_insert(str, pos, whitespace);
2312
 
                ptr = str->str + pos + strlen(whitespace);
2313
 
        }
 
2325
        gint cflags = REG_EXTENDED | REG_NEWLINE;
 
2326
 
 
2327
        /* transform leading tabs into indent widths (in spaces) */
 
2328
        whitespace = g_strnfill(iprefs->width, ' ');
 
2329
        regcomp(&regex, "^ *(\t)", cflags);
 
2330
        while (utils_string_regex_replace_all(buf, &regex, 1, whitespace));
2314
2331
        regfree(&regex);
 
2332
 
 
2333
        /* remaining tabs are for alignment */
 
2334
        if (iprefs->type != GEANY_INDENT_TYPE_TABS)
 
2335
                utils_string_replace_all(buf, "\t", whitespace);
 
2336
 
 
2337
        /* use leading tabs */
 
2338
        if (iprefs->type != GEANY_INDENT_TYPE_SPACES)
 
2339
        {
 
2340
                gchar *str;
 
2341
 
 
2342
                /* for tabs+spaces mode we want the real tab width, not indent width */
 
2343
                setptr(whitespace, g_strnfill(sci_get_tab_width(editor->sci), ' '));
 
2344
                str = g_strdup_printf("^\t*(%s)", whitespace);
 
2345
 
 
2346
                regcomp(&regex, str, cflags);
 
2347
                while (utils_string_regex_replace_all(buf, &regex, 1, "\t"));
 
2348
                regfree(&regex);
 
2349
                g_free(str);
 
2350
        }
 
2351
        g_free(whitespace);
2315
2352
}
2316
2353
 
2317
2354
 
2338
2375
{
2339
2376
        ScintillaObject *sci = editor->sci;
2340
2377
        gint line_start = sci_get_line_from_position(sci, insert_pos);
2341
 
        gint line_end;
2342
 
        gchar *whitespace;
2343
2378
        GString *buf;
2344
 
        const gchar cur_marker[] = "__GEANY_CURSOR_MARKER__";
2345
2379
        const gchar *eol = editor_get_eol_char(editor);
2346
 
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
 
2380
        gint idx;
2347
2381
 
2348
2382
        g_return_if_fail(text);
2349
2383
        g_return_if_fail(editor != NULL);
2352
2386
        buf = g_string_new(text);
2353
2387
 
2354
2388
        if (cursor_index >= 0)
2355
 
                g_string_insert(buf, cursor_index, cur_marker); /* remember cursor pos */
 
2389
                g_string_insert(buf, cursor_index, geany_cursor_marker);        /* remember cursor pos */
2356
2390
 
2357
2391
        if (newline_indent_size == -1)
2358
2392
        {
2359
2393
                /* count indent size up to insert_pos instead of asking sci
2360
2394
                 * because there may be spaces after it */
2361
2395
                gchar *tmp = sci_get_line(sci, line_start);
2362
 
                gint idx = insert_pos - sci_get_position_from_line(sci, line_start);
 
2396
 
 
2397
                idx = insert_pos - sci_get_position_from_line(sci, line_start);
2363
2398
                tmp[idx] = '\0';
2364
2399
                newline_indent_size = count_indent_size(editor, tmp);
2365
2400
                g_free(tmp);
2368
2403
        /* Add line indents (in spaces) */
2369
2404
        if (newline_indent_size > 0)
2370
2405
        {
 
2406
                const gchar *nl = replace_newlines ? "\n" : eol;
 
2407
                gchar *whitespace;
 
2408
                
2371
2409
                whitespace = g_strnfill(newline_indent_size, ' ');
2372
 
                setptr(whitespace, g_strconcat(eol, whitespace, NULL));
2373
 
                utils_string_replace_all(buf, eol, whitespace);
 
2410
                setptr(whitespace, g_strconcat(nl, whitespace, NULL));
 
2411
                utils_string_replace_all(buf, nl, whitespace);
2374
2412
                g_free(whitespace);
2375
2413
        }
2376
2414
 
2378
2416
        if (replace_newlines)
2379
2417
                utils_string_replace_all(buf, "\n", eol);
2380
2418
 
2381
 
        /* transform leading tabs into indent widths (in spaces) */
2382
 
        whitespace = g_strnfill(iprefs->width, ' ');
2383
 
        replace_leading_tabs(buf, whitespace);
2384
 
        /* remaining tabs are for alignment */
2385
 
        if (iprefs->type != GEANY_INDENT_TYPE_TABS)
2386
 
                utils_string_replace_all(buf, "\t", whitespace);
2387
 
        g_free(whitespace);
2388
 
 
2389
 
        sci_start_undo_action(sci);
2390
 
 
2391
 
        if (cursor_index >= 0)
 
2419
        fix_indentation(editor, buf);
 
2420
 
 
2421
        idx = replace_cursor_markers(editor, buf);
 
2422
        if (idx >= 0)
2392
2423
        {
2393
 
                gint idx = utils_strpos(buf->str, cur_marker);
2394
 
 
2395
 
                g_string_erase(buf, idx, strlen(cur_marker));
2396
 
 
2397
2424
                sci_insert_text(sci, insert_pos, buf->str);
2398
2425
                sci_set_current_position(sci, insert_pos + idx, FALSE);
2399
2426
        }
2400
2427
        else
2401
2428
                sci_insert_text(sci, insert_pos, buf->str);
2402
2429
 
2403
 
        /* fixup indentation (very useful for Tabs & Spaces indent type) */
2404
 
        line_end = sci_get_line_from_position(sci, insert_pos + buf->len);
2405
 
        fix_line_indents(editor, line_start, line_end);
2406
2430
        snippet_cursor_insert_pos = sci_get_current_position(sci);
2407
2431
 
2408
 
        sci_end_undo_action(sci);
2409
2432
        g_string_free(buf, TRUE);
2410
2433
}
2411
2434
 
2436
2459
}
2437
2460
 
2438
2461
 
2439
 
static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
2440
 
                gsize indent_size)
 
2462
static void snippets_make_replacements(GeanyEditor *editor, GString *pattern)
2441
2463
{
2442
 
        gssize cur_index = -1;
2443
 
        gchar *whitespace;
2444
 
        gint i, tmp_pos, whitespace_len, nl_count = 0;
2445
2464
        GHashTable *specials;
2446
 
        GList *temp_list = NULL;
2447
 
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
2448
 
        gint cursor_steps, old_cursor = 0;
2449
2465
 
2450
2466
        /* replace 'special' completions */
2451
2467
        specials = g_hash_table_lookup(snippet_hash, "Special");
2452
2468
        if (G_LIKELY(specials != NULL))
2453
2469
        {
2454
 
                /* ugly hack using global_pattern */
2455
 
                snippets_global_pattern = pattern;
2456
 
                g_hash_table_foreach(specials, snippets_replace_specials, NULL);
 
2470
                g_hash_table_foreach(specials, snippets_replace_specials, pattern);
2457
2471
        }
2458
2472
 
 
2473
        /* now transform other wildcards */
 
2474
        utils_string_replace_all(pattern, "%newline%", "\n");
 
2475
        utils_string_replace_all(pattern, "%ws%", "\t");
 
2476
 
 
2477
        /* replace %cursor% by a very unlikely string marker */
 
2478
        utils_string_replace_all(pattern, "%cursor%", geany_cursor_marker);
 
2479
 
 
2480
        /* unescape '%' after all %wildcards% */
 
2481
        templates_replace_valist(pattern, "{pc}", "%", NULL);
 
2482
 
2459
2483
        /* replace any template {foo} wildcards */
2460
2484
        templates_replace_common(pattern, editor->document->file_name, editor->document->file_type, NULL);
2461
 
 
2462
 
        /* transform other wildcards */
2463
 
        /* convert to %newlines%, else we get endless loops */
2464
 
        utils_string_replace_all(pattern, "\n", "%newline%");
2465
 
 
2466
 
        /* if spaces are used, replaces all tabs with %ws%, which is later replaced
2467
 
         * by real whitespace characters
2468
 
         * otherwise replace all %ws% by \t, which will be replaced later by tab
2469
 
         * characters,
2470
 
         * this makes seperating between tab and spaces intentation pretty easy */
2471
 
        if (iprefs->type == GEANY_INDENT_TYPE_SPACES)
2472
 
                utils_string_replace_all(pattern, "\t", "%ws%");
2473
 
        else
2474
 
                utils_string_replace_all(pattern, "%ws%", "\t");
2475
 
 
2476
 
        whitespace = g_strnfill(iprefs->width, ' '); /* use spaces for indentation, will be fixed up */
2477
 
        whitespace_len = strlen(whitespace);
 
2485
}
 
2486
 
 
2487
 
 
2488
static gssize replace_cursor_markers(GeanyEditor *editor, GString *pattern)
 
2489
{
 
2490
        gssize cur_index = -1;
 
2491
        gint i;
 
2492
        GList *temp_list = NULL;
 
2493
        gint cursor_steps = 0, old_cursor = 0;
 
2494
 
2478
2495
        i = 0;
2479
 
        while ((cursor_steps = utils_strpos(pattern->str, "%cursor%")) >= 0)
 
2496
        while (1)
2480
2497
        {
2481
 
                /* replace every %newline% (up to next %cursor%) with EOL,
2482
 
                 * and update cursor_steps after */
2483
 
                while ((tmp_pos = utils_strpos(pattern->str, "%newline%")) < cursor_steps && tmp_pos != -1)
2484
 
                {
2485
 
                        nl_count++;
2486
 
                        utils_string_replace_first(pattern, "%newline%", editor_get_eol_char(editor));
2487
 
                        cursor_steps = utils_strpos(pattern->str, "%cursor%");
2488
 
                }
2489
 
                /* replace every %ws% (up to next %cursor%) with whitespaces,
2490
 
                 * and update cursor_steps after */
2491
 
                while ((tmp_pos = utils_strpos(pattern->str, "%ws%")) < cursor_steps && tmp_pos != -1)
2492
 
                {
2493
 
                        utils_string_replace_first(pattern, "%ws%", whitespace);
2494
 
                        cursor_steps = utils_strpos(pattern->str, "%cursor%");
2495
 
                }
2496
 
                /* finally replace the next %cursor% */
2497
 
                utils_string_replace_first(pattern, "%cursor%", "");
2498
 
 
2499
 
                /* modify cursor_steps to take indentation count and type into account */
2500
 
 
2501
 
                /* We're saving the relative offset to each cursor position in a simple
2502
 
                 * linked list, including indentations between them. */
 
2498
                cursor_steps = utils_string_find(pattern, cursor_steps, -1, geany_cursor_marker);
 
2499
                if (cursor_steps == -1)
 
2500
                        break;
 
2501
 
 
2502
                g_string_erase(pattern, cursor_steps, strlen(geany_cursor_marker));
 
2503
 
2503
2504
                if (i++ > 0)
2504
2505
                {
2505
 
                        cursor_steps += (nl_count * indent_size);
2506
 
                        temp_list = g_list_append(temp_list, GINT_TO_POINTER(cursor_steps - old_cursor));
 
2506
                        /* save the relative offset to each cursor position */
 
2507
                        temp_list = g_list_prepend(temp_list, GINT_TO_POINTER(cursor_steps - old_cursor));
2507
2508
                }
2508
2509
                else
2509
2510
                {
2510
 
                        nl_count = 0;
 
2511
                        /* first cursor already includes newline positions */
2511
2512
                        cur_index = cursor_steps;
2512
2513
                }
2513
2514
                old_cursor = cursor_steps;
2514
2515
        }
2515
 
        /* replace remaining %ws% and %newline% which may occur after the last %cursor% */
2516
 
        utils_string_replace_all(pattern, "%newline%", editor_get_eol_char(editor));
2517
 
        utils_string_replace_all(pattern, "%ws%", whitespace);
2518
 
        g_free(whitespace);
2519
 
 
2520
 
        /* escape % last */
2521
 
        /* Bug: {ob}pc{cb} will be replaced by % too */
2522
 
        templates_replace_valist(pattern, "{pc}", "%", NULL);
2523
 
 
2524
 
        /* We put the cursor positions for the most recent
 
2516
 
 
2517
        /* put the cursor positions for the most recent
2525
2518
         * parsed snippet first, followed by any remaining positions */
2526
2519
        i = 0;
2527
2520
        if (temp_list)
2528
2521
        {
2529
2522
                GList *node;
2530
2523
 
 
2524
                temp_list = g_list_reverse(temp_list);
2531
2525
                foreach_list(node, temp_list)
2532
2526
                        g_queue_push_nth(snippet_offsets, node->data, i++);
2533
2527
 
2537
2531
 
2538
2532
                g_list_free(temp_list);
2539
2533
        }
 
2534
        /* if there's no first cursor, skip whole snippet */
2540
2535
        if (cur_index < 0)
2541
2536
                cur_index = pattern->len;
2542
2537
 
2798
2793
        doc = editor->document;
2799
2794
 
2800
2795
        /* remove comment open chars */
2801
 
        pos = document_find_text(doc, doc->file_type->comment_open, 0, TRUE, FALSE, NULL);
 
2796
        pos = document_find_text(doc, doc->file_type->comment_open, NULL, 0, TRUE, FALSE, NULL);
2802
2797
        SSM(editor->sci, SCI_DELETEBACK, 0, 0);
2803
2798
 
2804
2799
        /* check whether the line is empty and can be deleted */
2811
2806
        g_free(linebuf);
2812
2807
 
2813
2808
        /* remove comment close chars */
2814
 
        pos = document_find_text(doc, doc->file_type->comment_close, 0, FALSE, FALSE, NULL);
 
2809
        pos = document_find_text(doc, doc->file_type->comment_close, NULL, 0, FALSE, FALSE, NULL);
2815
2810
        SSM(editor->sci, SCI_DELETEBACK, 0, 0);
2816
2811
 
2817
2812
        /* check whether the line is empty and can be deleted */
2900
2895
                        ft = filetypes[GEANY_FILETYPES_XML];
2901
2896
        }
2902
2897
 
2903
 
        co = ft->comment_open;
2904
 
        cc = ft->comment_close;
2905
 
        if (co == NULL)
2906
 
                return 0;
 
2898
        co = ft->comment_single;
 
2899
        if (NZV(co))
 
2900
                cc = NULL;
 
2901
        else
 
2902
        {
 
2903
                co = ft->comment_open;
 
2904
                cc = ft->comment_close;
 
2905
                if (co == NULL)
 
2906
                        return 0;
 
2907
        }
2907
2908
 
2908
2909
        co_len = strlen(co);
2909
2910
        if (co_len == 0)
2931
2932
                if (x < line_len && sel[x] != '\0')
2932
2933
                {
2933
2934
                        /* use single line comment */
2934
 
                        if (cc == NULL || strlen(cc) == 0)
 
2935
                        if (! NZV(cc))
2935
2936
                        {
2936
2937
                                single_line = TRUE;
2937
2938
 
3032
3033
                        ft = filetypes[GEANY_FILETYPES_XML];
3033
3034
        }
3034
3035
 
3035
 
        co = ft->comment_open;
3036
 
        cc = ft->comment_close;
3037
 
        if (co == NULL)
3038
 
                return;
 
3036
        co = ft->comment_single;
 
3037
        if (NZV(co))
 
3038
                cc = NULL;
 
3039
        else
 
3040
        {
 
3041
                co = ft->comment_open;
 
3042
                cc = ft->comment_close;
 
3043
                if (co == NULL)
 
3044
                        return;
 
3045
        }
3039
3046
 
3040
3047
        co_len = strlen(co);
3041
3048
        if (co_len == 0)
3060
3067
                while (isspace(sel[x])) x++;
3061
3068
 
3062
3069
                /* use single line comment */
3063
 
                if (cc == NULL || strlen(cc) == 0)
 
3070
                if (! NZV(cc))
3064
3071
                {
3065
3072
                        gboolean do_continue = FALSE;
3066
3073
                        single_line = TRUE;
3196
3203
                        ft = filetypes[GEANY_FILETYPES_XML];
3197
3204
        }
3198
3205
 
3199
 
        co = ft->comment_open;
3200
 
        cc = ft->comment_close;
3201
 
        if (co == NULL)
3202
 
                return;
 
3206
        co = ft->comment_single;
 
3207
        if (NZV(co))
 
3208
                cc = NULL;
 
3209
        else
 
3210
        {
 
3211
                co = ft->comment_open;
 
3212
                cc = ft->comment_close;
 
3213
                if (co == NULL)
 
3214
                        return;
 
3215
        }
3203
3216
 
3204
3217
        co_len = strlen(co);
3205
3218
        if (co_len == 0)
3227
3240
                if (allow_empty_lines || (x < line_len && sel[x] != '\0'))
3228
3241
                {
3229
3242
                        /* use single line comment */
3230
 
                        if (cc == NULL || strlen(cc) == 0)
 
3243
                        if (cc == NULL || cc[0] == '\0')
3231
3244
                        {
3232
3245
                                gint start = line_start;
3233
3246
                                single_line = TRUE;
3361
3374
{
3362
3375
        switch (lexer)
3363
3376
        {
 
3377
                case SCLEX_COBOL:
3364
3378
                case SCLEX_CPP:
3365
3379
                        return (style == SCE_C_COMMENT ||
3366
3380
                                style == SCE_C_COMMENTDOC);
3416
3430
        {
3417
3431
                gchar *previous_line = sci_get_line(sci, cur_line - 1);
3418
3432
                /* the type of comment, '*' (C/C++/Java), '+' and the others (D) */
3419
 
                gchar *continuation = "*";
3420
 
                gchar *whitespace = ""; /* to hold whitespace if needed */
 
3433
                const gchar *continuation = "*";
 
3434
                const gchar *whitespace = ""; /* to hold whitespace if needed */
3421
3435
                gchar *result;
3422
3436
                gint len = strlen(previous_line);
3423
3437
                gint i;
3450
3464
                        whitespace = " ";
3451
3465
                }
3452
3466
 
3453
 
                if (G_UNLIKELY(style == SCE_D_COMMENTNESTED))
 
3467
                if (style == SCE_D_COMMENTNESTED)
3454
3468
                        continuation = "+"; /* for nested comments in D */
3455
3469
 
3456
3470
                result = g_strconcat(whitespace, continuation, " ", NULL);
3503
3517
        gboolean have_multiline_comment = FALSE;
3504
3518
        GeanyDocument *doc;
3505
3519
 
3506
 
        g_return_if_fail(editor != NULL &&
3507
 
                editor->document->file_type != NULL && editor->document->file_type->comment_open != NULL);
 
3520
        g_return_if_fail(editor != NULL && editor->document->file_type != NULL &&
 
3521
                (editor->document->file_type->comment_open != NULL ||
 
3522
                 editor->document->file_type->comment_single != NULL));
3508
3523
 
3509
3524
        sci_start_undo_action(editor->sci);
3510
3525
 
3511
3526
        doc = editor->document;
3512
3527
 
3513
 
        if (doc->file_type->comment_close != NULL && strlen(doc->file_type->comment_close) > 0)
 
3528
        if (NZV(doc->file_type->comment_close))
3514
3529
                have_multiline_comment = TRUE;
3515
3530
 
3516
3531
        /* insert three lines one line above of the current position */
3942
3957
 
3943
3958
 
3944
3959
/* wordchars: NULL or a string containing characters to match a word.
3945
 
 * Returns: the current selection or the current word. */
 
3960
 * Returns: the current selection or the current word.
 
3961
 * 
 
3962
 * Passing NULL as wordchars is NOT the same as passing GEANY_WORDCHARS: NULL means
 
3963
 * using Scintillas's word boundaries. */
3946
3964
gchar *editor_get_default_selection(GeanyEditor *editor, gboolean use_current_word,
3947
3965
                                                                        const gchar *wordchars)
3948
3966
{
3951
3969
        g_return_val_if_fail(editor != NULL, NULL);
3952
3970
 
3953
3971
        if (sci_get_lines_selected(editor->sci) == 1)
3954
 
        {
3955
 
                gint len = sci_get_selected_text_length(editor->sci);
3956
 
 
3957
 
                s = g_malloc(len + 1);
3958
 
                sci_get_selected_text(editor->sci, s);
3959
 
        }
 
3972
                s = sci_get_selection_contents(editor->sci);
3960
3973
        else if (sci_get_lines_selected(editor->sci) == 0 && use_current_word)
3961
3974
        {       /* use the word at current cursor position */
3962
3975
                gchar word[GEANY_MAX_WORD_LENGTH];
3963
3976
 
3964
 
                editor_find_current_word(editor, -1, word, sizeof(word), wordchars);
 
3977
                if (wordchars != NULL)
 
3978
                        editor_find_current_word(editor, -1, word, sizeof(word), wordchars);
 
3979
                else
 
3980
                        editor_find_current_word_sciwc(editor, -1, word, sizeof(word));
 
3981
 
3965
3982
                if (word[0] != '\0')
3966
3983
                        s = g_strdup(word);
3967
3984
        }
4422
4439
        font_name = g_strdup_printf("!%s", pango_font_description_get_family(pfd));
4423
4440
        pango_font_description_free(pfd);
4424
4441
 
4425
 
        for (style = 0; style <= 127; style++)
 
4442
        for (style = 0; style <= STYLE_MAX; style++)
4426
4443
                sci_set_font(editor->sci, style, font_name, size);
4427
4444
 
4428
 
        /* line number and braces */
4429
 
        sci_set_font(editor->sci, STYLE_LINENUMBER, font_name, size);
4430
 
        sci_set_font(editor->sci, STYLE_BRACELIGHT, font_name, size);
4431
 
        sci_set_font(editor->sci, STYLE_BRACEBAD, font_name, size);
4432
4445
        g_free(font_name);
4433
4446
 
4434
4447
        /* zoom to 100% to prevent confusion */
4457
4470
}
4458
4471
 
4459
4472
 
 
4473
void editor_set_indent_width(GeanyEditor *editor, gint width)
 
4474
{
 
4475
        editor_set_indent(editor, editor->indent_type, width);
 
4476
}
 
4477
 
 
4478
 
4460
4479
void editor_set_indent(GeanyEditor *editor, GeanyIndentType type, gint width)
4461
4480
{
4462
4481
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
4674
4693
 
4675
4694
        sci_set_symbol_margin(sci, editor_prefs.show_markers_margin);
4676
4695
        sci_set_lines_wrapped(sci, editor_prefs.line_wrapping);
4677
 
        sci_set_scrollbar_mode(sci, editor_prefs.show_scrollbars);
4678
4696
        sci_set_caret_policy_x(sci, CARET_JUMPS | CARET_EVEN, 0);
4679
4697
        /*sci_set_caret_policy_y(sci, CARET_JUMPS | CARET_EVEN, 0);*/
4680
4698
        SSM(sci, SCI_AUTOCSETSEPARATOR, '\n', 0);
4757
4775
 
4758
4776
static void on_document_save(GObject *obj, GeanyDocument *doc)
4759
4777
{
 
4778
        gchar *f = utils_build_path(app->configdir, "snippets.conf", NULL);
 
4779
 
4760
4780
        g_return_if_fail(NZV(doc->real_path));
4761
4781
 
4762
 
        if (utils_str_equal(doc->real_path,
4763
 
                utils_build_path(app->configdir, "snippets.conf", NULL)))
 
4782
        if (utils_str_equal(doc->real_path, f))
4764
4783
        {
4765
4784
                /* reload snippets */
4766
4785
                editor_snippets_free();
4767
4786
                editor_snippets_init();
4768
4787
        }
 
4788
        g_free(f);
4769
4789
}
4770
4790
 
4771
4791
 
4792
4812
void editor_init(void)
4793
4813
{
4794
4814
        static GeanyIndentPrefs indent_prefs;
 
4815
        gchar *f;
4795
4816
 
4796
4817
        memset(&editor_prefs, 0, sizeof(GeanyEditorPrefs));
4797
4818
        memset(&indent_prefs, 0, sizeof(GeanyIndentPrefs));
4801
4822
         * handler (on_editor_notify) is called */
4802
4823
        g_signal_connect_after(geany_object, "editor-notify", G_CALLBACK(on_editor_notify), NULL);
4803
4824
 
4804
 
        ui_add_config_file_menu_item(utils_build_path(app->configdir, "snippets.conf", NULL),
4805
 
                NULL, NULL);
 
4825
        f = utils_build_path(app->configdir, "snippets.conf", NULL);
 
4826
        ui_add_config_file_menu_item(f, NULL, NULL);
 
4827
        g_free(f);
4806
4828
        g_signal_connect(geany_object, "document-save", G_CALLBACK(on_document_save), NULL);
4807
4829
}
4808
4830
 
4839
4861
                case SCLEX_MAKEFILE:
4840
4862
                case SCLEX_ASM:
4841
4863
                case SCLEX_SQL:
 
4864
                case SCLEX_COBOL:
4842
4865
                case SCLEX_PROPERTIES:
4843
4866
                case SCLEX_FORTRAN: /* Is this the best option for Fortran? */
4844
4867
                case SCLEX_CAML:
4915
4938
 
4916
4939
        /* (dis)allow scrolling past end of document */
4917
4940
        sci_set_scroll_stop_at_last_line(sci, editor_prefs.scroll_stop_at_last_line);
 
4941
 
 
4942
        sci_set_scrollbar_mode(sci, editor_prefs.show_scrollbars);
4918
4943
}
4919
4944
 
4920
4945
 
5032
5057
 */
5033
5058
void editor_insert_snippet(GeanyEditor *editor, gint pos, const gchar *snippet)
5034
5059
{
5035
 
        gint cursor_pos;
5036
5060
        GString *pattern;
5037
5061
 
5038
5062
        pattern = g_string_new(snippet);
5039
 
        read_indent(editor, pos);
5040
 
        cursor_pos = snippets_make_replacements(editor, pattern, strlen(indent));
5041
 
        editor_insert_text_block(editor, pattern->str, pos, cursor_pos, -1, FALSE);
 
5063
        snippets_make_replacements(editor, pattern);
 
5064
        editor_insert_text_block(editor, pattern->str, pos, -1, -1, TRUE);
5042
5065
        g_string_free(pattern, TRUE);
5043
5066
}