~mhall119/ubuntu/precise/geany/add_quicklist

« back to all changes in this revision

Viewing changes to src/editor.c

  • Committer: Bazaar Package Importer
  • Author(s): Chow Loong Jin
  • Date: 2011-01-08 17:29:46 UTC
  • mfrom: (1.1.15 upstream)
  • Revision ID: james.westby@ubuntu.com-20110108172946-mm7j881jlozn0vt8
Tags: 0.20-0ubuntu1
* New upstream release
* Refresh 20_add_debian_specific_filetypes.dpatch
* Bump Breaks version for geany-plugins-common

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 5151 2010-08-12 12:58:00Z ntrel $
 
22
 * $Id: editor.c 5495 2010-12-22 13:44:41Z ntrel $
23
23
 */
24
24
 
25
25
/**
55
55
#include "document.h"
56
56
#include "documentprivate.h"
57
57
#include "filetypes.h"
 
58
#include "filetypesprivate.h"
58
59
#include "sciwrappers.h"
59
60
#include "ui_utils.h"
60
61
#include "utils.h"
66
67
#include "project.h"
67
68
#include "projectprivate.h"
68
69
#include "main.h"
 
70
#include "highlighting.h"
69
71
 
70
72
 
71
73
/* Note: use sciwrappers.h instead where possible.
76
78
static GHashTable *snippet_hash = NULL;
77
79
static GQueue *snippet_offsets = NULL;
78
80
static gint snippet_cursor_insert_pos;
 
81
static GtkAccelGroup *snippet_accel_group = NULL;
79
82
 
80
83
/* holds word under the mouse or keyboard cursor */
81
84
static gchar current_word[GEANY_MAX_WORD_LENGTH];
102
105
static gboolean handle_xml(GeanyEditor *editor, gint pos, gchar ch);
103
106
static void insert_indent_after_line(GeanyEditor *editor, gint line);
104
107
static void auto_multiline(GeanyEditor *editor, gint pos);
105
 
static gboolean is_code_style(gint lexer, gint style);
106
 
static gboolean is_string_style(gint lexer, gint style);
107
108
static void auto_close_chars(ScintillaObject *sci, gint pos, gchar c);
108
 
static void auto_table(GeanyEditor *editor, gint pos);
109
109
static void close_block(GeanyEditor *editor, gint pos);
110
110
static void editor_highlight_braces(GeanyEditor *editor, gint cur_pos);
111
111
static void read_current_word(GeanyEditor *editor, gint pos, gchar *word, size_t wordlen,
112
112
                const gchar *wc, gboolean stem);
113
113
static gsize count_indent_size(GeanyEditor *editor, const gchar *base_indent);
 
114
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);
114
117
 
115
118
 
116
119
void editor_snippets_free(void)
117
120
{
118
121
        g_hash_table_destroy(snippet_hash);
119
122
        g_queue_free(snippet_offsets);
 
123
        gtk_window_remove_accel_group(GTK_WINDOW(main_widgets.window), snippet_accel_group);
120
124
}
121
125
 
122
126
 
123
 
void editor_snippets_init(void)
 
127
static void snippets_load(GKeyFile *sysconfig, GKeyFile *userconfig)
124
128
{
125
129
        gsize i, j, len = 0, len_keys = 0;
126
 
        gchar *sysconfigfile, *userconfigfile;
127
130
        gchar **groups_user, **groups_sys;
128
131
        gchar **keys_user, **keys_sys;
129
132
        gchar *value;
130
 
        GKeyFile *sysconfig = g_key_file_new();
131
 
        GKeyFile *userconfig = g_key_file_new();
132
133
        GHashTable *tmp;
133
134
 
134
 
        snippet_offsets = g_queue_new();
135
 
 
136
 
        sysconfigfile = g_strconcat(app->datadir, G_DIR_SEPARATOR_S, "snippets.conf", NULL);
137
 
        userconfigfile = g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "snippets.conf", NULL);
138
 
 
139
 
        /* check for old autocomplete.conf files (backwards compatibility) */
140
 
        if (! g_file_test(userconfigfile, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))
141
 
                setptr(userconfigfile,
142
 
                        g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "autocomplete.conf", NULL));
143
 
 
144
 
        /* load the actual config files */
145
 
        g_key_file_load_from_file(sysconfig, sysconfigfile, G_KEY_FILE_NONE, NULL);
146
 
        g_key_file_load_from_file(userconfig, userconfigfile, G_KEY_FILE_NONE, NULL);
147
 
 
148
135
        /* keys are strings, values are GHashTables, so use g_free and g_hash_table_destroy */
149
136
        snippet_hash =
150
137
                g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_hash_table_destroy);
153
140
        groups_sys = g_key_file_get_groups(sysconfig, &len);
154
141
        for (i = 0; i < len; i++)
155
142
        {
 
143
                if (strcmp(groups_sys[i], "Keybindings") == 0)
 
144
                        continue;
156
145
                keys_sys = g_key_file_get_keys(sysconfig, groups_sys[i], &len_keys, NULL);
157
146
                /* create new hash table for the read section (=> filetype) */
158
147
                tmp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
165
154
                }
166
155
                g_strfreev(keys_sys);
167
156
        }
 
157
        g_strfreev(groups_sys);
168
158
 
169
159
        /* now read defined completions in user's configuration directory and add / replace them */
170
160
        groups_user = g_key_file_get_groups(userconfig, &len);
171
161
        for (i = 0; i < len; i++)
172
162
        {
 
163
                if (strcmp(groups_user[i], "Keybindings") == 0)
 
164
                        continue;
173
165
                keys_user = g_key_file_get_keys(userconfig, groups_user[i], &len_keys, NULL);
174
166
 
175
167
                tmp = g_hash_table_lookup(snippet_hash, groups_user[i]);
194
186
                }
195
187
                g_strfreev(keys_user);
196
188
        }
 
189
        g_strfreev(groups_user);
 
190
}
 
191
 
 
192
 
 
193
static void on_snippet_keybinding_activate(gchar *key)
 
194
{
 
195
        GeanyDocument *doc = document_get_current();
 
196
        const gchar *s;
 
197
        GHashTable *specials;
 
198
 
 
199
        if (!doc || !GTK_WIDGET_HAS_FOCUS(doc->editor->sci))
 
200
                return;
 
201
 
 
202
        s = snippets_find_completion_by_name(doc->file_type->name, key);
 
203
        if (!s) /* allow user to specify keybindings for "special" snippets */
 
204
        {
 
205
                specials = g_hash_table_lookup(snippet_hash, "Special");
 
206
                if (G_LIKELY(specials != NULL))
 
207
                        s = g_hash_table_lookup(specials, key);
 
208
        }
 
209
        if (!s)
 
210
        {
 
211
                utils_beep();
 
212
                return;
 
213
        }
 
214
 
 
215
        editor_insert_snippet(doc->editor, sci_get_current_position(doc->editor->sci), s);
 
216
        sci_scroll_caret(doc->editor->sci);
 
217
}
 
218
 
 
219
 
 
220
static void add_kb(GKeyFile *keyfile, const gchar *group, gchar **keys)
 
221
{
 
222
        gsize i;
 
223
 
 
224
        if (!keys)
 
225
                return;
 
226
        for (i = 0; i < g_strv_length(keys); i++)
 
227
        {
 
228
                guint key;
 
229
                GdkModifierType mods;
 
230
                gchar *accel_string = g_key_file_get_value(keyfile, group, keys[i], NULL);
 
231
 
 
232
                gtk_accelerator_parse(accel_string, &key, &mods);
 
233
                g_free(accel_string);
 
234
 
 
235
                if (key == 0 && mods == 0)
 
236
                {
 
237
                        g_warning("Can not parse accelerator \"%s\" from user snippets.conf", accel_string);
 
238
                        continue;
 
239
                }
 
240
                gtk_accel_group_connect(snippet_accel_group, key, mods, 0,
 
241
                        g_cclosure_new_swap((GCallback)on_snippet_keybinding_activate,
 
242
                                g_strdup(keys[i]), (GClosureNotify)g_free));
 
243
        }
 
244
}
 
245
 
 
246
 
 
247
static void load_kb(GKeyFile *sysconfig, GKeyFile *userconfig)
 
248
{
 
249
        const gchar kb_group[] = "Keybindings";
 
250
        gchar **keys = g_key_file_get_keys(userconfig, kb_group, NULL, NULL);
 
251
        gchar **ptr;
 
252
 
 
253
        /* remove overridden keys from system keyfile */
 
254
        foreach_strv(ptr, keys)
 
255
                g_key_file_remove_key(sysconfig, kb_group, *ptr, NULL);
 
256
 
 
257
        add_kb(userconfig, kb_group, keys);
 
258
        g_strfreev(keys);
 
259
 
 
260
        keys = g_key_file_get_keys(sysconfig, kb_group, NULL, NULL);
 
261
        add_kb(sysconfig, kb_group, keys);
 
262
        g_strfreev(keys);
 
263
}
 
264
 
 
265
 
 
266
void editor_snippets_init(void)
 
267
{
 
268
        gchar *sysconfigfile, *userconfigfile;
 
269
        GKeyFile *sysconfig = g_key_file_new();
 
270
        GKeyFile *userconfig = g_key_file_new();
 
271
 
 
272
        snippet_offsets = g_queue_new();
 
273
 
 
274
        sysconfigfile = g_strconcat(app->datadir, G_DIR_SEPARATOR_S, "snippets.conf", NULL);
 
275
        userconfigfile = g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "snippets.conf", NULL);
 
276
 
 
277
        /* check for old autocomplete.conf files (backwards compatibility) */
 
278
        if (! g_file_test(userconfigfile, G_FILE_TEST_IS_REGULAR))
 
279
                setptr(userconfigfile,
 
280
                        g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "autocomplete.conf", NULL));
 
281
 
 
282
        /* load the actual config files */
 
283
        g_key_file_load_from_file(sysconfig, sysconfigfile, G_KEY_FILE_NONE, NULL);
 
284
        g_key_file_load_from_file(userconfig, userconfigfile, G_KEY_FILE_NONE, NULL);
 
285
 
 
286
        snippets_load(sysconfig, userconfig);
 
287
 
 
288
        /* setup snippet keybindings */
 
289
        snippet_accel_group = gtk_accel_group_new();
 
290
        gtk_window_add_accel_group(GTK_WINDOW(main_widgets.window), snippet_accel_group);
 
291
        load_kb(sysconfig, userconfig);
197
292
 
198
293
        g_free(sysconfigfile);
199
294
        g_free(userconfigfile);
200
 
        g_strfreev(groups_sys);
201
 
        g_strfreev(groups_user);
202
295
        g_key_file_free(sysconfig);
203
296
        g_key_file_free(userconfig);
204
297
}
280
373
}
281
374
 
282
375
 
283
 
gint editor_get_long_line_type(void)
 
376
static gint editor_get_long_line_type(void)
284
377
{
285
378
        if (app->project)
286
379
                switch (app->project->long_line_behaviour)
290
383
                        case 1: /* use global settings */
291
384
                                break;
292
385
                        case 2: /* custom (enabled) */
293
 
                                return editor_prefs.long_line_global_type;
 
386
                                return editor_prefs.long_line_type;
294
387
                }
295
388
 
296
 
        if (!editor_prefs.long_line_global_enabled)
 
389
        if (!editor_prefs.long_line_enabled)
297
390
                return 2;
298
391
        else
299
 
                return editor_prefs.long_line_global_type;
 
392
                return editor_prefs.long_line_type;
300
393
}
301
394
 
302
395
 
303
 
gint editor_get_long_line_column(void)
 
396
static gint editor_get_long_line_column(void)
304
397
{
305
398
        if (app->project && app->project->long_line_behaviour != 1 /* use global settings */)
306
399
                return app->project->long_line_column;
307
400
        else
308
 
                return editor_prefs.long_line_global_column;
 
401
                return editor_prefs.long_line_column;
 
402
}
 
403
 
 
404
 
 
405
static const GeanyEditorPrefs *
 
406
get_default_prefs(void)
 
407
{
 
408
        static GeanyEditorPrefs eprefs;
 
409
 
 
410
        eprefs = editor_prefs;
 
411
 
 
412
        /* project overrides */
 
413
        eprefs.indentation = (GeanyIndentPrefs*)editor_get_indent_prefs(NULL);
 
414
        eprefs.long_line_type = editor_get_long_line_type();
 
415
        eprefs.long_line_column = editor_get_long_line_column();
 
416
        return &eprefs;
 
417
}
 
418
 
 
419
 
 
420
/* Gets the prefs for the editor.
 
421
 * Prefs can be different according to project or document.
 
422
 * @warning Always get a fresh result instead of keeping a pointer to it if the editor/project
 
423
 * settings may have changed, or if this function has been called for a different editor.
 
424
 * @param editor The editor, or @c NULL to get the default prefs.
 
425
 * @return The prefs. */
 
426
const GeanyEditorPrefs *editor_get_prefs(GeanyEditor *editor)
 
427
{
 
428
        static GeanyEditorPrefs eprefs;
 
429
        const GeanyEditorPrefs *dprefs = get_default_prefs();
 
430
 
 
431
        /* Return the address of the default prefs to allow returning default and editor
 
432
         * pref pointers without invalidating the contents of either. */
 
433
        if (editor == NULL)
 
434
                return dprefs;
 
435
 
 
436
        eprefs = *dprefs;
 
437
        eprefs.indentation = (GeanyIndentPrefs*)editor_get_indent_prefs(editor);
 
438
        /* add other editor & document overrides as needed */
 
439
        return &eprefs;
309
440
}
310
441
 
311
442
 
433
564
                if (c == GDK_space)
434
565
                {
435
566
                        gint diff, last_pos, last_col;
436
 
                        const gchar *eol = editor_get_eol_char(editor);
437
567
 
438
568
                        /* remember the distance between the current column and the last column on the line
439
569
                         * (we use column position in case the previous line gets altered, such as removing
443
573
                        diff = last_col - col;
444
574
 
445
575
                        /* break the line after the space */
446
 
                        sci_insert_text(sci, pos + 1, eol);
 
576
                        sci_set_current_position(sci, pos + 1, FALSE);
 
577
                        sci_cancel(sci);        /* don't select from completion list */
 
578
                        sci_send_command(sci, SCI_NEWLINE);
447
579
                        line++;
448
580
 
449
 
                        /* set position as if user had pressed return */
450
 
                        pos = sci_get_position_from_line(sci, line);
451
 
                        sci_set_current_position(sci, pos, FALSE);
452
 
                        /* add indentation, comment multilines, etc */
453
 
                        on_new_line_added(editor);
454
 
 
455
581
                        /* correct cursor position (might not be at line end) */
456
582
                        last_pos = sci_get_line_end_position(sci, line);
457
583
                        last_col = sci_get_col_from_position(sci, last_pos); /* get last column on line */
1048
1174
 
1049
1175
 
1050
1176
/** Gets the indentation prefs for the editor.
1051
 
 * In future, the prefs might be different according to project or filetype.
1052
 
 * @warning Always get a fresh result instead of keeping a pointer to it if the editor
1053
 
 * settings may have changed, or if this function has been called for a different @a editor.
 
1177
 * Prefs can be different according to project or document.
 
1178
 * @warning Always get a fresh result instead of keeping a pointer to it if the editor/project
 
1179
 * settings may have changed, or if this function has been called for a different editor.
1054
1180
 * @param editor The editor, or @c NULL to get the default indent prefs.
1055
1181
 * @return The indent prefs. */
1056
1182
const GeanyIndentPrefs *
1057
1183
editor_get_indent_prefs(GeanyEditor *editor)
1058
1184
{
1059
1185
        static GeanyIndentPrefs iprefs;
1060
 
 
1061
 
        iprefs = *get_default_indent_prefs();
1062
 
 
 
1186
        const GeanyIndentPrefs *dprefs = get_default_indent_prefs();
 
1187
 
 
1188
        /* Return the address of the default prefs to allow returning default and editor
 
1189
         * pref pointers without invalidating the contents of either. */
1063
1190
        if (editor == NULL)
1064
 
                return &iprefs;
 
1191
                return dprefs;
1065
1192
 
 
1193
        iprefs = *dprefs;
1066
1194
        iprefs.type = editor->indent_type;
 
1195
        iprefs.width = editor->indent_width;
1067
1196
 
1068
1197
        /* if per-document auto-indent is enabled, but we don't have a global mode set,
1069
1198
         * just use basic auto-indenting */
1199
1328
}
1200
1329
 
1201
1330
 
 
1331
static gint get_xml_indent(ScintillaObject *sci, gint line)
 
1332
{
 
1333
        gboolean need_close = FALSE;
 
1334
        gint end = sci_get_line_end_position(sci, line) - 1;
 
1335
        gint pos;
 
1336
 
 
1337
        /* don't indent if there's a closing tag to the right of the cursor */
 
1338
        pos = sci_get_current_position(sci);
 
1339
        if (sci_get_char_at(sci, pos) == '<' &&
 
1340
                sci_get_char_at(sci, pos + 1) == '/')
 
1341
                return 0;
 
1342
 
 
1343
        if (sci_get_char_at(sci, end) == '>' &&
 
1344
                sci_get_char_at(sci, end - 1) != '/')
 
1345
        {
 
1346
                gint style = sci_get_style_at(sci, end);
 
1347
 
 
1348
                if (style == SCE_H_TAG || style == SCE_H_TAGUNKNOWN)
 
1349
                {
 
1350
                        gint start = sci_get_position_from_line(sci, line);
 
1351
                        gchar *line_contents = sci_get_contents_range(sci, start, end + 1);
 
1352
                        gchar *opened_tag_name = utils_find_open_xml_tag(line_contents, end + 1 - start);
 
1353
 
 
1354
                        if (NZV(opened_tag_name))
 
1355
                        {
 
1356
                                need_close = TRUE;
 
1357
                                if (sci_get_lexer(sci) == SCLEX_HTML && utils_is_short_html_tag(opened_tag_name))
 
1358
                                        need_close = FALSE;
 
1359
                        }
 
1360
                        g_free(line_contents);
 
1361
                        g_free(opened_tag_name);
 
1362
                }
 
1363
        }
 
1364
 
 
1365
        return need_close ? 1 : 0;
 
1366
}
 
1367
 
 
1368
 
1202
1369
static gint get_indent_size_after_line(GeanyEditor *editor, gint line)
1203
1370
{
1204
1371
        ScintillaObject *sci = editor->sci;
1211
1378
 
1212
1379
        if (iprefs->auto_indent_mode > GEANY_AUTOINDENT_BASIC)
1213
1380
        {
 
1381
                gint additional_indent = 0;
 
1382
 
1214
1383
                if (lexer_has_braces(sci))
1215
 
                        size += iprefs->width * get_brace_indent(sci, line);
 
1384
                        additional_indent = iprefs->width * get_brace_indent(sci, line);
1216
1385
                else
1217
 
                if (FILETYPE_ID(editor->document->file_type) == GEANY_FILETYPES_PYTHON)
1218
 
                        size += iprefs->width * get_python_indent(sci, line);
 
1386
                if (editor->document->file_type->id == GEANY_FILETYPES_PYTHON)
 
1387
                        additional_indent = iprefs->width * get_python_indent(sci, line);
 
1388
 
 
1389
                /* HTML lexer "has braces" because of PHP and JavaScript.  If get_brace_indent() did not
 
1390
                 * recommend us to insert additional indent, we are probably not in PHP/JavaScript chunk and
 
1391
                 * should make the XML-related check */
 
1392
                if (additional_indent == 0 &&
 
1393
                        (sci_get_lexer(sci) == SCLEX_HTML ||
 
1394
                        sci_get_lexer(sci) == SCLEX_XML) &&
 
1395
                        editor->document->file_type->priv->xml_indent_tags)
 
1396
                {
 
1397
                        size += iprefs->width * get_xml_indent(sci, line);
 
1398
                }
 
1399
 
 
1400
                size += additional_indent;
1219
1401
        }
1220
1402
        return size;
1221
1403
}
1706
1888
 
1707
1889
        /* the style 1 before the brace (which may be highlighted) */
1708
1890
        style = sci_get_style_at(sci, pos - 1);
1709
 
        if (! is_code_style(lexer, style))
 
1891
        if (! highlighting_is_code_style(lexer, style))
1710
1892
                return FALSE;
1711
1893
 
1712
1894
        word[0] = '\0';
1737
1919
        g_return_val_if_fail(editor != NULL, NULL);
1738
1920
 
1739
1921
        str = g_string_new(NULL);
1740
 
        if (append_calltip(str, tag, FILETYPE_ID(editor->document->file_type)))
 
1922
        if (append_calltip(str, tag, editor->document->file_type->id))
1741
1923
                return g_string_free(str, FALSE);
1742
1924
        else
1743
1925
                return g_string_free(str, TRUE);
1971
2153
        style = sci_get_style_at(sci, pos - 2);
1972
2154
 
1973
2155
        /* don't autocomplete in comments and strings */
1974
 
        if (!force && !is_code_style(lexer, style))
 
2156
        if (!force && !highlighting_is_code_style(lexer, style))
1975
2157
                return FALSE;
1976
2158
 
1977
2159
        autocomplete_scope(editor);
2245
2427
                else
2246
2428
                        snippet_cursor_insert_pos += offset;
2247
2429
 
2248
 
                sci_set_current_position(sci, snippet_cursor_insert_pos, FALSE);
 
2430
                sci_set_current_position(sci, snippet_cursor_insert_pos, TRUE);
2249
2431
        }
2250
2432
        else
2251
2433
        {
2366
2548
{
2367
2549
        ScintillaObject *sci = editor->sci;
2368
2550
        gchar *str;
2369
 
        GString *pattern;
2370
 
        gssize cur_index = -1;
 
2551
        const gchar *completion;
2371
2552
        gint str_len;
2372
 
        gint ft_id = FILETYPE_ID(editor->document->file_type);
 
2553
        gint ft_id = editor->document->file_type->id;
2373
2554
 
2374
2555
        str = g_strdup(word);
2375
2556
        g_strstrip(str);
2376
 
        pattern = g_string_new(snippets_find_completion_by_name(filetypes[ft_id]->name, str));
2377
 
        if (pattern == NULL || pattern->len == 0)
 
2557
 
 
2558
        completion = snippets_find_completion_by_name(filetypes[ft_id]->name, str);
 
2559
        if (completion == NULL)
2378
2560
        {
2379
2561
                g_free(str);
2380
 
                g_string_free(pattern, TRUE);
2381
2562
                return FALSE;
2382
2563
        }
2383
2564
 
2384
 
        read_indent(editor, pos);
2385
 
 
2386
2565
        /* remove the typed word, it will be added again by the used auto completion
2387
2566
         * (not really necessary but this makes the auto completion more flexible,
2388
2567
         *  e.g. with a completion like hi=hello, so typing "hi<TAB>" will result in "hello") */
2392
2571
        sci_replace_sel(sci, "");
2393
2572
        pos -= str_len; /* pos has changed while deleting */
2394
2573
 
2395
 
        cur_index = snippets_make_replacements(editor, pattern, strlen(indent));
2396
 
 
2397
 
        /* finally insert the text and set the cursor */
2398
 
        editor_insert_text_block(editor, pattern->str, pos, cur_index, -1, FALSE);
 
2574
        editor_insert_snippet(editor, pos, completion);
2399
2575
        sci_scroll_caret(sci);
2400
2576
 
2401
2577
        g_free(str);
2402
 
        g_string_free(pattern, TRUE);
2403
2578
        return TRUE;
2404
2579
}
2405
2580
 
2494
2669
        sci_start_undo_action(sci);
2495
2670
        sci_replace_sel(sci, to_insert);
2496
2671
        if (ch == '>')
2497
 
        {
2498
2672
                sci_set_selection(sci, pos, pos);
2499
 
                if (utils_str_equal(tag_name, "table"))
2500
 
                        auto_table(editor, pos);
2501
 
        }
2502
2673
        sci_end_undo_action(sci);
2503
2674
        g_free(to_insert);
2504
2675
}
2514
2685
{
2515
2686
        ScintillaObject *sci = editor->sci;
2516
2687
        gint lexer = sci_get_lexer(sci);
2517
 
        gint min, style;
 
2688
        gint min, size, style;
2518
2689
        gchar *str_found, sel[512];
2519
2690
        gboolean result = FALSE;
2520
2691
 
2525
2696
 
2526
2697
        /* return if we are inside any embedded script */
2527
2698
        style = sci_get_style_at(sci, pos);
2528
 
        if (style > SCE_H_XCCOMMENT && ! is_string_style(lexer, style))
 
2699
        if (style > SCE_H_XCCOMMENT && ! highlighting_is_string_style(lexer, style))
2529
2700
                return FALSE;
2530
2701
 
2531
2702
        /* if ch is /, check for </, else quit */
2546
2717
                /* User typed something like "<br/>" */
2547
2718
                return FALSE;
2548
2719
 
2549
 
        str_found = utils_find_open_xml_tag(sel, pos - min, (ch == '/'));
 
2720
        size = pos - min;
 
2721
        if (ch == '/')
 
2722
                size -= 2; /* skip </ */
 
2723
        str_found = utils_find_open_xml_tag(sel, size);
2550
2724
 
2551
 
        /* when found string is something like br, img or another short tag, quit */
2552
 
        if (utils_str_equal(str_found, "br")
2553
 
         || utils_str_equal(str_found, "hr")
2554
 
         || utils_str_equal(str_found, "img")
2555
 
         || utils_str_equal(str_found, "base")
2556
 
         || utils_str_equal(str_found, "basefont")      /* < or not < */
2557
 
         || utils_str_equal(str_found, "frame")
2558
 
         || utils_str_equal(str_found, "input")
2559
 
         || utils_str_equal(str_found, "link")
2560
 
         || utils_str_equal(str_found, "area")
2561
 
         || utils_str_equal(str_found, "meta"))
 
2725
        if (lexer == SCLEX_HTML && utils_is_short_html_tag(str_found))
2562
2726
        {
2563
2727
                /* ignore tag */
2564
2728
        }
2591
2755
                        case '\t':
2592
2756
                                count += tab_size;
2593
2757
                                break;
 
2758
                        default:
 
2759
                                return count;
2594
2760
                }
2595
2761
        }
2596
2762
        return count;
2597
2763
}
2598
2764
 
2599
2765
 
2600
 
static void auto_table(GeanyEditor *editor, gint pos)
2601
 
{
2602
 
        ScintillaObject *sci = editor->sci;
2603
 
        gchar *table;
2604
 
        gint indent_pos;
2605
 
        const gchar *indent_str;
2606
 
 
2607
 
        if (sci_get_lexer(sci) != SCLEX_HTML) return;
2608
 
 
2609
 
        read_indent(editor, pos);
2610
 
        indent_pos = sci_get_line_indent_position(sci, sci_get_line_from_position(sci, pos));
2611
 
        if ((pos - 7) != indent_pos) /* 7 == strlen("<table>") */
2612
 
        {
2613
 
                gint i;
2614
 
                guint x;
2615
 
 
2616
 
                x = strlen(indent);
2617
 
                /* find the start of the <table tag */
2618
 
                i = 1;
2619
 
                while (i <= pos && sci_get_char_at(sci, pos - i) != '<') i++;
2620
 
                /* add all non whitespace before the tag to the indent string */
2621
 
                while ((pos - i) != indent_pos && x < sizeof(indent) - 1)
2622
 
                {
2623
 
                        indent[x++] = ' ';
2624
 
                        i++;
2625
 
                }
2626
 
                indent[x] = '\0';
2627
 
        }
2628
 
 
2629
 
        if (! editor->auto_indent)
2630
 
                indent_str = "";
2631
 
        else
2632
 
                indent_str = "\t";
2633
 
 
2634
 
        table = g_strconcat("\n", indent_str, "<tr>\n",
2635
 
                                                indent_str, indent_str, "<td> </td>\n",
2636
 
                                                indent_str, "</tr>\n",
2637
 
                                                NULL);
2638
 
        editor_insert_text_block(editor, table, pos, -1,
2639
 
                count_indent_size(editor, indent), TRUE);
2640
 
        g_free(table);
2641
 
}
2642
 
 
2643
 
 
2644
2766
static void real_comment_multiline(GeanyEditor *editor, gint line_start, gint last_line)
2645
2767
{
2646
2768
        const gchar *eol;
2739
2861
 * it returns just 1 */
2740
2862
gint editor_do_uncomment(GeanyEditor *editor, gint line, gboolean toggle)
2741
2863
{
2742
 
        gint first_line, last_line;
 
2864
        gint first_line, last_line, eol_char_len;
2743
2865
        gint x, i, line_start, line_len;
2744
2866
        gint sel_start, sel_end;
2745
2867
        gint count = 0;
2768
2890
        }
2769
2891
 
2770
2892
        ft = editor->document->file_type;
 
2893
        eol_char_len = editor_get_eol_char_len(editor);
2771
2894
 
2772
2895
        /* detection of HTML vs PHP code, if non-PHP set filetype to XML */
2773
2896
        line_start = sci_get_position_from_line(editor->sci, first_line);
2796
2919
                line_len = sci_get_line_length(editor->sci, i);
2797
2920
                x = 0;
2798
2921
 
2799
 
                buf_len = MIN((gint)sizeof(sel) - 1, line_len - 1);
 
2922
                buf_len = MIN((gint)sizeof(sel) - 1, line_len - eol_char_len);
2800
2923
                if (buf_len <= 0)
2801
2924
                        continue;
2802
2925
                sci_get_text_range(editor->sci, line_start, line_start + buf_len, sel);
2875
2998
 
2876
2999
void editor_do_comment_toggle(GeanyEditor *editor)
2877
3000
{
2878
 
        gint first_line, last_line;
 
3001
        gint first_line, last_line, eol_char_len;
2879
3002
        gint x, i, line_start, line_len, first_line_start;
2880
3003
        gint sel_start, sel_end;
2881
3004
        gint count_commented = 0, count_uncommented = 0;
2892
3015
        sel_end = sci_get_selection_end(editor->sci);
2893
3016
 
2894
3017
        ft = editor->document->file_type;
 
3018
        eol_char_len = editor_get_eol_char_len(editor);
2895
3019
 
2896
3020
        first_line = sci_get_line_from_position(editor->sci,
2897
3021
                sci_get_selection_start(editor->sci));
2927
3051
                line_len = sci_get_line_length(editor->sci, i);
2928
3052
                x = 0;
2929
3053
 
2930
 
                buf_len = MIN((gint)sizeof(sel) - 1, line_len - 1);
 
3054
                buf_len = MIN((gint)sizeof(sel) - 1, line_len - eol_char_len);
2931
3055
                if (buf_len < 0)
2932
3056
                        continue;
2933
3057
                sci_get_text_range(editor->sci, line_start, line_start + buf_len, sel);
3035
3159
/* set toggle to TRUE if the caller is the toggle function, FALSE otherwise */
3036
3160
void editor_do_comment(GeanyEditor *editor, gint line, gboolean allow_empty_lines, gboolean toggle)
3037
3161
{
3038
 
        gint first_line, last_line;
 
3162
        gint first_line, last_line, eol_char_len;
3039
3163
        gint x, i, line_start, line_len;
3040
3164
        gint sel_start, sel_end, co_len;
3041
3165
        gchar sel[256], *co, *cc;
3062
3186
        }
3063
3187
 
3064
3188
        ft = editor->document->file_type;
 
3189
        eol_char_len = editor_get_eol_char_len(editor);
3065
3190
 
3066
3191
        /* detection of HTML vs PHP code, if non-PHP set filetype to XML */
3067
3192
        line_start = sci_get_position_from_line(editor->sci, first_line);
3090
3215
                line_len = sci_get_line_length(editor->sci, i);
3091
3216
                x = 0;
3092
3217
 
3093
 
                buf_len = MIN((gint)sizeof(sel) - 1, line_len - 1);
 
3218
                buf_len = MIN((gint)sizeof(sel) - 1, line_len - eol_char_len);
3094
3219
                if (buf_len < 0)
3095
3220
                        continue;
3096
3221
                sci_get_text_range(editor->sci, line_start, line_start + buf_len, sel);
3337
3462
}
3338
3463
 
3339
3464
 
3340
 
/* Checks whether the given style is a string for the given lexer.
3341
 
 * It doesn't handle LEX_HTML, this should be done by the caller.
3342
 
 * Returns true if the style is a string, FALSE otherwise.
3343
 
 *
3344
 
 * Don't forget STRINGEOL, to prevent completion whilst typing a string with no closing char.
3345
 
 */
3346
 
static gboolean is_string_style(gint lexer, gint style)
3347
 
{
3348
 
        switch (lexer)
3349
 
        {
3350
 
                case SCLEX_CPP:
3351
 
                        return (style == SCE_C_CHARACTER ||
3352
 
                                style == SCE_C_STRING ||
3353
 
                                style == SCE_C_STRINGEOL);
3354
 
 
3355
 
                case SCLEX_PASCAL:
3356
 
                        return (style == SCE_PAS_CHARACTER ||
3357
 
                                style == SCE_PAS_STRING ||
3358
 
                                style == SCE_PAS_STRINGEOL);
3359
 
 
3360
 
                case SCLEX_D:
3361
 
                        return (style == SCE_D_STRING ||
3362
 
                                style == SCE_D_STRINGEOL ||
3363
 
                                style == SCE_D_CHARACTER ||
3364
 
                                style == SCE_D_STRINGB ||
3365
 
                                style == SCE_D_STRINGR);
3366
 
 
3367
 
                case SCLEX_PYTHON:
3368
 
                        return (style == SCE_P_STRING ||
3369
 
                                style == SCE_P_TRIPLE ||
3370
 
                                style == SCE_P_TRIPLEDOUBLE ||
3371
 
                                style == SCE_P_CHARACTER ||
3372
 
                                style == SCE_P_STRINGEOL);
3373
 
 
3374
 
                case SCLEX_F77:
3375
 
                case SCLEX_FORTRAN:
3376
 
                        return (style == SCE_F_STRING1 ||
3377
 
                                style == SCE_F_STRING2 ||
3378
 
                                style == SCE_F_STRINGEOL);
3379
 
 
3380
 
                case SCLEX_PERL:
3381
 
                        return (/*style == SCE_PL_STRING ||*/ /* may want variable autocompletion "$(foo)" */
3382
 
                                style == SCE_PL_CHARACTER ||
3383
 
                                style == SCE_PL_HERE_DELIM ||
3384
 
                                style == SCE_PL_HERE_Q ||
3385
 
                                style == SCE_PL_HERE_QQ ||
3386
 
                                style == SCE_PL_HERE_QX ||
3387
 
                                style == SCE_PL_POD ||
3388
 
                                style == SCE_PL_STRING_Q ||
3389
 
                                style == SCE_PL_STRING_QQ ||
3390
 
                                style == SCE_PL_STRING_QX ||
3391
 
                                style == SCE_PL_STRING_QR ||
3392
 
                                style == SCE_PL_STRING_QW ||
3393
 
                                style == SCE_PL_POD_VERB);
3394
 
 
3395
 
                case SCLEX_R:
3396
 
                        return (style == SCE_R_STRING);
3397
 
 
3398
 
                case SCLEX_RUBY:
3399
 
                        return (style == SCE_RB_CHARACTER ||
3400
 
                                style == SCE_RB_STRING ||
3401
 
                                style == SCE_RB_HERE_DELIM ||
3402
 
                                style == SCE_RB_HERE_Q ||
3403
 
                                style == SCE_RB_HERE_QQ ||
3404
 
                                style == SCE_RB_HERE_QX ||
3405
 
                                style == SCE_RB_POD);
3406
 
 
3407
 
                case SCLEX_BASH:
3408
 
                        return (style == SCE_SH_STRING);
3409
 
 
3410
 
                case SCLEX_SQL:
3411
 
                        return (style == SCE_SQL_STRING);
3412
 
 
3413
 
                case SCLEX_TCL:
3414
 
                        return (style == SCE_TCL_IN_QUOTE);
3415
 
 
3416
 
                case SCLEX_LUA:
3417
 
                        return (style == SCE_LUA_LITERALSTRING ||
3418
 
                                style == SCE_LUA_CHARACTER ||
3419
 
                                style == SCE_LUA_STRINGEOL ||
3420
 
                                style == SCE_LUA_STRING);
3421
 
 
3422
 
                case SCLEX_HASKELL:
3423
 
                        return (style == SCE_HA_CHARACTER ||
3424
 
                                style == SCE_HA_STRING);
3425
 
 
3426
 
                case SCLEX_FREEBASIC:
3427
 
                        return (style == SCE_B_STRING ||
3428
 
                                style == SCE_B_STRINGEOL);
3429
 
 
3430
 
                case SCLEX_MATLAB:
3431
 
                        return (style == SCE_MATLAB_STRING ||
3432
 
                                style == SCE_MATLAB_DOUBLEQUOTESTRING);
3433
 
 
3434
 
                case SCLEX_HTML:
3435
 
                        return (
3436
 
                                style == SCE_HBA_STRING ||
3437
 
                                style == SCE_HBA_STRINGEOL ||
3438
 
                                style == SCE_HB_STRING ||
3439
 
                                style == SCE_HB_STRINGEOL ||
3440
 
                                style == SCE_H_CDATA ||
3441
 
                                style == SCE_H_DOUBLESTRING ||
3442
 
                                style == SCE_HJA_DOUBLESTRING ||
3443
 
                                style == SCE_HJA_SINGLESTRING ||
3444
 
                                style == SCE_HJA_STRINGEOL ||
3445
 
                                style == SCE_HJ_DOUBLESTRING ||
3446
 
                                style == SCE_HJ_SINGLESTRING ||
3447
 
                                style == SCE_HJ_STRINGEOL ||
3448
 
                                style == SCE_HPA_CHARACTER ||
3449
 
                                style == SCE_HPA_STRING ||
3450
 
                                style == SCE_HPA_TRIPLE ||
3451
 
                                style == SCE_HPA_TRIPLEDOUBLE ||
3452
 
                                style == SCE_HP_CHARACTER ||
3453
 
                                style == SCE_HPHP_HSTRING ||
3454
 
                                style == SCE_HPHP_HSTRING ||  /* HSTRING is a heredoc */
3455
 
                                style == SCE_HPHP_HSTRING_VARIABLE ||
3456
 
                                style == SCE_HPHP_SIMPLESTRING ||
3457
 
                                style == SCE_HPHP_SIMPLESTRING ||
3458
 
                                style == SCE_HP_STRING ||
3459
 
                                style == SCE_HP_TRIPLE ||
3460
 
                                style == SCE_HP_TRIPLEDOUBLE ||
3461
 
                                style == SCE_H_SGML_DOUBLESTRING ||
3462
 
                                style == SCE_H_SGML_SIMPLESTRING ||
3463
 
                                style == SCE_H_SINGLESTRING);
3464
 
 
3465
 
                case SCLEX_CMAKE:
3466
 
                        return (style == SCE_CMAKE_STRINGDQ ||
3467
 
                                style == SCE_CMAKE_STRINGLQ ||
3468
 
                                style == SCE_CMAKE_STRINGRQ ||
3469
 
                                style == SCE_CMAKE_STRINGVAR);
3470
 
 
3471
 
                case SCLEX_NSIS:
3472
 
                        return (style == SCE_NSIS_STRINGDQ ||
3473
 
                                style == SCE_NSIS_STRINGLQ ||
3474
 
                                style == SCE_NSIS_STRINGRQ ||
3475
 
                                style == SCE_NSIS_STRINGVAR);
3476
 
 
3477
 
                case SCLEX_ADA:
3478
 
                        return (style == SCE_ADA_CHARACTER ||
3479
 
                                style == SCE_ADA_STRING ||
3480
 
                                style == SCE_ADA_CHARACTEREOL ||
3481
 
                                style == SCE_ADA_STRINGEOL);
3482
 
        }
3483
 
        return FALSE;
3484
 
}
3485
 
 
3486
 
 
3487
 
/* Checks whether the given style is a comment for the given lexer.
3488
 
 * It doesn't handle LEX_HTML, this should be done by the caller.
3489
 
 * Returns true if the style is a comment, FALSE otherwise.
3490
 
 */
3491
 
static gboolean is_comment_style(gint lexer, gint style)
3492
 
{
3493
 
        switch (lexer)
3494
 
        {
3495
 
                case SCLEX_CPP:
3496
 
                        return (style == SCE_C_COMMENT ||
3497
 
                                style == SCE_C_COMMENTLINE ||
3498
 
                                style == SCE_C_COMMENTDOC ||
3499
 
                                style == SCE_C_COMMENTLINEDOC ||
3500
 
                                style == SCE_C_COMMENTDOCKEYWORD ||
3501
 
                                style == SCE_C_COMMENTDOCKEYWORDERROR);
3502
 
 
3503
 
                case SCLEX_PASCAL:
3504
 
                        return (style == SCE_PAS_COMMENT ||
3505
 
                                style == SCE_PAS_COMMENT2 ||
3506
 
                                style == SCE_PAS_COMMENTLINE);
3507
 
 
3508
 
                case SCLEX_D:
3509
 
                        return (style == SCE_D_COMMENT ||
3510
 
                                style == SCE_D_COMMENTLINE ||
3511
 
                                style == SCE_D_COMMENTDOC ||
3512
 
                                style == SCE_D_COMMENTNESTED ||
3513
 
                                style == SCE_D_COMMENTLINEDOC ||
3514
 
                                style == SCE_D_COMMENTDOCKEYWORD ||
3515
 
                                style == SCE_D_COMMENTDOCKEYWORDERROR);
3516
 
 
3517
 
                case SCLEX_PYTHON:
3518
 
                        return (style == SCE_P_COMMENTLINE ||
3519
 
                                style == SCE_P_COMMENTBLOCK);
3520
 
 
3521
 
                case SCLEX_F77:
3522
 
                case SCLEX_FORTRAN:
3523
 
                        return (style == SCE_F_COMMENT);
3524
 
 
3525
 
                case SCLEX_PERL:
3526
 
                        return (style == SCE_PL_COMMENTLINE);
3527
 
 
3528
 
                case SCLEX_PROPERTIES:
3529
 
                        return (style == SCE_PROPS_COMMENT);
3530
 
 
3531
 
                case SCLEX_PO:
3532
 
                        return (style == SCE_PO_COMMENT);
3533
 
 
3534
 
                case SCLEX_LATEX:
3535
 
                        return (style == SCE_L_COMMENT);
3536
 
 
3537
 
                case SCLEX_MAKEFILE:
3538
 
                        return (style == SCE_MAKE_COMMENT);
3539
 
 
3540
 
                case SCLEX_RUBY:
3541
 
                        return (style == SCE_RB_COMMENTLINE);
3542
 
 
3543
 
                case SCLEX_BASH:
3544
 
                        return (style == SCE_SH_COMMENTLINE);
3545
 
 
3546
 
                case SCLEX_R:
3547
 
                        return (style == SCE_R_COMMENT);
3548
 
 
3549
 
                case SCLEX_SQL:
3550
 
                        return (style == SCE_SQL_COMMENT ||
3551
 
                                style == SCE_SQL_COMMENTLINE ||
3552
 
                                style == SCE_SQL_COMMENTDOC);
3553
 
 
3554
 
                case SCLEX_TCL:
3555
 
                        return (style == SCE_TCL_COMMENT ||
3556
 
                                style == SCE_TCL_COMMENTLINE ||
3557
 
                                style == SCE_TCL_COMMENT_BOX ||
3558
 
                                style == SCE_TCL_BLOCK_COMMENT);
3559
 
 
3560
 
                case SCLEX_MATLAB:
3561
 
                        return (style == SCE_MATLAB_COMMENT);
3562
 
 
3563
 
                case SCLEX_LUA:
3564
 
                        return (style == SCE_LUA_COMMENT ||
3565
 
                                style == SCE_LUA_COMMENTLINE ||
3566
 
                                style == SCE_LUA_COMMENTDOC);
3567
 
 
3568
 
                case SCLEX_HASKELL:
3569
 
                        return (style == SCE_HA_COMMENTLINE ||
3570
 
                                style == SCE_HA_COMMENTBLOCK ||
3571
 
                                style == SCE_HA_COMMENTBLOCK2 ||
3572
 
                                style == SCE_HA_COMMENTBLOCK3);
3573
 
 
3574
 
                case SCLEX_FREEBASIC:
3575
 
                        return (style == SCE_B_COMMENT);
3576
 
 
3577
 
                case SCLEX_YAML:
3578
 
                        return (style == SCE_YAML_COMMENT);
3579
 
 
3580
 
                case SCLEX_HTML:
3581
 
                        return (
3582
 
                                style == SCE_HBA_COMMENTLINE ||
3583
 
                                style == SCE_HB_COMMENTLINE ||
3584
 
                                style == SCE_H_COMMENT ||
3585
 
                                style == SCE_HJA_COMMENT ||
3586
 
                                style == SCE_HJA_COMMENTDOC ||
3587
 
                                style == SCE_HJA_COMMENTLINE ||
3588
 
                                style == SCE_HJ_COMMENT ||
3589
 
                                style == SCE_HJ_COMMENTDOC ||
3590
 
                                style == SCE_HJ_COMMENTLINE ||
3591
 
                                style == SCE_HPA_COMMENTLINE ||
3592
 
                                style == SCE_HP_COMMENTLINE ||
3593
 
                                style == SCE_HPHP_COMMENT ||
3594
 
                                style == SCE_HPHP_COMMENTLINE ||
3595
 
                                style == SCE_H_SGML_COMMENT);
3596
 
 
3597
 
                case SCLEX_CMAKE:
3598
 
                        return (style == SCE_CMAKE_COMMENT);
3599
 
 
3600
 
                case SCLEX_NSIS:
3601
 
                        return (style == SCE_NSIS_COMMENT ||
3602
 
                                style == SCE_NSIS_COMMENTBOX);
3603
 
 
3604
 
                case SCLEX_ADA:
3605
 
                        return (style == SCE_ADA_COMMENTLINE ||
3606
 
                                style == SCE_NSIS_COMMENTBOX);
3607
 
        }
3608
 
        return FALSE;
3609
 
}
3610
 
 
3611
 
 
3612
 
/* Checks whether the given style is normal code (not string, comment, preprocessor, etc).
3613
 
 * It doesn't handle LEX_HTML, this should be done by the caller.
3614
 
 */
3615
 
static gboolean is_code_style(gint lexer, gint style)
3616
 
{
3617
 
        switch (lexer)
3618
 
        {
3619
 
                case SCLEX_CPP:
3620
 
                        if (style == SCE_C_PREPROCESSOR)
3621
 
                                return FALSE;
3622
 
                        break;
3623
 
        }
3624
 
        return !(is_comment_style(lexer, style) ||
3625
 
                is_string_style(lexer, style));
3626
 
}
3627
 
 
3628
 
 
3629
3465
#if 0
3630
3466
static gboolean editor_lexer_is_c_like(gint lexer)
3631
3467
{
3726
3562
 * line can be -1 to use the current position. */
3727
3563
void editor_scroll_to_line(GeanyEditor *editor, gint line, gfloat percent_of_view)
3728
3564
{
3729
 
        gint vis1, los, delta;
 
3565
        gint los;
3730
3566
        GtkWidget *wid;
3731
3567
 
3732
3568
        g_return_if_fail(editor != NULL);
3743
3579
        /* calling SCI_VISIBLEFROMDOCLINE for line is more accurate than calling
3744
3580
         * SCI_DOCLINEFROMVISIBLE for vis1. */
3745
3581
        line = SSM(editor->sci, SCI_VISIBLEFROMDOCLINE, line, 0);
3746
 
        vis1 = SSM(editor->sci, SCI_GETFIRSTVISIBLELINE, 0, 0);
3747
3582
        los = SSM(editor->sci, SCI_LINESONSCREEN, 0, 0);
3748
 
        delta = (line - vis1) - los * percent_of_view;
3749
 
        sci_scroll_lines(editor->sci, delta);
 
3583
        line = line - los * percent_of_view;
 
3584
        SSM(editor->sci, SCI_SETFIRSTVISIBLELINE, line, 0);
3750
3585
        sci_scroll_caret(editor->sci); /* needed for horizontal scrolling */
3751
3586
}
3752
3587
 
3828
3663
}
3829
3664
 
3830
3665
 
3831
 
/* find the start or end of a paragraph by searching all lines in direction (UP or DOWN)
3832
 
 * starting at the given line and return the found line or return -1 if called on an empty line */
 
3666
static gboolean sci_is_blank_line(ScintillaObject *sci, gint line)
 
3667
{
 
3668
        return sci_get_line_indent_position(sci, line) ==
 
3669
                sci_get_line_end_position(sci, line);
 
3670
}
 
3671
 
 
3672
 
 
3673
/* Returns first line of paragraph for GTK_DIR_UP, line after paragraph
 
3674
 * ends for GTK_DIR_DOWN or -1 if called on an empty line. */
3833
3675
static gint find_paragraph_stop(GeanyEditor *editor, gint line, gint direction)
3834
3676
{
3835
 
        gboolean found_end = FALSE;
3836
3677
        gint step;
3837
 
        gchar *line_buf, *x;
3838
3678
        ScintillaObject *sci = editor->sci;
3839
3679
 
3840
3680
        /* first check current line and return -1 if it is empty to skip creating of a selection */
3841
 
        line_buf = x = sci_get_line(sci, line);
3842
 
        while (isspace(*x))
3843
 
                x++;
3844
 
        if (*x == '\0')
3845
 
        {
3846
 
                g_free(line_buf);
 
3681
        if (sci_is_blank_line(sci, line))
3847
3682
                return -1;
3848
 
        }
3849
3683
 
3850
3684
        if (direction == GTK_DIR_UP)
3851
3685
                step = -1;
3852
3686
        else
3853
3687
                step = 1;
3854
3688
 
3855
 
        while (! found_end)
 
3689
        while (TRUE)
3856
3690
        {
3857
3691
                line += step;
3858
 
 
3859
 
                /* sci_get_line checks for sanity of the given line, sci_get_line always return a string
3860
 
                 * containing at least '\0' so no need to check for NULL */
3861
 
                line_buf = x = sci_get_line(sci, line);
3862
 
 
3863
 
                /* check whether after skipping all whitespace we are at end of line and if so, assume
3864
 
                 * this line as end of paragraph */
3865
 
                while (isspace(*x))
3866
 
                        x++;
3867
 
                if (*x == '\0')
3868
 
                {
3869
 
                        found_end = TRUE;
3870
 
                        if (line == -1)
3871
 
                                /* called on the first line but there is no previous line so return line 0 */
3872
 
                                line = 0;
3873
 
                }
3874
 
                g_free(line_buf);
 
3692
                if (line == -1)
 
3693
                {
 
3694
                        /* start of document */
 
3695
                        line = 0;
 
3696
                        break;
 
3697
                }
 
3698
                if (line == sci_get_line_count(sci))
 
3699
                        break;
 
3700
 
 
3701
                if (sci_is_blank_line(sci, line))
 
3702
                {
 
3703
                        /* return line paragraph starts on */
 
3704
                        if (direction == GTK_DIR_UP)
 
3705
                                line++;
 
3706
                        break;
 
3707
                }
3875
3708
        }
3876
3709
        return line;
3877
3710
}
3883
3716
 
3884
3717
        g_return_if_fail(editor != NULL);
3885
3718
 
3886
 
        line_start = SSM(editor->sci, SCI_LINEFROMPOSITION,
3887
 
                                                SSM(editor->sci, SCI_GETCURRENTPOS, 0, 0), 0);
 
3719
        line_start = sci_get_current_line(editor->sci);
3888
3720
 
3889
3721
        line_found = find_paragraph_stop(editor, line_start, GTK_DIR_UP);
3890
3722
        if (line_found == -1)
3891
3723
                return;
3892
3724
 
3893
 
        /* find_paragraph_stop returns the emtpy line(previous to the real start of the paragraph),
3894
 
         * so use the next line for selection start */
3895
 
        if (line_found > 0)
3896
 
                line_found++;
3897
 
 
3898
3725
        pos_start = SSM(editor->sci, SCI_POSITIONFROMLINE, line_found, 0);
3899
3726
 
3900
3727
        line_found = find_paragraph_stop(editor, line_start, GTK_DIR_DOWN);
3904
3731
}
3905
3732
 
3906
3733
 
 
3734
/* Returns first line of block for GTK_DIR_UP, line after block
 
3735
 * ends for GTK_DIR_DOWN or -1 if called on an empty line. */
 
3736
static gint find_block_stop(GeanyEditor *editor, gint line, gint direction)
 
3737
{
 
3738
        gint step, ind;
 
3739
        ScintillaObject *sci = editor->sci;
 
3740
 
 
3741
        /* first check current line and return -1 if it is empty to skip creating of a selection */
 
3742
        if (sci_is_blank_line(sci, line))
 
3743
                return -1;
 
3744
 
 
3745
        if (direction == GTK_DIR_UP)
 
3746
                step = -1;
 
3747
        else
 
3748
                step = 1;
 
3749
 
 
3750
        ind = sci_get_line_indentation(sci, line);
 
3751
        while (TRUE)
 
3752
        {
 
3753
                line += step;
 
3754
                if (line == -1)
 
3755
                {
 
3756
                        /* start of document */
 
3757
                        line = 0;
 
3758
                        break;
 
3759
                }
 
3760
                if (line == sci_get_line_count(sci))
 
3761
                        break;
 
3762
 
 
3763
                if (sci_get_line_indentation(sci, line) != ind ||
 
3764
                        sci_is_blank_line(sci, line))
 
3765
                {
 
3766
                        /* return line block starts on */
 
3767
                        if (direction == GTK_DIR_UP)
 
3768
                                line++;
 
3769
                        break;
 
3770
                }
 
3771
        }
 
3772
        return line;
 
3773
}
 
3774
 
 
3775
 
 
3776
void editor_select_indent_block(GeanyEditor *editor)
 
3777
{
 
3778
        gint pos_start, pos_end, line_start, line_found;
 
3779
 
 
3780
        g_return_if_fail(editor != NULL);
 
3781
 
 
3782
        line_start = sci_get_current_line(editor->sci);
 
3783
 
 
3784
        line_found = find_block_stop(editor, line_start, GTK_DIR_UP);
 
3785
        if (line_found == -1)
 
3786
                return;
 
3787
 
 
3788
        pos_start = SSM(editor->sci, SCI_POSITIONFROMLINE, line_found, 0);
 
3789
 
 
3790
        line_found = find_block_stop(editor, line_start, GTK_DIR_DOWN);
 
3791
        pos_end = SSM(editor->sci, SCI_POSITIONFROMLINE, line_found, 0);
 
3792
 
 
3793
        sci_set_selection(editor->sci, pos_start, pos_end);
 
3794
}
 
3795
 
 
3796
 
3907
3797
/* simple indentation to indent the current line with the same indent as the previous one */
3908
3798
static void smart_line_indentation(GeanyEditor *editor, gint first_line, gint last_line)
3909
3799
{
4260
4150
 
4261
4151
 
4262
4152
/**
 
4153
 *  Retrieves the end of line characters mode (LF, CR/LF, CR) in the given editor.
 
4154
 *  If @a editor is @c NULL, the default end of line characters are used.
 
4155
 *
 
4156
 *  @param editor The editor to operate on, or @c NULL to query the default value.
 
4157
 *  @return The used end of line characters mode.
 
4158
 *
 
4159
 *  @since 0.20
 
4160
 */
 
4161
gint editor_get_eol_char_mode(GeanyEditor *editor)
 
4162
{
 
4163
        gint mode = file_prefs.default_eol_character;
 
4164
 
 
4165
        if (editor != NULL)
 
4166
                mode = sci_get_eol_mode(editor->sci);
 
4167
 
 
4168
        return mode;
 
4169
}
 
4170
 
 
4171
 
 
4172
/**
4263
4173
 *  Retrieves the localized name (for displaying) of the used end of line characters
4264
4174
 *  (LF, CR/LF, CR) in the given editor.
4265
4175
 *  If @a editor is @c NULL, the default end of line characters are used.
4322
4232
        if (editor != NULL)
4323
4233
                mode = sci_get_eol_mode(editor->sci);
4324
4234
 
4325
 
        switch (mode)
4326
 
        {
4327
 
                case SC_EOL_CRLF: return "\r\n"; break;
4328
 
                case SC_EOL_CR: return "\r"; break;
4329
 
                default: return "\n"; break;
4330
 
        }
 
4235
        return utils_get_eol_char(mode);
4331
4236
}
4332
4237
 
4333
4238
 
4497
4402
        }
4498
4403
        if (append_newline)
4499
4404
        {
4500
 
                const gchar *eol = "\n";
4501
 
                switch (sci_get_eol_mode(editor->sci))
4502
 
                {
4503
 
                        case SC_EOL_CRLF:
4504
 
                                eol = "\r\n";
4505
 
                                break;
4506
 
                        case SC_EOL_CR:
4507
 
                                eol = "\r";
4508
 
                                break;
4509
 
                }
 
4405
                const gchar *eol = editor_get_eol_char(editor);
 
4406
 
4510
4407
                sci_insert_text(editor->sci, end_document, eol);
4511
4408
        }
4512
4409
}
4556
4453
 */
4557
4454
void editor_set_indent_type(GeanyEditor *editor, GeanyIndentType type)
4558
4455
{
 
4456
        editor_set_indent(editor, type, editor->indent_width);
 
4457
}
 
4458
 
 
4459
 
 
4460
void editor_set_indent(GeanyEditor *editor, GeanyIndentType type, gint width)
 
4461
{
4559
4462
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
4560
4463
        ScintillaObject *sci = editor->sci;
4561
4464
        gboolean use_tabs = type != GEANY_INDENT_TYPE_SPACES;
4562
4465
 
4563
4466
        editor->indent_type = type;
 
4467
        editor->indent_width = width;
4564
4468
        sci_set_use_tabs(sci, use_tabs);
4565
4469
 
4566
4470
        if (type == GEANY_INDENT_TYPE_BOTH)
4576
4480
                }
4577
4481
        }
4578
4482
        else
4579
 
                sci_set_tab_width(sci, iprefs->width);
 
4483
                sci_set_tab_width(sci, width);
4580
4484
 
4581
 
        SSM(sci, SCI_SETINDENT, iprefs->width, 0);
 
4485
        SSM(sci, SCI_SETINDENT, width, 0);
4582
4486
 
4583
4487
        /* remove indent spaces on backspace, if using any spaces to indent */
4584
4488
        SSM(sci, SCI_SETBACKSPACEUNINDENTS, type != GEANY_INDENT_TYPE_TABS, 0);
4606
4510
}
4607
4511
 
4608
4512
 
4609
 
/* Move to position @a pos, switching to the document if necessary,
4610
 
 * setting a marker if @a mark is set. */
 
4513
/** Moves to position @a pos, switching to the document if necessary,
 
4514
 *  setting a marker if @a mark is set.
 
4515
 *
 
4516
 * @param editor Editor.
 
4517
 * @param pos The position.
 
4518
 * @param mark Whether to set a mark on the position.
 
4519
 * @return @c TRUE if action has been performed, otherwise @c FALSE.
 
4520
 *
 
4521
 *  @since 0.20
 
4522
 **/
4611
4523
gboolean editor_goto_pos(GeanyEditor *editor, gint pos, gboolean mark)
4612
4524
{
4613
4525
        gint page_num;
4807
4719
        sci = create_new_sci(editor);
4808
4720
        editor->sci = sci;
4809
4721
 
4810
 
        editor_set_indent_type(editor, iprefs->type);
 
4722
        editor_set_indent(editor, iprefs->type, iprefs->width);
4811
4723
        editor_set_font(editor, interface_prefs.editor_font);
4812
4724
        editor_apply_update_prefs(editor);
4813
4725
 
4949
4861
                case SCLEX_VHDL:
4950
4862
                case SCLEX_FREEBASIC:
4951
4863
                case SCLEX_D:
4952
 
                case SCLEX_MATLAB:
 
4864
                case SCLEX_OCTAVE:
4953
4865
                        mode = SC_IV_LOOKBOTH;
4954
4866
                        break;
4955
4867
 
4978
4890
                editor_get_long_line_column(), editor_prefs.long_line_color);
4979
4891
 
4980
4892
        /* update indent width, tab width */
4981
 
        editor_set_indent_type(editor, editor->indent_type);
 
4893
        editor_set_indent(editor, editor->indent_type, editor->indent_width);
4982
4894
        sci_set_tab_indents(sci, editor_prefs.use_tab_to_indent);
4983
4895
 
 
4896
        sci_assign_cmdkey(sci, SCK_HOME | (SCMOD_SHIFT << 16),
 
4897
                editor_prefs.smart_home_key ? SCI_VCHOMEEXTEND : SCI_HOMEEXTEND);
 
4898
        sci_assign_cmdkey(sci, SCK_HOME | ((SCMOD_SHIFT | SCMOD_ALT) << 16),
 
4899
                editor_prefs.smart_home_key ? SCI_VCHOMERECTEXTEND : SCI_HOMERECTEXTEND);
 
4900
 
4984
4901
        sci_set_autoc_max_height(sci, editor_prefs.symbolcompletion_max_height);
4985
4902
        SSM(sci, SCI_AUTOCSETDROPRESTOFWORD, editor_prefs.completion_drops_rest_of_word, 0);
4986
4903
 
5086
5003
                sci_set_current_line(sci, lstart);
5087
5004
        }
5088
5005
}
 
5006
 
 
5007
 
 
5008
/** Gets snippet by name.
 
5009
 *
 
5010
 * If @a editor is passed, returns a snippet specific to the document filetype.
 
5011
 * If @a editor is @c NULL, returns a snippet from the default set.
 
5012
 *
 
5013
 * @param editor Editor or @c NULL.
 
5014
 * @param snippet_name Snippet name.
 
5015
 * @return snippet or @c NULL if it was not found. Must not be freed.
 
5016
 */
 
5017
const gchar *editor_find_snippet(GeanyEditor *editor, const gchar *snippet_name)
 
5018
{
 
5019
        const gchar *subhash_name = editor ? editor->document->file_type->name : "Default";
 
5020
        GHashTable *subhash = g_hash_table_lookup(snippet_hash, subhash_name);
 
5021
 
 
5022
        return subhash ? g_hash_table_lookup(subhash, snippet_name) : NULL;
 
5023
}
 
5024
 
 
5025
 
 
5026
/** Replaces all special sequences in @a snippet and inserts it at @a pos.
 
5027
 * If you insert at the current position, consider calling @c sci_scroll_caret()
 
5028
 * after this function.
 
5029
 * @param editor .
 
5030
 * @param pos .
 
5031
 * @param snippet .
 
5032
 */
 
5033
void editor_insert_snippet(GeanyEditor *editor, gint pos, const gchar *snippet)
 
5034
{
 
5035
        gint cursor_pos;
 
5036
        GString *pattern;
 
5037
 
 
5038
        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);
 
5042
        g_string_free(pattern, TRUE);
 
5043
}