~ubuntu-branches/ubuntu/natty/geany/natty

« back to all changes in this revision

Viewing changes to src/editor.c

  • Committer: Bazaar Package Importer
  • Author(s): Chow Loong Jin
  • Date: 2010-08-07 03:23:12 UTC
  • mfrom: (1.4.3 upstream)
  • mto: This revision was merged to the branch mainline in revision 22.
  • Revision ID: james.westby@ubuntu.com-20100807032312-ot70ac9d50cn79we
Tags: upstream-0.19
ImportĀ upstreamĀ versionĀ 0.19

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 *      along with this program; if not, write to the Free Software
20
20
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
21
 *
22
 
 * $Id: editor.c 4630 2010-01-31 21:54:47Z eht16 $
 
22
 * $Id: editor.c 5015 2010-06-10 15:43:50Z ntrel $
23
23
 */
24
24
 
25
25
/**
44
44
#include "SciLexer.h"
45
45
#include "geany.h"
46
46
 
 
47
#ifdef HAVE_REGEX_H
 
48
# include <regex.h>
 
49
#else
 
50
# include "gnuregex.h"
 
51
#endif
 
52
 
47
53
#include "support.h"
48
54
#include "editor.h"
49
55
#include "document.h"
59
65
#include "keybindings.h"
60
66
#include "project.h"
61
67
#include "projectprivate.h"
62
 
#include "queue.h"
63
 
 
64
 
 
65
 
/* Note: Avoid using SSM in files not related to scintilla, use sciwrappers.h instead. */
 
68
#include "main.h"
 
69
 
 
70
 
 
71
/* Note: use sciwrappers.h instead where possible.
 
72
 * Do not use SSM in files unrelated to scintilla. */
66
73
#define SSM(s, m, w, l) scintilla_send_message(s, m, w, l)
67
74
 
68
75
 
69
 
static GeanyQueue *snippet_queue = NULL;
 
76
static GHashTable *snippet_hash = NULL;
 
77
static GQueue *snippet_offsets = NULL;
70
78
static gint snippet_cursor_insert_pos;
71
79
 
72
80
/* holds word under the mouse or keyboard cursor */
87
95
        ScintillaObject *sci;
88
96
} calltip = {NULL, FALSE, NULL, 0, 0, NULL};
89
97
 
 
98
static enum
 
99
{
 
100
        AUTOC_CANCELLED,
 
101
        AUTOC_SCOPE,
 
102
        AUTOC_TAGS,
 
103
        AUTOC_DOC_WORDS
 
104
} autocompletion_mode = AUTOC_CANCELLED;
 
105
 
90
106
static gchar indent[100];
91
107
 
92
108
 
100
116
static void auto_table(GeanyEditor *editor, gint pos);
101
117
static void close_block(GeanyEditor *editor, gint pos);
102
118
static void editor_highlight_braces(GeanyEditor *editor, gint cur_pos);
103
 
static void editor_auto_latex(GeanyEditor *editor, gint pos);
 
119
static void read_current_word(GeanyEditor *editor, gint pos, gchar *word, size_t wordlen,
 
120
                const gchar *wc, gboolean stem);
 
121
static gsize count_indent_size(GeanyEditor *editor, const gchar *base_indent);
104
122
 
105
123
 
106
124
void editor_snippets_free(void)
107
125
{
108
 
        g_hash_table_destroy(editor_prefs.snippets);
109
 
        queue_destroy(snippet_queue);
 
126
        g_hash_table_destroy(snippet_hash);
 
127
        g_queue_free(snippet_offsets);
110
128
}
111
129
 
112
130
 
121
139
        GKeyFile *userconfig = g_key_file_new();
122
140
        GHashTable *tmp;
123
141
 
124
 
        snippet_queue = queue_init();
 
142
        snippet_offsets = g_queue_new();
125
143
 
126
144
        sysconfigfile = g_strconcat(app->datadir, G_DIR_SEPARATOR_S, "snippets.conf", NULL);
127
145
        userconfigfile = g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "snippets.conf", NULL);
136
154
        g_key_file_load_from_file(userconfig, userconfigfile, G_KEY_FILE_NONE, NULL);
137
155
 
138
156
        /* keys are strings, values are GHashTables, so use g_free and g_hash_table_destroy */
139
 
        editor_prefs.snippets =
 
157
        snippet_hash =
140
158
                g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_hash_table_destroy);
141
159
 
142
160
        /* first read all globally defined auto completions */
146
164
                keys_sys = g_key_file_get_keys(sysconfig, groups_sys[i], &len_keys, NULL);
147
165
                /* create new hash table for the read section (=> filetype) */
148
166
                tmp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
149
 
                g_hash_table_insert(editor_prefs.snippets, g_strdup(groups_sys[i]), tmp);
 
167
                g_hash_table_insert(snippet_hash, g_strdup(groups_sys[i]), tmp);
150
168
 
151
169
                for (j = 0; j < len_keys; j++)
152
170
                {
162
180
        {
163
181
                keys_user = g_key_file_get_keys(userconfig, groups_user[i], &len_keys, NULL);
164
182
 
165
 
                tmp = g_hash_table_lookup(editor_prefs.snippets, groups_user[i]);
 
183
                tmp = g_hash_table_lookup(snippet_hash, groups_user[i]);
166
184
                if (tmp == NULL)
167
185
                {       /* new key found, create hash table */
168
186
                        tmp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
169
 
                        g_hash_table_insert(editor_prefs.snippets, g_strdup(groups_user[i]), tmp);
 
187
                        g_hash_table_insert(snippet_hash, g_strdup(groups_user[i]), tmp);
170
188
                }
171
189
                for (j = 0; j < len_keys; j++)
172
190
                {
270
288
}
271
289
 
272
290
 
 
291
gint editor_get_long_line_type(void)
 
292
{
 
293
        if (app->project)
 
294
                switch (app->project->long_line_behaviour)
 
295
                {
 
296
                        case 0: /* marker disabled */
 
297
                                return 2;
 
298
                        case 1: /* use global settings */
 
299
                                break;
 
300
                        case 2: /* custom (enabled) */
 
301
                                return editor_prefs.long_line_global_type;
 
302
                }
 
303
 
 
304
        if (!editor_prefs.long_line_global_enabled)
 
305
                return 2;
 
306
        else
 
307
                return editor_prefs.long_line_global_type;
 
308
}
 
309
 
 
310
 
 
311
gint editor_get_long_line_column(void)
 
312
{
 
313
        if (app->project && app->project->long_line_behaviour != 1 /* use global settings */)
 
314
                return app->project->long_line_column;
 
315
        else
 
316
                return editor_prefs.long_line_global_column;
 
317
}
 
318
 
 
319
 
273
320
void editor_toggle_fold(GeanyEditor *editor, gint line, gint modifiers)
274
321
{
275
322
        ScintillaObject *sci;
494
541
}
495
542
 
496
543
 
497
 
typedef struct
498
 
{
499
 
        gint message;
500
 
        gint pos;
501
 
        gchar *text;
502
 
} CalltipReshowInfo;
503
 
 
504
 
 
505
544
static gboolean reshow_calltip(gpointer data)
506
545
{
507
 
        CalltipReshowInfo *cri = data;
508
546
        GeanyDocument *doc;
509
547
 
510
548
        g_return_val_if_fail(calltip.sci != NULL, FALSE);
517
555
                /* we use the position where the calltip was previously started as SCI_GETCURRENTPOS
518
556
                 * may be completely wrong in case the user cancelled the auto completion with the mouse */
519
557
                SSM(calltip.sci, SCI_CALLTIPSHOW, calltip.pos, (sptr_t) calltip.text);
520
 
 
521
 
                /* now autocompletion has been cancelled by SCI_CALLTIPSHOW, so do it manually */
522
 
                if (cri->message == SCN_AUTOCSELECTION)
523
 
                {
524
 
                        gint pos = SSM(calltip.sci, SCI_GETCURRENTPOS, 0, 0);
525
 
 
526
 
                        sci_set_selection_start(calltip.sci, cri->pos);
527
 
                        sci_set_selection_end(calltip.sci, pos);
528
 
                        sci_replace_sel(calltip.sci, "");       /* clear root of word */
529
 
                        SSM(calltip.sci, SCI_INSERTTEXT, cri->pos, (sptr_t) cri->text);
530
 
                        sci_goto_pos(calltip.sci, cri->pos + strlen(cri->text), FALSE);
531
 
                }
532
558
        }
533
 
        g_free(cri->text);
534
 
        g_free(cri);
535
 
 
536
559
        return FALSE;
537
560
}
538
561
 
541
564
{
542
565
        if (calltip.set)
543
566
        {
544
 
                CalltipReshowInfo *cri = g_new0(CalltipReshowInfo, 1);
545
 
                cri->message = nt->nmhdr.code;
546
 
                cri->message = nt->lParam;
547
 
                cri->text = g_strdup(nt->text);
548
567
                /* delay the reshow of the calltip window to make sure it is actually displayed,
549
568
                 * without it might be not visible on SCN_AUTOCCANCEL */
550
 
                g_idle_add(reshow_calltip, cri);
 
569
                g_idle_add(reshow_calltip, NULL);
551
570
        }
552
571
}
553
572
 
 
573
 
554
574
static void autocomplete_scope(GeanyEditor *editor)
555
575
{
556
576
        ScintillaObject *sci = editor->sci;
592
612
                tags = tm_workspace_find_scope_members(obj ? obj->tags_array : NULL,
593
613
                        name, TRUE, FALSE);
594
614
                if (tags)
 
615
                {
 
616
                        autocompletion_mode = AUTOC_SCOPE;
595
617
                        show_tags_list(editor, tags, 0);
 
618
                }
596
619
        }
597
620
}
598
621
 
710
733
                        {
711
734
                                if (doExpand)
712
735
                                {
713
 
                                        if (!SSM(sci, SCI_GETFOLDEXPANDED, *line, 0))
 
736
                                        if (!sci_get_fold_expanded(sci, *line))
714
737
                                                SSM(sci, SCI_SETFOLDEXPANDED, *line, 1);
715
738
                                        expand(sci, line, TRUE, force, visLevels - 1, -1);
716
739
                                }
741
764
        }
742
765
        else if (levelPrev & SC_FOLDLEVELHEADERFLAG)
743
766
        {
744
 
                if (! SSM(sci, SCI_GETFOLDEXPANDED, line, 0))
 
767
                if (! sci_get_fold_expanded(sci, line))
745
768
                {       /* Removing the fold from one that has been contracted so should expand
746
769
                         * otherwise lines are left invisible with no way to make them visible */
747
770
                        SSM(sci, SCI_SETFOLDEXPANDED, line, 1);
752
775
                        ((levelPrev & SC_FOLDLEVELNUMBERMASK) > (levelNow & SC_FOLDLEVELNUMBERMASK)))
753
776
        {
754
777
                /* See if should still be hidden */
755
 
                gint parentLine = SSM(sci, SCI_GETFOLDPARENT, line, 0);
 
778
                gint parentLine = sci_get_fold_parent(sci, line);
756
779
                if (parentLine < 0)
757
780
                {
758
781
                        SSM(sci, SCI_SHOWLINES, line, line);
759
782
                }
760
 
                else if (SSM(sci, SCI_GETFOLDEXPANDED, parentLine, 0) &&
761
 
                                SSM(sci, SCI_GETLINEVISIBLE, parentLine, 0))
 
783
                else if (sci_get_fold_expanded(sci, parentLine) &&
 
784
                                sci_get_line_is_visible(sci, parentLine))
762
785
                {
763
786
                        SSM(sci, SCI_SHOWLINES, line, line);
764
787
                }
797
820
}
798
821
 
799
822
 
 
823
static void partial_complete(ScintillaObject *sci, const gchar *text)
 
824
{
 
825
        gint pos = sci_get_current_position(sci);
 
826
 
 
827
        sci_insert_text(sci, pos, text);
 
828
        sci_set_current_position(sci, pos + strlen(text), TRUE);
 
829
}
 
830
 
 
831
 
 
832
/* Complete the next word part from @a entry */
 
833
static gboolean check_partial_completion(GeanyEditor *editor, const gchar *entry)
 
834
{
 
835
        gchar *stem, *ptr, *text = utils_strdupa(entry);
 
836
 
 
837
        read_current_word(editor, -1, current_word, sizeof current_word, NULL, TRUE);
 
838
        stem = current_word;
 
839
        if (strstr(text, stem) != text)
 
840
                return FALSE;   /* shouldn't happen */
 
841
        if (strlen(text) <= strlen(stem))
 
842
                return FALSE;
 
843
 
 
844
        text += strlen(stem); /* skip stem */
 
845
        ptr = strstr(text + 1, "_");
 
846
        if (ptr)
 
847
        {
 
848
                ptr[1] = '\0';
 
849
                partial_complete(editor->sci, text);
 
850
                return TRUE;
 
851
        }
 
852
        else
 
853
        {
 
854
                /* CamelCase */
 
855
                foreach_str(ptr, text + 1)
 
856
                {
 
857
                        if (!ptr[0])
 
858
                                break;
 
859
                        if (g_ascii_isupper(*ptr) && g_ascii_islower(ptr[1]))
 
860
                        {
 
861
                                ptr[0] = '\0';
 
862
                                partial_complete(editor->sci, text);
 
863
                                return TRUE;
 
864
                        }
 
865
                }
 
866
        }
 
867
        return FALSE;
 
868
}
 
869
 
 
870
 
800
871
/* Callback for the "sci-notify" signal to emit a "editor-notify" signal.
801
872
 * Plugins can connect to the "editor-notify" signal. */
802
873
void editor_sci_notify_cb(G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gint scn,
820
891
        switch (nt->nmhdr.code)
821
892
        {
822
893
                case SCN_SAVEPOINTLEFT:
823
 
                {
824
894
                        document_set_text_changed(doc, TRUE);
825
895
                        break;
826
 
                }
 
896
 
827
897
                case SCN_SAVEPOINTREACHED:
828
 
                {
829
898
                        document_set_text_changed(doc, FALSE);
830
899
                        break;
831
 
                }
 
900
 
832
901
                case SCN_MODIFYATTEMPTRO:
833
 
                {
834
902
                        utils_beep();
835
903
                        break;
836
 
                }
 
904
 
837
905
                case SCN_MARGINCLICK:
838
906
                        on_margin_click(editor, nt);
839
907
                        break;
843
911
                        break;
844
912
 
845
913
                case SCN_MODIFIED:
846
 
                {
847
914
                        if (editor_prefs.show_linenumber_margin && (nt->modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) && nt->linesAdded)
848
915
                        {
849
916
                                /* automatically adjust Scintilla's line numbers margin width */
850
917
                                auto_update_margin_width(editor);
851
918
                        }
852
 
 
853
919
                        if (nt->modificationType & SC_STARTACTION && ! ignore_callback)
854
920
                        {
855
921
                                /* get notified about undo changes */
861
927
                                fold_changed(sci, nt->line, nt->foldLevelNow, nt->foldLevelPrev);
862
928
                        }
863
929
                        break;
864
 
                }
 
930
 
865
931
                case SCN_CHARADDED:
866
932
                        on_char_added(editor, nt);
867
933
                        break;
868
934
 
869
935
                case SCN_USERLISTSELECTION:
870
 
                {
871
936
                        if (nt->listType == 1)
872
937
                        {
873
 
                                SSM(sci, SCI_ADDTEXT, strlen(nt->text), (sptr_t) nt->text);
 
938
                                sci_add_text(sci, nt->text);
874
939
                        }
875
940
                        break;
876
 
                }
 
941
 
877
942
                case SCN_AUTOCSELECTION:
878
943
                        if (g_str_equal(nt->text, "..."))
879
944
                        {
883
948
                        }
884
949
                        /* fall through */
885
950
                case SCN_AUTOCCANCELLED:
886
 
                {
887
951
                        /* now that autocomplete is finishing or was cancelled, reshow calltips
888
952
                         * if they were showing */
 
953
                        autocompletion_mode = AUTOC_CANCELLED;
889
954
                        request_reshowing_calltip(nt);
890
955
                        break;
891
 
                }
 
956
 
892
957
#ifdef GEANY_DEBUG
893
958
                case SCN_STYLENEEDED:
894
 
                {
895
959
                        geany_debug("style");
896
960
                        break;
897
 
                }
898
961
#endif
899
962
                case SCN_NEEDSHOWN:
900
 
                {
901
963
                        ensure_range_visible(sci, nt->position, nt->position + nt->length, FALSE);
902
964
                        break;
903
 
                }
 
965
 
904
966
                case SCN_URIDROPPED:
905
 
                {
906
967
                        if (nt->text != NULL)
907
968
                        {
908
969
                                document_open_file_list(nt->text, -1);
909
970
                        }
910
971
                        break;
911
 
                }
 
972
 
912
973
                case SCN_CALLTIPCLICK:
913
 
                {
914
974
                        if (nt->position > 0)
915
975
                        {
916
976
                                switch (nt->position)
925
985
                                editor_show_calltip(editor, -1);
926
986
                        }
927
987
                        break;
928
 
                }
 
988
 
 
989
                case SCN_ZOOM:
 
990
                        /* recalculate line margin width */
 
991
                        sci_set_line_numbers(sci, editor_prefs.show_linenumber_margin, 0);
 
992
                        break;
929
993
        }
930
994
        /* we always return FALSE here to let plugins handle the event too */
931
995
        return FALSE;
987
1051
}
988
1052
 
989
1053
 
990
 
/** Get the indentation prefs for the editor.
 
1054
/** Gets the indentation prefs for the editor.
991
1055
 * In future, the prefs might be different according to project or filetype.
992
1056
 * @warning Always get a fresh result instead of keeping a pointer to it if the editor
993
1057
 * settings may have changed, or if this function has been called for a different @a editor.
1020
1084
static void on_new_line_added(GeanyEditor *editor)
1021
1085
{
1022
1086
        ScintillaObject *sci = editor->sci;
1023
 
        gint pos = sci_get_current_position(sci);
1024
1087
        gint line = sci_get_current_line(sci);
1025
1088
 
1026
1089
        /* simple indentation */
1034
1097
                auto_multiline(editor, line);
1035
1098
        }
1036
1099
 
1037
 
        if (editor_prefs.complete_snippets)
1038
 
        {
1039
 
                editor_auto_latex(editor, pos);
1040
 
        }
1041
 
 
1042
1100
        if (editor_prefs.newline_strip)
1043
1101
        {       /* strip the trailing spaces on the previous line */
1044
1102
                editor_strip_line_trailing_spaces(editor, line - 1);
1048
1106
 
1049
1107
static gboolean lexer_has_braces(ScintillaObject *sci)
1050
1108
{
1051
 
        gint lexer = SSM(sci, SCI_GETLEXER, 0, 0);
 
1109
        gint lexer = sci_get_lexer(sci);
1052
1110
 
1053
1111
        switch (lexer)
1054
1112
        {
1298
1356
        line = sci_get_line_from_position(sci, pos);
1299
1357
        line_len = sci_get_line_length(sci, line);
1300
1358
        /* set eol_char_len to 0 if on last line, because there is no EOL char */
1301
 
        eol_char_len = (line == (SSM(sci, SCI_GETLINECOUNT, 0, 0) - 1)) ? 0 :
 
1359
        eol_char_len = (line == (sci_get_line_count(sci) - 1)) ? 0 :
1302
1360
                                                                editor_get_eol_char_len(editor);
1303
1361
 
1304
1362
        /* check that the line is empty, to not kill text in the line */
1329
1387
                        text = g_strconcat(ind, "}", NULL);
1330
1388
                        line_start = sci_get_position_from_line(sci, line);
1331
1389
                        sci_set_anchor(sci, line_start);
1332
 
                        SSM(sci, SCI_REPLACESEL, 0, (sptr_t) text);
 
1390
                        sci_replace_sel(sci, text);
1333
1391
                        g_free(text);
1334
1392
                        g_free(ind);
1335
1393
                        return;
1354
1412
 * position can be -1, then the current position is used.
1355
1413
 * wc are the wordchars to use, if NULL, GEANY_WORDCHARS will be used */
1356
1414
static void read_current_word(GeanyEditor *editor, gint pos, gchar *word, size_t wordlen,
1357
 
                                                          const gchar *wc, gboolean stem)
 
1415
                const gchar *wc, gboolean stem)
1358
1416
{
1359
1417
        gint line, line_start, startword, endword;
1360
1418
        gchar *chunk;
1458
1516
        gchar c;
1459
1517
        gint orig_pos = pos;
1460
1518
 
1461
 
        c = SSM(sci, SCI_GETCHARAT, pos, 0);
 
1519
        c = sci_get_char_at(sci, pos);
1462
1520
        while (pos >= 0 && pos > orig_pos - 300)
1463
1521
        {
1464
 
                c = SSM(sci, SCI_GETCHARAT, pos, 0);
 
1522
                c = sci_get_char_at(sci, pos);
1465
1523
                pos--;
1466
1524
                if (utils_is_opening_brace(c, editor_prefs.brace_match_ltgt))
1467
1525
                        return pos;
1476
1534
        gint brackets = 0;
1477
1535
        gint orig_pos = pos;
1478
1536
 
1479
 
        c = SSM(sci, SCI_GETCHARAT, pos, 0);
 
1537
        c = sci_get_char_at(sci, pos);
1480
1538
        while (pos > 0 && pos > orig_pos - 300)
1481
1539
        {
1482
 
                c = SSM(sci, SCI_GETCHARAT, pos, 0);
 
1540
                c = sci_get_char_at(sci, pos);
1483
1541
                if (c == ')') brackets++;
1484
1542
                else if (c == '(') brackets--;
1485
1543
                pos--;
1636
1694
 
1637
1695
        sci = editor->sci;
1638
1696
 
1639
 
        lexer = SSM(sci, SCI_GETLEXER, 0, 0);
 
1697
        lexer = sci_get_lexer(sci);
1640
1698
 
1641
1699
        if (pos == -1)
1642
1700
        {
1643
1701
                /* position of '(' is unknown, so go backwards from current position to find it */
1644
 
                pos = SSM(sci, SCI_GETCURRENTPOS, 0, 0);
 
1702
                pos = sci_get_current_position(sci);
1645
1703
                pos--;
1646
1704
                orig_pos = pos;
1647
1705
                pos = (lexer == SCLEX_LATEX) ? find_previous_brace(sci, pos) :
1651
1709
        }
1652
1710
 
1653
1711
        /* the style 1 before the brace (which may be highlighted) */
1654
 
        style = SSM(sci, SCI_GETSTYLEAT, pos - 1, 0);
 
1712
        style = sci_get_style_at(sci, pos - 1);
1655
1713
        if (! is_code_style(lexer, style))
1656
1714
                return FALSE;
1657
1715
 
1741
1799
        tags = tm_workspace_find(root, tm_tag_max_t, attrs, TRUE, doc->file_type->lang);
1742
1800
        if (tags)
1743
1801
        {
 
1802
                autocompletion_mode = AUTOC_TAGS;
1744
1803
                show_tags_list(editor, tags, rootlen);
1745
1804
                return tags->len > 0;
1746
1805
        }
1770
1829
 
1771
1830
 
1772
1831
/* Algorithm based on based on Scite's StartAutoCompleteWord() */
1773
 
static gboolean autocomplete_doc_word(GeanyEditor *editor, gchar *root, gsize rootlen)
 
1832
static GString *get_doc_words(ScintillaObject *sci, gchar *root, gsize rootlen)
1774
1833
{
1775
 
        ScintillaObject *sci = editor->sci;
1776
1834
        gchar *word;
1777
1835
        gint len, current, word_end;
1778
1836
        gint pos_find, flags;
1779
1837
        guint word_length;
1780
1838
        gsize nmatches = 0;
1781
 
        gboolean ret = FALSE;
1782
1839
        GString *words;
1783
1840
        struct Sci_TextToFind ttf;
1784
1841
 
1793
1850
        flags = SCFIND_WORDSTART | SCFIND_MATCHCASE;
1794
1851
 
1795
1852
        words = g_string_sized_new(256);
 
1853
        /* put space before first entry to make searching with strstr easy */
1796
1854
        g_string_append_c(words, ' ');
1797
1855
 
1798
1856
        /* search the whole document for the word root and collect results */
1821
1879
                                g_free(word);
1822
1880
 
1823
1881
                                if (nmatches == editor_prefs.autocompletion_max_entries)
1824
 
                                {
1825
 
                                        g_string_append(words, "... ");
1826
1882
                                        break;
1827
 
                                }
1828
1883
                        }
1829
1884
                }
1830
1885
                ttf.chrg.cpMin = word_end;
1835
1890
        {
1836
1891
                g_strdelimit(words->str, " ", '\n');
1837
1892
                words->str[words->len - 1] = '\0'; /* remove the trailing '\n' */
1838
 
                show_autocomplete(sci, rootlen, words->str + 1);
1839
 
                ret = TRUE;
 
1893
                return words;
1840
1894
        }
1841
 
        else
 
1895
        g_string_free(words, TRUE);
 
1896
        return NULL;
 
1897
}
 
1898
 
 
1899
 
 
1900
static gboolean autocomplete_doc_word(GeanyEditor *editor, gchar *root, gsize rootlen)
 
1901
{
 
1902
        ScintillaObject *sci = editor->sci;
 
1903
        GString *words;
 
1904
        GString *str;
 
1905
        gchar *ptr;
 
1906
        GSList *node, *list = NULL;
 
1907
 
 
1908
        words = get_doc_words(sci, root, rootlen);
 
1909
        if (!words)
 
1910
        {
1842
1911
                scintilla_send_message(sci, SCI_AUTOCCANCEL, 0, 0);
1843
 
 
 
1912
                autocompletion_mode = AUTOC_CANCELLED;
 
1913
                return FALSE;
 
1914
        }
 
1915
 
 
1916
        /* words are unsorted, make list of words */
 
1917
        foreach_str(ptr, words->str)
 
1918
        {
 
1919
                if (*ptr == '\n')
 
1920
                {
 
1921
                        list = g_slist_prepend(list, ptr + 1);
 
1922
                        /* terminate previous string in list */
 
1923
                        ptr[0] = 0x0;
 
1924
                        ptr++;
 
1925
                }
 
1926
        }
 
1927
        list = g_slist_sort(list, (GCompareFunc)utils_str_casecmp);
 
1928
 
 
1929
        str = g_string_sized_new(words->len);
 
1930
        foreach_slist(node, list)
 
1931
        {
 
1932
                g_string_append(str, node->data);
 
1933
                if (node->next)
 
1934
                        g_string_append_c(str, '\n');
 
1935
        }
 
1936
        if (g_slist_length(list) >= editor_prefs.autocompletion_max_entries)
 
1937
                g_string_append(str, "\n...");
 
1938
 
 
1939
        g_slist_free(list);
1844
1940
        g_string_free(words, TRUE);
1845
 
        return ret;
 
1941
 
 
1942
        autocompletion_mode = AUTOC_DOC_WORDS;
 
1943
        show_autocomplete(sci, rootlen, str->str);
 
1944
        g_string_free(str, TRUE);
 
1945
        return TRUE;
1846
1946
}
1847
1947
 
1848
1948
 
1852
1952
        gchar *linebuf, *root;
1853
1953
        ScintillaObject *sci;
1854
1954
        gboolean ret = FALSE;
1855
 
        gchar *wordchars;
 
1955
        const gchar *wordchars;
1856
1956
        GeanyFiletype *ft;
1857
1957
 
1858
1958
        if (! editor_prefs.auto_complete_symbols && ! force)
1874
1974
        line_pos = pos - line_start - 1;
1875
1975
        current = pos - line_start;
1876
1976
        startword = current;
1877
 
        lexer = SSM(sci, SCI_GETLEXER, 0, 0);
1878
 
        style = SSM(sci, SCI_GETSTYLEAT, pos - 2, 0);
 
1977
        lexer = sci_get_lexer(sci);
 
1978
        style = sci_get_style_at(sci, pos - 2);
1879
1979
 
1880
1980
        /* don't autocomplete in comments and strings */
1881
1981
        if (!force && !is_code_style(lexer, style))
1899
1999
        root = linebuf + startword;
1900
2000
        rootlen = current - startword;
1901
2001
 
1902
 
        if (rootlen > 0)
 
2002
        if (rootlen > 0 && autocompletion_mode != AUTOC_SCOPE)
1903
2003
        {
1904
2004
                if (autocomplete_check_for_html(ft->id, style))
1905
2005
                {
1938
2038
}
1939
2039
 
1940
2040
 
1941
 
static void editor_auto_latex(GeanyEditor *editor, gint pos)
1942
 
{
1943
 
        ScintillaObject *sci;
1944
 
 
1945
 
        g_return_if_fail(editor != NULL);
1946
 
 
1947
 
        if (editor->document->file_type->id != GEANY_FILETYPES_LATEX)
1948
 
                return;
1949
 
 
1950
 
        sci = editor->sci;
1951
 
 
1952
 
        if (sci_get_char_at(sci, pos - 1 - editor_get_eol_char_len(editor)) == '}')
1953
 
        {
1954
 
                gchar *eol, *buf, *construct;
1955
 
                gchar env[50];
1956
 
                gint line = sci_get_line_from_position(sci, pos - 2);
1957
 
                gint line_len = sci_get_line_length(sci, line);
1958
 
                gint i, start;
1959
 
 
1960
 
                /* get the line */
1961
 
                buf = sci_get_line(sci, line);
1962
 
 
1963
 
                /* get to the first non-blank char (some kind of ltrim()) */
1964
 
                start = 0;
1965
 
                while (isspace(buf[start]) && buf[start] != '\0')
1966
 
                        start++;
1967
 
 
1968
 
                /* check for begin */
1969
 
                if (strncmp(buf + start, "\\begin", 6) == 0)
1970
 
                {
1971
 
                        gchar full_cmd[15];
1972
 
                        guint j = 0;
1973
 
 
1974
 
                        /* take also "\begingroup" (or whatever there can be) and
1975
 
                         * append "\endgroup" and so on. */
1976
 
                        i = start + 6;
1977
 
                        while (i < line_len && buf[i] != '{' && j < (sizeof(full_cmd) - 1))
1978
 
                        {       /* copy all between "\begin" and "{" to full_cmd */
1979
 
                                full_cmd[j] = buf[i];
1980
 
                                i++;
1981
 
                                j++;
1982
 
                        }
1983
 
                        full_cmd[j] = '\0';
1984
 
 
1985
 
                        /* go through the line and get the environment */
1986
 
                        for (i = start + j; i < line_len; i++)
1987
 
                        {
1988
 
                                if (buf[i] == '{')
1989
 
                                {
1990
 
                                        j = 0;
1991
 
                                        i++;
1992
 
                                        while (buf[i] != '}' && j < (sizeof(env) - 1))
1993
 
                                        {       /* this could be done in a shorter way, but so it remains readable ;-) */
1994
 
                                                env[j] = buf[i];
1995
 
                                                j++;
1996
 
                                                i++;
1997
 
                                        }
1998
 
                                        env[j] = '\0';
1999
 
                                        break;
2000
 
                                }
2001
 
                        }
2002
 
 
2003
 
                        /* Search whether the environment is closed within the next
2004
 
                         * lines. We assume, no \end is needed in such cases */
2005
 
                        /* TODO using sci_find_text() should be way faster than getting
2006
 
                         *      the line buffer and performing string comparisons */
2007
 
                        for (i = 1; i < 5; i++)
2008
 
                        {
2009
 
                                gchar *tmp;
2010
 
                                gchar *end_construct;
2011
 
                                tmp = sci_get_line(sci, line + i);
2012
 
                                /* Again get to the first non-blank char */
2013
 
                                start = 0;
2014
 
                                while (isspace(buf[start]) && buf[start] != '\0')
2015
 
                                        start++;
2016
 
                                end_construct = g_strdup_printf("\\end%s{%s}", full_cmd, env);
2017
 
                                if (strstr(tmp, end_construct) != NULL)
2018
 
                                {
2019
 
                                        utils_free_pointers(3, tmp, buf, end_construct, NULL);
2020
 
                                        return;
2021
 
                                }
2022
 
                                g_free(tmp);
2023
 
                        }
2024
 
 
2025
 
                        /* get the indentation */
2026
 
                        if (editor->auto_indent)
2027
 
                                read_indent(editor, pos);
2028
 
                        eol = g_strconcat(editor_get_eol_char(editor), indent, NULL);
2029
 
 
2030
 
                        construct = g_strdup_printf("%s\\end%s{%s}", eol, full_cmd, env);
2031
 
 
2032
 
                        SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
2033
 
                        sci_goto_pos(sci,pos, TRUE);
2034
 
                        g_free(construct);
2035
 
                        g_free(eol);
2036
 
                }
2037
 
                /* later there could be some else ifs for other keywords */
2038
 
 
2039
 
                g_free(buf);
2040
 
        }
2041
 
}
2042
 
 
2043
 
 
2044
 
static gchar *snippets_find_completion_by_name(const gchar *type, const gchar *name)
 
2041
static const gchar *snippets_find_completion_by_name(const gchar *type, const gchar *name)
2045
2042
{
2046
2043
        gchar *result = NULL;
2047
2044
        GHashTable *tmp;
2048
2045
 
2049
2046
        g_return_val_if_fail(type != NULL && name != NULL, NULL);
2050
2047
 
2051
 
        tmp = g_hash_table_lookup(editor_prefs.snippets, type);
 
2048
        tmp = g_hash_table_lookup(snippet_hash, type);
2052
2049
        if (tmp != NULL)
2053
2050
        {
2054
2051
                result = g_hash_table_lookup(tmp, name);
2057
2054
         * the particular completion for this filetype is not set (result is NULL) */
2058
2055
        if (tmp == NULL || result == NULL)
2059
2056
        {
2060
 
                tmp = g_hash_table_lookup(editor_prefs.snippets, "Default");
 
2057
                tmp = g_hash_table_lookup(snippet_hash, "Default");
2061
2058
                if (tmp != NULL)
2062
2059
                {
2063
2060
                        result = g_hash_table_lookup(tmp, name);
2066
2063
        /* if result is still NULL here, no completion could be found */
2067
2064
 
2068
2065
        /* result is owned by the hash table and will be freed when the table will destroyed */
2069
 
        return g_strdup(result);
 
2066
        return result;
2070
2067
}
2071
2068
 
2072
2069
 
2076
2073
 * ac_complete_constructs. Any hints to improve this are welcome. */
2077
2074
static GString *snippets_global_pattern = NULL;
2078
2075
 
2079
 
void snippets_replace_specials(gpointer key, gpointer value, gpointer user_data)
 
2076
static void snippets_replace_specials(gpointer key, gpointer value, gpointer user_data)
2080
2077
{
2081
2078
        gchar *needle;
2082
2079
 
2090
2087
}
2091
2088
 
2092
2089
 
2093
 
static void snippets_replace_wildcards(GeanyEditor *editor, GString *text)
2094
 
{
2095
 
        gchar *year = utils_get_date_time(template_prefs.year_format, NULL);
2096
 
        gchar *date = utils_get_date_time(template_prefs.date_format, NULL);
2097
 
        gchar *datetime = utils_get_date_time(template_prefs.datetime_format, NULL);
2098
 
        gchar *basename = g_path_get_basename(DOC_FILENAME(editor->document));
2099
 
 
2100
 
        templates_replace_all(text, year, date, datetime);
2101
 
        utils_string_replace_all(text, "{filename}", basename);
2102
 
 
2103
 
        utils_free_pointers(4, year, date, datetime, basename, NULL);
2104
 
}
2105
 
 
2106
 
 
2107
2090
/* this only works with spaces only indentation on the lines */
2108
2091
static void fix_line_indents(GeanyEditor *editor, gint line_start, gint line_end)
2109
2092
{
2128
2111
}
2129
2112
 
2130
2113
 
2131
 
/* Insert text, replacing \t tab chars with the correct indent width, and \n newline
2132
 
 * chars with the correct line ending string.
2133
 
 * @param text Intended as e.g. "if (1)\n\tdo_something();"
 
2114
static void replace_leading_tabs(GString *str, const gchar *whitespace)
 
2115
{
 
2116
        regex_t regex;
 
2117
        gssize pos;
 
2118
        regmatch_t matches[2];
 
2119
        gchar *ptr;
 
2120
 
 
2121
        if (regcomp(&regex, "^ *(\t)", 0) != 0)
 
2122
        {
 
2123
                g_return_if_fail(FALSE);
 
2124
        }
 
2125
        ptr = str->str;
 
2126
        while (ptr)
 
2127
        {
 
2128
                if (regexec(&regex, ptr,
 
2129
                        G_N_ELEMENTS(matches), matches, 0) != 0)
 
2130
                        break;
 
2131
 
 
2132
                pos = matches[1].rm_so;
 
2133
                g_return_if_fail(pos >= 0);
 
2134
                pos += ptr - str->str;
 
2135
                g_string_erase(str, pos, 1);
 
2136
                g_string_insert(str, pos, whitespace);
 
2137
                ptr = str->str + pos + strlen(whitespace);
 
2138
        }
 
2139
        regfree(&regex);
 
2140
}
 
2141
 
 
2142
 
 
2143
/** Inserts text, replacing \\t tab chars (@c 0x9) and \\n newline chars (@c 0xA)
 
2144
 * accordingly for the document.
 
2145
 * - Leading tabs are replaced with the correct indentation.
 
2146
 * - Non-leading tabs are replaced with spaces (except when using 'Tabs' indent type).
 
2147
 * - Newline chars are replaced with the correct line ending string.
 
2148
 * This is very useful for inserting code without having to handle the indent
 
2149
 * type yourself (Tabs & Spaces mode can be tricky).
 
2150
 * @param editor Editor.
 
2151
 * @param text Intended as e.g. @c "if (foo)\n\tbar();".
 
2152
 * @param insert_pos Document position to insert text at.
2134
2153
 * @param cursor_index If >= 0, the index into @a text to place the cursor.
2135
2154
 * @param newline_indent_size Indentation size (in spaces) to insert for each newline; use
2136
2155
 * -1 to read the indent size from the line with @a insert_pos on it.
2137
 
 * @param replace_newlines Whether to replace newlines in text or not. If
2138
 
 * newlines have been replaced before, this should be false, to avoid multiple
2139
 
 * replacements of newlines, which is error prone on Windows.
2140
 
 * @warning Make sure all \t tab chars in @a text are intended as indent widths,
2141
 
 * NOT any hard tabs (you get those when copying document text with the Tabs
2142
 
 * & Spaces indent mode set).
2143
 
 * @note This doesn't scroll the cursor in view afterwards. */
2144
 
static void editor_insert_text_block(GeanyEditor *editor, const gchar *text, gint insert_pos,
 
2156
 * @param replace_newlines Whether to replace newlines. If
 
2157
 * newlines have been replaced already, this should be false, to avoid errors e.g. on Windows.
 
2158
 * @warning Make sure all \\t tab chars in @a text are intended as indent widths or alignment,
 
2159
 * not hard tabs, as those won't be preserved.
 
2160
 * @note This doesn't scroll the cursor in view afterwards. **/
 
2161
void editor_insert_text_block(GeanyEditor *editor, const gchar *text, gint insert_pos,
2145
2162
                gint cursor_index, gint newline_indent_size, gboolean replace_newlines)
2146
2163
{
2147
2164
        ScintillaObject *sci = editor->sci;
2150
2167
        gchar *whitespace;
2151
2168
        GString *buf;
2152
2169
        const gchar cur_marker[] = "__GEANY_CURSOR_MARKER__";
 
2170
        const gchar *eol = editor_get_eol_char(editor);
 
2171
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
2153
2172
 
2154
2173
        g_return_if_fail(text);
 
2174
        g_return_if_fail(editor != NULL);
 
2175
        g_return_if_fail(insert_pos >= 0);
2155
2176
 
2156
2177
        buf = g_string_new(text);
2157
2178
 
2158
2179
        if (cursor_index >= 0)
2159
2180
                g_string_insert(buf, cursor_index, cur_marker); /* remember cursor pos */
2160
2181
 
 
2182
        if (newline_indent_size == -1)
 
2183
        {
 
2184
                /* count indent size up to insert_pos instead of asking sci
 
2185
                 * because there may be spaces after it */
 
2186
                gchar *tmp = sci_get_line(sci, line_start);
 
2187
                gint idx = insert_pos - sci_get_position_from_line(sci, line_start);
 
2188
                tmp[idx] = '\0';
 
2189
                newline_indent_size = count_indent_size(editor, tmp);
 
2190
                g_free(tmp);
 
2191
        }
 
2192
 
2161
2193
        /* Add line indents (in spaces) */
2162
 
 
2163
 
        if (newline_indent_size == -1)
2164
 
                newline_indent_size = sci_get_line_indentation(sci, line_start);
2165
 
 
2166
2194
        if (newline_indent_size > 0)
2167
2195
        {
2168
2196
                whitespace = g_strnfill(newline_indent_size, ' ');
2169
 
                setptr(whitespace, g_strconcat("\n", whitespace, NULL));
2170
 
                utils_string_replace_all(buf, "\n", whitespace);
 
2197
                setptr(whitespace, g_strconcat(eol, whitespace, NULL));
 
2198
                utils_string_replace_all(buf, eol, whitespace);
2171
2199
                g_free(whitespace);
2172
2200
        }
2173
2201
 
2174
2202
        /* transform line endings */
2175
2203
        if (replace_newlines)
2176
 
                utils_string_replace_all(buf, "\n", editor_get_eol_char(editor));
 
2204
                utils_string_replace_all(buf, "\n", eol);
2177
2205
 
2178
 
        /* transform tabs into indent widths (in spaces) */
2179
 
        whitespace = g_strnfill(editor_get_indent_prefs(editor)->width, ' ');
2180
 
        utils_string_replace_all(buf, "\t", whitespace);
 
2206
        /* transform leading tabs into indent widths (in spaces) */
 
2207
        whitespace = g_strnfill(iprefs->width, ' ');
 
2208
        replace_leading_tabs(buf, whitespace);
 
2209
        /* remaining tabs are for alignment */
 
2210
        if (iprefs->type != GEANY_INDENT_TYPE_TABS)
 
2211
                utils_string_replace_all(buf, "\t", whitespace);
2181
2212
        g_free(whitespace);
2182
2213
 
 
2214
        sci_start_undo_action(sci);
 
2215
 
2183
2216
        if (cursor_index >= 0)
2184
2217
        {
2185
2218
                gint idx = utils_strpos(buf->str, cur_marker);
2197
2230
        fix_line_indents(editor, line_start, line_end);
2198
2231
        snippet_cursor_insert_pos = sci_get_current_position(sci);
2199
2232
 
 
2233
        sci_end_undo_action(sci);
2200
2234
        g_string_free(buf, TRUE);
2201
2235
}
2202
2236
 
2203
2237
 
2204
2238
/* Move the cursor to the next specified cursor position in an inserted snippet.
2205
2239
 * Can, and should, be optimized to give better results */
2206
 
void snippet_goto_next_cursor(ScintillaObject *sci, gint current_pos)
 
2240
void editor_goto_next_snippet_cursor(GeanyEditor *editor)
2207
2241
{
2208
 
        if (snippet_queue)
 
2242
        ScintillaObject *sci = editor->sci;
 
2243
        gint current_pos = sci_get_current_position(sci);
 
2244
 
 
2245
        if (snippet_offsets && !g_queue_is_empty(snippet_offsets))
2209
2246
        {
2210
 
                gpointer offset;
 
2247
                gint offset;
2211
2248
 
2212
 
                snippet_queue = queue_delete(snippet_queue, &offset, FALSE);
 
2249
                offset = GPOINTER_TO_INT(g_queue_pop_head(snippet_offsets));
2213
2250
                if (current_pos > snippet_cursor_insert_pos)
2214
 
                        snippet_cursor_insert_pos = GPOINTER_TO_INT(offset) + current_pos;
 
2251
                        snippet_cursor_insert_pos = offset + current_pos;
2215
2252
                else
2216
 
                        snippet_cursor_insert_pos += GPOINTER_TO_INT(offset);
 
2253
                        snippet_cursor_insert_pos += offset;
2217
2254
 
2218
2255
                sci_set_current_position(sci, snippet_cursor_insert_pos, FALSE);
2219
2256
        }
 
2257
        else
 
2258
        {
 
2259
                utils_beep();
 
2260
        }
2220
2261
}
2221
2262
 
2222
2263
 
2223
 
static gboolean snippets_complete_constructs(GeanyEditor *editor, gint pos, const gchar *word)
 
2264
static gssize snippets_make_replacements(GeanyEditor *editor, GString *pattern,
 
2265
                gsize indent_size)
2224
2266
{
2225
 
        ScintillaObject *sci = editor->sci;
2226
 
        gchar *str, *whitespace;
2227
 
        GString *pattern;
2228
 
        gint i, str_len, tmp_pos, whitespace_len, nl_count = 0;
2229
2267
        gssize cur_index = -1;
2230
 
        gint ft_id = FILETYPE_ID(editor->document->file_type);
 
2268
        gchar *whitespace;
 
2269
        gint i, tmp_pos, whitespace_len, nl_count = 0;
2231
2270
        GHashTable *specials;
2232
 
        GeanyQueue *temp_list;
2233
 
        const GeanyIndentPrefs *iprefs;
2234
 
        gsize indent_size;
 
2271
        GList *temp_list = NULL;
 
2272
        const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
2235
2273
        gint cursor_steps, old_cursor = 0;
2236
2274
 
2237
 
        str = g_strdup(word);
2238
 
        g_strstrip(str);
2239
 
        pattern = g_string_new(snippets_find_completion_by_name(filetypes[ft_id]->name, str));
2240
 
        if (pattern == NULL || pattern->len == 0)
2241
 
        {
2242
 
                g_free(str);
2243
 
                g_string_free(pattern, TRUE);
2244
 
                return FALSE;
2245
 
        }
2246
 
 
2247
 
        temp_list = queue_init();
2248
 
        iprefs = editor_get_indent_prefs(editor);
2249
 
        read_indent(editor, pos);
2250
 
        indent_size = strlen(indent);
2251
 
 
2252
 
        /* remove the typed word, it will be added again by the used auto completion
2253
 
         * (not really necessary but this makes the auto completion more flexible,
2254
 
         *  e.g. with a completion like hi=hello, so typing "hi<TAB>" will result in "hello") */
2255
 
        str_len = strlen(str);
2256
 
        sci_set_selection_start(sci, pos - str_len);
2257
 
        sci_set_selection_end(sci, pos);
2258
 
        sci_replace_sel(sci, "");
2259
 
        pos -= str_len; /* pos has changed while deleting */
2260
 
 
2261
2275
        /* replace 'special' completions */
2262
 
        specials = g_hash_table_lookup(editor_prefs.snippets, "Special");
 
2276
        specials = g_hash_table_lookup(snippet_hash, "Special");
2263
2277
        if (G_LIKELY(specials != NULL))
2264
2278
        {
2265
2279
                /* ugly hack using global_pattern */
2267
2281
                g_hash_table_foreach(specials, snippets_replace_specials, NULL);
2268
2282
        }
2269
2283
 
2270
 
        /* replace any %template% wildcards */
2271
 
        snippets_replace_wildcards(editor, pattern);
 
2284
        /* replace any template {foo} wildcards */
 
2285
        templates_replace_common(pattern, editor->document->file_name, editor->document->file_type, NULL);
2272
2286
 
2273
2287
        /* transform other wildcards */
2274
2288
        /* convert to %newlines%, else we get endless loops */
2310
2324
                /* modify cursor_steps to take indentation count and type into account */
2311
2325
 
2312
2326
                /* We're saving the relative offset to each cursor position in a simple
2313
 
                 * linked list, including intendations between them. */
 
2327
                 * linked list, including indentations between them. */
2314
2328
                if (i++ > 0)
2315
2329
                {
2316
2330
                        cursor_steps += (nl_count * indent_size);
2317
 
                        queue_append(temp_list, GINT_TO_POINTER(cursor_steps - old_cursor));
 
2331
                        temp_list = g_list_append(temp_list, GINT_TO_POINTER(cursor_steps - old_cursor));
2318
2332
                }
2319
2333
                else
2320
2334
                {
2327
2341
        utils_string_replace_all(pattern, "%newline%", editor_get_eol_char(editor));
2328
2342
        utils_string_replace_all(pattern, "%ws%", whitespace);
2329
2343
        g_free(whitespace);
2330
 
        /* We create a new list, where the cursor positions for the most recent
2331
 
         * parsed snipped come first, followed by the remaining positions */
2332
 
        if (temp_list->data)
2333
 
                snippet_queue = queue_concat_copy(temp_list, snippet_queue);
 
2344
 
 
2345
        /* escape % last */
 
2346
        /* Bug: {ob}pc{cb} will be replaced by % too */
 
2347
        templates_replace_valist(pattern, "{pc}", "%", NULL);
 
2348
 
 
2349
        /* We put the cursor positions for the most recent
 
2350
         * parsed snippet first, followed by any remaining positions */
 
2351
        i = 0;
 
2352
        if (temp_list)
 
2353
        {
 
2354
                GList *node;
 
2355
 
 
2356
                foreach_list(node, temp_list)
 
2357
                        g_queue_push_nth(snippet_offsets, node->data, i++);
 
2358
 
 
2359
                /* limit length of queue */
 
2360
                while (g_queue_get_length(snippet_offsets) > 20)
 
2361
                        g_queue_pop_tail(snippet_offsets);
 
2362
 
 
2363
                g_list_free(temp_list);
 
2364
        }
2334
2365
        if (cur_index < 0)
2335
2366
                cur_index = pattern->len;
2336
2367
 
 
2368
        return cur_index;
 
2369
}
 
2370
 
 
2371
 
 
2372
static gboolean snippets_complete_constructs(GeanyEditor *editor, gint pos, const gchar *word)
 
2373
{
 
2374
        ScintillaObject *sci = editor->sci;
 
2375
        gchar *str;
 
2376
        GString *pattern;
 
2377
        gssize cur_index = -1;
 
2378
        gint str_len;
 
2379
        gint ft_id = FILETYPE_ID(editor->document->file_type);
 
2380
 
 
2381
        str = g_strdup(word);
 
2382
        g_strstrip(str);
 
2383
        pattern = g_string_new(snippets_find_completion_by_name(filetypes[ft_id]->name, str));
 
2384
        if (pattern == NULL || pattern->len == 0)
 
2385
        {
 
2386
                g_free(str);
 
2387
                g_string_free(pattern, TRUE);
 
2388
                return FALSE;
 
2389
        }
 
2390
 
 
2391
        read_indent(editor, pos);
 
2392
 
 
2393
        /* remove the typed word, it will be added again by the used auto completion
 
2394
         * (not really necessary but this makes the auto completion more flexible,
 
2395
         *  e.g. with a completion like hi=hello, so typing "hi<TAB>" will result in "hello") */
 
2396
        str_len = strlen(str);
 
2397
        sci_set_selection_start(sci, pos - str_len);
 
2398
        sci_set_selection_end(sci, pos);
 
2399
        sci_replace_sel(sci, "");
 
2400
        pos -= str_len; /* pos has changed while deleting */
 
2401
 
 
2402
        cur_index = snippets_make_replacements(editor, pattern, strlen(indent));
 
2403
 
2337
2404
        /* finally insert the text and set the cursor */
2338
2405
        editor_insert_text_block(editor, pattern->str, pos, cur_index, -1, FALSE);
2339
2406
        sci_scroll_caret(sci);
2340
2407
 
2341
2408
        g_free(str);
2342
2409
        g_string_free(pattern, TRUE);
2343
 
 
2344
2410
        return TRUE;
2345
2411
}
2346
2412
 
2367
2433
gboolean editor_complete_snippet(GeanyEditor *editor, gint pos)
2368
2434
{
2369
2435
        gboolean result = FALSE;
2370
 
        gint lexer, style;
2371
 
        gchar *wc;
 
2436
        const gchar *wc;
2372
2437
        const gchar *word;
2373
2438
        ScintillaObject *sci;
2374
2439
 
2375
2440
        g_return_val_if_fail(editor != NULL, FALSE);
2376
2441
 
2377
2442
        sci = editor->sci;
 
2443
        if (sci_has_selection(sci))
 
2444
                return FALSE;
2378
2445
        /* return if we are editing an existing line (chars on right of cursor) */
2379
2446
        if (keybindings_lookup_item(GEANY_KEY_GROUP_EDITOR,
2380
2447
                        GEANY_KEYS_EDITOR_COMPLETESNIPPET)->key == GDK_space &&
2381
2448
                ! editor_prefs.complete_snippets_whilst_editing && ! at_eol(sci, pos))
2382
2449
                return FALSE;
2383
2450
 
2384
 
        lexer = SSM(sci, SCI_GETLEXER, 0, 0);
2385
 
        style = SSM(sci, SCI_GETSTYLEAT, pos - 2, 0);
2386
 
 
2387
2451
        wc = snippets_find_completion_by_name("Special", "wordchars");
2388
2452
        word = editor_read_word_stem(editor, pos, wc);
2389
2453
 
2395
2459
                result = snippets_complete_constructs(editor, pos, word);
2396
2460
                sci_end_undo_action(sci);
2397
2461
                if (result)
2398
 
                        SSM(sci, SCI_CANCEL, 0, 0);     /* cancel any autocompletion list, etc */
 
2462
                        sci_cancel(sci);        /* cancel any autocompletion list, etc */
2399
2463
        }
2400
 
 
2401
 
        g_free(wc);
2402
2464
        return result;
2403
2465
}
2404
2466
 
2458
2520
static gboolean handle_xml(GeanyEditor *editor, gint pos, gchar ch)
2459
2521
{
2460
2522
        ScintillaObject *sci = editor->sci;
2461
 
        gint lexer = SSM(sci, SCI_GETLEXER, 0, 0);
 
2523
        gint lexer = sci_get_lexer(sci);
2462
2524
        gint min, style;
2463
2525
        gchar *str_found, sel[512];
2464
2526
        gboolean result = FALSE;
2549
2611
        gint indent_pos;
2550
2612
        const gchar *indent_str;
2551
2613
 
2552
 
        if (SSM(sci, SCI_GETLEXER, 0, 0) != SCLEX_HTML) return;
 
2614
        if (sci_get_lexer(sci) != SCLEX_HTML) return;
2553
2615
 
2554
2616
        read_indent(editor, pos);
2555
2617
        indent_pos = sci_get_line_indent_position(sci, sci_get_line_from_position(sci, pos));
2650
2712
 
2651
2713
static gint get_multiline_comment_style(GeanyEditor *editor, gint line_start)
2652
2714
{
2653
 
        gint lexer = SSM(editor->sci, SCI_GETLEXER, 0, 0);
 
2715
        gint lexer = sci_get_lexer(editor->sci);
2654
2716
        gint style_comment;
2655
2717
 
2656
2718
        /* List only those lexers which support multi line comments */
2731
2793
        if (co_len == 0)
2732
2794
                return 0;
2733
2795
 
2734
 
        SSM(editor->sci, SCI_BEGINUNDOACTION, 0, 0);
 
2796
        sci_start_undo_action(editor->sci);
2735
2797
 
2736
2798
        for (i = first_line; (i <= last_line) && (! break_loop); i++)
2737
2799
        {
2795
2857
                        }
2796
2858
                }
2797
2859
        }
2798
 
        SSM(editor->sci, SCI_ENDUNDOACTION, 0, 0);
 
2860
        sci_end_undo_action(editor->sci);
2799
2861
 
2800
2862
        /* restore selection if there is one
2801
2863
         * but don't touch the selection if caller is editor_do_comment_toggle */
2862
2924
        if (co_len == 0)
2863
2925
                return;
2864
2926
 
2865
 
        SSM(editor->sci, SCI_BEGINUNDOACTION, 0, 0);
 
2927
        sci_start_undo_action(editor->sci);
2866
2928
 
2867
2929
        for (i = first_line; (i <= last_line) && (! break_loop); i++)
2868
2930
        {
2929
2991
                }
2930
2992
        }
2931
2993
 
2932
 
        SSM(editor->sci, SCI_ENDUNDOACTION, 0, 0);
 
2994
        sci_end_undo_action(editor->sci);
2933
2995
 
2934
2996
        co_len += tm_len;
2935
2997
 
2954
3016
                        gint eol_len = editor_get_eol_char_len(editor);
2955
3017
                        if (count_uncommented > 0)
2956
3018
                        {
2957
 
                                sci_set_selection_start(editor->sci, sel_start - co_len - eol_len);
2958
 
                                sci_set_selection_end(editor->sci, sel_end - co_len - eol_len);
 
3019
                                sci_set_selection_start(editor->sci, sel_start - co_len + eol_len);
 
3020
                                sci_set_selection_end(editor->sci, sel_end - co_len + eol_len);
2959
3021
                        }
2960
 
                        else
 
3022
                        else if (count_commented > 0)
2961
3023
                        {
2962
 
                                sci_set_selection_start(editor->sci, sel_start + co_len + eol_len);
2963
 
                                sci_set_selection_end(editor->sci, sel_end + co_len + eol_len);
 
3024
                                sci_set_selection_start(editor->sci, sel_start + co_len - eol_len);
 
3025
                                sci_set_selection_end(editor->sci, sel_end + co_len - eol_len);
2964
3026
                        }
2965
3027
                }
2966
3028
        }
2967
3029
        else if (count_uncommented > 0)
2968
3030
        {
2969
 
                sci_set_current_position(editor->sci, sel_start - co_len, TRUE);
 
3031
                gint eol_len = single_line ? 0: editor_get_eol_char_len(editor);
 
3032
                sci_set_current_position(editor->sci, sel_start - co_len + eol_len, TRUE);
 
3033
        }
 
3034
        else if (count_commented > 0)
 
3035
        {
 
3036
                gint eol_len = single_line ? 0: editor_get_eol_char_len(editor);
 
3037
                sci_set_current_position(editor->sci, sel_start + co_len - eol_len, TRUE);
2970
3038
        }
2971
3039
}
2972
3040
 
3019
3087
        if (co_len == 0)
3020
3088
                return;
3021
3089
 
3022
 
        SSM(editor->sci, SCI_BEGINUNDOACTION, 0, 0);
 
3090
        sci_start_undo_action(editor->sci);
3023
3091
 
3024
3092
        for (i = first_line; (i <= last_line) && (! break_loop); i++)
3025
3093
        {
3076
3144
                        }
3077
3145
                }
3078
3146
        }
3079
 
        SSM(editor->sci, SCI_ENDUNDOACTION, 0, 0);
 
3147
        sci_end_undo_action(editor->sci);
3080
3148
 
3081
3149
        /* restore selection if there is one
3082
3150
         * but don't touch the selection if caller is editor_do_comment_toggle */
3221
3289
        /* Use the start of the line enter was pressed on, to avoid any doc keyword styles */
3222
3290
        indent_pos = sci_get_line_indent_position(sci, cur_line - 1);
3223
3291
        style = sci_get_style_at(sci, indent_pos);
 
3292
        if (!in_block_comment(lexer, style))
 
3293
                return;
3224
3294
 
3225
 
        if (in_block_comment(lexer, style))
 
3295
        /* Check whether the comment block continues on this line */
 
3296
        indent_pos = sci_get_line_indent_position(sci, cur_line);
 
3297
        if (sci_get_style_at(sci, indent_pos) == style)
3226
3298
        {
3227
3299
                gchar *previous_line = sci_get_line(sci, cur_line - 1);
3228
3300
                /* the type of comment, '*' (C/C++/Java), '+' and the others (D) */
3605
3677
        g_return_if_fail(editor != NULL &&
3606
3678
                editor->document->file_type != NULL && editor->document->file_type->comment_open != NULL);
3607
3679
 
 
3680
        sci_start_undo_action(editor->sci);
 
3681
 
3608
3682
        doc = editor->document;
3609
3683
 
3610
3684
        if (doc->file_type->comment_close != NULL && strlen(doc->file_type->comment_close) > 0)
3631
3705
        sci_insert_text(editor->sci, pos, text);
3632
3706
        g_free(text);
3633
3707
 
3634
 
 
3635
3708
        /* select the inserted lines for commenting */
3636
3709
        sci_set_selection_start(editor->sci, pos);
3637
3710
        sci_set_selection_end(editor->sci, pos + text_len);
3650
3723
        sci_set_current_position(editor->sci, pos, TRUE);
3651
3724
        /* reset the selection */
3652
3725
        sci_set_anchor(editor->sci, pos);
 
3726
 
 
3727
        sci_end_undo_action(editor->sci);
3653
3728
}
3654
3729
 
3655
3730
 
3887
3962
        if (pos == -1)
3888
3963
                pos = first_sel_start;
3889
3964
 
3890
 
        SSM(sci, SCI_BEGINUNDOACTION, 0, 0);
 
3965
        sci_start_undo_action(sci);
3891
3966
 
3892
3967
        smart_line_indentation(editor, first_line, last_line);
3893
3968
 
3906
3981
                sci_set_selection_end(sci, sci_get_position_from_line(sci, last_line + 1));
3907
3982
        }
3908
3983
 
3909
 
        SSM(sci, SCI_ENDUNDOACTION, 0, 0);
 
3984
        sci_end_undo_action(sci);
3910
3985
}
3911
3986
 
3912
3987
 
3929
4004
        if (pos == -1)
3930
4005
                pos = sel_start;
3931
4006
 
3932
 
        SSM(editor->sci, SCI_BEGINUNDOACTION, 0, 0);
 
4007
        sci_start_undo_action(editor->sci);
3933
4008
 
3934
4009
        for (i = first_line; i <= last_line; i++)
3935
4010
        {
3973
4048
        else
3974
4049
                sci_set_current_position(editor->sci, pos + count, FALSE);
3975
4050
 
3976
 
        SSM(editor->sci, SCI_ENDUNDOACTION, 0, 0);
 
4051
        sci_end_undo_action(editor->sci);
3977
4052
}
3978
4053
 
3979
4054
 
4128
4203
        /* don't set the indicator on whitespace */
4129
4204
        while (isspace(linebuf[i]))
4130
4205
                i++;
4131
 
        while (len > 1 && len > i && isspace(linebuf[len-1]))
 
4206
        while (len > 1 && len > i && isspace(linebuf[len - 1]))
4132
4207
        {
4133
4208
                len--;
4134
4209
                end--;
4191
4266
}
4192
4267
 
4193
4268
 
 
4269
/**
 
4270
 *  Retrieves the localized name (for displaying) of the used end of line characters
 
4271
 *  (LF, CR/LF, CR) in the given editor.
 
4272
 *  If @a editor is @c NULL, the default end of line characters are used.
 
4273
 *
 
4274
 *  @param editor The editor to operate on, or @c NULL to query the default value.
 
4275
 *  @return The name of the end of line characters.
 
4276
 *
 
4277
 *  @since 0.19
 
4278
 */
4194
4279
const gchar *editor_get_eol_char_name(GeanyEditor *editor)
4195
4280
{
4196
4281
        gint mode = file_prefs.default_eol_character;
4202
4287
}
4203
4288
 
4204
4289
 
4205
 
/* returns the end-of-line character(s) length of the specified editor */
 
4290
/**
 
4291
 *  Retrieves the length of the used end of line characters (LF, CR/LF, CR) in the given editor.
 
4292
 *  If @a editor is @c NULL, the default end of line characters are used.
 
4293
 *  The returned value is 1 for CR and LF and 2 for CR/LF.
 
4294
 *
 
4295
 *  @param editor The editor to operate on, or @c NULL to query the default value.
 
4296
 *  @return The length of the end of line characters.
 
4297
 *
 
4298
 *  @since 0.19
 
4299
 */
4206
4300
gint editor_get_eol_char_len(GeanyEditor *editor)
4207
4301
{
4208
4302
        gint mode = file_prefs.default_eol_character;
4218
4312
}
4219
4313
 
4220
4314
 
4221
 
/* returns the end-of-line character(s) of the specified editor */
 
4315
/**
 
4316
 *  Retrieves the used end of line characters (LF, CR/LF, CR) in the given editor.
 
4317
 *  If @a editor is @c NULL, the default end of line characters are used.
 
4318
 *  The returned value is either "\n", "\r\n" or "\r".
 
4319
 *
 
4320
 *  @param editor The editor to operate on, or @c NULL to query the default value.
 
4321
 *  @return The end of line characters.
 
4322
 *
 
4323
 *  @since 0.19
 
4324
 */
4222
4325
const gchar *editor_get_eol_char(GeanyEditor *editor)
4223
4326
{
4224
4327
        gint mode = file_prefs.default_eol_character;
4248
4351
        for (i = 0; i < lines; i++)
4249
4352
        {
4250
4353
                gint level = sci_get_fold_level(editor->sci, i);
 
4354
 
4251
4355
                if (level & SC_FOLDLEVELHEADERFLAG)
4252
4356
                {
4253
4357
                        if (sci_get_fold_expanded(editor->sci, i) == want_fold)
4291
4395
                if (search_pos == -1)
4292
4396
                        break;
4293
4397
 
4294
 
                pos_in_line = sci_get_col_from_position(editor->sci,search_pos);
 
4398
                pos_in_line = sci_get_col_from_position(editor->sci, search_pos);
4295
4399
                current_tab_true_length = tab_len - (pos_in_line % tab_len);
4296
4400
                tab_str = g_strnfill(current_tab_true_length, ' ');
4297
4401
                sci_set_target_start(editor->sci, search_pos);
4364
4468
                i--;
4365
4469
                ch = sci_get_char_at(editor->sci, i);
4366
4470
        }
4367
 
        if (i < (line_end-1))
 
4471
        if (i < (line_end - 1))
4368
4472
        {
4369
4473
                sci_set_target_start(editor->sci, i + 1);
4370
4474
                sci_set_target_end(editor->sci, line_end);
4451
4555
}
4452
4556
 
4453
4557
 
4454
 
/** Set the indent type for @a editor.
 
4558
/** Sets the indent type for @a editor.
4455
4559
 * @param editor Editor.
4456
4560
 * @param type Indent type.
4457
4561
 *
4467
4571
        sci_set_use_tabs(sci, use_tabs);
4468
4572
 
4469
4573
        if (type == GEANY_INDENT_TYPE_BOTH)
 
4574
        {
4470
4575
                sci_set_tab_width(sci, iprefs->hard_tab_width);
 
4576
                if (iprefs->hard_tab_width != 8)
 
4577
                {
 
4578
                        static gboolean warn = TRUE;
 
4579
                        if (warn)
 
4580
                                ui_set_statusbar(TRUE, _("Warning: non-standard hard tab width: %d != 8!"),
 
4581
                                        iprefs->hard_tab_width);
 
4582
                        warn = FALSE;
 
4583
                }
 
4584
        }
4471
4585
        else
4472
4586
                sci_set_tab_width(sci, iprefs->width);
 
4587
 
4473
4588
        SSM(sci, SCI_SETINDENT, iprefs->width, 0);
4474
4589
 
4475
4590
        /* remove indent spaces on backspace, if using any spaces to indent */
4478
4593
 
4479
4594
 
4480
4595
/* Convenience function for editor_goto_pos() to pass in a line number. */
4481
 
gboolean editor_goto_line(GeanyEditor *editor, gint line)
 
4596
gboolean editor_goto_line(GeanyEditor *editor, gint line_no, gint offset)
4482
4597
{
4483
4598
        gint pos;
4484
4599
 
4485
4600
        g_return_val_if_fail(editor, FALSE);
4486
 
        if (line < 0 || line >= sci_get_line_count(editor->sci))
 
4601
        if (line_no < 0 || line_no >= sci_get_line_count(editor->sci))
4487
4602
                return FALSE;
4488
4603
 
4489
 
        pos = sci_get_position_from_line(editor->sci, line);
 
4604
        if (offset != 0)
 
4605
        {
 
4606
                gint current_line = sci_get_current_line(editor->sci);
 
4607
                line_no *= offset;
 
4608
                line_no = current_line + line_no;
 
4609
        }
 
4610
 
 
4611
        pos = sci_get_position_from_line(editor->sci, line_no);
4490
4612
        return editor_goto_pos(editor, pos, TRUE);
4491
4613
}
4492
4614
 
4507
4629
 
4508
4630
                /* mark the tag with the yellow arrow */
4509
4631
                sci_marker_delete_all(editor->sci, 0);
4510
 
                sci_set_marker_at_line(editor->sci, line, TRUE, 0);
 
4632
                sci_set_marker_at_line(editor->sci, line, 0);
4511
4633
        }
4512
4634
 
4513
4635
        sci_goto_pos(editor->sci, pos, TRUE);
4603
4725
        sci_clear_cmdkey(sci, '\\' | (SCMOD_CTRL << 16)); /* Next word part */
4604
4726
        sci_clear_cmdkey(sci, SCK_UP | (SCMOD_CTRL << 16)); /* scroll line up */
4605
4727
        sci_clear_cmdkey(sci, SCK_DOWN | (SCMOD_CTRL << 16)); /* scroll line down */
4606
 
        sci_clear_cmdkey(sci, SCK_HOME);        /* line start */
 
4728
        sci_clear_cmdkey(sci, SCK_HOME); /* line start */
4607
4729
        sci_clear_cmdkey(sci, SCK_END); /* line end */
4608
4730
        sci_clear_cmdkey(sci, SCK_END | (SCMOD_ALT << 16));     /* visual line end */
4609
4731
 
4657
4779
        SSM(sci, SCI_REGISTERIMAGE, 1, (sptr_t)classviewer_var);
4658
4780
        SSM(sci, SCI_REGISTERIMAGE, 2, (sptr_t)classviewer_method);
4659
4781
 
 
4782
        /* necessary for column mode editing, implemented in Scintilla since 2.0 */
 
4783
        SSM(sci, SCI_SETADDITIONALSELECTIONTYPING, 1, 0);
 
4784
 
 
4785
        /* virtual space */
 
4786
        SSM(sci, SCI_SETVIRTUALSPACEOPTIONS, editor_prefs.show_virtual_space, 0);
 
4787
 
4660
4788
        /* only connect signals if this is for the document notebook, not split window */
4661
4789
        if (editor->sci == NULL)
4662
4790
        {
4670
4798
}
4671
4799
 
4672
4800
 
4673
 
/** Create a new Scintilla @c GtkWidget based on the settings for @a editor.
 
4801
/** Creates a new Scintilla @c GtkWidget based on the settings for @a editor.
4674
4802
 * @param editor Editor settings.
4675
4803
 * @return The new widget.
4676
4804
 *
4688
4816
 
4689
4817
        editor_set_indent_type(editor, iprefs->type);
4690
4818
        editor_set_font(editor, interface_prefs.editor_font);
 
4819
        editor_apply_update_prefs(editor);
4691
4820
 
4692
4821
        /* if editor already had a widget, restore it */
4693
4822
        if (old)
4735
4864
}
4736
4865
 
4737
4866
 
 
4867
gboolean editor_complete_word_part(GeanyEditor *editor)
 
4868
{
 
4869
        gchar *entry;
 
4870
 
 
4871
        g_return_val_if_fail(editor, FALSE);
 
4872
 
 
4873
        if (!SSM(editor->sci, SCI_AUTOCACTIVE, 0, 0))
 
4874
                return FALSE;
 
4875
 
 
4876
        entry = sci_get_string(editor->sci, SCI_AUTOCGETCURRENTTEXT, 0);
 
4877
 
 
4878
        /* if no word part, complete normally */
 
4879
        if (!check_partial_completion(editor, entry))
 
4880
                SSM(editor->sci, SCI_AUTOCCOMPLETE, 0, 0);
 
4881
 
 
4882
        g_free(entry);
 
4883
        return TRUE;
 
4884
}
 
4885
 
 
4886
 
4738
4887
void editor_init(void)
4739
4888
{
4740
4889
        static GeanyIndentPrefs indent_prefs;
4753
4902
}
4754
4903
 
4755
4904
 
4756
 
/** TODO: Should these be user-defined instead of hard-coded? */
 
4905
/* TODO: Should these be user-defined instead of hard-coded? */
4757
4906
void editor_set_indentation_guides(GeanyEditor *editor)
4758
4907
{
4759
4908
        gint mode;
4827
4976
 
4828
4977
        g_return_if_fail(editor != NULL);
4829
4978
 
 
4979
        if (main_status.quitting)
 
4980
                return;
 
4981
 
4830
4982
        sci = editor->sci;
4831
4983
 
4832
 
        sci_set_mark_long_lines(sci, editor_prefs.long_line_type,
4833
 
                editor_prefs.long_line_column, editor_prefs.long_line_color);
 
4984
        sci_set_mark_long_lines(sci, editor_get_long_line_type(),
 
4985
                editor_get_long_line_column(), editor_prefs.long_line_color);
4834
4986
 
4835
4987
        /* update indent width, tab width */
4836
4988
        editor_set_indent_type(editor, editor->indent_type);
4848
5000
 
4849
5001
        sci_set_folding_margin_visible(sci, editor_prefs.folding);
4850
5002
 
 
5003
        /* virtual space */
 
5004
        SSM(sci, SCI_SETVIRTUALSPACEOPTIONS, editor_prefs.show_virtual_space, 0);
 
5005
 
4851
5006
        /* (dis)allow scrolling past end of document */
4852
5007
        sci_set_scroll_stop_at_last_line(sci, editor_prefs.scroll_stop_at_last_line);
4853
5008
}
4938
5093
                sci_set_current_line(sci, lstart);
4939
5094
        }
4940
5095
}
4941
 
 
4942