~ubuntu-branches/ubuntu/raring/geany/raring-proposed

« back to all changes in this revision

Viewing changes to src/editor.c

  • Committer: Bazaar Package Importer
  • Author(s): Damián Viano
  • Date: 2008-10-26 19:44:46 UTC
  • mto: (1.3.1 upstream) (3.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 13.
  • Revision ID: james.westby@ubuntu.com-20081026194446-kytjyn3a831y1oc8
Import upstream version 0.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 *      along with this program; if not, write to the Free Software
19
19
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
20
 *
21
 
 * $Id: editor.c 2465 2008-04-10 17:46:13Z eht16 $
 
21
 * $Id: editor.c 3102 2008-10-16 11:39:34Z ntrel $
22
22
 */
23
23
 
24
 
/*
25
 
 * Callbacks for the Scintilla widget (ScintillaObject).
 
24
/**
 
25
 * @file editor.h
 
26
 * Editor-related functions for @ref GeanyEditor.
 
27
 * Geany uses the Scintilla editing widget, and this file is mostly built around
 
28
 * Scintilla's functionality.
 
29
 * @see sciwrappers.h.
 
30
 */
 
31
/* Callbacks for the Scintilla widget (ScintillaObject).
26
32
 * Most important is the sci-notify callback, handled in on_editor_notification().
27
33
 * This includes auto-indentation, comments, auto-completion, calltips, etc.
28
34
 * Also some general Scintilla-related functions.
29
35
 */
30
36
 
 
37
 
31
38
#include <ctype.h>
32
39
#include <string.h>
33
40
 
 
41
#include <gdk/gdkkeysyms.h>
 
42
 
34
43
#include "SciLexer.h"
35
44
#include "geany.h"
36
45
 
 
46
#include "support.h"
37
47
#include "editor.h"
38
48
#include "document.h"
 
49
#include "documentprivate.h"
39
50
#include "filetypes.h"
40
51
#include "sciwrappers.h"
41
52
#include "ui_utils.h"
42
53
#include "utils.h"
 
54
#include "dialogs.h"
43
55
#include "symbols.h"
 
56
#include "callbacks.h"
 
57
#include "geanyobject.h"
 
58
#include "templates.h"
 
59
#include "keybindings.h"
 
60
 
 
61
 
 
62
/* Note: Avoid using SSM in files not related to scintilla, use sciwrappers.h instead. */
 
63
#define SSM(s, m, w, l) scintilla_send_message(s, m, w, l)
44
64
 
45
65
 
46
66
/* holds word under the mouse or keyboard cursor */
47
67
static gchar current_word[GEANY_MAX_WORD_LENGTH];
48
68
 
49
69
/* Initialised in keyfile.c. */
50
 
EditorPrefs editor_prefs;
 
70
GeanyEditorPrefs editor_prefs;
51
71
 
52
72
EditorInfo editor_info = {current_word, -1};
53
73
 
57
77
        gboolean set;
58
78
        gchar *last_word;
59
79
        guint tag_index;
60
 
} calltip = {NULL, FALSE, NULL, 0};
 
80
        gint pos;
 
81
        ScintillaObject *sci;
 
82
} calltip = {NULL, FALSE, NULL, 0, 0, NULL};
61
83
 
62
84
static gchar indent[100];
63
85
 
64
86
 
65
 
static void on_new_line_added(gint idx);
66
 
static gboolean handle_xml(gint idx, gchar ch);
67
 
static void get_indent(document *doc, gint pos, gboolean use_this_line);
68
 
static void auto_multiline(gint idx, gint pos);
69
 
static gboolean is_comment(gint lexer, gint prev_style, gint style);
 
87
static void on_new_line_added(GeanyEditor *editor);
 
88
static gboolean handle_xml(GeanyEditor *editor, gchar ch);
 
89
static void insert_indent_after_line(GeanyEditor *editor, gint line);
 
90
static void auto_multiline(GeanyEditor *editor, gint pos);
 
91
static gboolean is_code_style(gint lexer, gint style);
70
92
static void auto_close_bracket(ScintillaObject *sci, gint pos, gchar c);
71
 
static void editor_auto_table(document *doc, gint pos);
72
 
 
73
 
 
74
 
/* calls the edit popup menu in the editor */
75
 
gboolean
 
93
static void auto_table(GeanyEditor *editor, gint pos);
 
94
static void close_block(GeanyEditor *editor, gint pos);
 
95
 
 
96
 
 
97
void editor_snippets_free()
 
98
{
 
99
        g_hash_table_destroy(editor_prefs.snippets);
 
100
}
 
101
 
 
102
 
 
103
void editor_snippets_init(void)
 
104
{
 
105
        gsize i, j, len = 0, len_keys = 0;
 
106
        gchar *sysconfigfile, *userconfigfile;
 
107
        gchar **groups_user, **groups_sys;
 
108
        gchar **keys_user, **keys_sys;
 
109
        gchar *value;
 
110
        GKeyFile *sysconfig = g_key_file_new();
 
111
        GKeyFile *userconfig = g_key_file_new();
 
112
        GHashTable *tmp;
 
113
 
 
114
        sysconfigfile = g_strconcat(app->datadir, G_DIR_SEPARATOR_S, "snippets.conf", NULL);
 
115
        userconfigfile = g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "snippets.conf", NULL);
 
116
 
 
117
        /* check for old autocomplete.conf files (backwards compatibility) */
 
118
        if (! g_file_test(userconfigfile, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))
 
119
                setptr(userconfigfile,
 
120
                        g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "autocomplete.conf", NULL));
 
121
 
 
122
        /* load the actual config files */
 
123
        g_key_file_load_from_file(sysconfig, sysconfigfile, G_KEY_FILE_NONE, NULL);
 
124
        g_key_file_load_from_file(userconfig, userconfigfile, G_KEY_FILE_NONE, NULL);
 
125
 
 
126
        /* keys are strings, values are GHashTables, so use g_free and g_hash_table_destroy */
 
127
        editor_prefs.snippets =
 
128
                g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_hash_table_destroy);
 
129
 
 
130
        /* first read all globally defined auto completions */
 
131
        groups_sys = g_key_file_get_groups(sysconfig, &len);
 
132
        for (i = 0; i < len; i++)
 
133
        {
 
134
                keys_sys = g_key_file_get_keys(sysconfig, groups_sys[i], &len_keys, NULL);
 
135
                /* create new hash table for the read section (=> filetype) */
 
136
                tmp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 
137
                g_hash_table_insert(editor_prefs.snippets, g_strdup(groups_sys[i]), tmp);
 
138
 
 
139
                for (j = 0; j < len_keys; j++)
 
140
                {
 
141
                        g_hash_table_insert(tmp, g_strdup(keys_sys[j]),
 
142
                                                utils_get_setting_string(sysconfig, groups_sys[i], keys_sys[j], ""));
 
143
                }
 
144
                g_strfreev(keys_sys);
 
145
        }
 
146
 
 
147
        /* now read defined completions in user's configuration directory and add / replace them */
 
148
        groups_user = g_key_file_get_groups(userconfig, &len);
 
149
        for (i = 0; i < len; i++)
 
150
        {
 
151
                keys_user = g_key_file_get_keys(userconfig, groups_user[i], &len_keys, NULL);
 
152
 
 
153
                tmp = g_hash_table_lookup(editor_prefs.snippets, groups_user[i]);
 
154
                if (tmp == NULL)
 
155
                {       /* new key found, create hash table */
 
156
                        tmp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 
157
                        g_hash_table_insert(editor_prefs.snippets, g_strdup(groups_user[i]), tmp);
 
158
                }
 
159
                for (j = 0; j < len_keys; j++)
 
160
                {
 
161
                        value = g_hash_table_lookup(tmp, keys_user[j]);
 
162
                        if (value == NULL)
 
163
                        {       /* value = NULL means the key doesn't yet exist, so insert */
 
164
                                g_hash_table_insert(tmp, g_strdup(keys_user[j]),
 
165
                                                utils_get_setting_string(userconfig, groups_user[i], keys_user[j], ""));
 
166
                        }
 
167
                        else
 
168
                        {       /* old key and value will be freed by destroy function (g_free) */
 
169
                                g_hash_table_replace(tmp, g_strdup(keys_user[j]),
 
170
                                                utils_get_setting_string(userconfig, groups_user[i], keys_user[j], ""));
 
171
                        }
 
172
                }
 
173
                g_strfreev(keys_user);
 
174
        }
 
175
 
 
176
        g_free(sysconfigfile);
 
177
        g_free(userconfigfile);
 
178
        g_strfreev(groups_sys);
 
179
        g_strfreev(groups_user);
 
180
        g_key_file_free(sysconfig);
 
181
        g_key_file_free(userconfig);
 
182
}
 
183
 
 
184
 
 
185
static gboolean
76
186
on_editor_button_press_event           (GtkWidget *widget,
77
187
                                        GdkEventButton *event,
78
188
                                        gpointer user_data)
79
189
{
80
 
        gint idx = GPOINTER_TO_INT(user_data);
81
 
        editor_info.click_pos = sci_get_position_from_xy(doc_list[idx].sci, (gint)event->x, (gint)event->y, FALSE);
 
190
        GeanyDocument *doc = user_data;
 
191
        ScintillaObject *sci = doc->editor->sci;
82
192
 
 
193
        editor_info.click_pos = sci_get_position_from_xy(doc->editor->sci, (gint)event->x, (gint)event->y, FALSE);
83
194
        if (event->button == 1)
84
195
        {
85
 
                if (GDK_BUTTON_PRESS == event->type && editor_prefs.disable_dnd)
86
 
                {
87
 
                        gint ss = sci_get_selection_start(doc_list[idx].sci);
88
 
                        sci_set_selection_end(doc_list[idx].sci, ss);
89
 
                }
90
 
                return utils_check_disk_status(idx, FALSE);
 
196
                guint state = event->state & GEANY_KEYS_MODIFIER_MASK;
 
197
 
 
198
                if (event->type == GDK_BUTTON_PRESS && editor_prefs.disable_dnd)
 
199
                {
 
200
                        gint ss = sci_get_selection_start(doc->editor->sci);
 
201
                        sci_set_selection_end(doc->editor->sci, ss);
 
202
                }
 
203
                if (event->type == GDK_BUTTON_PRESS && state == GDK_CONTROL_MASK)
 
204
                {
 
205
                        sci_set_current_position(sci, editor_info.click_pos, FALSE);
 
206
                        keybindings_send_command(GEANY_KEY_GROUP_GOTO, GEANY_KEYS_GOTO_TAGDEFINITION);
 
207
                        return TRUE;
 
208
                }
 
209
                return document_check_disk_status(doc, FALSE);
91
210
        }
92
211
 
 
212
        /* calls the edit popup menu in the editor */
93
213
        if (event->button == 3)
94
214
        {
95
 
                editor_find_current_word(doc_list[idx].sci, editor_info.click_pos,
 
215
                editor_find_current_word(doc->editor, editor_info.click_pos,
96
216
                        current_word, sizeof current_word, NULL);
97
217
 
98
218
                ui_update_popup_goto_items((current_word[0] != '\0') ? TRUE : FALSE);
99
 
                ui_update_popup_copy_items(idx);
100
 
                ui_update_insert_include_item(idx, 0);
101
 
                gtk_menu_popup(GTK_MENU(app->popup_menu), NULL, NULL, NULL, NULL, event->button, event->time);
102
 
 
103
 
                return TRUE;
104
 
        }
 
219
                ui_update_popup_copy_items(doc);
 
220
                ui_update_insert_include_item(doc, 0);
 
221
 
 
222
                if (geany_object)
 
223
                {
 
224
                        g_signal_emit_by_name(geany_object, "update-editor-menu",
 
225
                                current_word, editor_info.click_pos, doc);
 
226
                }
 
227
                gtk_menu_popup(GTK_MENU(main_widgets.editor_menu),
 
228
                        NULL, NULL, NULL, NULL, event->button, event->time);
 
229
 
 
230
                return TRUE;
 
231
        }
 
232
        return FALSE;
 
233
}
 
234
 
 
235
 
 
236
static gboolean is_style_php(gint style)
 
237
{
 
238
        if ((style >= SCE_HPHP_DEFAULT && style <= SCE_HPHP_OPERATOR) ||
 
239
                style == SCE_HPHP_COMPLEX_VARIABLE)
 
240
        {
 
241
                return TRUE;
 
242
        }
 
243
 
105
244
        return FALSE;
106
245
}
107
246
 
156
295
                gint line = sci_get_line_from_position(sci, nt->position);
157
296
                gboolean set = sci_is_marker_set_at_line(sci, line, 1);
158
297
 
159
 
                /*sci_marker_delete_all(doc_list[idx].sci, 1);*/
 
298
                /*sci_marker_delete_all(doc->editor->sci, 1);*/
160
299
                sci_set_marker_at_line(sci, line, ! set, 1);    /* toggle the marker */
161
300
        }
162
301
        /* left click on the folding margin to toggle folding state of current line */
167
306
}
168
307
 
169
308
 
170
 
static void on_update_ui(gint idx, G_GNUC_UNUSED SCNotification *nt)
 
309
static void on_update_ui(GeanyEditor *editor, G_GNUC_UNUSED SCNotification *nt)
171
310
{
172
 
        ScintillaObject *sci = doc_list[idx].sci;
 
311
        ScintillaObject *sci = editor->sci;
173
312
        gint pos = sci_get_current_position(sci);
174
313
 
175
314
        /* undo / redo menu update */
176
 
        ui_update_popup_reundo_items(idx);
 
315
        ui_update_popup_reundo_items(editor->document);
177
316
 
178
317
        /* brace highlighting */
179
 
        editor_highlight_braces(sci, pos);
 
318
        editor_highlight_braces(editor, pos);
180
319
 
181
 
        ui_update_statusbar(idx, pos);
 
320
        ui_update_statusbar(editor->document, pos);
182
321
 
183
322
        /* Visible lines are only laid out accurately once [SCN_UPDATEUI] is sent,
184
323
         * so we need to only call sci_scroll_to_line here, because the document
185
324
         * may have line wrapping and folding enabled.
186
325
         * http://scintilla.sourceforge.net/ScintillaDoc.html#LineWrapping */
187
 
        if (doc_list[idx].scroll_percent > 0.0F)
 
326
        if (editor->scroll_percent > 0.0F)
188
327
        {
189
 
                editor_scroll_to_line(sci, -1, doc_list[idx].scroll_percent);
190
 
                doc_list[idx].scroll_percent = -1.0F;   /* disable further scrolling */
 
328
                editor_scroll_to_line(editor, -1, editor->scroll_percent);
 
329
                editor->scroll_percent = -1.0F; /* disable further scrolling */
191
330
        }
192
331
#if 0
193
332
        /** experimental code for inverting selections */
206
345
}
207
346
 
208
347
 
209
 
static void on_char_added(gint idx, SCNotification *nt)
210
 
{
211
 
        ScintillaObject *sci = doc_list[idx].sci;
 
348
static void check_line_breaking(GeanyEditor *editor, gint pos, gchar c)
 
349
{
 
350
        ScintillaObject *sci = editor->sci;
 
351
        gint line, lstart, col;
 
352
 
 
353
        if (!editor->line_breaking)
 
354
                return;
 
355
 
 
356
        col = sci_get_col_from_position(sci, pos);
 
357
 
 
358
        if (c == GDK_space)
 
359
                pos--;  /* Look for previous space, not the new one */
 
360
 
 
361
        line = sci_get_current_line(sci);
 
362
 
 
363
        lstart = sci_get_position_from_line(sci, line);
 
364
 
 
365
        /* use column instead of position which might be different with multibyte characters */
 
366
        if (col < editor_prefs.line_break_column)
 
367
                return;
 
368
 
 
369
        /* look for the last space before line_break_column */
 
370
        pos = MIN(pos, lstart + editor_prefs.line_break_column);
 
371
 
 
372
        while (pos > lstart)
 
373
        {
 
374
                c = sci_get_char_at(sci, --pos);
 
375
                if (c == GDK_space)
 
376
                {
 
377
                        gint diff, last_pos, last_col;
 
378
                        const gchar *eol = editor_get_eol_char(editor);
 
379
 
 
380
                        /* remember the distance between the current column and the last column on the line
 
381
                         * (we use column position in case the previous line gets altered, such as removing
 
382
                         * trailing spaces or in case it contains multibyte characters) */
 
383
                        last_pos = sci_get_line_end_position(sci, line);
 
384
                        last_col = sci_get_col_from_position(sci, last_pos);
 
385
                        diff = last_col - col;
 
386
 
 
387
                        /* break the line after the space */
 
388
                        sci_insert_text(sci, pos + 1, eol);
 
389
                        line++;
 
390
 
 
391
                        /* set position as if user had pressed return */
 
392
                        pos = sci_get_position_from_line(sci, line);
 
393
                        sci_set_current_position(sci, pos, FALSE);
 
394
                        /* add indentation, comment multilines, etc */
 
395
                        on_new_line_added(editor);
 
396
 
 
397
                        /* correct cursor position (might not be at line end) */
 
398
                        last_pos = sci_get_line_end_position(sci, line);
 
399
                        last_col = sci_get_col_from_position(sci, last_pos); /* get last column on line */
 
400
                        /* last column - distance is the desired column, then retrieve its document position */
 
401
                        pos = SSM(sci, SCI_FINDCOLUMN, line, last_col - diff);
 
402
                        sci_set_current_position(sci, pos, FALSE);
 
403
 
 
404
                        return;
 
405
                }
 
406
        }
 
407
}
 
408
 
 
409
 
 
410
static void on_char_added(GeanyEditor *editor, SCNotification *nt)
 
411
{
 
412
        ScintillaObject *sci = editor->sci;
212
413
        gint pos = sci_get_current_position(sci);
213
414
 
214
415
        switch (nt->ch)
216
417
                case '\r':
217
418
                {       /* simple indentation (only for CR format) */
218
419
                        if (sci_get_eol_mode(sci) == SC_EOL_CR)
219
 
                                on_new_line_added(idx);
 
420
                                on_new_line_added(editor);
220
421
                        break;
221
422
                }
222
423
                case '\n':
223
424
                {       /* simple indentation (for CR/LF and LF format) */
224
 
                        on_new_line_added(idx);
 
425
                        on_new_line_added(editor);
225
426
                        break;
226
427
                }
227
428
                case '>':
228
429
                case '/':
229
430
                {       /* close xml-tags */
230
 
                        handle_xml(idx, nt->ch);
 
431
                        handle_xml(editor, nt->ch);
231
432
                        break;
232
433
                }
233
434
                case '(':
234
435
                {       /* show calltips */
235
 
                        editor_show_calltip(idx, --pos);
 
436
                        editor_show_calltip(editor, --pos);
236
437
                        break;
237
438
                }
238
439
                case ')':
243
444
                        }
244
445
                        g_free(calltip.text);
245
446
                        calltip.text = NULL;
 
447
                        calltip.pos = 0;
 
448
                        calltip.sci = NULL;
246
449
                        calltip.set = FALSE;
247
450
                        break;
248
451
                }
252
455
                        if (sci_get_lexer(sci) == SCLEX_LATEX)
253
456
                        {
254
457
                                auto_close_bracket(sci, pos, nt->ch);   /* Tex auto-closing */
255
 
                                editor_show_calltip(idx, --pos);
 
458
                                editor_show_calltip(editor, --pos);
256
459
                        }
257
460
                        break;
258
461
                }
259
462
                case '}':
260
463
                {       /* closing bracket handling */
261
 
                        if (doc_list[idx].auto_indent)
262
 
                                editor_close_block(idx, pos - 1);
 
464
                        if (editor->auto_indent)
 
465
                                close_block(editor, pos - 1);
263
466
                        break;
264
467
                }
265
 
                default: editor_start_auto_complete(idx, pos, FALSE);
 
468
                default:
 
469
                        editor_start_auto_complete(editor, pos, FALSE);
266
470
        }
 
471
        check_line_breaking(editor, pos, nt->ch);
267
472
}
268
473
 
269
474
 
374
579
}
375
580
 
376
581
 
 
582
static gboolean reshow_calltip(gpointer data)
 
583
{
 
584
        SCNotification *nt = data;
 
585
 
 
586
        g_return_val_if_fail(calltip.sci != NULL, FALSE);
 
587
 
 
588
        SSM(calltip.sci, SCI_CALLTIPCANCEL, 0, 0);
 
589
        /* we use the position where the calltip was previously started as SCI_GETCURRENTPOS
 
590
         * may be completely wrong in case the user cancelled the auto completion with the mouse */
 
591
        SSM(calltip.sci, SCI_CALLTIPSHOW, calltip.pos, (sptr_t) calltip.text);
 
592
 
 
593
        /* now autocompletion has been cancelled by SCI_CALLTIPSHOW, so do it manually */
 
594
        if (nt->nmhdr.code == SCN_AUTOCSELECTION)
 
595
        {
 
596
                gint pos = SSM(calltip.sci, SCI_GETCURRENTPOS, 0, 0);
 
597
                sci_set_selection_start(calltip.sci, nt->lParam);
 
598
                sci_set_selection_end(calltip.sci, pos);
 
599
                sci_replace_sel(calltip.sci, "");       /* clear root of word */
 
600
                SSM(calltip.sci, SCI_INSERTTEXT, nt->lParam, (sptr_t) nt->text);
 
601
                sci_goto_pos(calltip.sci, nt->lParam + strlen(nt->text), FALSE);
 
602
        }
 
603
        return FALSE;
 
604
}
 
605
 
 
606
 
 
607
static void auto_update_margin_width(GeanyDocument *doc)
 
608
{
 
609
        gint next_linecount = 1;
 
610
        gint linecount = sci_get_line_count(doc->editor->sci);
 
611
 
 
612
        while (next_linecount <= linecount)
 
613
                next_linecount *= 10;
 
614
 
 
615
        if (doc->priv->line_count != next_linecount)
 
616
        {
 
617
                doc->priv->line_count = next_linecount;
 
618
                sci_set_line_numbers(doc->editor->sci, TRUE, 0);
 
619
        }
 
620
}
 
621
 
 
622
 
377
623
/* callback func called by all editors when a signal arises */
378
 
void on_editor_notification(GtkWidget *editor, gint scn, gpointer lscn, gpointer user_data)
 
624
void on_editor_notification(GtkWidget *widget, gint scn, gpointer lscn, gpointer user_data)
379
625
{
380
626
        SCNotification *nt;
381
627
        ScintillaObject *sci;
382
 
        gint idx;
 
628
        GeanyDocument *doc = user_data;
 
629
        GeanyEditor *editor;
383
630
 
384
 
        idx = GPOINTER_TO_INT(user_data);
385
 
        sci = doc_list[idx].sci;
 
631
        editor = doc->editor;
 
632
        sci = editor->sci;
386
633
 
387
634
        nt = lscn;
388
635
        switch (nt->nmhdr.code)
389
636
        {
390
637
                case SCN_SAVEPOINTLEFT:
391
638
                {
392
 
                        doc_list[idx].changed = TRUE;
393
 
                        document_set_text_changed(idx);
 
639
                        document_set_text_changed(doc, TRUE);
394
640
                        break;
395
641
                }
396
642
                case SCN_SAVEPOINTREACHED:
397
643
                {
398
 
                        doc_list[idx].changed = FALSE;
399
 
                        document_set_text_changed(idx);
 
644
                        document_set_text_changed(doc, FALSE);
400
645
                        break;
401
646
                }
402
647
                case SCN_MODIFYATTEMPTRO:
409
654
                        break;
410
655
 
411
656
                case SCN_UPDATEUI:
412
 
                        on_update_ui(idx, nt);
 
657
                        on_update_ui(editor, nt);
413
658
                        break;
414
659
 
415
660
                case SCN_MODIFIED:
416
661
                {
417
 
                        if (nt->modificationType & SC_STARTACTION && ! app->ignore_callback)
 
662
                        if (editor_prefs.show_linenumber_margin && (nt->modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) && nt->linesAdded)
 
663
                        {
 
664
                                /* automatically adjust Scintilla's line numbers margin width */
 
665
                                auto_update_margin_width(doc);
 
666
                        }
 
667
 
 
668
                        if (nt->modificationType & SC_STARTACTION && ! ignore_callback)
418
669
                        {
419
670
                                /* get notified about undo changes */
420
 
                                document_undo_add(idx, UNDO_SCINTILLA, NULL);
 
671
                                document_undo_add(doc, UNDO_SCINTILLA, NULL);
421
672
                        }
422
673
                        if (editor_prefs.folding && (nt->modificationType & SC_MOD_CHANGEFOLD) != 0)
423
674
                        {
427
678
                        break;
428
679
                }
429
680
                case SCN_CHARADDED:
430
 
                        on_char_added(idx, nt);
 
681
                        on_char_added(editor, nt);
431
682
                        break;
432
683
 
433
684
                case SCN_USERLISTSELECTION:
447
698
                        }
448
699
                        break;
449
700
                }
 
701
                case SCN_AUTOCCANCELLED:
450
702
                case SCN_AUTOCSELECTION:
451
703
                {
452
 
                        /* now that autocomplete is finishing, reshow calltips if they were showing */
 
704
                        /* now that autocomplete is finishing or was cancelled, reshow calltips
 
705
                         * if they were showing */
453
706
                        if (calltip.set)
454
707
                        {
455
 
                                gint pos = sci_get_current_position(sci);
456
 
                                SSM(sci, SCI_CALLTIPSHOW, pos, (sptr_t) calltip.text);
457
 
                                /* now autocompletion has been cancelled, so do it manually */
458
 
                                sci_set_selection_start(sci, nt->lParam);
459
 
                                sci_set_selection_end(sci, pos);
460
 
                                sci_replace_sel(sci, "");       /* clear root of word */
461
 
                                SSM(sci, SCI_INSERTTEXT, nt->lParam, (sptr_t) nt->text);
462
 
                                sci_goto_pos(sci, nt->lParam + strlen(nt->text), FALSE);
 
708
                                /* delay the reshow of the calltip window to make sure it is actually displayed,
 
709
                                 * without it might be not visible on SCN_AUTOCCANCEL */
 
710
                                /* TODO g_idle_add() seems to be not enough, only with a timeout it works stable */
 
711
                                g_timeout_add(50, reshow_calltip, nt);
463
712
                        }
464
713
                        break;
465
714
                }
496
745
 
497
746
                                        case 2: calltip.tag_index++; break;     /* down arrow */
498
747
                                }
499
 
                                editor_show_calltip(idx, -1);
 
748
                                editor_show_calltip(editor, -1);
500
749
                        }
501
750
                        break;
502
751
                }
504
753
}
505
754
 
506
755
 
 
756
/* Note: this is the same as sci_get_tab_width(), but is still useful when you don't have
 
757
 * a scintilla pointer. */
 
758
static gint get_tab_width(const GeanyIndentPrefs *indent_prefs)
 
759
{
 
760
        if (indent_prefs->type == GEANY_INDENT_TYPE_BOTH)
 
761
                return indent_prefs->hard_tab_width;
 
762
 
 
763
        return indent_prefs->width;     /* tab width = indent width */
 
764
}
 
765
 
 
766
 
507
767
/* Returns a string containing width chars of whitespace, filled with simple space
508
 
 * characters or with the right number of tab characters, according to the
509
 
 * use_tabs setting. (Result is filled with tabs *and* spaces if width isn't a multiple of
510
 
 * editor_prefs.tab_width). */
 
768
 * characters or with the right number of tab characters, according to the indent prefs.
 
769
 * (Result is filled with tabs *and* spaces if width isn't a multiple of
 
770
 * the tab width). */
511
771
static gchar *
512
 
get_whitespace(gint width, gboolean use_tabs)
 
772
get_whitespace(const GeanyIndentPrefs *iprefs, gint width)
513
773
{
514
 
        gchar *str;
515
 
 
516
 
        g_return_val_if_fail(width > 0, NULL);
517
 
 
518
 
        if (use_tabs)
 
774
        g_return_val_if_fail(width >= 0, NULL);
 
775
 
 
776
        if (width == 0)
 
777
                return g_strdup("");
 
778
 
 
779
        if (iprefs->type == GEANY_INDENT_TYPE_SPACES)
 
780
        {
 
781
                return g_strnfill(width, ' ');
 
782
        }
 
783
        else
519
784
        {       /* first fill text with tabs and fill the rest with spaces */
520
 
                gint tabs = width / editor_prefs.tab_width;
521
 
                gint spaces = width % editor_prefs.tab_width;
 
785
                const gint tab_width = get_tab_width(iprefs);
 
786
                gint tabs = width / tab_width;
 
787
                gint spaces = width % tab_width;
522
788
                gint len = tabs + spaces;
 
789
                gchar *str;
523
790
 
524
791
                str = g_malloc(len + 1);
525
792
 
526
793
                memset(str, '\t', tabs);
527
794
                memset(str + tabs, ' ', spaces);
528
795
                str[len] = '\0';
 
796
                return str;
529
797
        }
530
 
        else
531
 
                str = g_strnfill(width, ' ');
532
 
 
533
 
        return str;
534
 
}
535
 
 
536
 
 
537
 
static void check_python_indent(gint idx, gint pos)
538
 
{
539
 
        document *doc = &doc_list[idx];
540
 
        gint last_char = pos - utils_get_eol_char_len(idx) - 1;
541
 
 
542
 
        /* add extra indentation for Python after colon */
543
 
        if (sci_get_char_at(doc->sci, last_char) == ':' &&
544
 
                sci_get_style_at(doc->sci, last_char) == SCE_P_OPERATOR)
545
 
        {
546
 
                /* creates and inserts one tabulator sign or
547
 
                 * whitespace of the amount of the tab width */
548
 
                gchar *text = get_whitespace(editor_prefs.tab_width, doc->use_tabs);
549
 
                sci_add_text(doc->sci, text);
550
 
                g_free(text);
551
 
        }
552
 
}
553
 
 
554
 
 
555
 
static void on_new_line_added(gint idx)
556
 
{
557
 
        ScintillaObject *sci = doc_list[idx].sci;
 
798
}
 
799
 
 
800
 
 
801
static const GeanyIndentPrefs *
 
802
get_default_indent_prefs(void)
 
803
{
 
804
        /* In future this might depend on the current project. */
 
805
        return editor_prefs.indentation;
 
806
}
 
807
 
 
808
 
 
809
/** Get the indentation prefs for the editor.
 
810
 * In future, the prefs might be different according to project or filetype.
 
811
 * @warning Always get a fresh result instead of keeping a pointer to it if the editor
 
812
 * settings may have changed, or if this function has been called for a different @a editor.
 
813
 * @param editor The editor, or @c NULL to get the default indent prefs.
 
814
 * @return The indent prefs. */
 
815
const GeanyIndentPrefs *
 
816
editor_get_indent_prefs(GeanyEditor *editor)
 
817
{
 
818
        static GeanyIndentPrefs iprefs;
 
819
 
 
820
        iprefs = *get_default_indent_prefs();
 
821
 
 
822
        if (!editor)
 
823
                return &iprefs;
 
824
 
 
825
        iprefs.type = editor->indent_type;
 
826
 
 
827
        /* if per-document auto-indent is enabled, but we don't have a global mode set,
 
828
         * just use basic auto-indenting */
 
829
        if (editor->auto_indent && iprefs.auto_indent_mode == GEANY_AUTOINDENT_NONE)
 
830
                iprefs.auto_indent_mode = GEANY_AUTOINDENT_BASIC;
 
831
 
 
832
        if (!editor->auto_indent)
 
833
                iprefs.auto_indent_mode = GEANY_AUTOINDENT_NONE;
 
834
 
 
835
        return &iprefs;
 
836
}
 
837
 
 
838
 
 
839
static gchar *get_single_indent(GeanyEditor *editor)
 
840
{
 
841
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
 
842
 
 
843
        return get_whitespace(iprefs, iprefs->width);
 
844
}
 
845
 
 
846
 
 
847
static void on_new_line_added(GeanyEditor *editor)
 
848
{
 
849
        ScintillaObject *sci = editor->sci;
558
850
        gint pos = sci_get_current_position(sci);
559
851
        gint line = sci_get_current_line(sci);
560
852
 
561
853
        /* simple indentation */
562
 
        if (doc_list[idx].auto_indent)
 
854
        if (editor->auto_indent)
563
855
        {
564
 
                get_indent(&doc_list[idx], pos, FALSE);
565
 
                sci_add_text(sci, indent);
 
856
                insert_indent_after_line(editor, line - 1);
 
857
        }
566
858
 
567
 
                if (editor_prefs.indent_mode > INDENT_BASIC &&
568
 
                        FILETYPE_ID(doc_list[idx].file_type) == GEANY_FILETYPES_PYTHON)
569
 
                        check_python_indent(idx, pos);
 
859
        if (editor_prefs.auto_continue_multiline)
 
860
        {       /* " * " auto completion in multiline C/C++/D/Java comments */
 
861
                auto_multiline(editor, line);
570
862
        }
571
863
 
572
864
        if (editor_prefs.complete_snippets)
573
865
        {
574
 
                /* " * " auto completion in multiline C/C++/D/Java comments */
575
 
                auto_multiline(idx, pos);
576
 
 
577
 
                editor_auto_latex(idx, pos);
 
866
                editor_auto_latex(editor, pos);
578
867
        }
579
868
 
580
869
        if (editor_prefs.newline_strip)
581
 
        {
582
 
                /* strip the trailing spaces on the previous line */
583
 
                document_strip_line_trailing_spaces(idx, line - 1);
 
870
        {       /* strip the trailing spaces on the previous line */
 
871
                editor_strip_line_trailing_spaces(editor, line - 1);
584
872
        }
585
873
}
586
874
 
605
893
}
606
894
 
607
895
 
608
 
/* in place indentation of one tab or equivalent spaces */
609
 
static void do_indent(gchar *buf, gsize len, guint *idx, gboolean use_tabs)
610
 
{
611
 
        guint j = *idx;
612
 
 
613
 
        if (use_tabs)
614
 
        {
615
 
                if (j < len - 1)        /* leave room for a \0 terminator. */
616
 
                        buf[j++] = '\t';
617
 
        }
618
 
        else
619
 
        {       /* insert as many spaces as a tab would take */
620
 
                guint k;
621
 
                for (k = 0; k < (guint) editor_prefs.tab_width && k < len - 1; k++)
622
 
                        buf[j++] = ' ';
623
 
        }
624
 
        *idx = j;
625
 
}
626
 
 
627
 
 
628
 
/* "use_this_line" to auto-indent only if it is a real new line
629
 
 * and ignore the case of editor_close_block */
630
 
static void get_indent(document *doc, gint pos, gboolean use_this_line)
631
 
{
632
 
        ScintillaObject *sci = doc->sci;
 
896
/* Read indent chars for the line that pos is on into indent global variable.
 
897
 * Note: Use sci_get_line_indentation() and get_whitespace() instead in any new code.  */
 
898
static void read_indent(GeanyEditor *editor, gint pos)
 
899
{
 
900
        ScintillaObject *sci = editor->sci;
633
901
        guint i, len, j = 0;
634
 
        gint prev_line;
 
902
        gint line;
635
903
        gchar *linebuf;
636
 
 
637
 
        prev_line = sci_get_line_from_position(sci, pos);
638
 
 
639
 
        if (! use_this_line)
640
 
                prev_line--;
641
 
        len = sci_get_line_length(sci, prev_line);
642
 
        linebuf = sci_get_line(sci, prev_line);
 
904
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
 
905
 
 
906
        line = sci_get_line_from_position(sci, pos);
 
907
 
 
908
        len = sci_get_line_length(sci, line);
 
909
        linebuf = sci_get_line(sci, line);
643
910
 
644
911
        for (i = 0; i < len && j <= (sizeof(indent) - 1); i++)
645
912
        {
646
913
                if (linebuf[i] == ' ' || linebuf[i] == '\t')    /* simple indentation */
647
914
                        indent[j++] = linebuf[i];
648
 
                else if (editor_prefs.indent_mode <= INDENT_BASIC)
649
 
                        break;
650
 
                else if (use_this_line)
651
 
                        break;
652
 
                else    /* editor_close_block */
653
 
                {
654
 
                        if (! lexer_has_braces(sci))
655
 
                                break;
656
 
 
657
 
                        /* i == (len - 1) prevents wrong indentation after lines like
658
 
                         * "    { return bless({}, shift); }" (Perl) */
659
 
                        if (linebuf[i] == '{' && i == (len - 1))
660
 
                        {
661
 
                                do_indent(indent, sizeof(indent), &j, doc->use_tabs);
662
 
                                break;
663
 
                        }
664
 
                        else
665
 
                        {
666
 
                                gint k = len - 1;
667
 
 
668
 
                                while (k > 0 && isspace(linebuf[k])) k--;
669
 
 
670
 
                                /* if last non-whitespace character is a { increase indentation by a tab
671
 
                                 * e.g. for (...) { */
672
 
                                if (linebuf[k] == '{')
673
 
                                {
674
 
                                        do_indent(indent, sizeof(indent), &j, doc->use_tabs);
675
 
                                }
676
 
                                break;
677
 
                        }
678
 
                }
 
915
                else if (iprefs->auto_indent_mode <= GEANY_AUTOINDENT_BASIC)
 
916
                        break;
679
917
        }
680
918
        indent[j] = '\0';
681
919
        g_free(linebuf);
682
920
}
683
921
 
684
922
 
 
923
static gint get_brace_indent(ScintillaObject *sci, gint line)
 
924
{
 
925
        guint i, len;
 
926
        gint ret = 0;
 
927
        gchar *linebuf;
 
928
 
 
929
        len = sci_get_line_length(sci, line);
 
930
        linebuf = sci_get_line(sci, line);
 
931
 
 
932
        for (i = 0; i < len; i++)
 
933
        {
 
934
                /* i == (len - 1) prevents wrong indentation after lines like
 
935
                 * "    { return bless({}, shift); }" (Perl) */
 
936
                if (linebuf[i] == '{' && i == (len - 1))
 
937
                {
 
938
                        ret++;
 
939
                        break;
 
940
                }
 
941
                else
 
942
                {
 
943
                        gint k = len - 1;
 
944
 
 
945
                        while (k > 0 && isspace(linebuf[k])) k--;
 
946
 
 
947
                        /* if last non-whitespace character is a { increase indentation by a tab
 
948
                         * e.g. for (...) { */
 
949
                        if (linebuf[k] == '{')
 
950
                        {
 
951
                                ret++;
 
952
                        }
 
953
                        break;
 
954
                }
 
955
        }
 
956
        g_free(linebuf);
 
957
        return ret;
 
958
}
 
959
 
 
960
 
 
961
static gint get_python_indent(ScintillaObject *sci, gint line)
 
962
{
 
963
        gint last_char = sci_get_line_end_position(sci, line) - 1;
 
964
 
 
965
        /* add extra indentation for Python after colon */
 
966
        if (sci_get_char_at(sci, last_char) == ':' &&
 
967
                sci_get_style_at(sci, last_char) == SCE_P_OPERATOR)
 
968
        {
 
969
                return 1;
 
970
        }
 
971
        return 0;
 
972
}
 
973
 
 
974
 
 
975
static gint get_indent_size_after_line(GeanyEditor *editor, gint line)
 
976
{
 
977
        ScintillaObject *sci = editor->sci;
 
978
        gint size;
 
979
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
 
980
 
 
981
        g_return_val_if_fail(line >= 0, 0);
 
982
 
 
983
        size = sci_get_line_indentation(sci, line);
 
984
 
 
985
        if (iprefs->auto_indent_mode > GEANY_AUTOINDENT_BASIC)
 
986
        {
 
987
                if (lexer_has_braces(sci))
 
988
                        size += iprefs->width * get_brace_indent(sci, line);
 
989
                else
 
990
                if (FILETYPE_ID(editor->document->file_type) == GEANY_FILETYPES_PYTHON)
 
991
                        size += iprefs->width * get_python_indent(sci, line);
 
992
        }
 
993
        return size;
 
994
}
 
995
 
 
996
 
 
997
static void insert_indent_after_line(GeanyEditor *editor, gint line)
 
998
{
 
999
        ScintillaObject *sci = editor->sci;
 
1000
        gint size = get_indent_size_after_line(editor, line);
 
1001
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
 
1002
 
 
1003
        if (size > 0)
 
1004
        {
 
1005
                gchar *text;
 
1006
 
 
1007
                text = get_whitespace(iprefs, size);
 
1008
                sci_add_text(sci, text);
 
1009
                g_free(text);
 
1010
        }
 
1011
}
 
1012
 
 
1013
 
685
1014
static void auto_close_bracket(ScintillaObject *sci, gint pos, gchar c)
686
1015
{
687
1016
        if (! editor_prefs.complete_snippets || SSM(sci, SCI_GETLEXER, 0, 0) != SCLEX_LATEX)
701
1030
 
702
1031
/* Finds a corresponding matching brace to the given pos
703
1032
 * (this is taken from Scintilla Editor.cxx,
704
 
 * fit to work with editor_close_block) */
 
1033
 * fit to work with close_block) */
705
1034
static gint brace_match(ScintillaObject *sci, gint pos)
706
1035
{
707
1036
        gchar chBrace = sci_get_char_at(sci, pos);
739
1068
 
740
1069
 
741
1070
/* Called after typing '}'. */
742
 
void editor_close_block(gint idx, gint pos)
 
1071
static void close_block(GeanyEditor *editor, gint pos)
743
1072
{
 
1073
        GeanyDocument *doc;
 
1074
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
744
1075
        gint x = 0, cnt = 0;
745
1076
        gint line, line_len, eol_char_len;
746
1077
        gchar *text, *line_buf;
747
1078
        ScintillaObject *sci;
748
1079
        gint line_indent, last_indent;
749
1080
 
750
 
        if (editor_prefs.indent_mode < INDENT_CURRENTCHARS)
 
1081
        if (iprefs->auto_indent_mode < GEANY_AUTOINDENT_CURRENTCHARS)
751
1082
                return;
752
 
        if (idx == -1 || ! doc_list[idx].is_valid || doc_list[idx].file_type == NULL)
 
1083
        if (editor == NULL || editor->document->file_type == NULL)
753
1084
                return;
754
1085
 
755
 
        sci = doc_list[idx].sci;
 
1086
        sci = editor->sci;
 
1087
        doc = editor->document;
756
1088
 
757
1089
        if (! lexer_has_braces(sci))
758
1090
                return;
761
1093
        line_len = sci_get_line_length(sci, line);
762
1094
        /* set eol_char_len to 0 if on last line, because there is no EOL char */
763
1095
        eol_char_len = (line == (SSM(sci, SCI_GETLINECOUNT, 0, 0) - 1)) ? 0 :
764
 
                                                                utils_get_eol_char_len(document_find_by_sci(sci));
 
1096
                                                                editor_get_eol_char_len(editor);
765
1097
 
766
1098
        /* check that the line is empty, to not kill text in the line */
767
1099
        line_buf = sci_get_line(sci, line);
776
1108
        if ((line_len - eol_char_len - 1) != cnt)
777
1109
                return;
778
1110
 
779
 
        if (editor_prefs.indent_mode == INDENT_MATCHBRACES)
 
1111
        if (iprefs->auto_indent_mode == GEANY_AUTOINDENT_MATCHBRACES)
780
1112
        {
781
1113
                gint start_brace = brace_match(sci, pos);
782
1114
 
783
1115
                if (start_brace >= 0)
784
1116
                {
785
1117
                        gint line_start;
 
1118
                        gint brace_line = sci_get_line_from_position(sci, start_brace);
 
1119
                        gint size = sci_get_line_indentation(sci, brace_line);
 
1120
                        gchar *ind = get_whitespace(iprefs, size);
786
1121
 
787
 
                        get_indent(&doc_list[idx], start_brace, TRUE);
788
 
                        text = g_strconcat(indent, "}", NULL);
 
1122
                        text = g_strconcat(ind, "}", NULL);
789
1123
                        line_start = sci_get_position_from_line(sci, line);
790
1124
                        sci_set_anchor(sci, line_start);
791
1125
                        SSM(sci, SCI_REPLACESEL, 0, (sptr_t) text);
792
1126
                        g_free(text);
 
1127
                        g_free(ind);
793
1128
                        return;
794
1129
                }
795
1130
                /* fall through - unmatched brace (possibly because of TCL, PHP lexer bugs) */
796
1131
        }
797
1132
 
798
 
        /* INDENT_CURRENTCHARS */
 
1133
        /* GEANY_AUTOINDENT_CURRENTCHARS */
799
1134
        line_indent = sci_get_line_indentation(sci, line);
800
1135
        last_indent = sci_get_line_indentation(sci, line - 1);
801
1136
 
802
1137
        if (line_indent < last_indent)
803
1138
                return;
804
 
        line_indent -= editor_prefs.tab_width;
 
1139
        line_indent -= iprefs->width;
805
1140
        line_indent = MAX(0, line_indent);
806
1141
        sci_set_line_indentation(sci, line, line_indent);
807
1142
}
811
1146
 * NULL terminated in any case, even when the word is truncated because wordlen is too small.
812
1147
 * position can be -1, then the current position is used.
813
1148
 * wc are the wordchars to use, if NULL, GEANY_WORDCHARS will be used */
814
 
void editor_find_current_word(ScintillaObject *sci, gint pos, gchar *word, size_t wordlen,
 
1149
void editor_find_current_word(GeanyEditor *editor, gint pos, gchar *word, size_t wordlen,
815
1150
                                                          const gchar *wc)
816
1151
{
817
1152
        gint line, line_start, startword, endword;
818
1153
        gchar *chunk;
 
1154
        ScintillaObject *sci;
 
1155
 
 
1156
        if (editor == NULL)
 
1157
                return;
 
1158
        sci = editor->sci;
819
1159
 
820
1160
        if (pos == -1)
821
1161
                pos = sci_get_current_position(sci);
831
1171
        if (wc == NULL)
832
1172
                wc = GEANY_WORDCHARS;
833
1173
 
834
 
        while (startword > 0 && strchr(wc, chunk[startword - 1]))
 
1174
        /* the checks for "c < 0" are to allow any Unicode character which should make the code
 
1175
         * a little bit more Unicode safe, anyway, this allows also any Unicode punctuation,
 
1176
         * TODO: improve this code */
 
1177
        while (startword > 0 && (strchr(wc, chunk[startword - 1]) || chunk[startword - 1] < 0))
835
1178
                startword--;
836
 
        while (chunk[endword] && strchr(wc, chunk[endword]))
 
1179
        while (chunk[endword] != 0 && (strchr(wc, chunk[endword]) || chunk[endword] < 0))
837
1180
                endword++;
838
1181
        if(startword == endword)
839
1182
                return;
911
1254
}
912
1255
 
913
1256
 
914
 
static gchar *find_calltip(const gchar *word, filetype *ft)
 
1257
static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
915
1258
{
916
1259
        const GPtrArray *tags;
917
1260
        const gint arg_types = tm_tag_function_t | tm_tag_prototype_t |
997
1340
 
998
1341
 
999
1342
/* use pos = -1 to search for the previous unmatched open bracket. */
1000
 
gboolean editor_show_calltip(gint idx, gint pos)
 
1343
gboolean editor_show_calltip(GeanyEditor *editor, gint pos)
1001
1344
{
1002
1345
        gint orig_pos = pos; /* the position for the calltip */
1003
1346
        gint lexer;
1006
1349
        gchar *str;
1007
1350
        ScintillaObject *sci;
1008
1351
 
1009
 
        if (idx == -1 || ! doc_list[idx].is_valid || doc_list[idx].file_type == NULL) return FALSE;
1010
 
        sci = doc_list[idx].sci;
 
1352
        if (editor == NULL || editor->document->file_type == NULL)
 
1353
                return FALSE;
 
1354
        sci = editor->sci;
1011
1355
 
1012
1356
        lexer = SSM(sci, SCI_GETLEXER, 0, 0);
1013
1357
 
1024
1368
 
1025
1369
        /* the style 1 before the brace (which may be highlighted) */
1026
1370
        style = SSM(sci, SCI_GETSTYLEAT, pos - 1, 0);
1027
 
        if (is_comment(lexer, style, style))
 
1371
        if (! is_code_style(lexer, style))
1028
1372
                return FALSE;
1029
1373
 
1030
1374
        word[0] = '\0';
1031
 
        editor_find_current_word(sci, pos - 1, word, sizeof word, NULL);
 
1375
        editor_find_current_word(editor, pos - 1, word, sizeof word, NULL);
1032
1376
        if (word[0] == '\0') return FALSE;
1033
1377
 
1034
 
        str = find_calltip(word, doc_list[idx].file_type);
 
1378
        str = find_calltip(word, editor->document->file_type);
1035
1379
        if (str)
1036
1380
        {
1037
1381
                g_free(calltip.text);   /* free the old calltip */
1038
1382
                calltip.text = str;
 
1383
                calltip.pos = orig_pos;
 
1384
                calltip.sci = sci;
1039
1385
                calltip.set = TRUE;
1040
1386
                utils_wrap_string(calltip.text, -1);
1041
1387
                SSM(sci, SCI_CALLTIPSHOW, orig_pos, (sptr_t) calltip.text);
1080
1426
}
1081
1427
 
1082
1428
 
 
1429
/* Current document & global tags autocompletion */
1083
1430
static gboolean
1084
 
autocomplete_tags(gint idx, gchar *root, gsize rootlen)
1085
 
{       /* PHP, LaTeX, C, C++, D and Java tag autocompletion */
 
1431
autocomplete_tags(GeanyEditor *editor, const gchar *root, gsize rootlen)
 
1432
{
1086
1433
        TMTagAttrType attrs[] = { tm_tag_attr_name_t, 0 };
1087
1434
        const GPtrArray *tags;
1088
1435
        ScintillaObject *sci;
 
1436
        GeanyDocument *doc;
1089
1437
 
1090
 
        if (! DOC_IDX_VALID(idx) || doc_list[idx].file_type == NULL)
 
1438
        if (editor == NULL || editor->document->file_type == NULL)
1091
1439
                return FALSE;
1092
 
        sci = doc_list[idx].sci;
 
1440
        sci = editor->sci;
 
1441
        doc = editor->document;
1093
1442
 
1094
 
        tags = tm_workspace_find(root, tm_tag_max_t, attrs, TRUE, doc_list[idx].file_type->lang);
 
1443
        tags = tm_workspace_find(root, tm_tag_max_t, attrs, TRUE, doc->file_type->lang);
1095
1444
        if (NULL != tags && tags->len > 0)
1096
1445
        {
1097
1446
                GString *words = g_string_sized_new(150);
1098
1447
                guint j;
1099
1448
 
1100
 
                for (j = 0; ((j < tags->len) && (j < GEANY_MAX_AUTOCOMPLETE_WORDS)); ++j)
 
1449
                for (j = 0; j < tags->len; ++j)
1101
1450
                {
1102
 
                        if (j > 0) g_string_append_c(words, '\n');
 
1451
                        if (j > 0)
 
1452
                                g_string_append_c(words, '\n');
 
1453
 
 
1454
                        if (j == editor_prefs.autocompletion_max_entries)
 
1455
                        {
 
1456
                                g_string_append(words, "...");
 
1457
                                break;
 
1458
                        }
1103
1459
                        g_string_append(words, ((TMTag *) tags->pdata[j])->name);
1104
1460
                }
1105
1461
                show_autocomplete(sci, rootlen, words->str);
1109
1465
}
1110
1466
 
1111
1467
 
1112
 
gboolean editor_start_auto_complete(gint idx, gint pos, gboolean force)
1113
 
{
1114
 
        gint line, line_start, line_len, line_pos, current, rootlen, startword, lexer, style, prev_style;
 
1468
/* Check whether to use entity autocompletion:
 
1469
 * - always in a HTML file except when inside embedded JavaScript, Python, ASP, ...
 
1470
 * - in a PHP file only when we are outside of <? ?> */
 
1471
static gboolean autocomplete_check_for_html(gint ft_id, gint style)
 
1472
{
 
1473
        /* use entity completion when style is not JavaScript, ASP, Python, PHP, ...
 
1474
         * (everything after SCE_HJ_START is for embedded scripting languages) */
 
1475
        if (ft_id == GEANY_FILETYPES_HTML && style < SCE_HJ_START)
 
1476
                return TRUE;
 
1477
 
 
1478
        if (ft_id == GEANY_FILETYPES_PHP)
 
1479
        {
 
1480
                /* use entity completion when style is outside of PHP styles */
 
1481
                if (! is_style_php(style))
 
1482
                        return TRUE;
 
1483
        }
 
1484
 
 
1485
        return FALSE;
 
1486
}
 
1487
 
 
1488
 
 
1489
gboolean editor_start_auto_complete(GeanyEditor *editor, gint pos, gboolean force)
 
1490
{
 
1491
        gint line, line_start, line_len, line_pos, current, rootlen, startword, lexer, style;
1115
1492
        gchar *linebuf, *root;
1116
1493
        ScintillaObject *sci;
1117
1494
        gboolean ret = FALSE;
1118
1495
        gchar *wordchars;
1119
 
        filetype *ft;
 
1496
        GeanyFiletype *ft;
1120
1497
 
1121
1498
        if ((! editor_prefs.auto_complete_symbols && ! force) ||
1122
 
                ! DOC_IDX_VALID(idx) || doc_list[idx].file_type == NULL)
1123
 
                return FALSE;
1124
 
 
1125
 
        sci = doc_list[idx].sci;
1126
 
        ft = doc_list[idx].file_type;
 
1499
                editor == NULL || editor->document->file_type == NULL)
 
1500
                return FALSE;
 
1501
 
 
1502
        /* If we are at the beginning of the document, we skip autocompletion as we can't determine the
 
1503
         * necessary styling information */
 
1504
        if (pos < 2)
 
1505
                return FALSE;
 
1506
 
 
1507
        sci = editor->sci;
 
1508
        ft = editor->document->file_type;
1127
1509
 
1128
1510
        line = sci_get_line_from_position(sci, pos);
1129
1511
        line_start = sci_get_position_from_line(sci, line);
1132
1514
        current = pos - line_start;
1133
1515
        startword = current;
1134
1516
        lexer = SSM(sci, SCI_GETLEXER, 0, 0);
1135
 
        prev_style = SSM(sci, SCI_GETSTYLEAT, pos - 2, 0);
1136
 
        style = SSM(sci, SCI_GETSTYLEAT, pos, 0);
 
1517
        style = SSM(sci, SCI_GETSTYLEAT, pos - 2, 0);
1137
1518
 
1138
 
         /* don't autocomplete in comments and strings */
1139
 
         if (!force && is_comment(lexer, prev_style, style))
 
1519
        /* don't autocomplete in comments and strings */
 
1520
        if (!force && !is_code_style(lexer, style))
1140
1521
                return FALSE;
1141
1522
 
1142
1523
        linebuf = sci_get_line(sci, line);
1155
1536
        root = linebuf + startword;
1156
1537
        rootlen = current - startword;
1157
1538
 
1158
 
        /* entity autocompletion always in a HTML file, in a PHP file only
1159
 
         * when we are outside of <? ?> */
1160
 
        if (ft->id == GEANY_FILETYPES_HTML ||
1161
 
                (ft->id == GEANY_FILETYPES_PHP && (style < SCE_HPHP_DEFAULT || style > SCE_HPHP_OPERATOR) &&
1162
 
                 line != (sci_get_line_count(sci) - 1))) /* this check is a workaround for a Scintilla bug:
1163
 
                                                                                                  * the last line in a PHP gets wrong styling */
 
1539
        if (autocomplete_check_for_html(ft->id, style))
1164
1540
                ret = autocomplete_html(sci, root, rootlen);
1165
1541
        else
1166
1542
        {
1167
1543
                /* force is set when called by keyboard shortcut, otherwise start at the
1168
1544
                 * editor_prefs.symbolcompletion_min_chars'th char */
1169
1545
                if (force || rootlen >= editor_prefs.symbolcompletion_min_chars)
1170
 
                        ret = autocomplete_tags(idx, root, rootlen);
 
1546
                        ret = autocomplete_tags(editor, root, rootlen);
1171
1547
        }
1172
1548
 
1173
1549
        g_free(linebuf);
1175
1551
}
1176
1552
 
1177
1553
 
1178
 
void editor_auto_latex(gint idx, gint pos)
 
1554
void editor_auto_latex(GeanyEditor *editor, gint pos)
1179
1555
{
1180
1556
        ScintillaObject *sci;
1181
1557
 
1182
 
        if (idx == -1 || ! doc_list[idx].is_valid || doc_list[idx].file_type == NULL) return;
1183
 
        sci = doc_list[idx].sci;
 
1558
        if (editor == NULL || editor->document->file_type == NULL)
 
1559
                return;
 
1560
        sci = editor->sci;
1184
1561
 
1185
1562
        if (sci_get_char_at(sci, pos - 2) == '}')
1186
1563
        {
1234
1611
                        }
1235
1612
 
1236
1613
                        /* get the indentation */
1237
 
                        if (doc_list[idx].auto_indent) get_indent(&doc_list[idx], pos, TRUE);
1238
 
                        eol = g_strconcat(utils_get_eol_char(idx), indent, NULL);
 
1614
                        if (editor->auto_indent)
 
1615
                                read_indent(editor, pos);
 
1616
                        eol = g_strconcat(editor_get_eol_char(editor), indent, NULL);
1239
1617
 
1240
1618
                        construct = g_strdup_printf("%s\\end%s{%s}", eol, full_cmd, env);
1241
1619
 
1300
1678
}
1301
1679
 
1302
1680
 
1303
 
static gboolean snippets_complete_constructs(gint idx, gint pos, const gchar *word)
 
1681
static gchar *snippets_replace_wildcards(GeanyEditor *editor, gchar *text)
 
1682
{
 
1683
        gchar *year = utils_get_date_time(template_prefs.year_format, NULL);
 
1684
        gchar *date = utils_get_date_time(template_prefs.date_format, NULL);
 
1685
        gchar *datetime = utils_get_date_time(template_prefs.datetime_format, NULL);
 
1686
        gchar *basename = g_path_get_basename(DOC_FILENAME(editor->document));
 
1687
 
 
1688
        text = templates_replace_all(text, year, date);
 
1689
        text = utils_str_replace(text, "{datetime}", datetime);
 
1690
        text = utils_str_replace(text, "{filename}", basename);
 
1691
 
 
1692
        g_free(year);
 
1693
        g_free(date);
 
1694
        g_free(datetime);
 
1695
        g_free(basename);
 
1696
 
 
1697
        return text;
 
1698
}
 
1699
 
 
1700
 
 
1701
static gboolean snippets_complete_constructs(GeanyEditor *editor, gint pos, const gchar *word)
1304
1702
{
1305
1703
        gchar *str;
1306
1704
        gchar *pattern;
1307
1705
        gchar *lindent;
1308
1706
        gchar *whitespace;
1309
1707
        gint step, str_len;
1310
 
        gint ft_id = FILETYPE_ID(doc_list[idx].file_type);
 
1708
        gint ft_id = FILETYPE_ID(editor->document->file_type);
1311
1709
        GHashTable *specials;
1312
 
        ScintillaObject *sci = doc_list[idx].sci;
 
1710
        ScintillaObject *sci = editor->sci;
1313
1711
 
1314
1712
        str = g_strdup(word);
1315
1713
        g_strstrip(str);
1321
1719
                return FALSE;
1322
1720
        }
1323
1721
 
1324
 
        get_indent(&doc_list[idx], pos, TRUE);
1325
 
        lindent = g_strconcat(utils_get_eol_char(idx), indent, NULL);
1326
 
        whitespace = get_whitespace(editor_prefs.tab_width, doc_list[idx].use_tabs);
 
1722
        read_indent(editor, pos);
 
1723
        lindent = g_strconcat(editor_get_eol_char(editor), indent, NULL);
 
1724
        whitespace = get_single_indent(editor);
1327
1725
 
1328
1726
        /* remove the typed word, it will be added again by the used auto completion
1329
1727
         * (not really necessary but this makes the auto completion more flexible,
1351
1749
        pattern = utils_str_replace(pattern, "\t", "%ws%"); /* to avoid endless replacing of \t */
1352
1750
        pattern = utils_str_replace(pattern, "%ws%", whitespace);
1353
1751
 
 
1752
        /* replace any %template% wildcards */
 
1753
        pattern = snippets_replace_wildcards(editor, pattern);
 
1754
 
1354
1755
        /* find the %cursor% pos (has to be done after all other operations) */
1355
1756
        step = utils_strpos(pattern, "%cursor%");
1356
1757
        if (step != -1)
1387
1788
}
1388
1789
 
1389
1790
 
1390
 
gboolean editor_complete_snippet(gint idx, gint pos)
 
1791
gboolean editor_complete_snippet(GeanyEditor *editor, gint pos)
1391
1792
{
1392
1793
        gboolean result = FALSE;
1393
1794
        gint lexer, style;
1394
1795
        gchar *wc;
1395
1796
        ScintillaObject *sci;
1396
1797
 
1397
 
        if (! DOC_IDX_VALID(idx))
 
1798
        if (editor == NULL)
1398
1799
                return FALSE;
1399
1800
 
1400
 
        sci = doc_list[idx].sci;
 
1801
        sci = editor->sci;
1401
1802
        /* return if we are editing an existing line (chars on right of cursor) */
1402
1803
        if (! editor_prefs.complete_snippets_whilst_editing && ! at_eol(sci, pos))
1403
1804
                return FALSE;
1406
1807
        style = SSM(sci, SCI_GETSTYLEAT, pos - 2, 0);
1407
1808
 
1408
1809
        wc = snippets_find_completion_by_name("Special", "wordchars");
1409
 
        editor_find_current_word(sci, pos, current_word, sizeof current_word, wc);
 
1810
        editor_find_current_word(editor, pos, current_word, sizeof current_word, wc);
1410
1811
 
1411
1812
        /* prevent completion of "for " */
1412
1813
        if (! isspace(sci_get_char_at(sci, pos - 1))) /* pos points to the line end char so use pos -1 */
1413
1814
        {
1414
1815
                sci_start_undo_action(sci);     /* needed because we insert a space separately from construct */
1415
 
                result = snippets_complete_constructs(idx, pos, current_word);
 
1816
                result = snippets_complete_constructs(editor, pos, current_word);
1416
1817
                sci_end_undo_action(sci);
 
1818
                if (result)
 
1819
                        SSM(sci, SCI_CANCEL, 0, 0);     /* cancel any autocompletion list, etc */
1417
1820
        }
1418
1821
 
1419
1822
        g_free(wc);
1421
1824
}
1422
1825
 
1423
1826
 
1424
 
void editor_show_macro_list(ScintillaObject *sci)
 
1827
void editor_show_macro_list(GeanyEditor *editor)
1425
1828
{
1426
1829
        GString *words;
1427
1830
 
1428
 
        if (sci == NULL) return;
 
1831
        if (editor == NULL) return;
1429
1832
 
1430
1833
        words = symbols_get_macro_list();
1431
1834
        if (words == NULL) return;
1432
1835
 
1433
 
        SSM(sci, SCI_USERLISTSHOW, 1, (sptr_t) words->str);
 
1836
        SSM(editor->sci, SCI_USERLISTSHOW, 1, (sptr_t) words->str);
1434
1837
        g_string_free(words, TRUE);
1435
1838
}
1436
1839
 
1437
1840
 
1438
 
/**
 
1841
static void insert_closing_tag(GeanyEditor *editor, gint pos, gchar ch, const gchar *tag_name)
 
1842
{
 
1843
        ScintillaObject *sci = editor->sci;
 
1844
        gchar *to_insert = NULL;
 
1845
 
 
1846
        if (ch == '/')
 
1847
        {
 
1848
                const gchar *gt = ">";
 
1849
                /* if there is already a '>' behind the cursor, don't add it */
 
1850
                if (sci_get_char_at(sci, pos) == '>')
 
1851
                        gt = "";
 
1852
 
 
1853
                to_insert = g_strconcat(tag_name, gt, NULL);
 
1854
        }
 
1855
        else
 
1856
                to_insert = g_strconcat("</", tag_name, ">", NULL);
 
1857
 
 
1858
        sci_start_undo_action(sci);
 
1859
        sci_replace_sel(sci, to_insert);
 
1860
        if (ch == '>')
 
1861
        {
 
1862
                SSM(sci, SCI_SETSEL, pos, pos);
 
1863
                if (utils_str_equal(tag_name, "table"))
 
1864
                        auto_table(editor, pos);
 
1865
        }
 
1866
        sci_end_undo_action(sci);
 
1867
        g_free(to_insert);
 
1868
}
 
1869
 
 
1870
 
 
1871
/*
1439
1872
 * (stolen from anjuta and heavily modified)
1440
1873
 * This routine will auto complete XML or HTML tags that are still open by closing them
1441
1874
 * @param ch The character we are dealing with, currently only works with the '>' character
1442
1875
 * @return True if handled, false otherwise
1443
1876
 */
1444
 
static gboolean handle_xml(gint idx, gchar ch)
 
1877
static gboolean handle_xml(GeanyEditor *editor, gchar ch)
1445
1878
{
1446
 
        ScintillaObject *sci = doc_list[idx].sci;
 
1879
        ScintillaObject *sci = editor->sci;
1447
1880
        gint lexer = SSM(sci, SCI_GETLEXER, 0, 0);
1448
1881
        gint pos, min;
1449
1882
        gchar *str_found, sel[512];
 
1883
        gboolean result = FALSE;
1450
1884
 
1451
1885
        /* If the user has turned us off, quit now.
1452
1886
         * This may make sense only in certain languages */
1456
1890
        pos = sci_get_current_position(sci);
1457
1891
 
1458
1892
        /* return if we are in PHP but not in a string or outside of <? ?> tags */
1459
 
        if (doc_list[idx].file_type->id == GEANY_FILETYPES_PHP)
 
1893
        if (editor->document->file_type->id == GEANY_FILETYPES_PHP)
1460
1894
        {
1461
1895
                gint style = sci_get_style_at(sci, pos);
1462
 
                if (style != SCE_HPHP_SIMPLESTRING && style != SCE_HPHP_HSTRING &&
1463
 
                        style <= SCE_HPHP_OPERATOR && style >= SCE_HPHP_DEFAULT)
 
1896
                if (is_style_php(style) && style != SCE_HPHP_SIMPLESTRING && style != SCE_HPHP_HSTRING)
1464
1897
                        return FALSE;
1465
1898
        }
1466
1899
 
1495
1928
         || utils_str_equal(str_found, "area")
1496
1929
         || utils_str_equal(str_found, "meta"))
1497
1930
        {
1498
 
                return FALSE;
 
1931
                /* ignore tag */
1499
1932
        }
1500
 
 
1501
 
        if (*str_found != '\0')
 
1933
        else if (NZV(str_found))
1502
1934
        {
1503
 
                gchar *to_insert;
1504
 
                if (ch == '/')
1505
 
                {
1506
 
                        gchar *gt = ">";
1507
 
                        /* if there is already a '>' behind the cursor, don't add it */
1508
 
                        if (sci_get_char_at(sci, pos) == '>')
1509
 
                                gt = "";
1510
 
 
1511
 
                        to_insert = g_strconcat(str_found, gt, NULL);
1512
 
                }
1513
 
                else
1514
 
                        to_insert = g_strconcat("</", str_found, ">", NULL);
1515
 
                sci_start_undo_action(sci);
1516
 
                sci_replace_sel(sci, to_insert);
1517
 
                if (ch == '>')
1518
 
                {
1519
 
                        SSM(sci, SCI_SETSEL, pos, pos);
1520
 
                        if (utils_str_equal(str_found, "table"))
1521
 
                                editor_auto_table(&doc_list[idx], pos);
1522
 
                }
1523
 
                sci_end_undo_action(sci);
1524
 
                g_free(to_insert);
1525
 
                g_free(str_found);
1526
 
                return TRUE;
 
1935
                insert_closing_tag(editor, pos, ch, str_found);
 
1936
                result = TRUE;
1527
1937
        }
1528
 
 
1529
1938
        g_free(str_found);
1530
 
        return FALSE;
1531
 
}
1532
 
 
1533
 
 
1534
 
static void editor_auto_table(document *doc, gint pos)
1535
 
{
1536
 
        ScintillaObject *sci = doc->sci;
 
1939
        return result;
 
1940
}
 
1941
 
 
1942
 
 
1943
static gsize count_indent_size(GeanyEditor *editor, const gchar *base_indent)
 
1944
{
 
1945
        const gchar *ptr;
 
1946
        gsize tab_size = sci_get_tab_width(editor->sci);
 
1947
        gsize count = 0;
 
1948
 
 
1949
        g_return_val_if_fail(base_indent, 0);
 
1950
 
 
1951
        for (ptr = base_indent; *ptr != 0; ptr++)
 
1952
        {
 
1953
                switch (*ptr)
 
1954
                {
 
1955
                        case ' ':
 
1956
                                count++;
 
1957
                                break;
 
1958
                        case '\t':
 
1959
                                count += tab_size;
 
1960
                                break;
 
1961
                }
 
1962
        }
 
1963
        return count;
 
1964
}
 
1965
 
 
1966
 
 
1967
static void string_append_indent_width(GString *str, const GeanyIndentPrefs *iprefs,
 
1968
                gsize width)
 
1969
{
 
1970
        gchar *ws = get_whitespace(iprefs, width);
 
1971
 
 
1972
        g_string_append(str, ws);
 
1973
        g_free(ws);
 
1974
}
 
1975
 
 
1976
 
 
1977
static gchar *get_table_body(GeanyEditor *editor, const gchar *base_indent)
 
1978
{
 
1979
        gsize base_size = count_indent_size(editor, base_indent);
 
1980
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
 
1981
        gsize indent_width = iprefs->width;
 
1982
        GString *str = g_string_new("\n");
 
1983
 
 
1984
        if (! editor->auto_indent)
 
1985
                indent_width = 0;
 
1986
 
 
1987
        string_append_indent_width(str, iprefs, base_size + indent_width);
 
1988
        g_string_append(str, "<tr>\n");
 
1989
        string_append_indent_width(str, iprefs, base_size + indent_width + indent_width);
 
1990
        g_string_append(str, "<td>\n");
 
1991
        string_append_indent_width(str, iprefs, base_size + indent_width + indent_width);
 
1992
        g_string_append(str, "</td>\n");
 
1993
        string_append_indent_width(str, iprefs, base_size + indent_width);
 
1994
        g_string_append(str, "</tr>\n");
 
1995
        string_append_indent_width(str, iprefs, base_size);
 
1996
 
 
1997
        return g_string_free(str, FALSE);
 
1998
}
 
1999
 
 
2000
 
 
2001
static void auto_table(GeanyEditor *editor, gint pos)
 
2002
{
 
2003
        ScintillaObject *sci = editor->sci;
1537
2004
        gchar *table;
1538
2005
        gint indent_pos;
1539
2006
 
1540
2007
        if (SSM(sci, SCI_GETLEXER, 0, 0) != SCLEX_HTML) return;
1541
2008
 
1542
 
        get_indent(doc, pos, TRUE);
 
2009
        read_indent(editor, pos);
1543
2010
        indent_pos = sci_get_line_indent_position(sci, sci_get_line_from_position(sci, pos));
1544
2011
        if ((pos - 7) != indent_pos) /* 7 == strlen("<table>") */
1545
2012
        {
1546
 
                gint i, x;
 
2013
                gint i;
 
2014
                guint x;
 
2015
 
1547
2016
                x = strlen(indent);
1548
2017
                /* find the start of the <table tag */
1549
2018
                i = 1;
1550
2019
                while (i <= pos && sci_get_char_at(sci, pos - i) != '<') i++;
1551
2020
                /* add all non whitespace before the tag to the indent string */
1552
 
                while ((pos - i) != indent_pos)
 
2021
                while ((pos - i) != indent_pos && x < sizeof(indent) - 1)
1553
2022
                {
1554
2023
                        indent[x++] = ' ';
1555
2024
                        i++;
1557
2026
                indent[x] = '\0';
1558
2027
        }
1559
2028
 
1560
 
        table = g_strconcat("\n", indent, "    <tr>\n", indent, "        <td>\n", indent, "        </td>\n",
1561
 
                                                indent, "    </tr>\n", indent, NULL);
 
2029
        /* get indent string for generated code */
 
2030
        table = get_table_body(editor, indent);
1562
2031
        sci_insert_text(sci, pos, table);
1563
2032
        g_free(table);
1564
2033
}
1565
2034
 
1566
2035
 
1567
 
static void real_comment_multiline(gint idx, gint line_start, gint last_line)
 
2036
static void real_comment_multiline(GeanyEditor *editor, gint line_start, gint last_line)
1568
2037
{
1569
2038
        const gchar *eol;
1570
2039
        gchar *str_begin, *str_end;
1571
2040
        gint line_len;
1572
2041
 
1573
 
        if (idx == -1 || ! doc_list[idx].is_valid || doc_list[idx].file_type == NULL) return;
 
2042
        if (editor == NULL || editor->document->file_type == NULL)
 
2043
                return;
1574
2044
 
1575
 
        eol = utils_get_eol_char(idx);
1576
 
        str_begin = g_strdup_printf("%s%s", doc_list[idx].file_type->comment_open, eol);
1577
 
        str_end = g_strdup_printf("%s%s", doc_list[idx].file_type->comment_close, eol);
 
2045
        eol = editor_get_eol_char(editor);
 
2046
        str_begin = g_strdup_printf("%s%s", editor->document->file_type->comment_open, eol);
 
2047
        str_end = g_strdup_printf("%s%s", editor->document->file_type->comment_close, eol);
1578
2048
 
1579
2049
        /* insert the comment strings */
1580
 
        sci_insert_text(doc_list[idx].sci, line_start, str_begin);
1581
 
        line_len = sci_get_position_from_line(doc_list[idx].sci, last_line + 2);
1582
 
        sci_insert_text(doc_list[idx].sci, line_len, str_end);
 
2050
        sci_insert_text(editor->sci, line_start, str_begin);
 
2051
        line_len = sci_get_position_from_line(editor->sci, last_line + 2);
 
2052
        sci_insert_text(editor->sci, line_len, str_end);
1583
2053
 
1584
2054
        g_free(str_begin);
1585
2055
        g_free(str_end);
1586
2056
}
1587
2057
 
1588
2058
 
1589
 
static void real_uncomment_multiline(gint idx)
 
2059
static void real_uncomment_multiline(GeanyEditor *editor)
1590
2060
{
1591
2061
        /* find the beginning of the multi line comment */
1592
2062
        gint pos, line, len, x;
1593
2063
        gchar *linebuf;
 
2064
        GeanyDocument *doc;
1594
2065
 
1595
 
        if (idx == -1 || ! doc_list[idx].is_valid || doc_list[idx].file_type == NULL) return;
 
2066
        if (editor == NULL || editor->document->file_type == NULL)
 
2067
                return;
 
2068
        doc = editor->document;
1596
2069
 
1597
2070
        /* remove comment open chars */
1598
 
        pos = document_find_text(idx, doc_list[idx].file_type->comment_open, 0, TRUE, FALSE, NULL);
1599
 
        SSM(doc_list[idx].sci, SCI_DELETEBACK, 0, 0);
 
2071
        pos = document_find_text(doc, doc->file_type->comment_open, 0, TRUE, FALSE, NULL);
 
2072
        SSM(doc->editor->sci, SCI_DELETEBACK, 0, 0);
1600
2073
 
1601
2074
        /* check whether the line is empty and can be deleted */
1602
 
        line = sci_get_line_from_position(doc_list[idx].sci, pos);
1603
 
        len = sci_get_line_length(doc_list[idx].sci, line);
1604
 
        linebuf = sci_get_line(doc_list[idx].sci, line);
 
2075
        line = sci_get_line_from_position(editor->sci, pos);
 
2076
        len = sci_get_line_length(editor->sci, line);
 
2077
        linebuf = sci_get_line(editor->sci, line);
1605
2078
        x = 0;
1606
2079
        while (linebuf[x] != '\0' && isspace(linebuf[x])) x++;
1607
 
        if (x == len) SSM(doc_list[idx].sci, SCI_LINEDELETE, 0, 0);
 
2080
        if (x == len) SSM(editor->sci, SCI_LINEDELETE, 0, 0);
1608
2081
        g_free(linebuf);
1609
2082
 
1610
2083
        /* remove comment close chars */
1611
 
        pos = document_find_text(idx, doc_list[idx].file_type->comment_close, 0, FALSE, FALSE, NULL);
1612
 
        SSM(doc_list[idx].sci, SCI_DELETEBACK, 0, 0);
 
2084
        pos = document_find_text(doc, doc->file_type->comment_close, 0, FALSE, FALSE, NULL);
 
2085
        SSM(editor->sci, SCI_DELETEBACK, 0, 0);
1613
2086
 
1614
2087
        /* check whether the line is empty and can be deleted */
1615
 
        line = sci_get_line_from_position(doc_list[idx].sci, pos);
1616
 
        len = sci_get_line_length(doc_list[idx].sci, line);
1617
 
        linebuf = sci_get_line(doc_list[idx].sci, line);
 
2088
        line = sci_get_line_from_position(editor->sci, pos);
 
2089
        len = sci_get_line_length(editor->sci, line);
 
2090
        linebuf = sci_get_line(editor->sci, line);
1618
2091
        x = 0;
1619
2092
        while (linebuf[x] != '\0' && isspace(linebuf[x])) x++;
1620
 
        if (x == len) SSM(doc_list[idx].sci, SCI_LINEDELETE, 0, 0);
 
2093
        if (x == len) SSM(editor->sci, SCI_LINEDELETE, 0, 0);
1621
2094
        g_free(linebuf);
1622
2095
}
1623
2096
 
1625
2098
/* set toggle to TRUE if the caller is the toggle function, FALSE otherwise
1626
2099
 * returns the amount of uncommented single comment lines, in case of multi line uncomment
1627
2100
 * it returns just 1 */
1628
 
gint editor_do_uncomment(gint idx, gint line, gboolean toggle)
 
2101
gint editor_do_uncomment(GeanyEditor *editor, gint line, gboolean toggle)
1629
2102
{
1630
2103
        gint first_line, last_line;
1631
2104
        gint x, i, line_start, line_len;
1634
2107
        gsize co_len;
1635
2108
        gchar sel[256], *co, *cc;
1636
2109
        gboolean break_loop = FALSE, single_line = FALSE;
1637
 
        filetype *ft;
 
2110
        GeanyFiletype *ft;
1638
2111
 
1639
 
        if (! DOC_IDX_VALID(idx) || doc_list[idx].file_type == NULL)
 
2112
        if (editor == NULL || editor->document->file_type == NULL)
1640
2113
                return 0;
1641
2114
 
1642
2115
        if (line < 0)
1643
2116
        {       /* use selection or current line */
1644
 
                sel_start = sci_get_selection_start(doc_list[idx].sci);
1645
 
                sel_end = sci_get_selection_end(doc_list[idx].sci);
 
2117
                sel_start = sci_get_selection_start(editor->sci);
 
2118
                sel_end = sci_get_selection_end(editor->sci);
1646
2119
 
1647
 
                first_line = sci_get_line_from_position(doc_list[idx].sci, sel_start);
 
2120
                first_line = sci_get_line_from_position(editor->sci, sel_start);
1648
2121
                /* Find the last line with chars selected (not EOL char) */
1649
 
                last_line = sci_get_line_from_position(doc_list[idx].sci,
1650
 
                        sel_end - utils_get_eol_char_len(idx));
 
2122
                last_line = sci_get_line_from_position(editor->sci,
 
2123
                        sel_end - editor_get_eol_char_len(editor));
1651
2124
                last_line = MAX(first_line, last_line);
1652
2125
        }
1653
2126
        else
1654
2127
        {
1655
2128
                first_line = last_line = line;
1656
 
                sel_start = sel_end = sci_get_position_from_line(doc_list[idx].sci, line);
 
2129
                sel_start = sel_end = sci_get_position_from_line(editor->sci, line);
1657
2130
        }
1658
2131
 
1659
 
        ft = doc_list[idx].file_type;
 
2132
        ft = editor->document->file_type;
1660
2133
 
1661
2134
        /* detection of HTML vs PHP code, if non-PHP set filetype to XML */
1662
 
        line_start = sci_get_position_from_line(doc_list[idx].sci, first_line);
 
2135
        line_start = sci_get_position_from_line(editor->sci, first_line);
1663
2136
        if (ft->id == GEANY_FILETYPES_PHP)
1664
2137
        {
1665
 
                if (sci_get_style_at(doc_list[idx].sci, line_start) < 118 ||
1666
 
                        sci_get_style_at(doc_list[idx].sci, line_start) > 127)
 
2138
                if (! is_style_php(sci_get_style_at(editor->sci, line_start)))
1667
2139
                        ft = filetypes[GEANY_FILETYPES_XML];
1668
2140
        }
1669
2141
 
1676
2148
        if (co_len == 0)
1677
2149
                return 0;
1678
2150
 
1679
 
        SSM(doc_list[idx].sci, SCI_BEGINUNDOACTION, 0, 0);
 
2151
        SSM(editor->sci, SCI_BEGINUNDOACTION, 0, 0);
1680
2152
 
1681
2153
        for (i = first_line; (i <= last_line) && (! break_loop); i++)
1682
2154
        {
1683
2155
                gint buf_len;
1684
2156
 
1685
 
                line_start = sci_get_position_from_line(doc_list[idx].sci, i);
1686
 
                line_len = sci_get_line_length(doc_list[idx].sci, i);
 
2157
                line_start = sci_get_position_from_line(editor->sci, i);
 
2158
                line_len = sci_get_line_length(editor->sci, i);
1687
2159
                x = 0;
1688
2160
 
1689
2161
                buf_len = MIN((gint)sizeof(sel) - 1, line_len - 1);
1690
2162
                if (buf_len <= 0)
1691
2163
                        continue;
1692
 
                sci_get_text_range(doc_list[idx].sci, line_start, line_start + buf_len, sel);
 
2164
                sci_get_text_range(editor->sci, line_start, line_start + buf_len, sel);
1693
2165
                sel[buf_len] = '\0';
1694
2166
 
1695
2167
                while (isspace(sel[x])) x++;
1700
2172
                        /* use single line comment */
1701
2173
                        if (cc == NULL || strlen(cc) == 0)
1702
2174
                        {
1703
 
                                gsize tm_len = strlen(GEANY_TOGGLE_MARK);
1704
 
 
1705
2175
                                single_line = TRUE;
1706
2176
 
1707
2177
                                if (toggle)
1708
2178
                                {
 
2179
                                        gsize tm_len = strlen(editor_prefs.comment_toggle_mark);
1709
2180
                                        if (strncmp(sel + x, co, co_len) != 0 ||
1710
 
                                                strncmp(sel + x + co_len, GEANY_TOGGLE_MARK, tm_len) != 0)
 
2181
                                                strncmp(sel + x + co_len, editor_prefs.comment_toggle_mark, tm_len) != 0)
1711
2182
                                                continue;
1712
2183
 
1713
2184
                                        co_len += tm_len;
1718
2189
                                                continue;
1719
2190
                                }
1720
2191
 
1721
 
                                SSM(doc_list[idx].sci, SCI_SETSEL, line_start + x, line_start + x + co_len);
1722
 
                                sci_replace_sel(doc_list[idx].sci, "");
 
2192
                                SSM(editor->sci, SCI_SETSEL, line_start + x, line_start + x + co_len);
 
2193
                                sci_replace_sel(editor->sci, "");
1723
2194
                                count++;
1724
2195
                        }
1725
2196
                        /* use multi line comment */
1726
2197
                        else
1727
2198
                        {
1728
2199
                                gint style_comment;
1729
 
                                gint lexer = SSM(doc_list[idx].sci, SCI_GETLEXER, 0, 0);
 
2200
                                gint lexer = SSM(editor->sci, SCI_GETLEXER, 0, 0);
1730
2201
 
1731
2202
                                /* process only lines which are already comments */
1732
2203
                                switch (lexer)
1734
2205
                                        case SCLEX_XML:
1735
2206
                                        case SCLEX_HTML:
1736
2207
                                        {
1737
 
                                                if (sci_get_style_at(doc_list[idx].sci, line_start) >= 118 &&
1738
 
                                                        sci_get_style_at(doc_list[idx].sci, line_start) <= 127)
 
2208
                                                if (is_style_php(sci_get_style_at(editor->sci, line_start)))
1739
2209
                                                        style_comment = SCE_HPHP_COMMENT;
1740
2210
                                                else style_comment = SCE_H_COMMENT;
1741
2211
                                                break;
1746
2216
                                        case SCLEX_D: style_comment = SCE_D_COMMENT; break;
1747
2217
                                        default: style_comment = SCE_C_COMMENT;
1748
2218
                                }
1749
 
                                if (sci_get_style_at(doc_list[idx].sci, line_start + x) == style_comment)
 
2219
                                if (sci_get_style_at(editor->sci, line_start + x) == style_comment)
1750
2220
                                {
1751
 
                                        real_uncomment_multiline(idx);
 
2221
                                        real_uncomment_multiline(editor);
1752
2222
                                        count = 1;
1753
2223
                                }
1754
2224
 
1758
2228
                        }
1759
2229
                }
1760
2230
        }
1761
 
        SSM(doc_list[idx].sci, SCI_ENDUNDOACTION, 0, 0);
 
2231
        SSM(editor->sci, SCI_ENDUNDOACTION, 0, 0);
1762
2232
 
1763
2233
        /* restore selection if there is one
1764
2234
         * but don't touch the selection if caller is editor_do_comment_toggle */
1766
2236
        {
1767
2237
                if (single_line)
1768
2238
                {
1769
 
                        sci_set_selection_start(doc_list[idx].sci, sel_start - co_len);
1770
 
                        sci_set_selection_end(doc_list[idx].sci, sel_end - (count * co_len));
 
2239
                        sci_set_selection_start(editor->sci, sel_start - co_len);
 
2240
                        sci_set_selection_end(editor->sci, sel_end - (count * co_len));
1771
2241
                }
1772
2242
                else
1773
2243
                {
1774
 
                        gint eol_len = utils_get_eol_char_len(idx);
1775
 
                        sci_set_selection_start(doc_list[idx].sci, sel_start - co_len - eol_len);
1776
 
                        sci_set_selection_end(doc_list[idx].sci, sel_end - co_len - eol_len);
 
2244
                        gint eol_len = editor_get_eol_char_len(editor);
 
2245
                        sci_set_selection_start(editor->sci, sel_start - co_len - eol_len);
 
2246
                        sci_set_selection_end(editor->sci, sel_end - co_len - eol_len);
1777
2247
                }
1778
2248
        }
1779
2249
 
1781
2251
}
1782
2252
 
1783
2253
 
1784
 
void editor_do_comment_toggle(gint idx)
 
2254
void editor_do_comment_toggle(GeanyEditor *editor)
1785
2255
{
1786
2256
        gint first_line, last_line;
1787
2257
        gint x, i, line_start, line_len, first_line_start;
1791
2261
        gboolean break_loop = FALSE, single_line = FALSE;
1792
2262
        gboolean first_line_was_comment = FALSE;
1793
2263
        gsize co_len;
1794
 
        gsize tm_len = strlen(GEANY_TOGGLE_MARK);
1795
 
        filetype *ft;
 
2264
        gsize tm_len = strlen(editor_prefs.comment_toggle_mark);
 
2265
        GeanyFiletype *ft;
1796
2266
 
1797
 
        if (! DOC_IDX_VALID(idx) || doc_list[idx].file_type == NULL)
 
2267
        if (editor == NULL || editor->document->file_type == NULL)
1798
2268
                return;
1799
2269
 
1800
 
        sel_start = sci_get_selection_start(doc_list[idx].sci);
1801
 
        sel_end = sci_get_selection_end(doc_list[idx].sci);
1802
 
 
1803
 
        ft = doc_list[idx].file_type;
1804
 
 
1805
 
        first_line = sci_get_line_from_position(doc_list[idx].sci,
1806
 
                sci_get_selection_start(doc_list[idx].sci));
 
2270
        sel_start = sci_get_selection_start(editor->sci);
 
2271
        sel_end = sci_get_selection_end(editor->sci);
 
2272
 
 
2273
        ft = editor->document->file_type;
 
2274
 
 
2275
        first_line = sci_get_line_from_position(editor->sci,
 
2276
                sci_get_selection_start(editor->sci));
1807
2277
        /* Find the last line with chars selected (not EOL char) */
1808
 
        last_line = sci_get_line_from_position(doc_list[idx].sci,
1809
 
                sci_get_selection_end(doc_list[idx].sci) - utils_get_eol_char_len(idx));
 
2278
        last_line = sci_get_line_from_position(editor->sci,
 
2279
                sci_get_selection_end(editor->sci) - editor_get_eol_char_len(editor));
1810
2280
        last_line = MAX(first_line, last_line);
1811
2281
 
1812
2282
        /* detection of HTML vs PHP code, if non-PHP set filetype to XML */
1813
 
        first_line_start = sci_get_position_from_line(doc_list[idx].sci, first_line);
 
2283
        first_line_start = sci_get_position_from_line(editor->sci, first_line);
1814
2284
        if (ft->id == GEANY_FILETYPES_PHP)
1815
2285
        {
1816
 
                if (sci_get_style_at(doc_list[idx].sci, first_line_start) < 118 ||
1817
 
                        sci_get_style_at(doc_list[idx].sci, first_line_start) > 127)
 
2286
                if (! is_style_php(sci_get_style_at(editor->sci, first_line_start)))
1818
2287
                        ft = filetypes[GEANY_FILETYPES_XML];
1819
2288
        }
1820
2289
 
1827
2296
        if (co_len == 0)
1828
2297
                return;
1829
2298
 
1830
 
        SSM(doc_list[idx].sci, SCI_BEGINUNDOACTION, 0, 0);
 
2299
        SSM(editor->sci, SCI_BEGINUNDOACTION, 0, 0);
1831
2300
 
1832
2301
        for (i = first_line; (i <= last_line) && (! break_loop); i++)
1833
2302
        {
1834
2303
                gint buf_len;
1835
2304
 
1836
 
                line_start = sci_get_position_from_line(doc_list[idx].sci, i);
1837
 
                line_len = sci_get_line_length(doc_list[idx].sci, i);
 
2305
                line_start = sci_get_position_from_line(editor->sci, i);
 
2306
                line_len = sci_get_line_length(editor->sci, i);
1838
2307
                x = 0;
1839
2308
 
1840
2309
                buf_len = MIN((gint)sizeof(sel) - 1, line_len - 1);
1841
2310
                if (buf_len < 0)
1842
2311
                        continue;
1843
 
                sci_get_text_range(doc_list[idx].sci, line_start, line_start + buf_len, sel);
 
2312
                sci_get_text_range(editor->sci, line_start, line_start + buf_len, sel);
1844
2313
                sel[buf_len] = '\0';
1845
2314
 
1846
2315
                while (isspace(sel[x])) x++;
1852
2321
                        single_line = TRUE;
1853
2322
 
1854
2323
                        if (strncmp(sel + x, co, co_len) == 0 &&
1855
 
                                strncmp(sel + x + co_len, GEANY_TOGGLE_MARK, tm_len) == 0)
 
2324
                                strncmp(sel + x + co_len, editor_prefs.comment_toggle_mark, tm_len) == 0)
1856
2325
                        {
1857
2326
                                do_continue = TRUE;
1858
2327
                        }
1862
2331
 
1863
2332
                        if (do_continue)
1864
2333
                        {
1865
 
                                count_uncommented += editor_do_uncomment(idx, i, TRUE);
 
2334
                                count_uncommented += editor_do_uncomment(editor, i, TRUE);
1866
2335
                                continue;
1867
2336
                        }
1868
2337
 
1869
2338
                        /* we are still here, so the above lines were not already comments, so comment it */
1870
 
                        editor_do_comment(idx, i, TRUE, TRUE);
 
2339
                        editor_do_comment(editor, i, TRUE, TRUE);
1871
2340
                        count_commented++;
1872
2341
                }
1873
2342
                /* use multi line comment */
1874
2343
                else
1875
2344
                {
1876
2345
                        gint style_comment;
1877
 
                        gint lexer = SSM(doc_list[idx].sci, SCI_GETLEXER, 0, 0);
 
2346
                        gint lexer = SSM(editor->sci, SCI_GETLEXER, 0, 0);
1878
2347
 
1879
2348
                        /* skip lines which are already comments */
1880
2349
                        switch (lexer)
1882
2351
                                case SCLEX_XML:
1883
2352
                                case SCLEX_HTML:
1884
2353
                                {
1885
 
                                        if (sci_get_style_at(doc_list[idx].sci, line_start) >= 118 &&
1886
 
                                                sci_get_style_at(doc_list[idx].sci, line_start) <= 127)
 
2354
                                        if (is_style_php(sci_get_style_at(editor->sci, line_start)))
1887
2355
                                                style_comment = SCE_HPHP_COMMENT;
1888
2356
                                        else style_comment = SCE_H_COMMENT;
1889
2357
                                        break;
1896
2364
                                case SCLEX_PERL: style_comment = SCE_PL_POD; break;
1897
2365
                                default: style_comment = SCE_C_COMMENT;
1898
2366
                        }
1899
 
                        if (sci_get_style_at(doc_list[idx].sci, line_start + x) == style_comment)
 
2367
                        if (sci_get_style_at(editor->sci, line_start + x) == style_comment)
1900
2368
                        {
1901
 
                                real_uncomment_multiline(idx);
 
2369
                                real_uncomment_multiline(editor);
1902
2370
                                count_uncommented++;
1903
2371
                        }
1904
2372
                        else
1905
2373
                        {
1906
 
                                real_comment_multiline(idx, line_start, last_line);
 
2374
                                real_comment_multiline(editor, line_start, last_line);
1907
2375
                                count_commented++;
1908
2376
                        }
1909
2377
 
1913
2381
                }
1914
2382
        }
1915
2383
 
1916
 
        SSM(doc_list[idx].sci, SCI_ENDUNDOACTION, 0, 0);
 
2384
        SSM(editor->sci, SCI_ENDUNDOACTION, 0, 0);
1917
2385
 
1918
2386
        co_len += tm_len;
1919
2387
 
1925
2393
                        gint a = (first_line_was_comment) ? - co_len : co_len;
1926
2394
 
1927
2395
                        /* don't modify sel_start when the selection starts within indentation */
1928
 
                        get_indent(&doc_list[idx], sel_start, TRUE);
 
2396
                        read_indent(editor, sel_start);
1929
2397
                        if ((sel_start - first_line_start) <= (gint) strlen(indent))
1930
2398
                                a = 0;
1931
2399
 
1932
 
                        sci_set_selection_start(doc_list[idx].sci, sel_start + a);
1933
 
                        sci_set_selection_end(doc_list[idx].sci, sel_end +
 
2400
                        sci_set_selection_start(editor->sci, sel_start + a);
 
2401
                        sci_set_selection_end(editor->sci, sel_end +
1934
2402
                                                                (count_commented * co_len) - (count_uncommented * co_len));
1935
2403
                }
1936
2404
                else
1937
2405
                {
1938
 
                        gint eol_len = utils_get_eol_char_len(idx);
 
2406
                        gint eol_len = editor_get_eol_char_len(editor);
1939
2407
                        if (count_uncommented > 0)
1940
2408
                        {
1941
 
                                sci_set_selection_start(doc_list[idx].sci, sel_start - co_len - eol_len);
1942
 
                                sci_set_selection_end(doc_list[idx].sci, sel_end - co_len - eol_len);
 
2409
                                sci_set_selection_start(editor->sci, sel_start - co_len - eol_len);
 
2410
                                sci_set_selection_end(editor->sci, sel_end - co_len - eol_len);
1943
2411
                        }
1944
2412
                        else
1945
2413
                        {
1946
 
                                sci_set_selection_start(doc_list[idx].sci, sel_start + co_len + eol_len);
1947
 
                                sci_set_selection_end(doc_list[idx].sci, sel_end + co_len + eol_len);
 
2414
                                sci_set_selection_start(editor->sci, sel_start + co_len + eol_len);
 
2415
                                sci_set_selection_end(editor->sci, sel_end + co_len + eol_len);
1948
2416
                        }
1949
2417
                }
1950
2418
        }
1951
2419
        else if (count_uncommented > 0)
1952
2420
        {
1953
 
                sci_set_current_position(doc_list[idx].sci, sel_start - co_len, TRUE);
 
2421
                sci_set_current_position(editor->sci, sel_start - co_len, TRUE);
1954
2422
        }
1955
2423
}
1956
2424
 
1957
2425
 
1958
2426
/* set toggle to TRUE if the caller is the toggle function, FALSE otherwise */
1959
 
void editor_do_comment(gint idx, gint line, gboolean allow_empty_lines, gboolean toggle)
 
2427
void editor_do_comment(GeanyEditor *editor, gint line, gboolean allow_empty_lines, gboolean toggle)
1960
2428
{
1961
2429
        gint first_line, last_line;
1962
2430
        gint x, i, line_start, line_len;
1963
2431
        gint sel_start, sel_end, co_len;
1964
2432
        gchar sel[256], *co, *cc;
1965
2433
        gboolean break_loop = FALSE, single_line = FALSE;
1966
 
        filetype *ft;
 
2434
        GeanyFiletype *ft;
1967
2435
 
1968
 
        if (! DOC_IDX_VALID(idx) || doc_list[idx].file_type == NULL) return;
 
2436
        if (editor == NULL || editor->document->file_type == NULL)
 
2437
                return;
1969
2438
 
1970
2439
        if (line < 0)
1971
2440
        {       /* use selection or current line */
1972
 
                sel_start = sci_get_selection_start(doc_list[idx].sci);
1973
 
                sel_end = sci_get_selection_end(doc_list[idx].sci);
 
2441
                sel_start = sci_get_selection_start(editor->sci);
 
2442
                sel_end = sci_get_selection_end(editor->sci);
1974
2443
 
1975
 
                first_line = sci_get_line_from_position(doc_list[idx].sci, sel_start);
 
2444
                first_line = sci_get_line_from_position(editor->sci, sel_start);
1976
2445
                /* Find the last line with chars selected (not EOL char) */
1977
 
                last_line = sci_get_line_from_position(doc_list[idx].sci,
1978
 
                        sel_end - utils_get_eol_char_len(idx));
 
2446
                last_line = sci_get_line_from_position(editor->sci,
 
2447
                        sel_end - editor_get_eol_char_len(editor));
1979
2448
                last_line = MAX(first_line, last_line);
1980
2449
        }
1981
2450
        else
1982
2451
        {
1983
2452
                first_line = last_line = line;
1984
 
                sel_start = sel_end = sci_get_position_from_line(doc_list[idx].sci, line);
 
2453
                sel_start = sel_end = sci_get_position_from_line(editor->sci, line);
1985
2454
        }
1986
2455
 
1987
 
        ft = doc_list[idx].file_type;
 
2456
        ft = editor->document->file_type;
1988
2457
 
1989
2458
        /* detection of HTML vs PHP code, if non-PHP set filetype to XML */
1990
 
        line_start = sci_get_position_from_line(doc_list[idx].sci, first_line);
 
2459
        line_start = sci_get_position_from_line(editor->sci, first_line);
1991
2460
        if (ft->id == GEANY_FILETYPES_PHP)
1992
2461
        {
1993
 
                if (sci_get_style_at(doc_list[idx].sci, line_start) < 118 ||
1994
 
                        sci_get_style_at(doc_list[idx].sci, line_start) > 127)
 
2462
                if (! is_style_php(sci_get_style_at(editor->sci, line_start)))
1995
2463
                        ft = filetypes[GEANY_FILETYPES_XML];
1996
2464
        }
1997
2465
 
2004
2472
        if (co_len == 0)
2005
2473
                return;
2006
2474
 
2007
 
        SSM(doc_list[idx].sci, SCI_BEGINUNDOACTION, 0, 0);
 
2475
        SSM(editor->sci, SCI_BEGINUNDOACTION, 0, 0);
2008
2476
 
2009
2477
        for (i = first_line; (i <= last_line) && (! break_loop); i++)
2010
2478
        {
2011
2479
                gint buf_len;
2012
2480
 
2013
 
                line_start = sci_get_position_from_line(doc_list[idx].sci, i);
2014
 
                line_len = sci_get_line_length(doc_list[idx].sci, i);
 
2481
                line_start = sci_get_position_from_line(editor->sci, i);
 
2482
                line_len = sci_get_line_length(editor->sci, i);
2015
2483
                x = 0;
2016
2484
 
2017
2485
                buf_len = MIN((gint)sizeof(sel) - 1, line_len - 1);
2018
2486
                if (buf_len < 0)
2019
2487
                        continue;
2020
 
                sci_get_text_range(doc_list[idx].sci, line_start, line_start + buf_len, sel);
 
2488
                sci_get_text_range(editor->sci, line_start, line_start + buf_len, sel);
2021
2489
                sel[buf_len] = '\0';
2022
2490
 
2023
2491
                while (isspace(sel[x])) x++;
2036
2504
 
2037
2505
                                if (toggle)
2038
2506
                                {
2039
 
                                        gchar *text = g_strconcat(co, GEANY_TOGGLE_MARK, NULL);
2040
 
                                        sci_insert_text(doc_list[idx].sci, start, text);
 
2507
                                        gchar *text = g_strconcat(co, editor_prefs.comment_toggle_mark, NULL);
 
2508
                                        sci_insert_text(editor->sci, start, text);
2041
2509
                                        g_free(text);
2042
2510
                                }
2043
2511
                                else
2044
 
                                        sci_insert_text(doc_list[idx].sci, start, co);
 
2512
                                        sci_insert_text(editor->sci, start, co);
2045
2513
                        }
2046
2514
                        /* use multi line comment */
2047
2515
                        else
2048
2516
                        {
2049
2517
                                gint style_comment;
2050
 
                                gint lexer = SSM(doc_list[idx].sci, SCI_GETLEXER, 0, 0);
 
2518
                                gint lexer = SSM(editor->sci, SCI_GETLEXER, 0, 0);
2051
2519
 
2052
2520
                                /* skip lines which are already comments */
2053
2521
                                switch (lexer)
2055
2523
                                        case SCLEX_XML:
2056
2524
                                        case SCLEX_HTML:
2057
2525
                                        {
2058
 
                                                if (sci_get_style_at(doc_list[idx].sci, line_start) >= 118 &&
2059
 
                                                        sci_get_style_at(doc_list[idx].sci, line_start) <= 127)
 
2526
                                                if (is_style_php(sci_get_style_at(editor->sci, line_start)))
2060
2527
                                                        style_comment = SCE_HPHP_COMMENT;
2061
2528
                                                else style_comment = SCE_H_COMMENT;
2062
2529
                                                break;
2067
2534
                                        case SCLEX_D: style_comment = SCE_D_COMMENT; break;
2068
2535
                                        default: style_comment = SCE_C_COMMENT;
2069
2536
                                }
2070
 
                                if (sci_get_style_at(doc_list[idx].sci, line_start + x) == style_comment) continue;
 
2537
                                if (sci_get_style_at(editor->sci, line_start + x) == style_comment) continue;
2071
2538
 
2072
 
                                real_comment_multiline(idx, line_start, last_line);
 
2539
                                real_comment_multiline(editor, line_start, last_line);
2073
2540
 
2074
2541
                                /* break because we are already on the last line */
2075
2542
                                break_loop = TRUE;
2077
2544
                        }
2078
2545
                }
2079
2546
        }
2080
 
        SSM(doc_list[idx].sci, SCI_ENDUNDOACTION, 0, 0);
 
2547
        SSM(editor->sci, SCI_ENDUNDOACTION, 0, 0);
2081
2548
 
2082
2549
        /* restore selection if there is one
2083
2550
         * but don't touch the selection if caller is editor_do_comment_toggle */
2085
2552
        {
2086
2553
                if (single_line)
2087
2554
                {
2088
 
                        sci_set_selection_start(doc_list[idx].sci, sel_start + co_len);
2089
 
                        sci_set_selection_end(doc_list[idx].sci, sel_end + ((i - first_line) * co_len));
 
2555
                        sci_set_selection_start(editor->sci, sel_start + co_len);
 
2556
                        sci_set_selection_end(editor->sci, sel_end + ((i - first_line) * co_len));
2090
2557
                }
2091
2558
                else
2092
2559
                {
2093
 
                        gint eol_len = utils_get_eol_char_len(idx);
2094
 
                        sci_set_selection_start(doc_list[idx].sci, sel_start + co_len + eol_len);
2095
 
                        sci_set_selection_end(doc_list[idx].sci, sel_end + co_len + eol_len);
 
2560
                        gint eol_len = editor_get_eol_char_len(editor);
 
2561
                        sci_set_selection_start(editor->sci, sel_start + co_len + eol_len);
 
2562
                        sci_set_selection_end(editor->sci, sel_end + co_len + eol_len);
2096
2563
                }
2097
2564
        }
2098
2565
}
2099
2566
 
2100
2567
 
2101
 
void editor_highlight_braces(ScintillaObject *sci, gint cur_pos)
 
2568
void editor_highlight_braces(GeanyEditor *editor, gint cur_pos)
2102
2569
{
2103
2570
        gint brace_pos = cur_pos - 1;
2104
2571
        gint end_pos;
2105
2572
 
2106
 
        if (! utils_isbrace(sci_get_char_at(sci, brace_pos), editor_prefs.brace_match_ltgt))
 
2573
        if (! utils_isbrace(sci_get_char_at(editor->sci, brace_pos), editor_prefs.brace_match_ltgt))
2107
2574
        {
2108
2575
                brace_pos++;
2109
 
                if (! utils_isbrace(sci_get_char_at(sci, brace_pos), editor_prefs.brace_match_ltgt))
 
2576
                if (! utils_isbrace(sci_get_char_at(editor->sci, brace_pos), editor_prefs.brace_match_ltgt))
2110
2577
                {
2111
 
                        SSM(sci, SCI_BRACEBADLIGHT, (uptr_t)-1, 0);
 
2578
                        SSM(editor->sci, SCI_SETHIGHLIGHTGUIDE, 0, 0);
 
2579
                        SSM(editor->sci, SCI_BRACEBADLIGHT, (uptr_t)-1, 0);
2112
2580
                        return;
2113
2581
                }
2114
2582
        }
2115
 
        end_pos = SSM(sci, SCI_BRACEMATCH, brace_pos, 0);
 
2583
        end_pos = SSM(editor->sci, SCI_BRACEMATCH, brace_pos, 0);
2116
2584
 
2117
2585
        if (end_pos >= 0)
2118
 
                SSM(sci, SCI_BRACEHIGHLIGHT, brace_pos, end_pos);
2119
 
        else
2120
 
                SSM(sci, SCI_BRACEBADLIGHT, brace_pos, 0);
2121
 
}
2122
 
 
2123
 
 
2124
 
static gboolean is_doc_comment_char(gchar c, gint lexer)
2125
 
{
2126
 
        if (c == '*' && (lexer == SCLEX_HTML || lexer == SCLEX_CPP))
2127
 
                return TRUE;
2128
 
        else if ((c == '*' || c == '+') && lexer == SCLEX_D)
2129
 
                return TRUE;
2130
 
        else
2131
 
                return FALSE;
2132
 
}
2133
 
 
2134
 
 
2135
 
static void auto_multiline(gint idx, gint pos)
2136
 
{
2137
 
        ScintillaObject *sci = doc_list[idx].sci;
2138
 
        gint style = SSM(sci, SCI_GETSTYLEAT, pos - 1 - utils_get_eol_char_len(idx), 0);
2139
 
        gint lexer = SSM(sci, SCI_GETLEXER, 0, 0);
2140
 
        gint i;
2141
 
 
2142
 
        if ((lexer == SCLEX_CPP && (style == SCE_C_COMMENT || style == SCE_C_COMMENTDOC)) ||
2143
 
                (lexer == SCLEX_HTML && style == SCE_HPHP_COMMENT) ||
2144
 
                (lexer == SCLEX_D && (style == SCE_D_COMMENT ||
2145
 
                                                          style == SCE_D_COMMENTDOC ||
2146
 
                                                          style == SCE_D_COMMENTNESTED)))
2147
 
        {
2148
 
                gchar *previous_line = sci_get_line(sci, sci_get_line_from_position(sci, pos - 2));
 
2586
        {
 
2587
                gint col = MIN(sci_get_col_from_position(editor->sci, brace_pos),
 
2588
                        sci_get_col_from_position(editor->sci, end_pos));
 
2589
                SSM(editor->sci, SCI_SETHIGHLIGHTGUIDE, col, 0);
 
2590
                SSM(editor->sci, SCI_BRACEHIGHLIGHT, brace_pos, end_pos);
 
2591
        }
 
2592
        else
 
2593
        {
 
2594
                SSM(editor->sci, SCI_SETHIGHLIGHTGUIDE, 0, 0);
 
2595
                SSM(editor->sci, SCI_BRACEBADLIGHT, brace_pos, 0);
 
2596
        }
 
2597
}
 
2598
 
 
2599
 
 
2600
static gboolean in_block_comment(gint lexer, gint style)
 
2601
{
 
2602
        switch (lexer)
 
2603
        {
 
2604
                case SCLEX_CPP:
 
2605
                        return (style == SCE_C_COMMENT ||
 
2606
                                style == SCE_C_COMMENTDOC);
 
2607
 
 
2608
                case SCLEX_D:
 
2609
                        return (style == SCE_D_COMMENT ||
 
2610
                                style == SCE_D_COMMENTDOC ||
 
2611
                                style == SCE_D_COMMENTNESTED);
 
2612
 
 
2613
                case SCLEX_HTML:
 
2614
                        return (style == SCE_HPHP_COMMENT);
 
2615
 
 
2616
                case SCLEX_CSS:
 
2617
                        return (style == SCE_CSS_COMMENT);
 
2618
 
 
2619
                default:
 
2620
                        return FALSE;
 
2621
        }
 
2622
}
 
2623
 
 
2624
 
 
2625
static gboolean is_comment_char(gchar c, gint lexer)
 
2626
{
 
2627
        if ((c == '*' || c == '+') && lexer == SCLEX_D)
 
2628
                return TRUE;
 
2629
        else
 
2630
        if (c == '*')
 
2631
                return TRUE;
 
2632
 
 
2633
        return FALSE;
 
2634
}
 
2635
 
 
2636
 
 
2637
static void auto_multiline(GeanyEditor *editor, gint cur_line)
 
2638
{
 
2639
        ScintillaObject *sci = editor->sci;
 
2640
        gint indent_pos, style;
 
2641
        gint lexer = sci_get_lexer(sci);
 
2642
 
 
2643
        /* Use the start of the line enter was pressed on, to avoid any doc keyword styles */
 
2644
        indent_pos = sci_get_line_indent_position(sci, cur_line - 1);
 
2645
        style = sci_get_style_at(sci, indent_pos);
 
2646
 
 
2647
        if (in_block_comment(lexer, style))
 
2648
        {
 
2649
                gchar *previous_line = sci_get_line(sci, cur_line - 1);
2149
2650
                /* the type of comment, '*' (C/C++/Java), '+' and the others (D) */
2150
2651
                gchar *continuation = "*";
2151
2652
                gchar *whitespace = ""; /* to hold whitespace if needed */
2152
2653
                gchar *result;
2153
2654
                gint len = strlen(previous_line);
 
2655
                gint i;
2154
2656
 
2155
2657
                /* find and stop at end of multi line comment */
2156
2658
                i = len - 1;
2157
2659
                while (i >= 0 && isspace(previous_line[i])) i--;
2158
 
                if (i >= 1 && is_doc_comment_char(previous_line[i - 1], lexer) && previous_line[i] == '/')
 
2660
                if (i >= 1 && is_comment_char(previous_line[i - 1], lexer) && previous_line[i] == '/')
2159
2661
                {
2160
 
                        gint cur_line = sci_get_current_line(sci);
2161
 
                        gint indent_pos = sci_get_line_indent_position(sci, cur_line);
2162
 
                        gint indent_len = sci_get_col_from_position(sci, indent_pos);
 
2662
                        gint indent_len, indent_width;
 
2663
 
 
2664
                        indent_pos = sci_get_line_indent_position(sci, cur_line);
 
2665
                        indent_len = sci_get_col_from_position(sci, indent_pos);
 
2666
                        indent_width = editor_get_indent_prefs(editor)->width;
2163
2667
 
2164
2668
                        /* if there is one too many spaces, delete the last space,
2165
2669
                         * to return to the indent used before the multiline comment was started. */
2166
 
                        if (indent_len % editor_prefs.tab_width == 1)
 
2670
                        if (indent_len % indent_width == 1)
2167
2671
                                SSM(sci, SCI_DELETEBACKNOTLINE, 0, 0);  /* remove whitespace indent */
2168
2672
                        g_free(previous_line);
2169
2673
                        return;
2173
2677
                while (i < len && isspace(previous_line[i])) i++; /* get to start of the line */
2174
2678
 
2175
2679
                if (i + 1 < len &&
2176
 
                        previous_line[i] == '/' && is_doc_comment_char(previous_line[i + 1], lexer))
 
2680
                        previous_line[i] == '/' && is_comment_char(previous_line[i + 1], lexer))
2177
2681
                { /* we are on the second line of a multi line comment, so we have to insert white space */
2178
2682
                        whitespace = " ";
2179
2683
                }
2180
2684
 
2181
 
                if (style == SCE_D_COMMENTNESTED) continuation = "+"; /* for nested comments in D */
 
2685
                if (style == SCE_D_COMMENTNESTED)
 
2686
                        continuation = "+"; /* for nested comments in D */
2182
2687
 
2183
2688
                result = g_strconcat(whitespace, continuation, " ", NULL);
2184
2689
                sci_add_text(sci, result);
2189
2694
}
2190
2695
 
2191
2696
 
2192
 
/* Checks whether the given style is a comment or string for the given lexer.
 
2697
/* Checks whether the given style is a string for the given lexer.
2193
2698
 * It doesn't handle LEX_HTML, this should be done by the caller.
2194
 
 * prev_style is used for some lexers where the style of two positions before is needed.
2195
 
 * Returns true if the style is a comment, FALSE otherwise.
 
2699
 * Returns true if the style is a string, FALSE otherwise.
2196
2700
 */
2197
 
static gboolean is_comment(gint lexer, gint prev_style, gint style)
 
2701
static gboolean is_string_style(gint lexer, gint style)
2198
2702
{
2199
 
        gboolean result = FALSE;
2200
 
 
2201
2703
        switch (lexer)
2202
2704
        {
2203
2705
                case SCLEX_CPP:
2204
2706
                case SCLEX_PASCAL:
2205
 
                {
2206
 
                        if (style == SCE_C_COMMENT ||
2207
 
                                style == SCE_C_COMMENTLINE ||
2208
 
                                style == SCE_C_COMMENTDOC ||
2209
 
                                style == SCE_C_COMMENTLINEDOC ||
2210
 
                                style == SCE_C_CHARACTER ||
2211
 
                                style == SCE_C_PREPROCESSOR ||
2212
 
                                style == SCE_C_STRING)
2213
 
                                result = TRUE;
2214
 
                        break;
2215
 
                }
 
2707
                        return (style == SCE_C_CHARACTER ||
 
2708
                                style == SCE_C_STRING);
 
2709
 
2216
2710
                case SCLEX_D:
2217
 
                {
2218
 
                        if (style == SCE_D_COMMENT ||
2219
 
                                style == SCE_D_COMMENTLINE ||
2220
 
                                style == SCE_D_COMMENTDOC ||
2221
 
                                style == SCE_D_COMMENTLINEDOC ||
2222
 
                                style == SCE_D_COMMENTNESTED ||
2223
 
                                style == SCE_D_CHARACTER ||
2224
 
                                style == SCE_D_STRING)
2225
 
                                result = TRUE;
2226
 
                        break;
2227
 
                }
 
2711
                        return (style == SCE_D_CHARACTER ||
 
2712
                                style == SCE_D_STRING);
 
2713
 
2228
2714
                case SCLEX_PYTHON:
2229
 
                {
2230
 
                        if (style == SCE_P_COMMENTLINE ||
2231
 
                                style == SCE_P_COMMENTBLOCK ||
2232
 
                                prev_style == SCE_P_COMMENTLINE ||
2233
 
                                prev_style == SCE_P_COMMENTBLOCK ||
2234
 
                                style == SCE_P_STRING ||
 
2715
                        return (style == SCE_P_STRING ||
2235
2716
                                style == SCE_P_TRIPLE ||
2236
2717
                                style == SCE_P_TRIPLEDOUBLE ||
2237
 
                                style == SCE_P_CHARACTER)
2238
 
                                result = TRUE;
2239
 
                        break;
2240
 
                }
 
2718
                                style == SCE_P_CHARACTER);
 
2719
 
2241
2720
                case SCLEX_F77:
2242
 
                {
2243
 
                        if (style == SCE_F_COMMENT ||
2244
 
                                style == SCE_F_STRING1 ||
2245
 
                                style == SCE_F_STRING2)
2246
 
                                result = TRUE;
2247
 
                        break;
2248
 
                }
 
2721
                case SCLEX_FORTRAN:
 
2722
                        return (style == SCE_F_STRING1 ||
 
2723
                                style == SCE_F_STRING2);
 
2724
 
2249
2725
                case SCLEX_PERL:
2250
 
                {
2251
 
                        if (prev_style == SCE_PL_COMMENTLINE ||
2252
 
                                prev_style == SCE_PL_STRING ||
2253
 
                                style == SCE_PL_COMMENTLINE ||
2254
 
                                style == SCE_PL_STRING ||
 
2726
                        return (style == SCE_PL_STRING ||
2255
2727
                                style == SCE_PL_HERE_DELIM ||
2256
2728
                                style == SCE_PL_HERE_Q ||
2257
2729
                                style == SCE_PL_HERE_QQ ||
2258
2730
                                style == SCE_PL_HERE_QX ||
2259
2731
                                style == SCE_PL_POD ||
2260
 
                                style == SCE_PL_POD_VERB)
2261
 
                                result = TRUE;
2262
 
                        break;
2263
 
                }
2264
 
                case SCLEX_PROPERTIES:
2265
 
                {
2266
 
                        if (style == SCE_PROPS_COMMENT)
2267
 
                                result = TRUE;
2268
 
                        break;
2269
 
                }
2270
 
                case SCLEX_LATEX:
2271
 
                {
2272
 
                        if (style == SCE_L_COMMENT)
2273
 
                                result = TRUE;
2274
 
                        break;
2275
 
                }
2276
 
                case SCLEX_MAKEFILE:
2277
 
                {
2278
 
                        if (style == SCE_MAKE_COMMENT)
2279
 
                                result = TRUE;
2280
 
                        break;
2281
 
                }
 
2732
                                style == SCE_PL_POD_VERB);
 
2733
 
 
2734
                case SCLEX_R:
 
2735
                        return (style == SCE_R_STRING);
 
2736
 
2282
2737
                case SCLEX_RUBY:
2283
 
                {
2284
 
                        if (prev_style == SCE_RB_COMMENTLINE ||
2285
 
                                style == SCE_RB_CHARACTER ||
 
2738
                        return (style == SCE_RB_CHARACTER ||
2286
2739
                                style == SCE_RB_STRING ||
2287
2740
                                style == SCE_RB_HERE_DELIM ||
2288
2741
                                style == SCE_RB_HERE_Q ||
2289
2742
                                style == SCE_RB_HERE_QQ ||
2290
2743
                                style == SCE_RB_HERE_QX ||
2291
 
                                style == SCE_RB_POD)
2292
 
                                result = TRUE;
2293
 
                        break;
2294
 
                }
2295
 
                case SCLEX_BASH:
2296
 
                {
2297
 
                        if (prev_style == SCE_SH_COMMENTLINE ||
2298
 
                                style == SCE_SH_STRING)
2299
 
                                result = TRUE;
2300
 
                        break;
2301
 
                }
2302
 
                case SCLEX_SQL:
2303
 
                {
2304
 
                        if (style == SCE_SQL_COMMENT ||
 
2744
                                style == SCE_RB_POD);
 
2745
 
 
2746
                case SCLEX_BASH:
 
2747
                        return (style == SCE_SH_STRING);
 
2748
 
 
2749
                case SCLEX_SQL:
 
2750
                        return (style == SCE_SQL_STRING);
 
2751
 
 
2752
                case SCLEX_TCL:
 
2753
                        return (style == SCE_TCL_IN_QUOTE);
 
2754
 
 
2755
                case SCLEX_LUA:
 
2756
                        return (style == SCE_LUA_LITERALSTRING ||
 
2757
                                style == SCE_LUA_CHARACTER ||
 
2758
                                style == SCE_LUA_STRING);
 
2759
 
 
2760
                case SCLEX_HASKELL:
 
2761
                        return (style == SCE_HA_CHARACTER ||
 
2762
                                style == SCE_HA_STRING);
 
2763
 
 
2764
                case SCLEX_FREEBASIC:
 
2765
                        return (style == SCE_B_STRING);
 
2766
 
 
2767
                case SCLEX_HTML:
 
2768
                        return (style == SCE_HPHP_SIMPLESTRING ||
 
2769
                                style == SCE_HPHP_HSTRING ||  /* HSTRING is a heredoc */
 
2770
                                style == SCE_HPHP_HSTRING_VARIABLE ||
 
2771
                                style == SCE_H_DOUBLESTRING ||
 
2772
                                style == SCE_H_SINGLESTRING ||
 
2773
                                style == SCE_H_CDATA ||
 
2774
                                style == SCE_H_SGML_DOUBLESTRING ||
 
2775
                                style == SCE_H_SGML_SIMPLESTRING);
 
2776
        }
 
2777
        return FALSE;
 
2778
}
 
2779
 
 
2780
 
 
2781
/* Checks whether the given style is a comment for the given lexer.
 
2782
 * It doesn't handle LEX_HTML, this should be done by the caller.
 
2783
 * Returns true if the style is a comment, FALSE otherwise.
 
2784
 */
 
2785
static gboolean is_comment_style(gint lexer, gint style)
 
2786
{
 
2787
        switch (lexer)
 
2788
        {
 
2789
                case SCLEX_CPP:
 
2790
                case SCLEX_PASCAL:
 
2791
                        return (style == SCE_C_COMMENT ||
 
2792
                                style == SCE_C_COMMENTLINE ||
 
2793
                                style == SCE_C_COMMENTDOC ||
 
2794
                                style == SCE_C_COMMENTLINEDOC ||
 
2795
                                style == SCE_C_COMMENTDOCKEYWORD ||
 
2796
                                style == SCE_C_COMMENTDOCKEYWORDERROR);
 
2797
 
 
2798
                case SCLEX_D:
 
2799
                        return (style == SCE_D_COMMENT ||
 
2800
                                style == SCE_D_COMMENTLINE ||
 
2801
                                style == SCE_D_COMMENTDOC ||
 
2802
                                style == SCE_D_COMMENTNESTED ||
 
2803
                                style == SCE_D_COMMENTLINEDOC ||
 
2804
                                style == SCE_D_COMMENTDOCKEYWORD ||
 
2805
                                style == SCE_D_COMMENTDOCKEYWORDERROR);
 
2806
 
 
2807
                case SCLEX_PYTHON:
 
2808
                        return (style == SCE_P_COMMENTLINE ||
 
2809
                                style == SCE_P_COMMENTBLOCK);
 
2810
 
 
2811
                case SCLEX_F77:
 
2812
                case SCLEX_FORTRAN:
 
2813
                        return (style == SCE_F_COMMENT);
 
2814
 
 
2815
                case SCLEX_PERL:
 
2816
                        return (style == SCE_PL_COMMENTLINE);
 
2817
 
 
2818
                case SCLEX_PROPERTIES:
 
2819
                        return (style == SCE_PROPS_COMMENT);
 
2820
 
 
2821
                case SCLEX_PO:
 
2822
                        return (style == SCE_PO_COMMENT);
 
2823
 
 
2824
                case SCLEX_LATEX:
 
2825
                        return (style == SCE_L_COMMENT);
 
2826
 
 
2827
                case SCLEX_MAKEFILE:
 
2828
                        return (style == SCE_MAKE_COMMENT);
 
2829
 
 
2830
                case SCLEX_RUBY:
 
2831
                        return (style == SCE_RB_COMMENTLINE);
 
2832
 
 
2833
                case SCLEX_BASH:
 
2834
                        return (style == SCE_SH_COMMENTLINE);
 
2835
 
 
2836
                case SCLEX_R:
 
2837
                        return (style == SCE_R_COMMENT);
 
2838
 
 
2839
                case SCLEX_SQL:
 
2840
                        return (style == SCE_SQL_COMMENT ||
2305
2841
                                style == SCE_SQL_COMMENTLINE ||
2306
 
                                style == SCE_SQL_COMMENTDOC ||
2307
 
                                style == SCE_SQL_STRING)
2308
 
                                result = TRUE;
2309
 
                        break;
2310
 
                }
 
2842
                                style == SCE_SQL_COMMENTDOC);
 
2843
 
2311
2844
                case SCLEX_TCL:
2312
 
                {
2313
 
                        if (style == SCE_TCL_COMMENT ||
 
2845
                        return (style == SCE_TCL_COMMENT ||
2314
2846
                                style == SCE_TCL_COMMENTLINE ||
2315
2847
                                style == SCE_TCL_COMMENT_BOX ||
2316
 
                                style == SCE_TCL_BLOCK_COMMENT ||
2317
 
                                style == SCE_TCL_IN_QUOTE)
2318
 
                                result = TRUE;
2319
 
                        break;
2320
 
                }
 
2848
                                style == SCE_TCL_BLOCK_COMMENT);
 
2849
 
2321
2850
                case SCLEX_LUA:
2322
 
                {
2323
 
                        if (style == SCE_LUA_COMMENT ||
 
2851
                        return (style == SCE_LUA_COMMENT ||
2324
2852
                                style == SCE_LUA_COMMENTLINE ||
2325
 
                                style == SCE_LUA_COMMENTDOC ||
2326
 
                                style == SCE_LUA_LITERALSTRING ||
2327
 
                                style == SCE_LUA_CHARACTER ||
2328
 
                                style == SCE_LUA_STRING)
2329
 
                                result = TRUE;
2330
 
                        break;
2331
 
                }
 
2853
                                style == SCE_LUA_COMMENTDOC);
 
2854
 
2332
2855
                case SCLEX_HASKELL:
2333
 
                {
2334
 
                        if (prev_style == SCE_HA_COMMENTLINE ||
 
2856
                        return (style == SCE_HA_COMMENTLINE ||
2335
2857
                                style == SCE_HA_COMMENTBLOCK ||
2336
2858
                                style == SCE_HA_COMMENTBLOCK2 ||
2337
 
                                style == SCE_HA_COMMENTBLOCK3 ||
2338
 
                                style == SCE_HA_CHARACTER ||
2339
 
                                style == SCE_HA_STRING)
2340
 
                                result = TRUE;
2341
 
                        break;
2342
 
                }
 
2859
                                style == SCE_HA_COMMENTBLOCK3);
 
2860
 
2343
2861
                case SCLEX_FREEBASIC:
2344
 
                {
2345
 
                        if (style == SCE_B_COMMENT ||
2346
 
                                style == SCE_B_STRING)
2347
 
                                result = TRUE;
2348
 
                        break;
2349
 
                }
 
2862
                        return (style == SCE_B_COMMENT);
 
2863
 
2350
2864
                case SCLEX_HTML:
2351
 
                {
2352
 
                        if (prev_style == SCE_HPHP_SIMPLESTRING ||
2353
 
                                prev_style == SCE_HPHP_HSTRING ||
2354
 
                                prev_style == SCE_HPHP_COMMENTLINE ||
2355
 
                                prev_style == SCE_HPHP_COMMENT ||
2356
 
                                prev_style == SCE_HPHP_HSTRING ||  /* HSTRING is a heredoc */
2357
 
                                prev_style == SCE_HPHP_HSTRING_VARIABLE ||
2358
 
                                prev_style == SCE_H_DOUBLESTRING ||
2359
 
                                prev_style == SCE_H_SINGLESTRING ||
2360
 
                                prev_style == SCE_H_CDATA ||
2361
 
                                prev_style == SCE_H_COMMENT ||
2362
 
                                prev_style == SCE_H_SGML_DOUBLESTRING ||
2363
 
                                prev_style == SCE_H_SGML_SIMPLESTRING ||
2364
 
                                prev_style == SCE_H_SGML_COMMENT)
2365
 
                                result = TRUE;
 
2865
                        return (style == SCE_HPHP_COMMENTLINE ||
 
2866
                                style == SCE_HPHP_COMMENT ||
 
2867
                                style == SCE_H_COMMENT ||
 
2868
                                style == SCE_H_SGML_COMMENT);
 
2869
        }
 
2870
        return FALSE;
 
2871
}
 
2872
 
 
2873
 
 
2874
/* Checks whether the given style is normal code (not string, comment, preprocessor, etc).
 
2875
 * It doesn't handle LEX_HTML, this should be done by the caller.
 
2876
 */
 
2877
static gboolean is_code_style(gint lexer, gint style)
 
2878
{
 
2879
        switch (lexer)
 
2880
        {
 
2881
                case SCLEX_CPP:
 
2882
                        if (style == SCE_C_PREPROCESSOR)
 
2883
                                return FALSE;
2366
2884
                        break;
2367
 
                }
2368
2885
        }
2369
 
 
2370
 
        return result;
 
2886
        return !(is_comment_style(lexer, style) ||
 
2887
                is_string_style(lexer, style));
2371
2888
}
2372
2889
 
2373
2890
 
2403
2920
 
2404
2921
 
2405
2922
/* inserts a three-line comment at one line above current cursor position */
2406
 
void editor_insert_multiline_comment(gint idx)
 
2923
void editor_insert_multiline_comment(GeanyEditor *editor)
2407
2924
{
2408
2925
        gchar *text;
2409
2926
        gint text_len;
2410
2927
        gint line;
2411
2928
        gint pos;
2412
2929
        gboolean have_multiline_comment = FALSE;
 
2930
        GeanyDocument *doc;
2413
2931
 
2414
 
        if (doc_list[idx].file_type == NULL || doc_list[idx].file_type->comment_open == NULL)
 
2932
        if (editor == NULL || editor->document->file_type == NULL ||
 
2933
                editor->document->file_type->comment_open == NULL)
 
2934
        {
2415
2935
                return;
 
2936
        }
 
2937
        doc = editor->document;
2416
2938
 
2417
 
        if (doc_list[idx].file_type->comment_close != NULL &&
2418
 
                strlen(doc_list[idx].file_type->comment_close) > 0)
 
2939
        if (doc->file_type->comment_close != NULL && strlen(doc->file_type->comment_close) > 0)
2419
2940
                have_multiline_comment = TRUE;
2420
2941
 
2421
2942
        /* insert three lines one line above of the current position */
2422
 
        line = sci_get_line_from_position(doc_list[idx].sci, editor_info.click_pos);
2423
 
        pos = sci_get_position_from_line(doc_list[idx].sci, line);
 
2943
        line = sci_get_line_from_position(editor->sci, editor_info.click_pos);
 
2944
        pos = sci_get_position_from_line(editor->sci, line);
2424
2945
 
2425
2946
        /* use the indent on the current line but only when comment indentation is used
2426
2947
         * and we don't have multi line comment characters */
2427
 
        if (doc_list[idx].auto_indent && ! have_multiline_comment &&
2428
 
                doc_list[idx].file_type->comment_use_indent)
 
2948
        if (editor->auto_indent &&
 
2949
                ! have_multiline_comment &&     doc->file_type->comment_use_indent)
2429
2950
        {
2430
 
                get_indent(&doc_list[idx], editor_info.click_pos, TRUE);
 
2951
                read_indent(editor, editor_info.click_pos);
2431
2952
                text = g_strdup_printf("%s\n%s\n%s\n", indent, indent, indent);
2432
2953
                text_len = strlen(text);
2433
2954
        }
2436
2957
                text = g_strdup("\n\n\n");
2437
2958
                text_len = 3;
2438
2959
        }
2439
 
        sci_insert_text(doc_list[idx].sci, pos, text);
 
2960
        sci_insert_text(editor->sci, pos, text);
2440
2961
        g_free(text);
2441
2962
 
2442
2963
 
2443
2964
        /* select the inserted lines for commenting */
2444
 
        sci_set_selection_start(doc_list[idx].sci, pos);
2445
 
        sci_set_selection_end(doc_list[idx].sci, pos + text_len);
 
2965
        sci_set_selection_start(editor->sci, pos);
 
2966
        sci_set_selection_end(editor->sci, pos + text_len);
2446
2967
 
2447
 
        editor_do_comment(idx, -1, TRUE, FALSE);
 
2968
        editor_do_comment(editor, -1, TRUE, FALSE);
2448
2969
 
2449
2970
        /* set the current position to the start of the first inserted line */
2450
 
        pos += strlen(doc_list[idx].file_type->comment_open);
 
2971
        pos += strlen(doc->file_type->comment_open);
2451
2972
 
2452
2973
        /* on multi line comment jump to the next line, otherwise add the length of added indentation */
2453
2974
        if (have_multiline_comment)
2455
2976
        else
2456
2977
                pos += strlen(indent);
2457
2978
 
2458
 
        sci_set_current_position(doc_list[idx].sci, pos, TRUE);
 
2979
        sci_set_current_position(editor->sci, pos, TRUE);
2459
2980
        /* reset the selection */
2460
 
        sci_set_anchor(doc_list[idx].sci, pos);
 
2981
        sci_set_anchor(editor->sci, pos);
2461
2982
}
2462
2983
 
2463
2984
 
2464
2985
/* Note: If the editor is pending a redraw, set document::scroll_percent instead.
2465
2986
 * Scroll the view to make line appear at percent_of_view.
2466
2987
 * line can be -1 to use the current position. */
2467
 
void editor_scroll_to_line(ScintillaObject *sci, gint line, gfloat percent_of_view)
 
2988
void editor_scroll_to_line(GeanyEditor *editor, gint line, gfloat percent_of_view)
2468
2989
{
2469
2990
        gint vis1, los, delta;
2470
 
        GtkWidget *wid = GTK_WIDGET(sci);
 
2991
        GtkWidget *wid;
 
2992
 
 
2993
        if (editor == NULL)
 
2994
                return;
 
2995
 
 
2996
        wid = GTK_WIDGET(editor->sci);
2471
2997
 
2472
2998
        if (! wid->window || ! gdk_window_is_viewable(wid->window))
2473
2999
                return; /* prevent gdk_window_scroll warning */
2474
3000
 
2475
3001
        if (line == -1)
2476
 
                line = sci_get_current_line(sci);
 
3002
                line = sci_get_current_line(editor->sci);
2477
3003
 
2478
3004
        /* sci 'visible line' != doc line number because of folding and line wrapping */
2479
3005
        /* calling SCI_VISIBLEFROMDOCLINE for line is more accurate than calling
2480
3006
         * SCI_DOCLINEFROMVISIBLE for vis1. */
2481
 
        line = SSM(sci, SCI_VISIBLEFROMDOCLINE, line, 0);
2482
 
        vis1 = SSM(sci, SCI_GETFIRSTVISIBLELINE, 0, 0);
2483
 
        los = SSM(sci, SCI_LINESONSCREEN, 0, 0);
 
3007
        line = SSM(editor->sci, SCI_VISIBLEFROMDOCLINE, line, 0);
 
3008
        vis1 = SSM(editor->sci, SCI_GETFIRSTVISIBLELINE, 0, 0);
 
3009
        los = SSM(editor->sci, SCI_LINESONSCREEN, 0, 0);
2484
3010
        delta = (line - vis1) - los * percent_of_view;
2485
 
        sci_scroll_lines(sci, delta);
2486
 
        sci_scroll_caret(sci); /* needed for horizontal scrolling */
 
3011
        sci_scroll_lines(editor->sci, delta);
 
3012
        sci_scroll_caret(editor->sci); /* needed for horizontal scrolling */
2487
3013
}
2488
3014
 
2489
3015
 
2490
 
void editor_insert_alternative_whitespace(gint idx)
 
3016
/* creates and inserts one tab or whitespace of the amount of the tab width */
 
3017
void editor_insert_alternative_whitespace(GeanyEditor *editor)
2491
3018
{
2492
 
        /* creates and inserts one tabulator sign or whitespace of the amount of the tab width */
2493
 
        gchar *text = get_whitespace(editor_prefs.tab_width, ! doc_list[idx].use_tabs);
2494
 
        sci_add_text(doc_list[idx].sci, text);
 
3019
        gchar *text;
 
3020
        GeanyIndentPrefs iprefs = *editor_get_indent_prefs(editor);
 
3021
 
 
3022
        switch (iprefs.type)
 
3023
        {
 
3024
                case GEANY_INDENT_TYPE_TABS:
 
3025
                        iprefs.type = GEANY_INDENT_TYPE_SPACES;
 
3026
                        break;
 
3027
                case GEANY_INDENT_TYPE_SPACES:
 
3028
                case GEANY_INDENT_TYPE_BOTH:    /* most likely we want a tab */
 
3029
                        iprefs.type = GEANY_INDENT_TYPE_TABS;
 
3030
                        break;
 
3031
        }
 
3032
        text = get_whitespace(&iprefs, iprefs.width);
 
3033
        sci_add_text(editor->sci, text);
2495
3034
        g_free(text);
2496
3035
}
2497
3036
 
2498
3037
 
2499
 
void editor_select_word(ScintillaObject *sci)
 
3038
void editor_select_word(GeanyEditor *editor)
2500
3039
{
2501
3040
        gint pos;
2502
3041
        gint start;
2503
3042
        gint end;
2504
3043
 
2505
 
        g_return_if_fail(sci != NULL);
 
3044
        g_return_if_fail(editor != NULL);
2506
3045
 
2507
 
        pos = SSM(sci, SCI_GETCURRENTPOS, 0, 0);
2508
 
        start = SSM(sci, SCI_WORDSTARTPOSITION, pos, TRUE);
2509
 
        end = SSM(sci, SCI_WORDENDPOSITION, pos, TRUE);
 
3046
        pos = SSM(editor->sci, SCI_GETCURRENTPOS, 0, 0);
 
3047
        start = SSM(editor->sci, SCI_WORDSTARTPOSITION, pos, TRUE);
 
3048
        end = SSM(editor->sci, SCI_WORDENDPOSITION, pos, TRUE);
2510
3049
 
2511
3050
        if (start == end) /* caret in whitespaces sequence */
2512
3051
        {
2513
3052
                /* look forward but reverse the selection direction,
2514
3053
                 * so the caret end up stay as near as the original position. */
2515
 
                end = SSM(sci, SCI_WORDENDPOSITION, pos, FALSE);
2516
 
                start = SSM(sci, SCI_WORDENDPOSITION, end, TRUE);
 
3054
                end = SSM(editor->sci, SCI_WORDENDPOSITION, pos, FALSE);
 
3055
                start = SSM(editor->sci, SCI_WORDENDPOSITION, end, TRUE);
2517
3056
                if (start == end)
2518
3057
                        return;
2519
3058
        }
2520
3059
 
2521
 
        SSM(sci, SCI_SETSEL, start, end);
 
3060
        SSM(editor->sci, SCI_SETSEL, start, end);
2522
3061
}
2523
3062
 
2524
3063
 
2525
3064
/* extra_line is for selecting the cursor line or anchor line at the bottom of a selection,
2526
3065
 * when those lines have no selection. */
2527
 
void editor_select_lines(ScintillaObject *sci, gboolean extra_line)
 
3066
void editor_select_lines(GeanyEditor *editor, gboolean extra_line)
2528
3067
{
2529
3068
        gint start, end, line;
2530
3069
 
2531
 
        g_return_if_fail(sci != NULL);
 
3070
        g_return_if_fail(editor != NULL);
2532
3071
 
2533
 
        start = sci_get_selection_start(sci);
2534
 
        end = sci_get_selection_end(sci);
 
3072
        start = sci_get_selection_start(editor->sci);
 
3073
        end = sci_get_selection_end(editor->sci);
2535
3074
 
2536
3075
        /* check if whole lines are already selected */
2537
3076
        if (! extra_line && start != end &&
2538
 
                sci_get_col_from_position(sci, start) == 0 &&
2539
 
                sci_get_col_from_position(sci, end) == 0)
 
3077
                sci_get_col_from_position(editor->sci, start) == 0 &&
 
3078
                sci_get_col_from_position(editor->sci, end) == 0)
2540
3079
                        return;
2541
3080
 
2542
 
        line = sci_get_line_from_position(sci, start);
2543
 
        start = sci_get_position_from_line(sci, line);
2544
 
 
2545
 
        line = sci_get_line_from_position(sci, end);
2546
 
        end = sci_get_position_from_line(sci, line + 1);
2547
 
 
2548
 
        SSM(sci, SCI_SETSEL, start, end);
 
3081
        line = sci_get_line_from_position(editor->sci, start);
 
3082
        start = sci_get_position_from_line(editor->sci, line);
 
3083
 
 
3084
        line = sci_get_line_from_position(editor->sci, end);
 
3085
        end = sci_get_position_from_line(editor->sci, line + 1);
 
3086
 
 
3087
        SSM(editor->sci, SCI_SETSEL, start, end);
2549
3088
}
2550
3089
 
2551
3090
 
2552
3091
/* find the start or end of a paragraph by searching all lines in direction (UP or DOWN)
2553
3092
 * starting at the given line and return the found line or return -1 if called on an empty line */
2554
 
static gint find_paragraph_stop(ScintillaObject *sci, gint line, gint direction)
 
3093
static gint find_paragraph_stop(GeanyEditor *editor, gint line, gint direction)
2555
3094
{
2556
3095
        gboolean found_end = FALSE;
2557
3096
        gint step;
2558
3097
        gchar *line_buf, *x;
 
3098
        ScintillaObject *sci = editor->sci;
2559
3099
 
2560
3100
        /* first check current line and return -1 if it is empty to skip creating of a selection */
2561
3101
        line_buf = x = sci_get_line(sci, line);
2597
3137
}
2598
3138
 
2599
3139
 
2600
 
void editor_select_paragraph(ScintillaObject *sci)
 
3140
void editor_select_paragraph(GeanyEditor *editor)
2601
3141
{
2602
3142
        gint pos_start, pos_end, line_start, line_found;
2603
3143
 
2604
 
        g_return_if_fail(sci != NULL);
2605
 
 
2606
 
        line_start = SSM(sci, SCI_LINEFROMPOSITION, SSM(sci, SCI_GETCURRENTPOS, 0, 0), 0);
2607
 
 
2608
 
        line_found = find_paragraph_stop(sci, line_start, UP);
 
3144
        g_return_if_fail(editor != NULL);
 
3145
 
 
3146
        line_start = SSM(editor->sci, SCI_LINEFROMPOSITION,
 
3147
                                                SSM(editor->sci, SCI_GETCURRENTPOS, 0, 0), 0);
 
3148
 
 
3149
        line_found = find_paragraph_stop(editor, line_start, UP);
2609
3150
        if (line_found == -1)
2610
3151
                return;
2611
3152
 
2614
3155
        if (line_found > 0)
2615
3156
                line_found++;
2616
3157
 
2617
 
        pos_start = SSM(sci, SCI_POSITIONFROMLINE, line_found, 0);
2618
 
 
2619
 
        line_found = find_paragraph_stop(sci, line_start, DOWN);
2620
 
        pos_end = SSM(sci, SCI_POSITIONFROMLINE, line_found, 0);
2621
 
 
2622
 
        SSM(sci, SCI_SETSEL, pos_start, pos_end);
 
3158
        pos_start = SSM(editor->sci, SCI_POSITIONFROMLINE, line_found, 0);
 
3159
 
 
3160
        line_found = find_paragraph_stop(editor, line_start, DOWN);
 
3161
        pos_end = SSM(editor->sci, SCI_POSITIONFROMLINE, line_found, 0);
 
3162
 
 
3163
        SSM(editor->sci, SCI_SETSEL, pos_start, pos_end);
2623
3164
}
2624
3165
 
2625
3166
 
2626
 
/* simple auto indentation to indent the current line with the same indent as the previous one */
2627
 
void editor_auto_line_indentation(gint idx, gint pos)
 
3167
/* simple indentation to indent the current line with the same indent as the previous one */
 
3168
static void smart_line_indentation(GeanyEditor *editor, gint first_line, gint last_line)
2628
3169
{
2629
 
        gint i, first_line, last_line;
2630
 
        gint first_sel_start, first_sel_end, sel_start = 0, sel_end = 0;
2631
 
 
2632
 
        g_return_if_fail(DOC_IDX_VALID(idx));
2633
 
 
2634
 
        first_sel_start = sci_get_selection_start(doc_list[idx].sci);
2635
 
        first_sel_end = sci_get_selection_end(doc_list[idx].sci);
2636
 
 
2637
 
        first_line = sci_get_line_from_position(doc_list[idx].sci, first_sel_start);
2638
 
        /* Find the last line with chars selected (not EOL char) */
2639
 
        last_line = sci_get_line_from_position(doc_list[idx].sci,
2640
 
                first_sel_end - utils_get_eol_char_len(idx));
2641
 
        last_line = MAX(first_line, last_line);
2642
 
 
2643
 
        if (pos == -1)
2644
 
                pos = first_sel_start;
2645
 
 
2646
 
        /* get previous line and use it for get_indent to use that line
 
3170
        gint i, sel_start = 0, sel_end = 0;
 
3171
 
 
3172
        /* get previous line and use it for read_indent to use that line
2647
3173
         * (otherwise it would fail on a line only containing "{" in advanced indentation mode) */
2648
 
        get_indent(&doc_list[idx],
2649
 
                sci_get_position_from_line(doc_list[idx].sci, first_line - 1), TRUE);
2650
 
        SSM(doc_list[idx].sci, SCI_BEGINUNDOACTION, 0, 0);
 
3174
        read_indent(editor, sci_get_position_from_line(editor->sci, first_line - 1));
2651
3175
 
2652
3176
        for (i = first_line; i <= last_line; i++)
2653
3177
        {
2654
3178
                /* skip the first line or if the indentation of the previous and current line are equal */
2655
3179
                if (i == 0 ||
2656
 
                        SSM(doc_list[idx].sci, SCI_GETLINEINDENTATION, i - 1, 0) ==
2657
 
                        SSM(doc_list[idx].sci, SCI_GETLINEINDENTATION, i, 0))
 
3180
                        SSM(editor->sci, SCI_GETLINEINDENTATION, i - 1, 0) ==
 
3181
                        SSM(editor->sci, SCI_GETLINEINDENTATION, i, 0))
2658
3182
                        continue;
2659
3183
 
2660
 
                sel_start = SSM(doc_list[idx].sci, SCI_POSITIONFROMLINE, i, 0);
2661
 
                sel_end = SSM(doc_list[idx].sci, SCI_GETLINEINDENTPOSITION, i, 0);
 
3184
                sel_start = SSM(editor->sci, SCI_POSITIONFROMLINE, i, 0);
 
3185
                sel_end = SSM(editor->sci, SCI_GETLINEINDENTPOSITION, i, 0);
2662
3186
                if (sel_start < sel_end)
2663
3187
                {
2664
 
                        SSM(doc_list[idx].sci, SCI_SETSEL, sel_start, sel_end);
2665
 
                        sci_replace_sel(doc_list[idx].sci, "");
 
3188
                        SSM(editor->sci, SCI_SETSEL, sel_start, sel_end);
 
3189
                        sci_replace_sel(editor->sci, "");
2666
3190
                }
2667
 
                sci_insert_text(doc_list[idx].sci, sel_start, indent);
 
3191
                sci_insert_text(editor->sci, sel_start, indent);
2668
3192
        }
 
3193
}
 
3194
 
 
3195
 
 
3196
/* simple indentation to indent the current line with the same indent as the previous one */
 
3197
void editor_smart_line_indentation(GeanyEditor *editor, gint pos)
 
3198
{
 
3199
        gint first_line, last_line;
 
3200
        gint first_sel_start, first_sel_end;
 
3201
        ScintillaObject *sci;
 
3202
 
 
3203
        g_return_if_fail(editor != NULL);
 
3204
 
 
3205
        sci = editor->sci;
 
3206
 
 
3207
        first_sel_start = sci_get_selection_start(sci);
 
3208
        first_sel_end = sci_get_selection_end(sci);
 
3209
 
 
3210
        first_line = sci_get_line_from_position(sci, first_sel_start);
 
3211
        /* Find the last line with chars selected (not EOL char) */
 
3212
        last_line = sci_get_line_from_position(sci, first_sel_end - editor_get_eol_char_len(editor));
 
3213
        last_line = MAX(first_line, last_line);
 
3214
 
 
3215
        if (pos == -1)
 
3216
                pos = first_sel_start;
 
3217
 
 
3218
        SSM(sci, SCI_BEGINUNDOACTION, 0, 0);
 
3219
 
 
3220
        smart_line_indentation(editor, first_line, last_line);
2669
3221
 
2670
3222
        /* set cursor position if there was no selection */
2671
 
        /** TODO implement selection handling if there was a selection */
2672
3223
        if (first_sel_start == first_sel_end)
2673
 
                sci_set_current_position(doc_list[idx].sci,
2674
 
                        pos - (sel_end - sel_start) + strlen(indent), FALSE);
2675
 
 
2676
 
        SSM(doc_list[idx].sci, SCI_ENDUNDOACTION, 0, 0);
 
3224
        {
 
3225
                gint indent_pos = SSM(sci, SCI_GETLINEINDENTPOSITION, first_line, 0);
 
3226
 
 
3227
                /* use indent position as user may wish to change indentation afterwards */
 
3228
                sci_set_current_position(sci, indent_pos, FALSE);
 
3229
        }
 
3230
        else
 
3231
        {
 
3232
                /* fully select all the lines affected */
 
3233
                sci_set_selection_start(sci, sci_get_position_from_line(sci, first_line));
 
3234
                sci_set_selection_end(sci, sci_get_position_from_line(sci, last_line + 1));
 
3235
        }
 
3236
 
 
3237
        SSM(sci, SCI_ENDUNDOACTION, 0, 0);
2677
3238
}
2678
3239
 
2679
3240
 
2680
3241
/* increase / decrease current line or selection by one space */
2681
 
void editor_indentation_by_one_space(gint idx, gint pos, gboolean decrease)
 
3242
void editor_indentation_by_one_space(GeanyEditor *editor, gint pos, gboolean decrease)
2682
3243
{
2683
3244
        gint i, first_line, last_line, line_start, indentation_end, count = 0;
2684
3245
        gint sel_start, sel_end, first_line_offset = 0;
2685
3246
 
2686
 
        g_return_if_fail(DOC_IDX_VALID(idx));
2687
 
 
2688
 
        sel_start = sci_get_selection_start(doc_list[idx].sci);
2689
 
        sel_end = sci_get_selection_end(doc_list[idx].sci);
2690
 
 
2691
 
        first_line = sci_get_line_from_position(doc_list[idx].sci, sel_start);
 
3247
        g_return_if_fail(editor != NULL);
 
3248
 
 
3249
        sel_start = sci_get_selection_start(editor->sci);
 
3250
        sel_end = sci_get_selection_end(editor->sci);
 
3251
 
 
3252
        first_line = sci_get_line_from_position(editor->sci, sel_start);
2692
3253
        /* Find the last line with chars selected (not EOL char) */
2693
 
        last_line = sci_get_line_from_position(doc_list[idx].sci,
2694
 
                sel_end - utils_get_eol_char_len(idx));
 
3254
        last_line = sci_get_line_from_position(editor->sci, sel_end - editor_get_eol_char_len(editor));
2695
3255
        last_line = MAX(first_line, last_line);
2696
3256
 
2697
3257
        if (pos == -1)
2698
3258
                pos = sel_start;
2699
3259
 
2700
 
        SSM(doc_list[idx].sci, SCI_BEGINUNDOACTION, 0, 0);
 
3260
        SSM(editor->sci, SCI_BEGINUNDOACTION, 0, 0);
2701
3261
 
2702
3262
        for (i = first_line; i <= last_line; i++)
2703
3263
        {
2704
 
                indentation_end = SSM(doc_list[idx].sci, SCI_GETLINEINDENTPOSITION, i, 0);
 
3264
                indentation_end = SSM(editor->sci, SCI_GETLINEINDENTPOSITION, i, 0);
2705
3265
                if (decrease)
2706
3266
                {
2707
 
                        line_start = SSM(doc_list[idx].sci, SCI_POSITIONFROMLINE, i, 0);
 
3267
                        line_start = SSM(editor->sci, SCI_POSITIONFROMLINE, i, 0);
2708
3268
                        /* searching backwards for a space to remove */
2709
 
                        while (sci_get_char_at(doc_list[idx].sci, indentation_end) != ' ' &&
2710
 
                                   indentation_end > line_start)
 
3269
                        while (sci_get_char_at(editor->sci, indentation_end) != ' ' && indentation_end > line_start)
2711
3270
                                indentation_end--;
2712
3271
 
2713
 
                        if (sci_get_char_at(doc_list[idx].sci, indentation_end) == ' ')
 
3272
                        if (sci_get_char_at(editor->sci, indentation_end) == ' ')
2714
3273
                        {
2715
 
                                SSM(doc_list[idx].sci, SCI_SETSEL, indentation_end, indentation_end + 1);
2716
 
                                sci_replace_sel(doc_list[idx].sci, "");
 
3274
                                SSM(editor->sci, SCI_SETSEL, indentation_end, indentation_end + 1);
 
3275
                                sci_replace_sel(editor->sci, "");
2717
3276
                                count--;
2718
3277
                                if (i == first_line)
2719
3278
                                        first_line_offset = -1;
2721
3280
                }
2722
3281
                else
2723
3282
                {
2724
 
                        sci_insert_text(doc_list[idx].sci, indentation_end, " ");
 
3283
                        sci_insert_text(editor->sci, indentation_end, " ");
2725
3284
                        count++;
2726
3285
                        if (i == first_line)
2727
3286
                                first_line_offset = 1;
2734
3293
                gint start = sel_start + first_line_offset;
2735
3294
                if (first_line_offset < 0)
2736
3295
                        start = MAX(sel_start + first_line_offset,
2737
 
                                                SSM(doc_list[idx].sci, SCI_POSITIONFROMLINE, first_line, 0));
 
3296
                                                SSM(editor->sci, SCI_POSITIONFROMLINE, first_line, 0));
2738
3297
 
2739
 
                sci_set_selection_start(doc_list[idx].sci, start);
2740
 
                sci_set_selection_end(doc_list[idx].sci, sel_end + count);
 
3298
                sci_set_selection_start(editor->sci, start);
 
3299
                sci_set_selection_end(editor->sci, sel_end + count);
2741
3300
        }
2742
3301
        else
2743
 
                sci_set_current_position(doc_list[idx].sci, pos + count, FALSE);
 
3302
                sci_set_current_position(editor->sci, pos + count, FALSE);
2744
3303
 
2745
 
        SSM(doc_list[idx].sci, SCI_ENDUNDOACTION, 0, 0);
 
3304
        SSM(editor->sci, SCI_ENDUNDOACTION, 0, 0);
2746
3305
}
2747
3306
 
2748
3307
 
2749
3308
void editor_finalize()
2750
3309
{
2751
 
        g_hash_table_destroy(editor_prefs.snippets);
2752
 
 
2753
3310
        scintilla_release_resources();
2754
3311
}
2755
3312
 
2756
3313
 
2757
3314
/* wordchars: NULL or a string containing characters to match a word.
2758
3315
 * Returns: the current selection or the current word. */
2759
 
gchar *editor_get_default_selection(gint idx, gboolean use_current_word, const gchar *wordchars)
 
3316
gchar *editor_get_default_selection(GeanyEditor *editor, gboolean use_current_word,
 
3317
                                                                        const gchar *wordchars)
2760
3318
{
2761
3319
        gchar *s = NULL;
2762
3320
 
2763
 
        if (! DOC_IDX_VALID(idx))
 
3321
        if (editor == NULL)
2764
3322
                return NULL;
2765
3323
 
2766
 
        if (sci_get_lines_selected(doc_list[idx].sci) == 1)
 
3324
        if (sci_get_lines_selected(editor->sci) == 1)
2767
3325
        {
2768
 
                gint len = sci_get_selected_text_length(doc_list[idx].sci);
 
3326
                gint len = sci_get_selected_text_length(editor->sci);
2769
3327
 
2770
3328
                s = g_malloc(len + 1);
2771
 
                sci_get_selected_text(doc_list[idx].sci, s);
 
3329
                sci_get_selected_text(editor->sci, s);
2772
3330
        }
2773
 
        else if (sci_get_lines_selected(doc_list[idx].sci) == 0 && use_current_word)
 
3331
        else if (sci_get_lines_selected(editor->sci) == 0 && use_current_word)
2774
3332
        {       /* use the word at current cursor position */
2775
3333
                gchar word[GEANY_MAX_WORD_LENGTH];
2776
3334
 
2777
 
                editor_find_current_word(doc_list[idx].sci, -1, word, sizeof(word), wordchars);
 
3335
                editor_find_current_word(editor, -1, word, sizeof(word), wordchars);
2778
3336
                if (word[0] != '\0')
2779
3337
                        s = g_strdup(word);
2780
3338
        }
2785
3343
/* Note: Usually the line should be made visible (not folded) before calling this.
2786
3344
 * Returns: TRUE if line is/will be displayed to the user, or FALSE if it is
2787
3345
 * outside the view. */
2788
 
gboolean editor_line_in_view(ScintillaObject *sci, gint line)
 
3346
gboolean editor_line_in_view(GeanyEditor *editor, gint line)
2789
3347
{
2790
3348
        gint vis1, los;
2791
3349
 
2792
 
        line = SSM(sci, SCI_VISIBLEFROMDOCLINE, line, 0);       /* convert to visible line number */
2793
 
        vis1 = SSM(sci, SCI_GETFIRSTVISIBLELINE, 0, 0);
2794
 
        los = SSM(sci, SCI_LINESONSCREEN, 0, 0);
 
3350
        if (editor == NULL)
 
3351
                return FALSE;
 
3352
 
 
3353
        /* If line is wrapped the result may occur on another virtual line than the first and may be
 
3354
         * still hidden, so increase the line number to check for the next document line */
 
3355
        if (SSM(editor->sci, SCI_WRAPCOUNT, line, 0) > 1)
 
3356
                line++;
 
3357
 
 
3358
        line = SSM(editor->sci, SCI_VISIBLEFROMDOCLINE, line, 0);       /* convert to visible line number */
 
3359
        vis1 = SSM(editor->sci, SCI_GETFIRSTVISIBLELINE, 0, 0);
 
3360
        los = SSM(editor->sci, SCI_LINESONSCREEN, 0, 0);
2795
3361
 
2796
3362
        return (line >= vis1 && line < vis1 + los);
2797
3363
}
2799
3365
 
2800
3366
/* If the current line is outside the current view window, scroll the line
2801
3367
 * so it appears at percent_of_view. */
2802
 
void editor_display_current_line(gint idx, gfloat percent_of_view)
 
3368
void editor_display_current_line(GeanyEditor *editor, gfloat percent_of_view)
2803
3369
{
2804
 
        ScintillaObject *sci = doc_list[idx].sci;
2805
 
        gint line = sci_get_current_line(sci);
 
3370
        gint line;
 
3371
 
 
3372
        if (editor == NULL)
 
3373
                return;
 
3374
 
 
3375
        line = sci_get_current_line(editor->sci);
2806
3376
 
2807
3377
        /* unfold maybe folded results */
2808
 
        sci_ensure_line_is_visible(doc_list[idx].sci, line);
 
3378
        sci_ensure_line_is_visible(editor->sci, line);
2809
3379
 
2810
3380
        /* scroll the line if it's off screen */
2811
 
        if (! editor_line_in_view(sci, line))
2812
 
                doc_list[idx].scroll_percent = percent_of_view;
2813
 
}
2814
 
 
 
3381
        if (! editor_line_in_view(editor, line))
 
3382
                editor->scroll_percent = percent_of_view;
 
3383
}
 
3384
 
 
3385
 
 
3386
/**
 
3387
 *  Deletes all currently set indicators in the @a editor window.
 
3388
 *  Error indicators (red squiggly underlines) and usual line markers are removed.
 
3389
 *
 
3390
 *  @param editor The editor to operate on.
 
3391
 **/
 
3392
void editor_clear_indicators(GeanyEditor *editor)
 
3393
{
 
3394
        glong last_pos;
 
3395
 
 
3396
        g_return_if_fail(editor != NULL);
 
3397
 
 
3398
        last_pos = sci_get_length(editor->sci);
 
3399
        if (last_pos > 0)
 
3400
                sci_indicator_clear(editor->sci, 0, last_pos);
 
3401
 
 
3402
        sci_marker_delete_all(editor->sci, 0);  /* remove the yellow error line marker */
 
3403
}
 
3404
 
 
3405
 
 
3406
/**
 
3407
 *  This is a convenience function for editor_set_indicator(). It sets an error indicator
 
3408
 *  (red squiggly underline) on the whole given line.
 
3409
 *  Whitespace at the start and the end of the line is not marked.
 
3410
 *
 
3411
 *  @param editor The editor to operate on.
 
3412
 *  @param line The line number which should be marked.
 
3413
 **/
 
3414
void editor_set_indicator_on_line(GeanyEditor *editor, gint line)
 
3415
{
 
3416
        gint start, end;
 
3417
        guint i = 0, len;
 
3418
        gchar *linebuf;
 
3419
 
 
3420
        if (editor == NULL)
 
3421
                return;
 
3422
 
 
3423
        start = sci_get_position_from_line(editor->sci, line);
 
3424
        end = sci_get_position_from_line(editor->sci, line + 1);
 
3425
 
 
3426
        /* skip blank lines */
 
3427
        if ((start + 1) == end ||
 
3428
                sci_get_line_length(editor->sci, line) == editor_get_eol_char_len(editor))
 
3429
                return;
 
3430
 
 
3431
        /* don't set the indicator on whitespace */
 
3432
        len = end - start;
 
3433
        linebuf = sci_get_line(editor->sci, line);
 
3434
 
 
3435
        while (isspace(linebuf[i])) i++;
 
3436
        while (len > 1 && len > i && isspace(linebuf[len-1]))
 
3437
        {
 
3438
                len--;
 
3439
                end--;
 
3440
        }
 
3441
        g_free(linebuf);
 
3442
 
 
3443
        editor_set_indicator(editor, start + i, end);
 
3444
}
 
3445
 
 
3446
 
 
3447
/**
 
3448
 *  Sets an error indicator (red squiggly underline) on the range specified by @c start and @c end.
 
3449
 *  No error checking or whitespace removal is performed, this should be done by the calling
 
3450
 *  function if necessary.
 
3451
 *
 
3452
 *  @param editor The editor to operate on.
 
3453
 *  @param start The starting position for the marker.
 
3454
 *  @param end The ending position for the marker.
 
3455
 **/
 
3456
void editor_set_indicator(GeanyEditor *editor, gint start, gint end)
 
3457
{
 
3458
        if (editor == NULL || start >= end)
 
3459
                return;
 
3460
 
 
3461
        sci_set_indicator(editor->sci, 0);
 
3462
        sci_indicator_fill(editor->sci, start, end - start);
 
3463
}
 
3464
 
 
3465
 
 
3466
/* Inserts the given colour (format should be #...), if there is a selection starting with 0x...
 
3467
 * the replacement will also start with 0x... */
 
3468
void editor_insert_color(GeanyEditor *editor, const gchar *colour)
 
3469
{
 
3470
        g_return_if_fail(editor != NULL);
 
3471
 
 
3472
        if (sci_has_selection(editor->sci))
 
3473
        {
 
3474
                gint start = sci_get_selection_start(editor->sci);
 
3475
                const gchar *replacement = colour;
 
3476
 
 
3477
                if (sci_get_char_at(editor->sci, start) == '0' &&
 
3478
                        sci_get_char_at(editor->sci, start + 1) == 'x')
 
3479
                {
 
3480
                        sci_set_selection_start(editor->sci, start + 2);
 
3481
                        sci_set_selection_end(editor->sci, start + 8);
 
3482
                        replacement++; /* skip the leading "0x" */
 
3483
                }
 
3484
                else if (sci_get_char_at(editor->sci, start - 1) == '#')
 
3485
                {       /* double clicking something like #00ffff may only select 00ffff because of wordchars */
 
3486
                        replacement++; /* so skip the '#' to only replace the colour value */
 
3487
                }
 
3488
                sci_replace_sel(editor->sci, replacement);
 
3489
        }
 
3490
        else
 
3491
                sci_add_text(editor->sci, colour);
 
3492
}
 
3493
 
 
3494
 
 
3495
const gchar *editor_get_eol_char_name(GeanyEditor *editor)
 
3496
{
 
3497
        gint mode = file_prefs.default_eol_character;
 
3498
 
 
3499
        if (editor != NULL)
 
3500
                mode = sci_get_eol_mode(editor->sci);
 
3501
 
 
3502
        switch (mode)
 
3503
        {
 
3504
                case SC_EOL_CRLF: return _("Win (CRLF)"); break;
 
3505
                case SC_EOL_CR: return _("Mac (CR)"); break;
 
3506
                default: return _("Unix (LF)"); break;
 
3507
        }
 
3508
}
 
3509
 
 
3510
 
 
3511
/* returns the end-of-line character(s) length of the specified editor */
 
3512
gint editor_get_eol_char_len(GeanyEditor *editor)
 
3513
{
 
3514
        gint mode = file_prefs.default_eol_character;
 
3515
 
 
3516
        if (editor != NULL)
 
3517
                mode = sci_get_eol_mode(editor->sci);
 
3518
 
 
3519
        switch (mode)
 
3520
        {
 
3521
                case SC_EOL_CRLF: return 2; break;
 
3522
                default: return 1; break;
 
3523
        }
 
3524
}
 
3525
 
 
3526
 
 
3527
/* returns the end-of-line character(s) of the specified editor */
 
3528
const gchar *editor_get_eol_char(GeanyEditor *editor)
 
3529
{
 
3530
        gint mode = file_prefs.default_eol_character;
 
3531
 
 
3532
        if (editor != NULL)
 
3533
                mode = sci_get_eol_mode(editor->sci);
 
3534
 
 
3535
        switch (mode)
 
3536
        {
 
3537
                case SC_EOL_CRLF: return "\r\n"; break;
 
3538
                case SC_EOL_CR: return "\r"; break;
 
3539
                default: return "\n"; break;
 
3540
        }
 
3541
}
 
3542
 
 
3543
 
 
3544
static void fold_all(GeanyEditor *editor, gboolean want_fold)
 
3545
{
 
3546
        gint lines, first, i;
 
3547
 
 
3548
        if (editor == NULL || ! editor_prefs.folding)
 
3549
                return;
 
3550
 
 
3551
        lines = sci_get_line_count(editor->sci);
 
3552
        first = sci_get_first_visible_line(editor->sci);
 
3553
 
 
3554
        for (i = 0; i < lines; i++)
 
3555
        {
 
3556
                gint level = sci_get_fold_level(editor->sci, i);
 
3557
                if (level & SC_FOLDLEVELHEADERFLAG)
 
3558
                {
 
3559
                        if (sci_get_fold_expanded(editor->sci, i) == want_fold)
 
3560
                                        sci_toggle_fold(editor->sci, i);
 
3561
                }
 
3562
        }
 
3563
        editor_scroll_to_line(editor, first, 0.0F);
 
3564
}
 
3565
 
 
3566
 
 
3567
void editor_unfold_all(GeanyEditor *editor)
 
3568
{
 
3569
        fold_all(editor, FALSE);
 
3570
}
 
3571
 
 
3572
 
 
3573
void editor_fold_all(GeanyEditor *editor)
 
3574
{
 
3575
        fold_all(editor, TRUE);
 
3576
}
 
3577
 
 
3578
 
 
3579
void editor_replace_tabs(GeanyEditor *editor)
 
3580
{
 
3581
        gint search_pos, pos_in_line, current_tab_true_length;
 
3582
        gint tab_len;
 
3583
        gchar *tab_str;
 
3584
        struct TextToFind ttf;
 
3585
 
 
3586
        if (editor == NULL)
 
3587
                return;
 
3588
 
 
3589
        sci_start_undo_action(editor->sci);
 
3590
        tab_len = sci_get_tab_width(editor->sci);
 
3591
        ttf.chrg.cpMin = 0;
 
3592
        ttf.chrg.cpMax = sci_get_length(editor->sci);
 
3593
        ttf.lpstrText = (gchar*) "\t";
 
3594
 
 
3595
        while (TRUE)
 
3596
        {
 
3597
                search_pos = sci_find_text(editor->sci, SCFIND_MATCHCASE, &ttf);
 
3598
                if (search_pos == -1)
 
3599
                        break;
 
3600
 
 
3601
                pos_in_line = sci_get_col_from_position(editor->sci,search_pos);
 
3602
                current_tab_true_length = tab_len - (pos_in_line % tab_len);
 
3603
                tab_str = g_strnfill(current_tab_true_length, ' ');
 
3604
                sci_target_start(editor->sci, search_pos);
 
3605
                sci_target_end(editor->sci, search_pos + 1);
 
3606
                sci_target_replace(editor->sci, tab_str, FALSE);
 
3607
                /* next search starts after replacement */
 
3608
                ttf.chrg.cpMin = search_pos + current_tab_true_length - 1;
 
3609
                /* update end of range now text has changed */
 
3610
                ttf.chrg.cpMax += current_tab_true_length - 1;
 
3611
                g_free(tab_str);
 
3612
        }
 
3613
        sci_end_undo_action(editor->sci);
 
3614
}
 
3615
 
 
3616
 
 
3617
/* Replaces all occurrences all spaces of the length of a given tab_width. */
 
3618
void editor_replace_spaces(GeanyEditor *editor)
 
3619
{
 
3620
        gint search_pos;
 
3621
        static gdouble tab_len_f = -1.0; /* keep the last used value */
 
3622
        gint tab_len;
 
3623
        struct TextToFind ttf;
 
3624
 
 
3625
        if (editor == NULL)
 
3626
                return;
 
3627
 
 
3628
        if (tab_len_f < 0.0)
 
3629
                tab_len_f = sci_get_tab_width(editor->sci);
 
3630
 
 
3631
        if (! dialogs_show_input_numeric(
 
3632
                _("Enter Tab Width"),
 
3633
                _("Enter the amount of spaces which should be replaced by a tab character."),
 
3634
                &tab_len_f, 1, 100, 1))
 
3635
        {
 
3636
                return;
 
3637
        }
 
3638
        tab_len = (gint) tab_len_f;
 
3639
 
 
3640
        sci_start_undo_action(editor->sci);
 
3641
        ttf.chrg.cpMin = 0;
 
3642
        ttf.chrg.cpMax = sci_get_length(editor->sci);
 
3643
        ttf.lpstrText = g_strnfill(tab_len, ' ');
 
3644
 
 
3645
        while (TRUE)
 
3646
        {
 
3647
                search_pos = sci_find_text(editor->sci, SCFIND_MATCHCASE, &ttf);
 
3648
                if (search_pos == -1)
 
3649
                        break;
 
3650
 
 
3651
                sci_target_start(editor->sci, search_pos);
 
3652
                sci_target_end(editor->sci, search_pos + tab_len);
 
3653
                sci_target_replace(editor->sci, "\t", FALSE);
 
3654
                ttf.chrg.cpMin = search_pos;
 
3655
                /* update end of range now text has changed */
 
3656
                ttf.chrg.cpMax -= tab_len - 1;
 
3657
        }
 
3658
        sci_end_undo_action(editor->sci);
 
3659
        g_free(ttf.lpstrText);
 
3660
}
 
3661
 
 
3662
 
 
3663
void editor_strip_line_trailing_spaces(GeanyEditor *editor, gint line)
 
3664
{
 
3665
        gint line_start = sci_get_position_from_line(editor->sci, line);
 
3666
        gint line_end = sci_get_line_end_position(editor->sci, line);
 
3667
        gint i = line_end - 1;
 
3668
        gchar ch = sci_get_char_at(editor->sci, i);
 
3669
 
 
3670
        while ((i >= line_start) && ((ch == ' ') || (ch == '\t')))
 
3671
        {
 
3672
                i--;
 
3673
                ch = sci_get_char_at(editor->sci, i);
 
3674
        }
 
3675
        if (i < (line_end-1))
 
3676
        {
 
3677
                sci_target_start(editor->sci, i + 1);
 
3678
                sci_target_end(editor->sci, line_end);
 
3679
                sci_target_replace(editor->sci, "", FALSE);
 
3680
        }
 
3681
}
 
3682
 
 
3683
 
 
3684
void editor_strip_trailing_spaces(GeanyEditor *editor)
 
3685
{
 
3686
        gint max_lines = sci_get_line_count(editor->sci);
 
3687
        gint line;
 
3688
 
 
3689
        sci_start_undo_action(editor->sci);
 
3690
 
 
3691
        for (line = 0; line < max_lines; line++)
 
3692
        {
 
3693
                editor_strip_line_trailing_spaces(editor, line);
 
3694
        }
 
3695
        sci_end_undo_action(editor->sci);
 
3696
}
 
3697
 
 
3698
 
 
3699
void editor_ensure_final_newline(GeanyEditor *editor)
 
3700
{
 
3701
        gint max_lines = sci_get_line_count(editor->sci);
 
3702
        gboolean append_newline = (max_lines == 1);
 
3703
        gint end_document = sci_get_position_from_line(editor->sci, max_lines);
 
3704
 
 
3705
        if (max_lines > 1)
 
3706
        {
 
3707
                append_newline = end_document > sci_get_position_from_line(editor->sci, max_lines - 1);
 
3708
        }
 
3709
        if (append_newline)
 
3710
        {
 
3711
                const gchar *eol = "\n";
 
3712
                switch (sci_get_eol_mode(editor->sci))
 
3713
                {
 
3714
                        case SC_EOL_CRLF:
 
3715
                                eol = "\r\n";
 
3716
                                break;
 
3717
                        case SC_EOL_CR:
 
3718
                                eol = "\r";
 
3719
                                break;
 
3720
                }
 
3721
                sci_insert_text(editor->sci, end_document, eol);
 
3722
        }
 
3723
}
 
3724
 
 
3725
 
 
3726
void editor_set_font(GeanyEditor *editor, const gchar *font)
 
3727
{
 
3728
        gint style, size;
 
3729
        gchar *font_name;
 
3730
        PangoFontDescription *pfd;
 
3731
 
 
3732
        g_return_if_fail(editor);
 
3733
 
 
3734
        pfd = pango_font_description_from_string(font);
 
3735
        size = pango_font_description_get_size(pfd) / PANGO_SCALE;
 
3736
        font_name = g_strdup_printf("!%s", pango_font_description_get_family(pfd));
 
3737
        pango_font_description_free(pfd);
 
3738
 
 
3739
        for (style = 0; style <= 127; style++)
 
3740
                sci_set_font(editor->sci, style, font_name, size);
 
3741
 
 
3742
        /* line number and braces */
 
3743
        sci_set_font(editor->sci, STYLE_LINENUMBER, font_name, size);
 
3744
        sci_set_font(editor->sci, STYLE_BRACELIGHT, font_name, size);
 
3745
        sci_set_font(editor->sci, STYLE_BRACEBAD, font_name, size);
 
3746
        g_free(font_name);
 
3747
 
 
3748
        /* zoom to 100% to prevent confusion */
 
3749
        sci_zoom_off(editor->sci);
 
3750
}
 
3751
 
 
3752
 
 
3753
void editor_set_line_wrapping(GeanyEditor *editor, gboolean wrap)
 
3754
{
 
3755
        g_return_if_fail(editor != NULL);
 
3756
 
 
3757
        editor->line_wrapping = wrap;
 
3758
        sci_set_lines_wrapped(editor->sci, wrap);
 
3759
}
 
3760
 
 
3761
 
 
3762
/* Also sets indent width, tab width. */
 
3763
void editor_set_indent_type(GeanyEditor *editor, GeanyIndentType type)
 
3764
{
 
3765
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
 
3766
        ScintillaObject *sci = editor->sci;
 
3767
        gboolean use_tabs = type != GEANY_INDENT_TYPE_SPACES;
 
3768
 
 
3769
        editor->indent_type = type;
 
3770
        sci_set_use_tabs(sci, use_tabs);
 
3771
 
 
3772
        if (type == GEANY_INDENT_TYPE_BOTH)
 
3773
                sci_set_tab_width(sci, iprefs->hard_tab_width);
 
3774
        else
 
3775
                sci_set_tab_width(sci, iprefs->width);
 
3776
        SSM(sci, SCI_SETINDENT, iprefs->width, 0);
 
3777
 
 
3778
        /* remove indent spaces on backspace, if using any spaces to indent */
 
3779
        SSM(sci, SCI_SETBACKSPACEUNINDENTS, type != GEANY_INDENT_TYPE_TABS, 0);
 
3780
}
 
3781
 
 
3782
 
 
3783
/* Move to position @a pos, switching to the document if necessary,
 
3784
 * setting a marker if @a mark is set. */
 
3785
gboolean editor_goto_pos(GeanyEditor *editor, gint pos, gboolean mark)
 
3786
{
 
3787
        gint page_num;
 
3788
 
 
3789
        g_return_val_if_fail(editor, FALSE);
 
3790
        if (pos < 0)
 
3791
                return FALSE;
 
3792
 
 
3793
        if (mark)
 
3794
        {
 
3795
                gint line = sci_get_line_from_position(editor->sci, pos);
 
3796
 
 
3797
                /* mark the tag with the yellow arrow */
 
3798
                sci_marker_delete_all(editor->sci, 0);
 
3799
                sci_set_marker_at_line(editor->sci, line, TRUE, 0);
 
3800
        }
 
3801
 
 
3802
        sci_goto_pos(editor->sci, pos, TRUE);
 
3803
        editor->scroll_percent = 0.25F;
 
3804
 
 
3805
        /* finally switch to the page */
 
3806
        page_num = gtk_notebook_page_num(GTK_NOTEBOOK(main_widgets.notebook), GTK_WIDGET(editor->sci));
 
3807
        gtk_notebook_set_current_page(GTK_NOTEBOOK(main_widgets.notebook), page_num);
 
3808
 
 
3809
        return TRUE;
 
3810
}
 
3811
 
 
3812
 
 
3813
static gboolean
 
3814
on_editor_scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
 
3815
{
 
3816
        /* Handle scroll events if Alt is pressed and scroll whole pages instead of a
 
3817
         * few lines only, maybe this could/should be done in Scintilla directly */
 
3818
        if (event->state & GDK_MOD1_MASK)
 
3819
        {
 
3820
                GeanyEditor *editor = user_data;
 
3821
                sci_cmd(editor->sci, (event->direction == GDK_SCROLL_DOWN) ? SCI_PAGEDOWN : SCI_PAGEUP);
 
3822
                return TRUE;
 
3823
        }
 
3824
 
 
3825
        return FALSE; /* let Scintilla handle all other cases */
 
3826
}
 
3827
 
 
3828
 
 
3829
static void editor_colourise(ScintillaObject *sci)
 
3830
{
 
3831
        sci_colourise(sci, 0, -1);
 
3832
 
 
3833
        /* now that the current document is colourised, fold points are now accurate,
 
3834
         * so force an update of the current function/tag. */
 
3835
        symbols_get_current_function(NULL, NULL);
 
3836
        ui_update_statusbar(NULL, -1);
 
3837
}
 
3838
 
 
3839
 
 
3840
static gboolean on_editor_expose_event(GtkWidget *widget, GdkEventExpose *event,
 
3841
                gpointer user_data)
 
3842
{
 
3843
        GeanyDocument *doc = user_data;
 
3844
 
 
3845
        if (doc->priv->colourise_needed)
 
3846
        {
 
3847
                editor_colourise(doc->editor->sci);
 
3848
                doc->priv->colourise_needed = FALSE;
 
3849
        }
 
3850
        return FALSE;   /* propagate event */
 
3851
}
 
3852
 
 
3853
 
 
3854
static void setup_sci_keys(ScintillaObject *sci)
 
3855
{
 
3856
        /* disable some Scintilla keybindings to be able to redefine them cleanly */
 
3857
        sci_clear_cmdkey(sci, 'A' | (SCMOD_CTRL << 16)); /* select all */
 
3858
        sci_clear_cmdkey(sci, 'D' | (SCMOD_CTRL << 16)); /* duplicate */
 
3859
        sci_clear_cmdkey(sci, 'T' | (SCMOD_CTRL << 16)); /* line transpose */
 
3860
        sci_clear_cmdkey(sci, 'T' | (SCMOD_CTRL << 16) | (SCMOD_SHIFT << 16)); /* line copy */
 
3861
        sci_clear_cmdkey(sci, 'L' | (SCMOD_CTRL << 16)); /* line cut */
 
3862
        sci_clear_cmdkey(sci, 'L' | (SCMOD_CTRL << 16) | (SCMOD_SHIFT << 16)); /* line delete */
 
3863
        sci_clear_cmdkey(sci, '/' | (SCMOD_CTRL << 16)); /* Previous word part */
 
3864
        sci_clear_cmdkey(sci, '\\' | (SCMOD_CTRL << 16)); /* Next word part */
 
3865
        sci_clear_cmdkey(sci, SCK_UP | (SCMOD_CTRL << 16)); /* scroll line up */
 
3866
        sci_clear_cmdkey(sci, SCK_DOWN | (SCMOD_CTRL << 16)); /* scroll line down */
 
3867
        sci_clear_cmdkey(sci, SCK_HOME);        /* line start */
 
3868
        sci_clear_cmdkey(sci, SCK_END); /* line end */
 
3869
 
 
3870
        if (editor_prefs.use_gtk_word_boundaries)
 
3871
        {
 
3872
                /* use GtkEntry-like word boundaries */
 
3873
                sci_assign_cmdkey(sci, SCK_RIGHT | (SCMOD_CTRL << 16), SCI_WORDRIGHTEND);
 
3874
                sci_assign_cmdkey(sci, SCK_RIGHT | (SCMOD_CTRL << 16) | (SCMOD_SHIFT << 16), SCI_WORDRIGHTENDEXTEND);
 
3875
                sci_assign_cmdkey(sci, SCK_DELETE | (SCMOD_CTRL << 16), SCI_DELWORDRIGHTEND);
 
3876
        }
 
3877
        sci_assign_cmdkey(sci, SCK_UP | (SCMOD_ALT << 16), SCI_LINESCROLLUP);
 
3878
        sci_assign_cmdkey(sci, SCK_DOWN | (SCMOD_ALT << 16), SCI_LINESCROLLDOWN);
 
3879
        sci_assign_cmdkey(sci, SCK_UP | (SCMOD_CTRL << 16), SCI_PARAUP);
 
3880
        sci_assign_cmdkey(sci, SCK_UP | (SCMOD_CTRL << 16) | (SCMOD_SHIFT << 16), SCI_PARAUPEXTEND);
 
3881
        sci_assign_cmdkey(sci, SCK_DOWN | (SCMOD_CTRL << 16), SCI_PARADOWN);
 
3882
        sci_assign_cmdkey(sci, SCK_DOWN | (SCMOD_CTRL << 16) | (SCMOD_SHIFT << 16), SCI_PARADOWNEXTEND);
 
3883
 
 
3884
        sci_clear_cmdkey(sci, SCK_BACK | (SCMOD_ALT << 16)); /* clear Alt-Backspace (Undo) */
 
3885
}
 
3886
 
 
3887
 
 
3888
/* Create new editor widget (scintilla).
 
3889
 * @note The @c "sci-notify" signal is connected separately. */
 
3890
/* TODO: change to use GeanyEditor */
 
3891
static ScintillaObject *create_new_sci(GeanyDocument *doc)
 
3892
{
 
3893
        ScintillaObject *sci;
 
3894
 
 
3895
        sci = SCINTILLA(scintilla_new());
 
3896
        scintilla_set_id(sci, doc->index);
 
3897
 
 
3898
        gtk_widget_show(GTK_WIDGET(sci));
 
3899
 
 
3900
        sci_set_codepage(sci, SC_CP_UTF8);
 
3901
        /*SSM(sci, SCI_SETWRAPSTARTINDENT, 4, 0);*/
 
3902
        /* disable scintilla provided popup menu */
 
3903
        sci_use_popup(sci, FALSE);
 
3904
 
 
3905
        setup_sci_keys(sci);
 
3906
 
 
3907
        sci_set_symbol_margin(sci, editor_prefs.show_markers_margin);
 
3908
        sci_set_lines_wrapped(sci, editor_prefs.line_wrapping);
 
3909
        sci_set_scrollbar_mode(sci, editor_prefs.show_scrollbars);
 
3910
        sci_set_caret_policy_x(sci, CARET_JUMPS | CARET_EVEN, 0);
 
3911
        /*sci_set_caret_policy_y(sci, CARET_JUMPS | CARET_EVEN, 0);*/
 
3912
        SSM(sci, SCI_AUTOCSETSEPARATOR, '\n', 0);
 
3913
        SSM(sci, SCI_SETSCROLLWIDTHTRACKING, 1, 0);
 
3914
 
 
3915
        /* only connect signals if this is for the document notebook, not split window */
 
3916
        if (doc->editor->sci == NULL)
 
3917
        {
 
3918
                g_signal_connect(sci, "button-press-event", G_CALLBACK(on_editor_button_press_event), doc);
 
3919
                g_signal_connect(sci, "scroll-event", G_CALLBACK(on_editor_scroll_event), doc->editor);
 
3920
                g_signal_connect(sci, "motion-notify-event", G_CALLBACK(on_motion_event), NULL);
 
3921
                g_signal_connect(sci, "expose-event", G_CALLBACK(on_editor_expose_event), doc);
 
3922
        }
 
3923
        return sci;
 
3924
}
 
3925
 
 
3926
 
 
3927
/** Create a new Scintilla @c GtkWidget based on the settings for @a editor.
 
3928
 * @param editor Editor settings.
 
3929
 * @return The new widget. */
 
3930
ScintillaObject *editor_create_widget(GeanyEditor *editor)
 
3931
{
 
3932
        const GeanyIndentPrefs *iprefs = get_default_indent_prefs();
 
3933
        ScintillaObject *old, *sci;
 
3934
 
 
3935
        /* temporarily change editor to use the new sci widget */
 
3936
        old = editor->sci;
 
3937
        sci = create_new_sci(editor->document);
 
3938
        editor->sci = sci;
 
3939
 
 
3940
        editor_set_indent_type(editor, iprefs->type);
 
3941
        editor_set_font(editor, interface_prefs.editor_font);
 
3942
 
 
3943
        /* if editor already had a widget, restore it */
 
3944
        if (old)
 
3945
                editor->sci = old;
 
3946
        return sci;
 
3947
}
 
3948
 
 
3949
 
 
3950
GeanyEditor *editor_create(GeanyDocument *doc)
 
3951
{
 
3952
        const GeanyIndentPrefs *iprefs = get_default_indent_prefs();
 
3953
        GeanyEditor *editor = g_new0(GeanyEditor, 1);
 
3954
 
 
3955
        editor->document = doc;
 
3956
        doc->editor = editor;   /* needed in case some editor functions/callbacks expect it */
 
3957
 
 
3958
        editor->auto_indent = (iprefs->auto_indent_mode != GEANY_AUTOINDENT_NONE);
 
3959
        editor->line_wrapping = editor_prefs.line_wrapping;
 
3960
        editor->scroll_percent = -1.0F;
 
3961
        editor->line_breaking = FALSE;
 
3962
 
 
3963
        editor->sci = editor_create_widget(editor);
 
3964
        return editor;
 
3965
}
 
3966
 
 
3967
 
 
3968
/* in case we need to free some fields in future */
 
3969
void editor_destroy(GeanyEditor *editor)
 
3970
{
 
3971
        g_free(editor);
 
3972
}
 
3973
 
 
3974
 
 
3975
void editor_init(void)
 
3976
{
 
3977
        static GeanyIndentPrefs indent_prefs;
 
3978
 
 
3979
        memset(&editor_prefs, 0, sizeof(GeanyEditorPrefs));
 
3980
        memset(&indent_prefs, 0, sizeof(GeanyIndentPrefs));
 
3981
        editor_prefs.indentation = &indent_prefs;
 
3982
}
 
3983
 
 
3984
 
 
3985
/** TODO: Should these be user-defined instead of hard-coded? */
 
3986
void editor_set_indentation_guides(GeanyEditor *editor)
 
3987
{
 
3988
        gint mode;
 
3989
        gint lexer;
 
3990
 
 
3991
        g_return_if_fail(editor != NULL);
 
3992
 
 
3993
        if (! editor_prefs.show_indent_guide)
 
3994
        {
 
3995
                sci_set_indentation_guides(editor->sci, SC_IV_NONE);
 
3996
                return;
 
3997
        }
 
3998
 
 
3999
        lexer = sci_get_lexer(editor->sci);
 
4000
        switch (lexer)
 
4001
        {
 
4002
                /* Lines added/removed are prefixed with +/- characters, so
 
4003
                 * those lines will not be shown with any indentation guides.
 
4004
                 * It can be distracting that only a few of lines in a diff/patch
 
4005
                 * file will show the guides. */
 
4006
                case SCLEX_DIFF:
 
4007
                        mode = SC_IV_NONE;
 
4008
                        break;
 
4009
 
 
4010
                /* These languages use indentation for control blocks; the "look forward" method works
 
4011
                 * best here */
 
4012
                case SCLEX_PYTHON:
 
4013
                case SCLEX_HASKELL:
 
4014
                case SCLEX_MAKEFILE:
 
4015
                case SCLEX_ASM:
 
4016
                case SCLEX_SQL:
 
4017
                case SCLEX_PROPERTIES:
 
4018
                case SCLEX_FORTRAN: /* Is this the best option for Fortran? */
 
4019
                case SCLEX_CAML:
 
4020
                        mode = SC_IV_LOOKFORWARD;
 
4021
                        break;
 
4022
 
 
4023
                /* C-like (structured) languages benefit from the "look both" method */
 
4024
                case SCLEX_CPP:
 
4025
                case SCLEX_HTML:
 
4026
                case SCLEX_XML:
 
4027
                case SCLEX_PERL:
 
4028
                case SCLEX_LATEX:
 
4029
                case SCLEX_LUA:
 
4030
                case SCLEX_PASCAL:
 
4031
                case SCLEX_RUBY:
 
4032
                case SCLEX_TCL:
 
4033
                case SCLEX_F77:
 
4034
                case SCLEX_CSS:
 
4035
                case SCLEX_BASH:
 
4036
                case SCLEX_VHDL:
 
4037
                case SCLEX_FREEBASIC:
 
4038
                case SCLEX_D:
 
4039
                case SCLEX_OMS:
 
4040
                        mode = SC_IV_LOOKBOTH;
 
4041
                        break;
 
4042
 
 
4043
                default:
 
4044
                        mode = SC_IV_REAL;
 
4045
                        break;
 
4046
        }
 
4047
 
 
4048
        sci_set_indentation_guides(editor->sci, mode);
 
4049
}
 
4050
 
 
4051
 
 
4052
/* Apply just the prefs that can change in the Preferences dialog */
 
4053
void editor_apply_update_prefs(GeanyEditor *editor)
 
4054
{
 
4055
        ScintillaObject *sci;
 
4056
 
 
4057
        g_return_if_fail(editor != NULL);
 
4058
 
 
4059
        sci = editor->sci;
 
4060
 
 
4061
        sci_set_mark_long_lines(sci, editor_prefs.long_line_type,
 
4062
                editor_prefs.long_line_column, editor_prefs.long_line_color);
 
4063
 
 
4064
        /* update indent width, tab width */
 
4065
        editor_set_indent_type(editor, editor->indent_type);
 
4066
        sci_set_tab_indents(sci, editor_prefs.use_tab_to_indent);
 
4067
 
 
4068
        sci_set_autoc_max_height(sci, editor_prefs.symbolcompletion_max_height);
 
4069
 
 
4070
        editor_set_indentation_guides(editor);
 
4071
 
 
4072
        sci_set_visible_white_spaces(sci, editor_prefs.show_white_space);
 
4073
        sci_set_visible_eols(sci, editor_prefs.show_line_endings);
 
4074
 
 
4075
        sci_set_folding_margin_visible(sci, editor_prefs.folding);
 
4076
 
 
4077
        /* (dis)allow scrolling past end of document */
 
4078
        sci_set_scroll_stop_at_last_line(sci, editor_prefs.scroll_stop_at_last_line);
 
4079
 
 
4080
        sci_assign_cmdkey(sci, SCK_HOME,
 
4081
                editor_prefs.smart_home_key ? SCI_VCHOMEWRAP : SCI_HOMEWRAP);
 
4082
        sci_assign_cmdkey(sci, SCK_END,  SCI_LINEENDWRAP);
 
4083
}
2815
4084