60
} calltip = {NULL, FALSE, NULL, 0};
82
} calltip = {NULL, FALSE, NULL, 0, 0, NULL};
62
84
static gchar indent[100];
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);
74
/* calls the edit popup menu in the editor */
93
static void auto_table(GeanyEditor *editor, gint pos);
94
static void close_block(GeanyEditor *editor, gint pos);
97
void editor_snippets_free()
99
g_hash_table_destroy(editor_prefs.snippets);
103
void editor_snippets_init(void)
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;
110
GKeyFile *sysconfig = g_key_file_new();
111
GKeyFile *userconfig = g_key_file_new();
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);
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));
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);
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);
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++)
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);
139
for (j = 0; j < len_keys; j++)
141
g_hash_table_insert(tmp, g_strdup(keys_sys[j]),
142
utils_get_setting_string(sysconfig, groups_sys[i], keys_sys[j], ""));
144
g_strfreev(keys_sys);
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++)
151
keys_user = g_key_file_get_keys(userconfig, groups_user[i], &len_keys, NULL);
153
tmp = g_hash_table_lookup(editor_prefs.snippets, groups_user[i]);
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);
159
for (j = 0; j < len_keys; j++)
161
value = g_hash_table_lookup(tmp, keys_user[j]);
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], ""));
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], ""));
173
g_strfreev(keys_user);
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);
76
186
on_editor_button_press_event (GtkWidget *widget,
77
187
GdkEventButton *event,
78
188
gpointer user_data)
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;
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)
85
if (GDK_BUTTON_PRESS == event->type && editor_prefs.disable_dnd)
87
gint ss = sci_get_selection_start(doc_list[idx].sci);
88
sci_set_selection_end(doc_list[idx].sci, ss);
90
return utils_check_disk_status(idx, FALSE);
196
guint state = event->state & GEANY_KEYS_MODIFIER_MASK;
198
if (event->type == GDK_BUTTON_PRESS && editor_prefs.disable_dnd)
200
gint ss = sci_get_selection_start(doc->editor->sci);
201
sci_set_selection_end(doc->editor->sci, ss);
203
if (event->type == GDK_BUTTON_PRESS && state == GDK_CONTROL_MASK)
205
sci_set_current_position(sci, editor_info.click_pos, FALSE);
206
keybindings_send_command(GEANY_KEY_GROUP_GOTO, GEANY_KEYS_GOTO_TAGDEFINITION);
209
return document_check_disk_status(doc, FALSE);
212
/* calls the edit popup menu in the editor */
93
213
if (event->button == 3)
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);
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);
219
ui_update_popup_copy_items(doc);
220
ui_update_insert_include_item(doc, 0);
224
g_signal_emit_by_name(geany_object, "update-editor-menu",
225
current_word, editor_info.click_pos, doc);
227
gtk_menu_popup(GTK_MENU(main_widgets.editor_menu),
228
NULL, NULL, NULL, NULL, event->button, event->time);
236
static gboolean is_style_php(gint style)
238
if ((style >= SCE_HPHP_DEFAULT && style <= SCE_HPHP_OPERATOR) ||
239
style == SCE_HPHP_COMPLEX_VARIABLE)
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)
760
if (indent_prefs->type == GEANY_INDENT_TYPE_BOTH)
761
return indent_prefs->hard_tab_width;
763
return indent_prefs->width; /* tab width = indent width */
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
512
get_whitespace(gint width, gboolean use_tabs)
772
get_whitespace(const GeanyIndentPrefs *iprefs, gint width)
516
g_return_val_if_fail(width > 0, NULL);
774
g_return_val_if_fail(width >= 0, NULL);
779
if (iprefs->type == GEANY_INDENT_TYPE_SPACES)
781
return g_strnfill(width, ' ');
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;
524
791
str = g_malloc(len + 1);
526
793
memset(str, '\t', tabs);
527
794
memset(str + tabs, ' ', spaces);
531
str = g_strnfill(width, ' ');
537
static void check_python_indent(gint idx, gint pos)
539
document *doc = &doc_list[idx];
540
gint last_char = pos - utils_get_eol_char_len(idx) - 1;
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)
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);
555
static void on_new_line_added(gint idx)
557
ScintillaObject *sci = doc_list[idx].sci;
801
static const GeanyIndentPrefs *
802
get_default_indent_prefs(void)
804
/* In future this might depend on the current project. */
805
return editor_prefs.indentation;
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)
818
static GeanyIndentPrefs iprefs;
820
iprefs = *get_default_indent_prefs();
825
iprefs.type = editor->indent_type;
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;
832
if (!editor->auto_indent)
833
iprefs.auto_indent_mode = GEANY_AUTOINDENT_NONE;
839
static gchar *get_single_indent(GeanyEditor *editor)
841
const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
843
return get_whitespace(iprefs, iprefs->width);
847
static void on_new_line_added(GeanyEditor *editor)
849
ScintillaObject *sci = editor->sci;
558
850
gint pos = sci_get_current_position(sci);
559
851
gint line = sci_get_current_line(sci);
561
853
/* simple indentation */
562
if (doc_list[idx].auto_indent)
854
if (editor->auto_indent)
564
get_indent(&doc_list[idx], pos, FALSE);
565
sci_add_text(sci, indent);
856
insert_indent_after_line(editor, line - 1);
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);
572
864
if (editor_prefs.complete_snippets)
574
/* " * " auto completion in multiline C/C++/D/Java comments */
575
auto_multiline(idx, pos);
577
editor_auto_latex(idx, pos);
866
editor_auto_latex(editor, pos);
580
869
if (editor_prefs.newline_strip)
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);
608
/* in place indentation of one tab or equivalent spaces */
609
static void do_indent(gchar *buf, gsize len, guint *idx, gboolean use_tabs)
615
if (j < len - 1) /* leave room for a \0 terminator. */
619
{ /* insert as many spaces as a tab would take */
621
for (k = 0; k < (guint) editor_prefs.tab_width && k < len - 1; k++)
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)
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)
900
ScintillaObject *sci = editor->sci;
633
901
guint i, len, j = 0;
637
prev_line = sci_get_line_from_position(sci, pos);
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);
906
line = sci_get_line_from_position(sci, pos);
908
len = sci_get_line_length(sci, line);
909
linebuf = sci_get_line(sci, line);
644
911
for (i = 0; i < len && j <= (sizeof(indent) - 1); i++)
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)
650
else if (use_this_line)
652
else /* editor_close_block */
654
if (! lexer_has_braces(sci))
657
/* i == (len - 1) prevents wrong indentation after lines like
658
* " { return bless({}, shift); }" (Perl) */
659
if (linebuf[i] == '{' && i == (len - 1))
661
do_indent(indent, sizeof(indent), &j, doc->use_tabs);
668
while (k > 0 && isspace(linebuf[k])) k--;
670
/* if last non-whitespace character is a { increase indentation by a tab
671
* e.g. for (...) { */
672
if (linebuf[k] == '{')
674
do_indent(indent, sizeof(indent), &j, doc->use_tabs);
915
else if (iprefs->auto_indent_mode <= GEANY_AUTOINDENT_BASIC)
680
918
indent[j] = '\0';
923
static gint get_brace_indent(ScintillaObject *sci, gint line)
929
len = sci_get_line_length(sci, line);
930
linebuf = sci_get_line(sci, line);
932
for (i = 0; i < len; i++)
934
/* i == (len - 1) prevents wrong indentation after lines like
935
* " { return bless({}, shift); }" (Perl) */
936
if (linebuf[i] == '{' && i == (len - 1))
945
while (k > 0 && isspace(linebuf[k])) k--;
947
/* if last non-whitespace character is a { increase indentation by a tab
948
* e.g. for (...) { */
949
if (linebuf[k] == '{')
961
static gint get_python_indent(ScintillaObject *sci, gint line)
963
gint last_char = sci_get_line_end_position(sci, line) - 1;
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)
975
static gint get_indent_size_after_line(GeanyEditor *editor, gint line)
977
ScintillaObject *sci = editor->sci;
979
const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
981
g_return_val_if_fail(line >= 0, 0);
983
size = sci_get_line_indentation(sci, line);
985
if (iprefs->auto_indent_mode > GEANY_AUTOINDENT_BASIC)
987
if (lexer_has_braces(sci))
988
size += iprefs->width * get_brace_indent(sci, line);
990
if (FILETYPE_ID(editor->document->file_type) == GEANY_FILETYPES_PYTHON)
991
size += iprefs->width * get_python_indent(sci, line);
997
static void insert_indent_after_line(GeanyEditor *editor, gint line)
999
ScintillaObject *sci = editor->sci;
1000
gint size = get_indent_size_after_line(editor, line);
1001
const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
1007
text = get_whitespace(iprefs, size);
1008
sci_add_text(sci, text);
685
1014
static void auto_close_bracket(ScintillaObject *sci, gint pos, gchar c)
687
1016
if (! editor_prefs.complete_snippets || SSM(sci, SCI_GETLEXER, 0, 0) != SCLEX_LATEX)
1557
2026
indent[x] = '\0';
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);
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)
1569
2038
const gchar *eol;
1570
2039
gchar *str_begin, *str_end;
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)
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);
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);
1584
2054
g_free(str_begin);
1585
2055
g_free(str_end);
1589
static void real_uncomment_multiline(gint idx)
2059
static void real_uncomment_multiline(GeanyEditor *editor)
1591
2061
/* find the beginning of the multi line comment */
1592
2062
gint pos, line, len, x;
1593
2063
gchar *linebuf;
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)
2068
doc = editor->document;
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);
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);
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);
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);
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);
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);
1925
2393
gint a = (first_line_was_comment) ? - co_len : co_len;
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))
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));
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)
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);
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);
1951
2419
else if (count_uncommented > 0)
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);
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)
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;
1968
if (! DOC_IDX_VALID(idx) || doc_list[idx].file_type == NULL) return;
2436
if (editor == NULL || editor->document->file_type == NULL)
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);
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);
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);
1987
ft = doc_list[idx].file_type;
2456
ft = editor->document->file_type;
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)
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];
2086
2553
if (single_line)
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));
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);
2101
void editor_highlight_braces(ScintillaObject *sci, gint cur_pos)
2568
void editor_highlight_braces(GeanyEditor *editor, gint cur_pos)
2103
2570
gint brace_pos = cur_pos - 1;
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))
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))
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);
2115
end_pos = SSM(sci, SCI_BRACEMATCH, brace_pos, 0);
2583
end_pos = SSM(editor->sci, SCI_BRACEMATCH, brace_pos, 0);
2117
2585
if (end_pos >= 0)
2118
SSM(sci, SCI_BRACEHIGHLIGHT, brace_pos, end_pos);
2120
SSM(sci, SCI_BRACEBADLIGHT, brace_pos, 0);
2124
static gboolean is_doc_comment_char(gchar c, gint lexer)
2126
if (c == '*' && (lexer == SCLEX_HTML || lexer == SCLEX_CPP))
2128
else if ((c == '*' || c == '+') && lexer == SCLEX_D)
2135
static void auto_multiline(gint idx, gint pos)
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);
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)))
2148
gchar *previous_line = sci_get_line(sci, sci_get_line_from_position(sci, pos - 2));
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);
2594
SSM(editor->sci, SCI_SETHIGHLIGHTGUIDE, 0, 0);
2595
SSM(editor->sci, SCI_BRACEBADLIGHT, brace_pos, 0);
2600
static gboolean in_block_comment(gint lexer, gint style)
2605
return (style == SCE_C_COMMENT ||
2606
style == SCE_C_COMMENTDOC);
2609
return (style == SCE_D_COMMENT ||
2610
style == SCE_D_COMMENTDOC ||
2611
style == SCE_D_COMMENTNESTED);
2614
return (style == SCE_HPHP_COMMENT);
2617
return (style == SCE_CSS_COMMENT);
2625
static gboolean is_comment_char(gchar c, gint lexer)
2627
if ((c == '*' || c == '+') && lexer == SCLEX_D)
2637
static void auto_multiline(GeanyEditor *editor, gint cur_line)
2639
ScintillaObject *sci = editor->sci;
2640
gint indent_pos, style;
2641
gint lexer = sci_get_lexer(sci);
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);
2647
if (in_block_comment(lexer, style))
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 */
2153
2654
gint len = strlen(previous_line);
2155
2657
/* find and stop at end of multi line comment */
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] == '/')
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;
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;
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);
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.
2197
static gboolean is_comment(gint lexer, gint prev_style, gint style)
2701
static gboolean is_string_style(gint lexer, gint style)
2199
gboolean result = FALSE;
2203
2705
case SCLEX_CPP:
2204
2706
case SCLEX_PASCAL:
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)
2707
return (style == SCE_C_CHARACTER ||
2708
style == SCE_C_STRING);
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)
2711
return (style == SCE_D_CHARACTER ||
2712
style == SCE_D_STRING);
2228
2714
case SCLEX_PYTHON:
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)
2718
style == SCE_P_CHARACTER);
2241
2720
case SCLEX_F77:
2243
if (style == SCE_F_COMMENT ||
2244
style == SCE_F_STRING1 ||
2245
style == SCE_F_STRING2)
2722
return (style == SCE_F_STRING1 ||
2723
style == SCE_F_STRING2);
2249
2725
case SCLEX_PERL:
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)
2264
case SCLEX_PROPERTIES:
2266
if (style == SCE_PROPS_COMMENT)
2272
if (style == SCE_L_COMMENT)
2276
case SCLEX_MAKEFILE:
2278
if (style == SCE_MAKE_COMMENT)
2732
style == SCE_PL_POD_VERB);
2735
return (style == SCE_R_STRING);
2282
2737
case SCLEX_RUBY:
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)
2297
if (prev_style == SCE_SH_COMMENTLINE ||
2298
style == SCE_SH_STRING)
2304
if (style == SCE_SQL_COMMENT ||
2744
style == SCE_RB_POD);
2747
return (style == SCE_SH_STRING);
2750
return (style == SCE_SQL_STRING);
2753
return (style == SCE_TCL_IN_QUOTE);
2756
return (style == SCE_LUA_LITERALSTRING ||
2757
style == SCE_LUA_CHARACTER ||
2758
style == SCE_LUA_STRING);
2761
return (style == SCE_HA_CHARACTER ||
2762
style == SCE_HA_STRING);
2764
case SCLEX_FREEBASIC:
2765
return (style == SCE_B_STRING);
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);
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.
2785
static gboolean is_comment_style(gint lexer, gint style)
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);
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);
2808
return (style == SCE_P_COMMENTLINE ||
2809
style == SCE_P_COMMENTBLOCK);
2813
return (style == SCE_F_COMMENT);
2816
return (style == SCE_PL_COMMENTLINE);
2818
case SCLEX_PROPERTIES:
2819
return (style == SCE_PROPS_COMMENT);
2822
return (style == SCE_PO_COMMENT);
2825
return (style == SCE_L_COMMENT);
2827
case SCLEX_MAKEFILE:
2828
return (style == SCE_MAKE_COMMENT);
2831
return (style == SCE_RB_COMMENTLINE);
2834
return (style == SCE_SH_COMMENTLINE);
2837
return (style == SCE_R_COMMENT);
2840
return (style == SCE_SQL_COMMENT ||
2305
2841
style == SCE_SQL_COMMENTLINE ||
2306
style == SCE_SQL_COMMENTDOC ||
2307
style == SCE_SQL_STRING)
2842
style == SCE_SQL_COMMENTDOC);
2311
2844
case SCLEX_TCL:
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)
2848
style == SCE_TCL_BLOCK_COMMENT);
2321
2850
case SCLEX_LUA:
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)
2853
style == SCE_LUA_COMMENTDOC);
2332
2855
case SCLEX_HASKELL:
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)
2859
style == SCE_HA_COMMENTBLOCK3);
2343
2861
case SCLEX_FREEBASIC:
2345
if (style == SCE_B_COMMENT ||
2346
style == SCE_B_STRING)
2862
return (style == SCE_B_COMMENT);
2350
2864
case SCLEX_HTML:
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)
2865
return (style == SCE_HPHP_COMMENTLINE ||
2866
style == SCE_HPHP_COMMENT ||
2867
style == SCE_H_COMMENT ||
2868
style == SCE_H_SGML_COMMENT);
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.
2877
static gboolean is_code_style(gint lexer, gint style)
2882
if (style == SCE_C_PREPROCESSOR)
2886
return !(is_comment_style(lexer, style) ||
2887
is_string_style(lexer, style));
2456
2977
pos += strlen(indent);
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);
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)
2469
2990
gint vis1, los, delta;
2470
GtkWidget *wid = GTK_WIDGET(sci);
2996
wid = GTK_WIDGET(editor->sci);
2472
2998
if (! wid->window || ! gdk_window_is_viewable(wid->window))
2473
2999
return; /* prevent gdk_window_scroll warning */
2475
3001
if (line == -1)
2476
line = sci_get_current_line(sci);
3002
line = sci_get_current_line(editor->sci);
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 */
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)
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);
3020
GeanyIndentPrefs iprefs = *editor_get_indent_prefs(editor);
3022
switch (iprefs.type)
3024
case GEANY_INDENT_TYPE_TABS:
3025
iprefs.type = GEANY_INDENT_TYPE_SPACES;
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;
3032
text = get_whitespace(&iprefs, iprefs.width);
3033
sci_add_text(editor->sci, text);
2499
void editor_select_word(ScintillaObject *sci)
3038
void editor_select_word(GeanyEditor *editor)
2505
g_return_if_fail(sci != NULL);
3044
g_return_if_fail(editor != NULL);
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);
2511
3050
if (start == end) /* caret in whitespaces sequence */
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)
2521
SSM(sci, SCI_SETSEL, start, end);
3060
SSM(editor->sci, SCI_SETSEL, start, end);
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)
2529
3068
gint start, end, line;
2531
g_return_if_fail(sci != NULL);
3070
g_return_if_fail(editor != NULL);
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);
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)
2542
line = sci_get_line_from_position(sci, start);
2543
start = sci_get_position_from_line(sci, line);
2545
line = sci_get_line_from_position(sci, end);
2546
end = sci_get_position_from_line(sci, line + 1);
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);
3084
line = sci_get_line_from_position(editor->sci, end);
3085
end = sci_get_position_from_line(editor->sci, line + 1);
3087
SSM(editor->sci, SCI_SETSEL, start, end);
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)
2556
3095
gboolean found_end = FALSE;
2558
3097
gchar *line_buf, *x;
3098
ScintillaObject *sci = editor->sci;
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);
2614
3155
if (line_found > 0)
2617
pos_start = SSM(sci, SCI_POSITIONFROMLINE, line_found, 0);
2619
line_found = find_paragraph_stop(sci, line_start, DOWN);
2620
pos_end = SSM(sci, SCI_POSITIONFROMLINE, line_found, 0);
2622
SSM(sci, SCI_SETSEL, pos_start, pos_end);
3158
pos_start = SSM(editor->sci, SCI_POSITIONFROMLINE, line_found, 0);
3160
line_found = find_paragraph_stop(editor, line_start, DOWN);
3161
pos_end = SSM(editor->sci, SCI_POSITIONFROMLINE, line_found, 0);
3163
SSM(editor->sci, SCI_SETSEL, pos_start, pos_end);
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)
2629
gint i, first_line, last_line;
2630
gint first_sel_start, first_sel_end, sel_start = 0, sel_end = 0;
2632
g_return_if_fail(DOC_IDX_VALID(idx));
2634
first_sel_start = sci_get_selection_start(doc_list[idx].sci);
2635
first_sel_end = sci_get_selection_end(doc_list[idx].sci);
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);
2644
pos = first_sel_start;
2646
/* get previous line and use it for get_indent to use that line
3170
gint i, sel_start = 0, sel_end = 0;
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));
2652
3176
for (i = first_line; i <= last_line; i++)
2654
3178
/* skip the first line or if the indentation of the previous and current line are equal */
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))
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)
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, "");
2667
sci_insert_text(doc_list[idx].sci, sel_start, indent);
3191
sci_insert_text(editor->sci, sel_start, indent);
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)
3199
gint first_line, last_line;
3200
gint first_sel_start, first_sel_end;
3201
ScintillaObject *sci;
3203
g_return_if_fail(editor != NULL);
3207
first_sel_start = sci_get_selection_start(sci);
3208
first_sel_end = sci_get_selection_end(sci);
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);
3216
pos = first_sel_start;
3218
SSM(sci, SCI_BEGINUNDOACTION, 0, 0);
3220
smart_line_indentation(editor, first_line, last_line);
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);
2676
SSM(doc_list[idx].sci, SCI_ENDUNDOACTION, 0, 0);
3225
gint indent_pos = SSM(sci, SCI_GETLINEINDENTPOSITION, first_line, 0);
3227
/* use indent position as user may wish to change indentation afterwards */
3228
sci_set_current_position(sci, indent_pos, FALSE);
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));
3237
SSM(sci, SCI_ENDUNDOACTION, 0, 0);
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)
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;
2686
g_return_if_fail(DOC_IDX_VALID(idx));
2688
sel_start = sci_get_selection_start(doc_list[idx].sci);
2689
sel_end = sci_get_selection_end(doc_list[idx].sci);
2691
first_line = sci_get_line_from_position(doc_list[idx].sci, sel_start);
3247
g_return_if_fail(editor != NULL);
3249
sel_start = sci_get_selection_start(editor->sci);
3250
sel_end = sci_get_selection_end(editor->sci);
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);
2698
3258
pos = sel_start;
2700
SSM(doc_list[idx].sci, SCI_BEGINUNDOACTION, 0, 0);
3260
SSM(editor->sci, SCI_BEGINUNDOACTION, 0, 0);
2702
3262
for (i = first_line; i <= last_line; i++)
2704
indentation_end = SSM(doc_list[idx].sci, SCI_GETLINEINDENTPOSITION, i, 0);
3264
indentation_end = SSM(editor->sci, SCI_GETLINEINDENTPOSITION, i, 0);
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--;
2713
if (sci_get_char_at(doc_list[idx].sci, indentation_end) == ' ')
3272
if (sci_get_char_at(editor->sci, indentation_end) == ' ')
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, "");
2718
3277
if (i == first_line)
2719
3278
first_line_offset = -1;
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)
2804
ScintillaObject *sci = doc_list[idx].sci;
2805
gint line = sci_get_current_line(sci);
3375
line = sci_get_current_line(editor->sci);
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);
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;
3381
if (! editor_line_in_view(editor, line))
3382
editor->scroll_percent = percent_of_view;
3387
* Deletes all currently set indicators in the @a editor window.
3388
* Error indicators (red squiggly underlines) and usual line markers are removed.
3390
* @param editor The editor to operate on.
3392
void editor_clear_indicators(GeanyEditor *editor)
3396
g_return_if_fail(editor != NULL);
3398
last_pos = sci_get_length(editor->sci);
3400
sci_indicator_clear(editor->sci, 0, last_pos);
3402
sci_marker_delete_all(editor->sci, 0); /* remove the yellow error line marker */
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.
3411
* @param editor The editor to operate on.
3412
* @param line The line number which should be marked.
3414
void editor_set_indicator_on_line(GeanyEditor *editor, gint line)
3423
start = sci_get_position_from_line(editor->sci, line);
3424
end = sci_get_position_from_line(editor->sci, line + 1);
3426
/* skip blank lines */
3427
if ((start + 1) == end ||
3428
sci_get_line_length(editor->sci, line) == editor_get_eol_char_len(editor))
3431
/* don't set the indicator on whitespace */
3433
linebuf = sci_get_line(editor->sci, line);
3435
while (isspace(linebuf[i])) i++;
3436
while (len > 1 && len > i && isspace(linebuf[len-1]))
3443
editor_set_indicator(editor, start + i, end);
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.
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.
3456
void editor_set_indicator(GeanyEditor *editor, gint start, gint end)
3458
if (editor == NULL || start >= end)
3461
sci_set_indicator(editor->sci, 0);
3462
sci_indicator_fill(editor->sci, start, end - start);
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)
3470
g_return_if_fail(editor != NULL);
3472
if (sci_has_selection(editor->sci))
3474
gint start = sci_get_selection_start(editor->sci);
3475
const gchar *replacement = colour;
3477
if (sci_get_char_at(editor->sci, start) == '0' &&
3478
sci_get_char_at(editor->sci, start + 1) == 'x')
3480
sci_set_selection_start(editor->sci, start + 2);
3481
sci_set_selection_end(editor->sci, start + 8);
3482
replacement++; /* skip the leading "0x" */
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 */
3488
sci_replace_sel(editor->sci, replacement);
3491
sci_add_text(editor->sci, colour);
3495
const gchar *editor_get_eol_char_name(GeanyEditor *editor)
3497
gint mode = file_prefs.default_eol_character;
3500
mode = sci_get_eol_mode(editor->sci);
3504
case SC_EOL_CRLF: return _("Win (CRLF)"); break;
3505
case SC_EOL_CR: return _("Mac (CR)"); break;
3506
default: return _("Unix (LF)"); break;
3511
/* returns the end-of-line character(s) length of the specified editor */
3512
gint editor_get_eol_char_len(GeanyEditor *editor)
3514
gint mode = file_prefs.default_eol_character;
3517
mode = sci_get_eol_mode(editor->sci);
3521
case SC_EOL_CRLF: return 2; break;
3522
default: return 1; break;
3527
/* returns the end-of-line character(s) of the specified editor */
3528
const gchar *editor_get_eol_char(GeanyEditor *editor)
3530
gint mode = file_prefs.default_eol_character;
3533
mode = sci_get_eol_mode(editor->sci);
3537
case SC_EOL_CRLF: return "\r\n"; break;
3538
case SC_EOL_CR: return "\r"; break;
3539
default: return "\n"; break;
3544
static void fold_all(GeanyEditor *editor, gboolean want_fold)
3546
gint lines, first, i;
3548
if (editor == NULL || ! editor_prefs.folding)
3551
lines = sci_get_line_count(editor->sci);
3552
first = sci_get_first_visible_line(editor->sci);
3554
for (i = 0; i < lines; i++)
3556
gint level = sci_get_fold_level(editor->sci, i);
3557
if (level & SC_FOLDLEVELHEADERFLAG)
3559
if (sci_get_fold_expanded(editor->sci, i) == want_fold)
3560
sci_toggle_fold(editor->sci, i);
3563
editor_scroll_to_line(editor, first, 0.0F);
3567
void editor_unfold_all(GeanyEditor *editor)
3569
fold_all(editor, FALSE);
3573
void editor_fold_all(GeanyEditor *editor)
3575
fold_all(editor, TRUE);
3579
void editor_replace_tabs(GeanyEditor *editor)
3581
gint search_pos, pos_in_line, current_tab_true_length;
3584
struct TextToFind ttf;
3589
sci_start_undo_action(editor->sci);
3590
tab_len = sci_get_tab_width(editor->sci);
3592
ttf.chrg.cpMax = sci_get_length(editor->sci);
3593
ttf.lpstrText = (gchar*) "\t";
3597
search_pos = sci_find_text(editor->sci, SCFIND_MATCHCASE, &ttf);
3598
if (search_pos == -1)
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;
3613
sci_end_undo_action(editor->sci);
3617
/* Replaces all occurrences all spaces of the length of a given tab_width. */
3618
void editor_replace_spaces(GeanyEditor *editor)
3621
static gdouble tab_len_f = -1.0; /* keep the last used value */
3623
struct TextToFind ttf;
3628
if (tab_len_f < 0.0)
3629
tab_len_f = sci_get_tab_width(editor->sci);
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))
3638
tab_len = (gint) tab_len_f;
3640
sci_start_undo_action(editor->sci);
3642
ttf.chrg.cpMax = sci_get_length(editor->sci);
3643
ttf.lpstrText = g_strnfill(tab_len, ' ');
3647
search_pos = sci_find_text(editor->sci, SCFIND_MATCHCASE, &ttf);
3648
if (search_pos == -1)
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;
3658
sci_end_undo_action(editor->sci);
3659
g_free(ttf.lpstrText);
3663
void editor_strip_line_trailing_spaces(GeanyEditor *editor, gint line)
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);
3670
while ((i >= line_start) && ((ch == ' ') || (ch == '\t')))
3673
ch = sci_get_char_at(editor->sci, i);
3675
if (i < (line_end-1))
3677
sci_target_start(editor->sci, i + 1);
3678
sci_target_end(editor->sci, line_end);
3679
sci_target_replace(editor->sci, "", FALSE);
3684
void editor_strip_trailing_spaces(GeanyEditor *editor)
3686
gint max_lines = sci_get_line_count(editor->sci);
3689
sci_start_undo_action(editor->sci);
3691
for (line = 0; line < max_lines; line++)
3693
editor_strip_line_trailing_spaces(editor, line);
3695
sci_end_undo_action(editor->sci);
3699
void editor_ensure_final_newline(GeanyEditor *editor)
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);
3707
append_newline = end_document > sci_get_position_from_line(editor->sci, max_lines - 1);
3711
const gchar *eol = "\n";
3712
switch (sci_get_eol_mode(editor->sci))
3721
sci_insert_text(editor->sci, end_document, eol);
3726
void editor_set_font(GeanyEditor *editor, const gchar *font)
3730
PangoFontDescription *pfd;
3732
g_return_if_fail(editor);
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);
3739
for (style = 0; style <= 127; style++)
3740
sci_set_font(editor->sci, style, font_name, size);
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);
3748
/* zoom to 100% to prevent confusion */
3749
sci_zoom_off(editor->sci);
3753
void editor_set_line_wrapping(GeanyEditor *editor, gboolean wrap)
3755
g_return_if_fail(editor != NULL);
3757
editor->line_wrapping = wrap;
3758
sci_set_lines_wrapped(editor->sci, wrap);
3762
/* Also sets indent width, tab width. */
3763
void editor_set_indent_type(GeanyEditor *editor, GeanyIndentType type)
3765
const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(editor);
3766
ScintillaObject *sci = editor->sci;
3767
gboolean use_tabs = type != GEANY_INDENT_TYPE_SPACES;
3769
editor->indent_type = type;
3770
sci_set_use_tabs(sci, use_tabs);
3772
if (type == GEANY_INDENT_TYPE_BOTH)
3773
sci_set_tab_width(sci, iprefs->hard_tab_width);
3775
sci_set_tab_width(sci, iprefs->width);
3776
SSM(sci, SCI_SETINDENT, iprefs->width, 0);
3778
/* remove indent spaces on backspace, if using any spaces to indent */
3779
SSM(sci, SCI_SETBACKSPACEUNINDENTS, type != GEANY_INDENT_TYPE_TABS, 0);
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)
3789
g_return_val_if_fail(editor, FALSE);
3795
gint line = sci_get_line_from_position(editor->sci, pos);
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);
3802
sci_goto_pos(editor->sci, pos, TRUE);
3803
editor->scroll_percent = 0.25F;
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);
3814
on_editor_scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
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)
3820
GeanyEditor *editor = user_data;
3821
sci_cmd(editor->sci, (event->direction == GDK_SCROLL_DOWN) ? SCI_PAGEDOWN : SCI_PAGEUP);
3825
return FALSE; /* let Scintilla handle all other cases */
3829
static void editor_colourise(ScintillaObject *sci)
3831
sci_colourise(sci, 0, -1);
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);
3840
static gboolean on_editor_expose_event(GtkWidget *widget, GdkEventExpose *event,
3843
GeanyDocument *doc = user_data;
3845
if (doc->priv->colourise_needed)
3847
editor_colourise(doc->editor->sci);
3848
doc->priv->colourise_needed = FALSE;
3850
return FALSE; /* propagate event */
3854
static void setup_sci_keys(ScintillaObject *sci)
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 */
3870
if (editor_prefs.use_gtk_word_boundaries)
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);
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);
3884
sci_clear_cmdkey(sci, SCK_BACK | (SCMOD_ALT << 16)); /* clear Alt-Backspace (Undo) */
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)
3893
ScintillaObject *sci;
3895
sci = SCINTILLA(scintilla_new());
3896
scintilla_set_id(sci, doc->index);
3898
gtk_widget_show(GTK_WIDGET(sci));
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);
3905
setup_sci_keys(sci);
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);
3915
/* only connect signals if this is for the document notebook, not split window */
3916
if (doc->editor->sci == NULL)
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);
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)
3932
const GeanyIndentPrefs *iprefs = get_default_indent_prefs();
3933
ScintillaObject *old, *sci;
3935
/* temporarily change editor to use the new sci widget */
3937
sci = create_new_sci(editor->document);
3940
editor_set_indent_type(editor, iprefs->type);
3941
editor_set_font(editor, interface_prefs.editor_font);
3943
/* if editor already had a widget, restore it */
3950
GeanyEditor *editor_create(GeanyDocument *doc)
3952
const GeanyIndentPrefs *iprefs = get_default_indent_prefs();
3953
GeanyEditor *editor = g_new0(GeanyEditor, 1);
3955
editor->document = doc;
3956
doc->editor = editor; /* needed in case some editor functions/callbacks expect it */
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;
3963
editor->sci = editor_create_widget(editor);
3968
/* in case we need to free some fields in future */
3969
void editor_destroy(GeanyEditor *editor)
3975
void editor_init(void)
3977
static GeanyIndentPrefs indent_prefs;
3979
memset(&editor_prefs, 0, sizeof(GeanyEditorPrefs));
3980
memset(&indent_prefs, 0, sizeof(GeanyIndentPrefs));
3981
editor_prefs.indentation = &indent_prefs;
3985
/** TODO: Should these be user-defined instead of hard-coded? */
3986
void editor_set_indentation_guides(GeanyEditor *editor)
3991
g_return_if_fail(editor != NULL);
3993
if (! editor_prefs.show_indent_guide)
3995
sci_set_indentation_guides(editor->sci, SC_IV_NONE);
3999
lexer = sci_get_lexer(editor->sci);
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. */
4010
/* These languages use indentation for control blocks; the "look forward" method works
4014
case SCLEX_MAKEFILE:
4017
case SCLEX_PROPERTIES:
4018
case SCLEX_FORTRAN: /* Is this the best option for Fortran? */
4020
mode = SC_IV_LOOKFORWARD;
4023
/* C-like (structured) languages benefit from the "look both" method */
4037
case SCLEX_FREEBASIC:
4040
mode = SC_IV_LOOKBOTH;
4048
sci_set_indentation_guides(editor->sci, mode);
4052
/* Apply just the prefs that can change in the Preferences dialog */
4053
void editor_apply_update_prefs(GeanyEditor *editor)
4055
ScintillaObject *sci;
4057
g_return_if_fail(editor != NULL);
4061
sci_set_mark_long_lines(sci, editor_prefs.long_line_type,
4062
editor_prefs.long_line_column, editor_prefs.long_line_color);
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);
4068
sci_set_autoc_max_height(sci, editor_prefs.symbolcompletion_max_height);
4070
editor_set_indentation_guides(editor);
4072
sci_set_visible_white_spaces(sci, editor_prefs.show_white_space);
4073
sci_set_visible_eols(sci, editor_prefs.show_line_endings);
4075
sci_set_folding_margin_visible(sci, editor_prefs.folding);
4077
/* (dis)allow scrolling past end of document */
4078
sci_set_scroll_stop_at_last_line(sci, editor_prefs.scroll_stop_at_last_line);
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);