Merge pull request #3877 from techee/ctags_sync6
[geany-mirror.git] / src / highlighting.c
blobb2d5608b5746e04e991d5dd191b0938263dc44f3
1 /*
2 * highlighting.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2005 The Geany contributors
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 /**
22 * @file highlighting.h
23 * Syntax highlighting for the different filetypes, using the Scintilla lexers.
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include "highlighting.h"
31 #include "highlightingmappings.h"
33 #include "app.h"
34 #include "dialogs.h"
35 #include "document.h"
36 #include "editor.h"
37 #include "filetypesprivate.h"
38 #include "sciwrappers.h"
39 #include "support.h"
40 #include "symbols.h"
41 #include "ui_utils.h"
42 #include "utils.h"
44 #include "SciLexer.h"
46 #include <stdlib.h>
47 #include <ctype.h>
48 #include <string.h>
49 #include <glib.h>
50 #include <glib/gprintf.h>
53 #define GEANY_COLORSCHEMES_SUBDIR "colorschemes"
55 /* Whitespace has to be set after setting wordchars. */
56 #define GEANY_WHITESPACE_CHARS " \t" "!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~"
59 static gchar *whitespace_chars = NULL;
62 typedef struct
64 gsize count; /* number of styles */
65 GeanyLexerStyle *styling; /* array of styles, NULL if not used or uninitialised */
66 gchar **keywords;
67 gchar *wordchars; /* NULL used for style sets with no styles */
68 gchar **property_keys;
69 gchar **property_values;
70 } StyleSet;
72 /* each filetype has a styleset but GEANY_FILETYPES_NONE uses common_style_set for styling */
73 static StyleSet *style_sets = NULL;
76 enum /* Geany common styling */
78 GCS_DEFAULT,
79 GCS_SELECTION,
80 GCS_BRACE_GOOD,
81 GCS_BRACE_BAD,
82 GCS_MARGIN_LINENUMBER,
83 GCS_MARGIN_FOLDING,
84 GCS_FOLD_SYMBOL_HIGHLIGHT,
85 GCS_CURRENT_LINE,
86 GCS_CARET,
87 GCS_INDENT_GUIDE,
88 GCS_WHITE_SPACE,
89 GCS_LINE_WRAP_VISUALS,
90 GCS_LINE_WRAP_INDENT,
91 GCS_TRANSLUCENCY,
92 GCS_MARKER_LINE,
93 GCS_MARKER_SEARCH,
94 GCS_MARKER_MARK,
95 GCS_MARKER_TRANSLUCENCY,
96 GCS_LINE_HEIGHT,
97 GCS_CALLTIPS,
98 GCS_INDICATOR_ERROR,
99 GCS_MAX
102 static struct
104 GeanyLexerStyle styling[GCS_MAX];
106 /* icon style, 1-4 */
107 gint fold_marker;
108 /* vertical line style, 0-2 */
109 gint fold_lines;
110 /* horizontal line when folded, 0-2 */
111 gint fold_draw_line;
113 gchar *wordchars;
114 } common_style_set = { { { 0 } }, 0, 0, 0, NULL };
117 /* For filetypes.common [named_styles] section.
118 * 0xBBGGRR format.
119 * e.g. "comment" => &GeanyLexerStyle{0x0000d0, 0xffffff, FALSE, FALSE} */
120 static GHashTable *named_style_hash = NULL;
122 /* 0xBBGGRR format, set by "default" named style. */
123 static GeanyLexerStyle gsd_default = {0x000000, 0xffffff, FALSE, FALSE};
126 /* filetypes should use the filetypes.foo [lexer_properties] group instead of hardcoding */
127 static void sci_set_property(ScintillaObject *sci, const gchar *name, const gchar *value)
129 SSM(sci, SCI_SETPROPERTY, (uptr_t) name, (sptr_t) value);
133 static void new_styleset(guint file_type_id, gsize styling_count)
135 StyleSet *set = &style_sets[file_type_id];
137 set->count = styling_count;
138 set->styling = g_new0(GeanyLexerStyle, styling_count);
142 static void free_styleset(guint file_type_id)
144 StyleSet *style_ptr;
145 style_ptr = &style_sets[file_type_id];
147 style_ptr->count = 0;
148 g_free(style_ptr->styling);
149 style_ptr->styling = NULL;
150 g_strfreev(style_ptr->keywords);
151 style_ptr->keywords = NULL;
152 g_free(style_ptr->wordchars);
153 style_ptr->wordchars = NULL;
154 g_strfreev(style_ptr->property_keys);
155 style_ptr->property_keys = NULL;
156 g_strfreev(style_ptr->property_values);
157 style_ptr->property_values = NULL;
161 static void get_keyfile_keywords(GKeyFile *config, GKeyFile *configh,
162 const gchar *key, guint ft_id, guint pos)
164 style_sets[ft_id].keywords[pos] =
165 utils_get_setting(string, configh, config, "keywords", key, "");
169 static void get_keyfile_wordchars(GKeyFile *config, GKeyFile *configh, gchar **wordchars,
170 const gchar *default_wordchars)
172 *wordchars = utils_get_setting(string, configh, config,
173 "settings", "wordchars", default_wordchars);
177 static gboolean read_named_style(const gchar *named_style, GeanyLexerStyle *style)
179 GeanyLexerStyle *cs;
180 gchar *comma, *name = NULL;
181 const gchar *bold = NULL;
182 const gchar *italic = NULL;
184 g_return_val_if_fail(named_style, FALSE);
185 name = utils_strdupa(named_style); /* named_style must not be written to, may be a static string */
187 comma = strstr(name, ",");
188 if (comma)
190 bold = strstr(comma, ",bold");
191 italic = strstr(comma, ",italic");
192 *comma = '\0'; /* terminate name to make lookup work */
194 cs = g_hash_table_lookup(named_style_hash, name);
196 if (cs)
198 *style = *cs;
199 if (bold)
200 style->bold = !style->bold;
201 if (italic)
202 style->italic = !style->italic;
204 else
206 *style = gsd_default;
208 return (cs != NULL);
212 /* Parses a color in `str` which can be an HTML color (ex. #0099cc),
213 * an abbreviated HTML color (ex. #09c) or a hex string color
214 * (ex. 0x0099cc). The result of the conversion is stored into the
215 * location pointed to by `clr`. */
216 static void parse_color(GKeyFile *kf, const gchar *str, gint *clr)
218 gint c;
219 gchar *named_color = NULL;
221 g_return_if_fail(clr != NULL);
223 if (G_UNLIKELY(EMPTY(str)))
224 return;
226 named_color = g_key_file_get_string(kf, "named_colors", str, NULL);
227 if (named_color)
228 str = named_color;
230 c = utils_parse_color_to_bgr(str);
231 if (c == -1)
232 geany_debug("Bad color '%s'", str);
233 else
234 *clr = c;
236 g_free(named_color);
240 static void parse_keyfile_style(GKeyFile *kf, gchar **list,
241 const GeanyLexerStyle *default_style, GeanyLexerStyle *style)
243 gsize len;
245 g_return_if_fail(default_style);
246 g_return_if_fail(style);
248 *style = *default_style;
250 if (!list)
251 return;
253 len = g_strv_length(list);
254 if (len == 0)
255 return;
256 else if (len == 1)
258 gchar **items = g_strsplit(list[0], ",", 0);
259 if (items != NULL)
261 if (g_strv_length(items) > 0)
263 if (g_hash_table_lookup(named_style_hash, items[0]) != NULL)
265 if (!read_named_style(list[0], style))
266 geany_debug("Unable to read named style '%s'", items[0]);
267 g_strfreev(items);
268 return;
270 else if (strchr(list[0], ',') != NULL)
272 geany_debug("Unknown named style '%s'", items[0]);
273 g_strfreev(items);
274 return;
277 g_strfreev(items);
281 switch (len)
283 case 4:
284 style->italic = utils_atob(list[3]);
285 /* fall through */
286 case 3:
287 style->bold = utils_atob(list[2]);
288 /* fall through */
289 case 2:
290 parse_color(kf, list[1], &style->background);
291 /* fall through */
292 case 1:
293 parse_color(kf, list[0], &style->foreground);
298 static void get_keyfile_style(GKeyFile *config, GKeyFile *configh,
299 const gchar *key_name, GeanyLexerStyle *style)
301 gchar **list;
302 gsize len;
304 g_return_if_fail(config);
305 g_return_if_fail(configh);
306 g_return_if_fail(key_name);
307 g_return_if_fail(style);
309 list = g_key_file_get_string_list(configh, "styling", key_name, &len, NULL);
310 if (list == NULL)
312 list = g_key_file_get_string_list(config, "styling", key_name, &len, NULL);
313 parse_keyfile_style(config, list, &gsd_default, style);
315 else
316 parse_keyfile_style(configh, list, &gsd_default, style);
318 g_strfreev(list);
322 static void convert_int(const gchar *int_str, gint *val)
324 gchar *end;
325 gint v = strtol(int_str, &end, 10);
327 if (int_str != end)
328 *val = v;
332 /* Get first and second integer numbers, store in foreground and background fields of @a style. */
333 static void get_keyfile_int(GKeyFile *config, GKeyFile *configh, const gchar *section,
334 const gchar *key, gint fdefault_val, gint sdefault_val,
335 GeanyLexerStyle *style)
337 gchar **list;
338 gsize len;
339 GeanyLexerStyle def = {fdefault_val, sdefault_val, FALSE, FALSE};
341 g_return_if_fail(config);
342 g_return_if_fail(configh);
343 g_return_if_fail(section);
344 g_return_if_fail(key);
346 list = g_key_file_get_string_list(configh, section, key, &len, NULL);
347 if (list == NULL)
348 list = g_key_file_get_string_list(config, section, key, &len, NULL);
350 *style = def;
351 if (!list)
352 return;
354 if (list[0])
356 convert_int(list[0], &style->foreground);
357 if (list[1])
359 convert_int(list[1], &style->background);
362 g_strfreev(list);
366 /* first or second can be NULL. */
367 static void get_keyfile_ints(GKeyFile *config, GKeyFile *configh, const gchar *section,
368 const gchar *key,
369 gint fdefault_val, gint sdefault_val,
370 gint *first, gint *second)
372 GeanyLexerStyle tmp_style;
374 get_keyfile_int(config, configh, section, key, fdefault_val, sdefault_val, &tmp_style);
375 if (first)
376 *first = tmp_style.foreground;
377 if (second)
378 *second = tmp_style.background;
382 static guint invert(guint icolour)
384 if (interface_prefs.highlighting_invert_all)
385 return 0xffffff - icolour;
387 return icolour;
391 static GeanyLexerStyle *get_style(guint ft_id, guint styling_index)
393 g_assert(ft_id < filetypes_array->len);
395 if (G_UNLIKELY(ft_id == GEANY_FILETYPES_NONE))
397 g_assert(styling_index < GCS_MAX);
398 return &common_style_set.styling[styling_index];
400 else
402 StyleSet *set = &style_sets[ft_id];
404 g_assert(styling_index < set->count);
405 return &set->styling[styling_index];
410 static void set_sci_style(ScintillaObject *sci, guint style, guint ft_id, guint styling_index)
412 GeanyLexerStyle *style_ptr = get_style(ft_id, styling_index);
414 SSM(sci, SCI_STYLESETFORE, style, invert(style_ptr->foreground));
415 SSM(sci, SCI_STYLESETBACK, style, invert(style_ptr->background));
416 SSM(sci, SCI_STYLESETBOLD, style, style_ptr->bold);
417 SSM(sci, SCI_STYLESETITALIC, style, style_ptr->italic);
421 void highlighting_free_styles(void)
423 guint i;
425 for (i = 0; i < filetypes_array->len; i++)
426 free_styleset(i);
428 if (named_style_hash)
429 g_hash_table_destroy(named_style_hash);
431 g_free(style_sets);
435 static gchar*
436 get_keyfile_whitespace_chars(GKeyFile *config, GKeyFile *configh)
438 return utils_get_setting(string, configh, config,
439 "settings", "whitespace_chars", GEANY_WHITESPACE_CHARS);
443 static void add_named_style(GKeyFile *config, const gchar *key)
445 const gchar group[] = "named_styles";
446 gchar **list;
447 gsize len;
449 list = g_key_file_get_string_list(config, group, key, &len, NULL);
450 /* we allow a named style to reference another style above it */
451 if (list && len >= 1)
453 GeanyLexerStyle *style = g_new0(GeanyLexerStyle, 1);
455 parse_keyfile_style(config, list, &gsd_default, style);
456 g_hash_table_insert(named_style_hash, g_strdup(key), style);
458 g_strfreev(list);
462 static void get_named_styles(GKeyFile *config)
464 const gchar group[] = "named_styles";
465 gchar **keys = g_key_file_get_keys(config, group, NULL, NULL);
466 gchar **ptr = keys;
468 if (!ptr)
469 return;
471 while (1)
473 const gchar *key = *ptr;
475 if (!key)
476 break;
478 /* don't replace already read default style with system one */
479 if (!g_str_equal(key, "default"))
480 add_named_style(config, key);
482 ptr++;
484 g_strfreev(keys);
488 static GKeyFile *utils_key_file_new(const gchar *filename)
490 GKeyFile *config = g_key_file_new();
492 g_key_file_load_from_file(config, filename, G_KEY_FILE_KEEP_COMMENTS, NULL);
493 return config;
497 static void load_named_styles(GKeyFile *config, GKeyFile *config_home)
499 const gchar *scheme = editor_prefs.color_scheme;
500 gboolean free_kf = FALSE;
502 if (named_style_hash)
503 g_hash_table_destroy(named_style_hash); /* reloading */
505 named_style_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
507 if (!EMPTY(scheme))
509 gchar *path, *path_home;
511 path = g_build_path(G_DIR_SEPARATOR_S, app->datadir, GEANY_COLORSCHEMES_SUBDIR, scheme, NULL);
512 path_home = g_build_path(G_DIR_SEPARATOR_S, app->configdir, GEANY_COLORSCHEMES_SUBDIR, scheme, NULL);
514 if (g_file_test(path, G_FILE_TEST_EXISTS) || g_file_test(path_home, G_FILE_TEST_EXISTS))
516 config = utils_key_file_new(path);
517 config_home = utils_key_file_new(path_home);
518 free_kf = TRUE;
520 /* if color scheme is missing, use default */
521 g_free(path);
522 g_free(path_home);
524 /* first set default to the "default" named style */
525 add_named_style(config, "default");
526 read_named_style("default", &gsd_default); /* in case user overrides but not with both colors */
527 add_named_style(config_home, "default");
528 read_named_style("default", &gsd_default);
530 get_named_styles(config);
531 /* home overrides any system named style */
532 get_named_styles(config_home);
534 if (free_kf)
536 g_key_file_free(config);
537 g_key_file_free(config_home);
542 static void styleset_common_init(GKeyFile *config, GKeyFile *config_home)
544 load_named_styles(config, config_home);
546 get_keyfile_style(config, config_home, "default", &common_style_set.styling[GCS_DEFAULT]);
547 get_keyfile_style(config, config_home, "selection", &common_style_set.styling[GCS_SELECTION]);
548 get_keyfile_style(config, config_home, "brace_good", &common_style_set.styling[GCS_BRACE_GOOD]);
549 get_keyfile_style(config, config_home, "brace_bad", &common_style_set.styling[GCS_BRACE_BAD]);
550 get_keyfile_style(config, config_home, "margin_linenumber", &common_style_set.styling[GCS_MARGIN_LINENUMBER]);
551 get_keyfile_style(config, config_home, "margin_folding", &common_style_set.styling[GCS_MARGIN_FOLDING]);
552 get_keyfile_style(config, config_home, "fold_symbol_highlight", &common_style_set.styling[GCS_FOLD_SYMBOL_HIGHLIGHT]);
553 get_keyfile_style(config, config_home, "current_line", &common_style_set.styling[GCS_CURRENT_LINE]);
554 get_keyfile_style(config, config_home, "caret", &common_style_set.styling[GCS_CARET]);
555 get_keyfile_style(config, config_home, "indent_guide", &common_style_set.styling[GCS_INDENT_GUIDE]);
556 get_keyfile_style(config, config_home, "white_space", &common_style_set.styling[GCS_WHITE_SPACE]);
557 get_keyfile_style(config, config_home, "marker_line", &common_style_set.styling[GCS_MARKER_LINE]);
558 get_keyfile_style(config, config_home, "marker_search", &common_style_set.styling[GCS_MARKER_SEARCH]);
559 get_keyfile_style(config, config_home, "marker_mark", &common_style_set.styling[GCS_MARKER_MARK]);
560 get_keyfile_style(config, config_home, "calltips", &common_style_set.styling[GCS_CALLTIPS]);
561 get_keyfile_style(config, config_home, "indicator_error", &common_style_set.styling[GCS_INDICATOR_ERROR]);
563 get_keyfile_ints(config, config_home, "styling", "folding_style",
564 1, 1, &common_style_set.fold_marker, &common_style_set.fold_lines);
565 get_keyfile_ints(config, config_home, "styling", "folding_horiz_line",
566 2, 0, &common_style_set.fold_draw_line, NULL);
567 get_keyfile_ints(config, config_home, "styling", "caret_width",
568 1, 0, &common_style_set.styling[GCS_CARET].background, NULL); /* caret.foreground used earlier */
569 get_keyfile_int(config, config_home, "styling", "line_wrap_visuals",
570 3, 0, &common_style_set.styling[GCS_LINE_WRAP_VISUALS]);
571 get_keyfile_int(config, config_home, "styling", "line_wrap_indent",
572 0, 0, &common_style_set.styling[GCS_LINE_WRAP_INDENT]);
573 get_keyfile_int(config, config_home, "styling", "translucency",
574 256, 256, &common_style_set.styling[GCS_TRANSLUCENCY]);
575 get_keyfile_int(config, config_home, "styling", "marker_translucency",
576 256, 256, &common_style_set.styling[GCS_MARKER_TRANSLUCENCY]);
577 get_keyfile_int(config, config_home, "styling", "line_height",
578 0, 0, &common_style_set.styling[GCS_LINE_HEIGHT]);
580 g_free(common_style_set.wordchars);
581 get_keyfile_wordchars(config, config_home, &common_style_set.wordchars, GEANY_WORDCHARS);
582 g_free(whitespace_chars);
583 whitespace_chars = get_keyfile_whitespace_chars(config, config_home);
587 static void set_character_classes(ScintillaObject *sci, guint ft_id)
589 const gchar *word = (ft_id == GEANY_FILETYPES_NONE ?
590 common_style_set.wordchars : style_sets[ft_id].wordchars);
591 gchar *whitespace;
592 guint i, j;
594 SSM(sci, SCI_SETWORDCHARS, 0, (sptr_t) word);
596 /* setting wordchars resets character classes, so we have to set whitespaces after
597 * wordchars, but we want wordchars to have precenence over whitepace chars */
598 whitespace = g_malloc0(strlen(whitespace_chars) + 1);
599 for (i = 0, j = 0; whitespace_chars[i] != 0; i++)
601 if (! strchr(word, whitespace_chars[i]))
602 whitespace[j++] = whitespace_chars[i];
604 whitespace[j] = 0;
606 SSM(sci, SCI_SETWHITESPACECHARS, 0, (sptr_t) whitespace);
608 g_free(whitespace);
612 static void styleset_common(ScintillaObject *sci, guint ft_id)
614 GeanyLexerStyle *style;
616 SSM(sci, SCI_STYLECLEARALL, 0, 0);
618 set_character_classes(sci, ft_id);
620 /* caret colour, style and width */
621 SSM(sci, SCI_SETCARETFORE, invert(common_style_set.styling[GCS_CARET].foreground), 0);
622 SSM(sci, SCI_SETCARETWIDTH, common_style_set.styling[GCS_CARET].background, 0);
623 if (common_style_set.styling[GCS_CARET].bold)
624 SSM(sci, SCI_SETCARETSTYLE, CARETSTYLE_BLOCK, 0);
625 else
626 SSM(sci, SCI_SETCARETSTYLE, CARETSTYLE_LINE, 0);
628 /* line height */
629 SSM(sci, SCI_SETEXTRAASCENT, common_style_set.styling[GCS_LINE_HEIGHT].foreground, 0);
630 SSM(sci, SCI_SETEXTRADESCENT, common_style_set.styling[GCS_LINE_HEIGHT].background, 0);
632 /* colourise the current line */
633 SSM(sci, SCI_SETCARETLINEBACK, invert(common_style_set.styling[GCS_CURRENT_LINE].background), 0);
634 /* bold=enable current line */
635 SSM(sci, SCI_SETCARETLINEVISIBLE, common_style_set.styling[GCS_CURRENT_LINE].bold, 0);
637 /* Translucency for current line and selection */
638 SSM(sci, SCI_SETCARETLINEBACKALPHA, common_style_set.styling[GCS_TRANSLUCENCY].foreground, 0);
639 SSM(sci, SCI_SETSELALPHA, common_style_set.styling[GCS_TRANSLUCENCY].background, 0);
641 /* line wrapping visuals */
642 SSM(sci, SCI_SETWRAPVISUALFLAGS,
643 common_style_set.styling[GCS_LINE_WRAP_VISUALS].foreground, 0);
644 SSM(sci, SCI_SETWRAPVISUALFLAGSLOCATION,
645 common_style_set.styling[GCS_LINE_WRAP_VISUALS].background, 0);
646 SSM(sci, SCI_SETWRAPSTARTINDENT, common_style_set.styling[GCS_LINE_WRAP_INDENT].foreground, 0);
647 SSM(sci, SCI_SETWRAPINDENTMODE, common_style_set.styling[GCS_LINE_WRAP_INDENT].background, 0);
649 /* Error indicator */
650 SSM(sci, SCI_INDICSETSTYLE, GEANY_INDICATOR_ERROR, INDIC_SQUIGGLEPIXMAP);
651 SSM(sci, SCI_INDICSETFORE, GEANY_INDICATOR_ERROR,
652 invert(common_style_set.styling[GCS_INDICATOR_ERROR].foreground));
654 /* Search indicator, used for 'Mark' matches */
655 SSM(sci, SCI_INDICSETSTYLE, GEANY_INDICATOR_SEARCH, INDIC_ROUNDBOX);
656 SSM(sci, SCI_INDICSETFORE, GEANY_INDICATOR_SEARCH,
657 invert(common_style_set.styling[GCS_MARKER_SEARCH].background));
658 SSM(sci, SCI_INDICSETALPHA, GEANY_INDICATOR_SEARCH, 60);
660 /* Snippet cursor indicator, when inserting snippets with multiple
661 * cursor positions. */
662 SSM(sci, SCI_INDICSETSTYLE, GEANY_INDICATOR_SNIPPET, INDIC_DOTBOX);
663 SSM(sci, SCI_INDICSETALPHA, GEANY_INDICATOR_SNIPPET, 60);
665 /* define marker symbols
666 * 0 -> line marker */
667 SSM(sci, SCI_MARKERDEFINE, 0, SC_MARK_SHORTARROW);
668 SSM(sci, SCI_MARKERSETFORE, 0, invert(common_style_set.styling[GCS_MARKER_LINE].foreground));
669 SSM(sci, SCI_MARKERSETBACK, 0, invert(common_style_set.styling[GCS_MARKER_LINE].background));
670 SSM(sci, SCI_MARKERSETALPHA, 0, common_style_set.styling[GCS_MARKER_TRANSLUCENCY].foreground);
672 /* 1 -> user marker */
673 SSM(sci, SCI_MARKERDEFINE, 1, SC_MARK_PLUS);
674 SSM(sci, SCI_MARKERSETFORE, 1, invert(common_style_set.styling[GCS_MARKER_MARK].foreground));
675 SSM(sci, SCI_MARKERSETBACK, 1, invert(common_style_set.styling[GCS_MARKER_MARK].background));
676 SSM(sci, SCI_MARKERSETALPHA, 1, common_style_set.styling[GCS_MARKER_TRANSLUCENCY].background);
678 /* 2 -> folding marker, other folding settings */
679 SSM(sci, SCI_SETMARGINTYPEN, 2, SC_MARGIN_SYMBOL);
680 SSM(sci, SCI_SETMARGINMASKN, 2, SC_MASK_FOLDERS);
682 /* drawing a horizontal line when text if folded */
683 switch (common_style_set.fold_draw_line)
685 case 1:
687 SSM(sci, SCI_SETFOLDFLAGS, 4, 0);
688 break;
690 case 2:
692 SSM(sci, SCI_SETFOLDFLAGS, 16, 0);
693 break;
695 default:
697 SSM(sci, SCI_SETFOLDFLAGS, 0, 0);
698 break;
702 /* choose the folding style - boxes or circles, I prefer boxes, so it is default ;-) */
703 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND, SC_MARK_EMPTY);
704 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_EMPTY);
705 switch (common_style_set.fold_marker)
707 case 2:
708 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS);
709 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS);
710 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND, SC_MARK_CIRCLEPLUSCONNECTED);
711 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_CIRCLEMINUSCONNECTED);
712 break;
713 default:
714 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS);
715 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS);
716 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED);
717 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED);
718 break;
719 case 3:
720 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_ARROWDOWN);
721 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_ARROW);
722 break;
723 case 4:
724 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_MINUS);
725 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_PLUS);
726 break;
729 /* choose the folding style - straight or curved, I prefer straight, so it is default ;-) */
730 switch (common_style_set.fold_lines)
732 case 2:
733 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE);
734 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE);
735 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
736 break;
737 default:
738 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER);
739 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER);
740 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
741 break;
742 case 0:
743 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_EMPTY);
744 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_EMPTY);
745 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_EMPTY);
746 break;
749 gint markers[] = {
750 SC_MARKNUM_FOLDEROPEN,
751 SC_MARKNUM_FOLDER,
752 SC_MARKNUM_FOLDERSUB,
753 SC_MARKNUM_FOLDERTAIL,
754 SC_MARKNUM_FOLDEREND,
755 SC_MARKNUM_FOLDEROPENMID,
756 SC_MARKNUM_FOLDERMIDTAIL
758 guint i;
760 foreach_range(i, G_N_ELEMENTS(markers))
762 SSM(sci, SCI_MARKERSETFORE, markers[i],
763 invert(common_style_set.styling[GCS_FOLD_SYMBOL_HIGHLIGHT].foreground));
764 SSM(sci, SCI_MARKERSETBACK, markers[i],
765 invert(common_style_set.styling[GCS_MARGIN_FOLDING].foreground));
769 /* set some common defaults */
770 sci_set_property(sci, "fold", "1");
771 sci_set_property(sci, "fold.compact", "0");
772 sci_set_property(sci, "fold.comment", "1");
773 sci_set_property(sci, "fold.preprocessor", "1");
774 sci_set_property(sci, "fold.at.else", "1");
776 style = &common_style_set.styling[GCS_SELECTION];
777 if (!style->bold && !style->italic)
779 geany_debug("selection style is set to invisible - ignoring!");
780 style->italic = TRUE;
781 style->background = 0xc0c0c0;
783 /* bold (3rd argument) is whether to override default foreground selection */
784 SSM(sci, SCI_SETSELFORE, style->bold, invert(style->foreground));
785 /* italic (4th argument) is whether to override default background selection */
786 SSM(sci, SCI_SETSELBACK, style->italic, invert(style->background));
788 SSM(sci, SCI_SETFOLDMARGINCOLOUR, 1, invert(common_style_set.styling[GCS_MARGIN_FOLDING].background));
789 SSM(sci, SCI_SETFOLDMARGINHICOLOUR, 1, invert(common_style_set.styling[GCS_MARGIN_FOLDING].background));
790 set_sci_style(sci, STYLE_LINENUMBER, GEANY_FILETYPES_NONE, GCS_MARGIN_LINENUMBER);
791 set_sci_style(sci, STYLE_BRACELIGHT, GEANY_FILETYPES_NONE, GCS_BRACE_GOOD);
792 set_sci_style(sci, STYLE_BRACEBAD, GEANY_FILETYPES_NONE, GCS_BRACE_BAD);
793 set_sci_style(sci, STYLE_INDENTGUIDE, GEANY_FILETYPES_NONE, GCS_INDENT_GUIDE);
795 /* bold = common whitespace settings enabled */
796 SSM(sci, SCI_SETWHITESPACEFORE, common_style_set.styling[GCS_WHITE_SPACE].bold,
797 invert(common_style_set.styling[GCS_WHITE_SPACE].foreground));
798 SSM(sci, SCI_SETWHITESPACEBACK, common_style_set.styling[GCS_WHITE_SPACE].italic,
799 invert(common_style_set.styling[GCS_WHITE_SPACE].background));
801 if (common_style_set.styling[GCS_CALLTIPS].bold)
802 SSM(sci, SCI_CALLTIPSETFORE, invert(common_style_set.styling[GCS_CALLTIPS].foreground), 1);
803 if (common_style_set.styling[GCS_CALLTIPS].italic)
804 SSM(sci, SCI_CALLTIPSETBACK, invert(common_style_set.styling[GCS_CALLTIPS].background), 1);
808 /* Merge & assign global typedefs and user secondary keywords.
809 * keyword_idx is used for both style_sets[].keywords and scintilla keyword style number */
810 static void merge_type_keywords(ScintillaObject *sci, guint ft_id, guint keyword_idx)
812 const gchar *user_words = style_sets[ft_id].keywords[keyword_idx];
813 GString *s;
815 s = symbols_find_typenames_as_string(filetypes[ft_id]->lang, TRUE);
816 if (G_UNLIKELY(s == NULL))
817 s = g_string_sized_new(200);
818 else
819 g_string_append_c(s, ' '); /* append a space as delimiter to the existing list of words */
821 g_string_append(s, user_words);
823 sci_set_keywords(sci, keyword_idx, s->str);
824 g_string_free(s, TRUE);
828 static void styleset_init_from_mapping(guint ft_id, GKeyFile *config, GKeyFile *config_home,
829 const HLStyle *styles, gsize n_styles,
830 const HLKeyword *keywords, gsize n_keywords)
832 gsize i;
834 /* styles */
835 new_styleset(ft_id, n_styles);
836 foreach_range(i, n_styles)
838 GeanyLexerStyle *style = &style_sets[ft_id].styling[i];
840 get_keyfile_style(config, config_home, styles[i].name, style);
843 /* keywords */
844 if (n_keywords < 1)
845 style_sets[ft_id].keywords = NULL;
846 else
848 style_sets[ft_id].keywords = g_new(gchar*, n_keywords + 1);
849 foreach_range(i, n_keywords)
850 get_keyfile_keywords(config, config_home, keywords[i].key, ft_id, i);
851 style_sets[ft_id].keywords[i] = NULL;
856 /* STYLE_DEFAULT will be set to match the first style. */
857 static void styleset_from_mapping(ScintillaObject *sci, guint ft_id, guint lexer,
858 const HLStyle *styles, gsize n_styles,
859 const HLKeyword *keywords, gsize n_keywords,
860 const HLProperty *properties, gsize n_properties)
862 gsize i;
864 g_assert(ft_id != GEANY_FILETYPES_NONE);
866 /* lexer */
867 sci_set_lexer(sci, lexer);
869 /* styles */
870 styleset_common(sci, ft_id);
871 if (n_styles > 0)
873 /* first style is also default one */
874 set_sci_style(sci, STYLE_DEFAULT, ft_id, 0);
875 foreach_range(i, n_styles)
877 if (styles[i].fill_eol)
878 SSM(sci, SCI_STYLESETEOLFILLED, styles[i].style, TRUE);
879 set_sci_style(sci, styles[i].style, ft_id, i);
883 /* keywords */
884 foreach_range(i, n_keywords)
886 if (keywords[i].merge)
887 merge_type_keywords(sci, ft_id, i);
888 else
889 sci_set_keywords(sci, keywords[i].id, style_sets[ft_id].keywords[i]);
892 /* properties */
893 foreach_range(i, n_properties)
894 sci_set_property(sci, properties[i].property, properties[i].value);
899 static void styleset_default(ScintillaObject *sci, guint ft_id)
901 sci_set_lexer(sci, SCLEX_NULL);
903 /* we need to set STYLE_DEFAULT before we call SCI_STYLECLEARALL in styleset_common() */
904 set_sci_style(sci, STYLE_DEFAULT, GEANY_FILETYPES_NONE, GCS_DEFAULT);
906 styleset_common(sci, ft_id);
910 static void get_key_values(GKeyFile *config, const gchar *group, gchar **keys, gchar **values)
912 while (*keys)
914 gchar *str = g_key_file_get_string(config, group, *keys, NULL);
916 if (str)
917 SETPTR(*values, str);
919 keys++;
920 values++;
925 static void read_properties(GeanyFiletype *ft, GKeyFile *config, GKeyFile *configh)
927 gchar group[] = "lexer_properties";
928 gchar **keys;
929 gchar **keysh = g_key_file_get_keys(configh, group, NULL, NULL);
930 gchar **ptr;
932 /* remove overridden keys from system keyfile */
933 foreach_strv(ptr, keysh)
934 g_key_file_remove_key(config, group, *ptr, NULL);
936 /* merge sys and user keys */
937 keys = g_key_file_get_keys(config, group, NULL, NULL);
938 keys = utils_strv_join(keys, keysh);
940 if (keys)
942 gchar **values = g_new0(gchar*, g_strv_length(keys) + 1);
944 style_sets[ft->id].property_keys = keys;
945 style_sets[ft->id].property_values = values;
947 get_key_values(config, group, keys, values);
948 get_key_values(configh, group, keys, values);
953 static guint get_lexer_filetype(GeanyFiletype *ft)
955 ft = FALLBACK(ft->lexer_filetype, ft);
956 return ft->id;
960 #define init_styleset_case(LANG_NAME) \
961 case (GEANY_FILETYPES_##LANG_NAME): \
962 styleset_init_from_mapping(filetype_idx, config, configh, \
963 highlighting_styles_##LANG_NAME, \
964 HL_N_ENTRIES(highlighting_styles_##LANG_NAME), \
965 highlighting_keywords_##LANG_NAME, \
966 HL_N_ENTRIES(highlighting_keywords_##LANG_NAME)); \
967 break
969 /* Called by filetypes_load_config(). */
970 void highlighting_init_styles(guint filetype_idx, GKeyFile *config, GKeyFile *configh)
972 GeanyFiletype *ft = filetypes[filetype_idx];
973 guint lexer_id = get_lexer_filetype(ft);
974 gchar *default_str;
976 if (!style_sets)
977 style_sets = g_new0(StyleSet, filetypes_array->len);
979 /* Clear old information if necessary - e.g. when reloading config */
980 free_styleset(filetype_idx);
982 read_properties(ft, config, configh);
983 /* If a default style exists, check it uses a named style
984 * Note: almost all filetypes have a "default" style, except HTML ones */
985 default_str = utils_get_setting(string, configh, config,
986 "styling", "default", "default");
987 ft->priv->warn_color_scheme = !g_ascii_isalpha(*default_str);
988 g_free(default_str);
990 /* None filetype handled specially */
991 if (filetype_idx == GEANY_FILETYPES_NONE)
993 styleset_common_init(config, configh);
994 return;
996 /* All stylesets depend on filetypes.common */
997 filetypes_load_config(GEANY_FILETYPES_NONE, FALSE);
999 switch (lexer_id)
1001 init_styleset_case(ABAQUS);
1002 init_styleset_case(ADA);
1003 init_styleset_case(ASCIIDOC);
1004 init_styleset_case(ASM);
1005 init_styleset_case(AU3);
1006 init_styleset_case(BASIC);
1007 init_styleset_case(BATCH);
1008 init_styleset_case(C);
1009 init_styleset_case(CAML);
1010 init_styleset_case(CMAKE);
1011 init_styleset_case(COBOL);
1012 init_styleset_case(COFFEESCRIPT);
1013 init_styleset_case(CONF);
1014 init_styleset_case(CSS);
1015 init_styleset_case(D);
1016 init_styleset_case(DIFF);
1017 init_styleset_case(LISP);
1018 init_styleset_case(ERLANG);
1019 init_styleset_case(DOCBOOK);
1020 init_styleset_case(F77);
1021 init_styleset_case(FORTH);
1022 init_styleset_case(FORTRAN);
1023 init_styleset_case(GDSCRIPT);
1024 init_styleset_case(GO);
1025 init_styleset_case(HASKELL);
1026 init_styleset_case(HAXE);
1027 init_styleset_case(AS);
1028 init_styleset_case(HTML);
1029 init_styleset_case(JAVA);
1030 init_styleset_case(JS);
1031 init_styleset_case(JULIA);
1032 init_styleset_case(LATEX);
1033 init_styleset_case(LUA);
1034 init_styleset_case(MAKE);
1035 init_styleset_case(MATLAB);
1036 init_styleset_case(MARKDOWN);
1037 init_styleset_case(NSIS);
1038 init_styleset_case(OBJECTIVEC);
1039 init_styleset_case(PASCAL);
1040 init_styleset_case(PERL);
1041 init_styleset_case(PHP);
1042 init_styleset_case(PO);
1043 init_styleset_case(POWERSHELL);
1044 init_styleset_case(PYTHON);
1045 init_styleset_case(R);
1046 init_styleset_case(RAKU);
1047 init_styleset_case(RUBY);
1048 init_styleset_case(RUST);
1049 init_styleset_case(SH);
1050 init_styleset_case(SMALLTALK);
1051 init_styleset_case(SQL);
1052 init_styleset_case(TCL);
1053 init_styleset_case(TXT2TAGS);
1054 init_styleset_case(VHDL);
1055 init_styleset_case(VERILOG);
1056 init_styleset_case(XML);
1057 init_styleset_case(YAML);
1058 init_styleset_case(ZEPHIR);
1059 default:
1060 if (ft->lexer_filetype)
1061 geany_debug("Filetype %s has a recursive lexer_filetype %s set!",
1062 ft->name, ft->lexer_filetype->name);
1065 /* should be done in filetypes.c really: */
1066 get_keyfile_wordchars(config, configh, &style_sets[filetype_idx].wordchars,
1067 common_style_set.wordchars);
1071 #define styleset_case(LANG_NAME) \
1072 case (GEANY_FILETYPES_##LANG_NAME): \
1073 styleset_from_mapping(sci, ft->id, highlighting_lexer_##LANG_NAME, \
1074 highlighting_styles_##LANG_NAME, \
1075 HL_N_ENTRIES(highlighting_styles_##LANG_NAME), \
1076 highlighting_keywords_##LANG_NAME, \
1077 HL_N_ENTRIES(highlighting_keywords_##LANG_NAME), \
1078 highlighting_properties_##LANG_NAME, \
1079 HL_N_ENTRIES(highlighting_properties_##LANG_NAME)); \
1080 break
1082 /** Sets up highlighting and other visual settings.
1083 * @param sci Scintilla widget.
1084 * @param ft Filetype settings to use. */
1085 GEANY_API_SYMBOL
1086 void highlighting_set_styles(ScintillaObject *sci, GeanyFiletype *ft)
1088 guint lexer_id = get_lexer_filetype(ft);
1090 filetypes_load_config(ft->id, FALSE); /* load filetypes.ext */
1092 switch (lexer_id)
1094 styleset_case(ABAQUS);
1095 styleset_case(ADA);
1096 styleset_case(ASCIIDOC);
1097 styleset_case(ASM);
1098 styleset_case(AU3);
1099 styleset_case(BASIC);
1100 styleset_case(BATCH);
1101 styleset_case(C);
1102 styleset_case(CAML);
1103 styleset_case(CMAKE);
1104 styleset_case(COBOL);
1105 styleset_case(COFFEESCRIPT);
1106 styleset_case(CONF);
1107 styleset_case(CSS);
1108 styleset_case(D);
1109 styleset_case(DIFF);
1110 styleset_case(LISP);
1111 styleset_case(ERLANG);
1112 styleset_case(DOCBOOK);
1113 styleset_case(F77);
1114 styleset_case(FORTH);
1115 styleset_case(FORTRAN);
1116 styleset_case(GDSCRIPT);
1117 styleset_case(GO);
1118 styleset_case(HASKELL);
1119 styleset_case(HAXE);
1120 styleset_case(AS);
1121 styleset_case(HTML);
1122 styleset_case(JAVA);
1123 styleset_case(JS);
1124 styleset_case(JULIA);
1125 styleset_case(LATEX);
1126 styleset_case(LUA);
1127 styleset_case(MAKE);
1128 styleset_case(MARKDOWN);
1129 styleset_case(MATLAB);
1130 styleset_case(NSIS);
1131 styleset_case(OBJECTIVEC);
1132 styleset_case(PASCAL);
1133 styleset_case(PERL);
1134 styleset_case(PHP);
1135 styleset_case(PO);
1136 styleset_case(POWERSHELL);
1137 styleset_case(PYTHON);
1138 styleset_case(R);
1139 styleset_case(RAKU);
1140 styleset_case(RUBY);
1141 styleset_case(RUST);
1142 styleset_case(SH);
1143 styleset_case(SMALLTALK);
1144 styleset_case(SQL);
1145 styleset_case(TCL);
1146 styleset_case(TXT2TAGS);
1147 styleset_case(VHDL);
1148 styleset_case(VERILOG);
1149 styleset_case(XML);
1150 styleset_case(YAML);
1151 styleset_case(ZEPHIR);
1152 case GEANY_FILETYPES_NONE:
1153 default:
1154 styleset_default(sci, ft->id);
1156 /* [lexer_properties] settings */
1157 if (style_sets[ft->id].property_keys)
1159 gchar **prop = style_sets[ft->id].property_keys;
1160 gchar **val = style_sets[ft->id].property_values;
1162 while (*prop)
1164 sci_set_property(sci, *prop, *val);
1165 prop++;
1166 val++;
1172 /** Retrieves a style @a style_id for the filetype @a ft_id.
1173 * If the style was not already initialised
1174 * (e.g. by by opening a file of this type), it will be initialised. The returned pointer is
1175 * owned by Geany and must not be freed.
1176 * @param ft_id Filetype ID, e.g. @c GEANY_FILETYPES_DIFF.
1177 * @param style_id A Scintilla lexer style, e.g. @c SCE_DIFF_ADDED. See scintilla/lexilla/include/SciLexer.h.
1178 * @return A pointer to the style struct.
1179 * @see Scintilla messages @c SCI_STYLEGETFORE, etc, for use with scintilla_send_message(). */
1180 GEANY_API_SYMBOL
1181 const GeanyLexerStyle *highlighting_get_style(gint ft_id, gint style_id)
1183 g_return_val_if_fail(ft_id >= 0 && (guint) ft_id < filetypes_array->len, NULL);
1184 g_return_val_if_fail(style_id >= 0, NULL);
1186 /* ensure filetype loaded */
1187 filetypes_load_config((guint) ft_id, FALSE);
1189 /* TODO: style_id might not be the real array index (Scintilla styles are not always synced
1190 * with array indices) */
1191 return get_style((guint) ft_id, (guint) style_id);
1195 enum
1197 SCHEME_MARKUP,
1198 SCHEME_FILE,
1199 SCHEME_COLUMNS
1202 static void on_color_scheme_changed(GtkTreeSelection *treesel, gpointer dummy)
1204 GtkTreeModel *model;
1205 GtkTreeIter iter;
1206 gchar *fname;
1207 gchar *path;
1209 if (!gtk_tree_selection_get_selected(treesel, &model, &iter))
1210 return;
1211 gtk_tree_model_get(model, &iter, SCHEME_FILE, &fname, -1);
1213 /* check if default item */
1214 if (!fname)
1216 SETPTR(editor_prefs.color_scheme, NULL);
1217 filetypes_reload();
1218 return;
1220 SETPTR(fname, utils_get_locale_from_utf8(fname));
1222 /* fname is just the basename from the menu item, so prepend the custom files path */
1223 path = g_build_path(G_DIR_SEPARATOR_S, app->configdir, GEANY_COLORSCHEMES_SUBDIR, fname, NULL);
1224 if (!g_file_test(path, G_FILE_TEST_EXISTS))
1226 /* try the system path */
1227 g_free(path);
1228 path = g_build_path(G_DIR_SEPARATOR_S, app->datadir, GEANY_COLORSCHEMES_SUBDIR, fname, NULL);
1230 if (g_file_test(path, G_FILE_TEST_EXISTS))
1232 SETPTR(editor_prefs.color_scheme, fname);
1233 fname = NULL;
1234 filetypes_reload();
1236 else
1238 SETPTR(fname, utils_get_utf8_from_locale(fname));
1239 ui_set_statusbar(TRUE, _("Could not find file '%s'."), fname);
1241 g_free(path);
1242 g_free(fname);
1246 static gchar *utils_get_setting_locale_string(GKeyFile *keyfile,
1247 const gchar *group, const gchar *key, const gchar *default_value)
1249 gchar *result = g_key_file_get_locale_string(keyfile, group, key, NULL, NULL);
1251 return FALLBACK(result, g_strdup(default_value));
1255 static void add_color_scheme_item(GtkListStore *store,
1256 gchar *name, gchar *desc, const gchar *fn, GtkTreeIter *current_iter)
1258 GtkTreeIter iter;
1259 gchar *markup;
1261 /* reuse parameters */
1262 name = g_markup_escape_text(name, -1);
1263 desc = g_markup_escape_text(desc, -1);
1264 markup = g_strdup_printf("<big><b>%s</b></big>\n%s", name, desc);
1265 g_free(name);
1266 g_free(desc);
1268 gtk_list_store_append(store, &iter);
1269 gtk_list_store_set(store, &iter, SCHEME_MARKUP, markup,
1270 SCHEME_FILE, fn, -1);
1271 g_free(markup);
1273 /* select the current iter if the the color scheme matches, or if it's the
1274 * default (fn == NULL), in case of bad config file. the default theme is
1275 * first anyway so if a later scheme matches it will override default */
1276 if ((! fn || utils_str_equal(fn, editor_prefs.color_scheme)) && current_iter)
1277 *current_iter = iter;
1281 static void add_color_scheme_file(GtkListStore *store, const gchar *fname, GtkTreeIter *current_iter)
1283 GKeyFile *hkeyfile, *skeyfile;
1284 gchar *path, *theme_name, *theme_desc;
1285 gchar *theme_fn = utils_get_utf8_from_locale(fname);
1287 path = g_build_filename(app->configdir, GEANY_COLORSCHEMES_SUBDIR, fname, NULL);
1288 hkeyfile = utils_key_file_new(path);
1289 SETPTR(path, g_build_filename(app->datadir, GEANY_COLORSCHEMES_SUBDIR, fname, NULL));
1290 skeyfile = utils_key_file_new(path);
1292 theme_name = utils_get_setting(locale_string, hkeyfile, skeyfile, "theme_info", "name", theme_fn);
1293 theme_desc = utils_get_setting(locale_string, hkeyfile, skeyfile, "theme_info", "description", NULL);
1294 add_color_scheme_item(store, theme_name, theme_desc, theme_fn, current_iter);
1296 g_free(path);
1297 g_free(theme_fn);
1298 g_free(theme_name);
1299 g_free(theme_desc);
1300 g_key_file_free(hkeyfile);
1301 g_key_file_free(skeyfile);
1305 static gboolean add_color_scheme_items(GtkListStore *store, GtkTreeIter *current_iter)
1307 GSList *list, *node;
1309 add_color_scheme_item(store, _("Default"), _("Default"), NULL, current_iter);
1310 list = utils_get_config_files(GEANY_COLORSCHEMES_SUBDIR);
1312 foreach_slist(node, list)
1314 gchar *fname = node->data;
1316 if (g_str_has_suffix(fname, ".conf"))
1317 add_color_scheme_file(store, fname, current_iter);
1319 g_free(fname);
1321 g_slist_free(list);
1322 return list != NULL;
1326 static void on_color_scheme_dialog_response(GtkWidget *dialog,
1327 gint response, gpointer *dialog_ptr)
1329 *dialog_ptr = NULL;
1330 gtk_widget_destroy(dialog);
1334 void highlighting_show_color_scheme_dialog(void)
1336 static GtkWidget *dialog = NULL;
1337 GtkListStore *store = gtk_list_store_new(SCHEME_COLUMNS,
1338 G_TYPE_STRING, G_TYPE_STRING);
1339 GtkCellRenderer *text_renderer;
1340 GtkTreeViewColumn *column;
1341 GtkTreeSelection *treesel;
1342 GtkTreeIter current_iter;
1343 GtkTreePath *path;
1344 GtkWidget *vbox, *swin, *tree;
1345 GeanyDocument *doc;
1347 doc = document_get_current();
1348 if (doc && doc->file_type->priv->warn_color_scheme)
1349 dialogs_show_msgbox_with_secondary(GTK_MESSAGE_WARNING,
1350 _("The current filetype overrides the default style."),
1351 _("This may cause color schemes to display incorrectly."));
1353 tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1354 g_object_unref(store);
1355 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE);
1356 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), FALSE);
1358 text_renderer = gtk_cell_renderer_text_new();
1359 g_object_set(text_renderer, "wrap-mode", PANGO_WRAP_WORD, NULL);
1360 column = gtk_tree_view_column_new_with_attributes(
1361 NULL, text_renderer, "markup", SCHEME_MARKUP, NULL);
1362 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
1364 add_color_scheme_items(store, &current_iter);
1366 treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1367 gtk_tree_selection_select_iter(treesel, &current_iter);
1368 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &current_iter);
1369 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tree), path, NULL, FALSE, 0, 0);
1370 gtk_tree_path_free(path);
1371 g_signal_connect(treesel, "changed", G_CALLBACK(on_color_scheme_changed), NULL);
1373 /* old dialog may still be showing */
1374 if (dialog)
1375 gtk_widget_destroy(dialog);
1376 dialog = gtk_dialog_new_with_buttons(_("Color Schemes"),
1377 GTK_WINDOW(main_widgets.window), GTK_DIALOG_DESTROY_WITH_PARENT,
1378 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
1379 vbox = ui_dialog_vbox_new(GTK_DIALOG(dialog));
1380 gtk_box_set_spacing(GTK_BOX(vbox), 6);
1381 gtk_widget_set_name(dialog, "GeanyDialog");
1382 gtk_window_set_default_size(GTK_WINDOW(dialog),
1383 GEANY_DEFAULT_DIALOG_HEIGHT * 7/4, GEANY_DEFAULT_DIALOG_HEIGHT);
1385 swin = gtk_scrolled_window_new(NULL, NULL);
1386 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swin), GTK_SHADOW_IN);
1387 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
1388 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1389 gtk_container_add(GTK_CONTAINER(swin), tree);
1390 gtk_box_pack_start(GTK_BOX(vbox), swin, TRUE, TRUE, 0);
1391 g_signal_connect(dialog, "response", G_CALLBACK(on_color_scheme_dialog_response), &dialog);
1392 gtk_widget_show_all(dialog);
1396 /** Checks whether the given style is a string for the given lexer.
1398 * @param lexer Scintilla lexer type (@c SCLEX_*).
1399 * @param style Scintilla style (@c SCE_*).
1401 * @return @c TRUE if the style is a string, @c FALSE otherwise.
1403 GEANY_API_SYMBOL
1404 gboolean highlighting_is_string_style(gint lexer, gint style)
1406 /* Don't forget STRINGEOL, to prevent completion whilst typing a string with no closing char. */
1408 switch (lexer)
1410 case SCLEX_CPP:
1411 return (style == SCE_C_CHARACTER ||
1412 style == SCE_C_STRING ||
1413 style == SCE_C_STRINGEOL ||
1414 style == SCE_C_STRINGRAW ||
1415 style == SCE_C_VERBATIM ||
1416 style == SCE_C_USERLITERAL ||
1417 style == SCE_C_TRIPLEVERBATIM ||
1418 style == SCE_C_REGEX ||
1419 style == SCE_C_HASHQUOTEDSTRING ||
1420 style == SCE_C_ESCAPESEQUENCE);
1422 case SCLEX_PASCAL:
1423 return (style == SCE_PAS_CHARACTER ||
1424 style == SCE_PAS_STRING ||
1425 style == SCE_PAS_STRINGEOL);
1427 case SCLEX_D:
1428 return (style == SCE_D_STRING ||
1429 style == SCE_D_STRINGEOL ||
1430 style == SCE_D_CHARACTER ||
1431 style == SCE_D_STRINGB ||
1432 style == SCE_D_STRINGR);
1434 case SCLEX_PYTHON:
1435 return (style == SCE_P_STRING ||
1436 style == SCE_P_TRIPLE ||
1437 style == SCE_P_TRIPLEDOUBLE ||
1438 style == SCE_P_CHARACTER ||
1439 style == SCE_P_FSTRING ||
1440 style == SCE_P_FCHARACTER ||
1441 style == SCE_P_FTRIPLE ||
1442 style == SCE_P_FTRIPLEDOUBLE ||
1443 style == SCE_P_STRINGEOL);
1445 case SCLEX_GDSCRIPT:
1446 return (style == SCE_GD_STRING ||
1447 style == SCE_GD_TRIPLE ||
1448 style == SCE_GD_TRIPLEDOUBLE ||
1449 style == SCE_GD_CHARACTER ||
1450 style == SCE_GD_STRINGEOL);
1452 case SCLEX_F77:
1453 case SCLEX_FORTRAN:
1454 return (style == SCE_F_STRING1 ||
1455 style == SCE_F_STRING2 ||
1456 style == SCE_F_STRINGEOL);
1458 case SCLEX_PERL:
1459 return (style == SCE_PL_STRING ||
1460 style == SCE_PL_CHARACTER ||
1461 style == SCE_PL_HERE_DELIM ||
1462 style == SCE_PL_HERE_Q ||
1463 style == SCE_PL_HERE_QQ ||
1464 style == SCE_PL_HERE_QX ||
1465 style == SCE_PL_POD ||
1466 style == SCE_PL_STRING_Q ||
1467 style == SCE_PL_STRING_QQ ||
1468 style == SCE_PL_STRING_QX ||
1469 style == SCE_PL_STRING_QR ||
1470 style == SCE_PL_STRING_QW ||
1471 style == SCE_PL_POD_VERB ||
1472 style == SCE_PL_REGEX ||
1473 style == SCE_PL_REGEX_VAR ||
1474 style == SCE_PL_XLAT
1475 /* we don't include any STRING_*_VAR for autocompletion */);
1477 case SCLEX_PO:
1478 return (style == SCE_PO_MSGCTXT_TEXT ||
1479 style == SCE_PO_MSGCTXT_TEXT_EOL ||
1480 style == SCE_PO_MSGID_TEXT ||
1481 style == SCE_PO_MSGID_TEXT_EOL ||
1482 style == SCE_PO_MSGSTR_TEXT ||
1483 style == SCE_PO_MSGSTR_TEXT_EOL);
1485 case SCLEX_R:
1486 return (style == SCE_R_STRING);
1488 case SCLEX_RAKU:
1489 return (style == SCE_RAKU_CHARACTER ||
1490 style == SCE_RAKU_HEREDOC_Q ||
1491 style == SCE_RAKU_HEREDOC_QQ ||
1492 style == SCE_RAKU_STRING ||
1493 style == SCE_RAKU_STRING_Q ||
1494 style == SCE_RAKU_STRING_QQ ||
1495 style == SCE_RAKU_STRING_Q_LANG ||
1496 style == SCE_RAKU_REGEX);
1498 case SCLEX_RUBY:
1499 return (style == SCE_RB_CHARACTER ||
1500 style == SCE_RB_STRING ||
1501 style == SCE_RB_HERE_DELIM ||
1502 style == SCE_RB_HERE_Q ||
1503 style == SCE_RB_HERE_QQ ||
1504 style == SCE_RB_HERE_QX ||
1505 style == SCE_RB_REGEX ||
1506 style == SCE_RB_STRING_Q ||
1507 style == SCE_RB_STRING_QQ ||
1508 style == SCE_RB_STRING_QX ||
1509 style == SCE_RB_STRING_QR ||
1510 style == SCE_RB_STRING_QW ||
1511 style == SCE_RB_POD);
1513 case SCLEX_BASH:
1514 return (style == SCE_SH_STRING);
1516 case SCLEX_SQL:
1517 return (style == SCE_SQL_STRING);
1519 case SCLEX_TCL:
1520 return (style == SCE_TCL_IN_QUOTE);
1522 case SCLEX_LUA:
1523 return (style == SCE_LUA_LITERALSTRING ||
1524 style == SCE_LUA_CHARACTER ||
1525 style == SCE_LUA_STRINGEOL ||
1526 style == SCE_LUA_STRING);
1528 case SCLEX_HASKELL:
1529 case SCLEX_LITERATEHASKELL:
1530 return (style == SCE_HA_CHARACTER ||
1531 style == SCE_HA_STRINGEOL ||
1532 style == SCE_HA_STRING);
1534 case SCLEX_FREEBASIC:
1535 return (style == SCE_B_STRING ||
1536 style == SCE_B_STRINGEOL);
1538 case SCLEX_OCTAVE:
1539 return (style == SCE_MATLAB_STRING ||
1540 style == SCE_MATLAB_DOUBLEQUOTESTRING);
1542 case SCLEX_JULIA:
1543 return (style == SCE_JULIA_CHAR ||
1544 style == SCE_JULIA_STRING ||
1545 style == SCE_JULIA_DOCSTRING ||
1546 style == SCE_JULIA_COMMAND ||
1547 style == SCE_JULIA_STRINGINTERP);
1549 case SCLEX_XML:
1550 case SCLEX_HTML:
1551 case SCLEX_PHPSCRIPT:
1552 return (
1553 style == SCE_HBA_STRING ||
1554 style == SCE_HBA_STRINGEOL ||
1555 style == SCE_HB_STRING ||
1556 style == SCE_HB_STRINGEOL ||
1557 style == SCE_H_CDATA ||
1558 style == SCE_H_DOUBLESTRING ||
1559 style == SCE_HJA_DOUBLESTRING ||
1560 style == SCE_HJA_SINGLESTRING ||
1561 style == SCE_HJA_STRINGEOL ||
1562 style == SCE_HJA_REGEX ||
1563 style == SCE_HJ_DOUBLESTRING ||
1564 style == SCE_HJ_SINGLESTRING ||
1565 style == SCE_HJ_STRINGEOL ||
1566 style == SCE_HJ_REGEX ||
1567 style == SCE_HPA_CHARACTER ||
1568 style == SCE_HPA_STRING ||
1569 style == SCE_HPA_TRIPLE ||
1570 style == SCE_HPA_TRIPLEDOUBLE ||
1571 style == SCE_HP_CHARACTER ||
1572 style == SCE_HPHP_HSTRING || /* HSTRING is a heredoc */
1573 style == SCE_HPHP_HSTRING_VARIABLE ||
1574 style == SCE_HPHP_SIMPLESTRING ||
1575 style == SCE_HP_STRING ||
1576 style == SCE_HP_TRIPLE ||
1577 style == SCE_HP_TRIPLEDOUBLE ||
1578 style == SCE_H_SGML_DOUBLESTRING ||
1579 style == SCE_H_SGML_SIMPLESTRING ||
1580 style == SCE_H_SINGLESTRING);
1582 case SCLEX_CMAKE:
1583 return (style == SCE_CMAKE_STRINGDQ ||
1584 style == SCE_CMAKE_STRINGLQ ||
1585 style == SCE_CMAKE_STRINGRQ ||
1586 style == SCE_CMAKE_STRINGVAR);
1588 case SCLEX_NSIS:
1589 return (style == SCE_NSIS_STRINGDQ ||
1590 style == SCE_NSIS_STRINGLQ ||
1591 style == SCE_NSIS_STRINGRQ ||
1592 style == SCE_NSIS_STRINGVAR);
1594 case SCLEX_ADA:
1595 return (style == SCE_ADA_CHARACTER ||
1596 style == SCE_ADA_STRING ||
1597 style == SCE_ADA_CHARACTEREOL ||
1598 style == SCE_ADA_STRINGEOL);
1600 case SCLEX_ABAQUS:
1601 return (style == SCE_ABAQUS_STRING);
1603 case SCLEX_RUST:
1604 return (style == SCE_RUST_CHARACTER ||
1605 style == SCE_RUST_BYTECHARACTER ||
1606 style == SCE_RUST_STRING ||
1607 style == SCE_RUST_STRINGR ||
1608 style == SCE_RUST_BYTESTRING ||
1609 style == SCE_RUST_BYTESTRINGR ||
1610 style == SCE_RUST_LEXERROR);
1612 case SCLEX_COFFEESCRIPT:
1613 return (style == SCE_COFFEESCRIPT_CHARACTER ||
1614 style == SCE_COFFEESCRIPT_STRING ||
1615 style == SCE_COFFEESCRIPT_REGEX ||
1616 style == SCE_COFFEESCRIPT_VERBOSE_REGEX ||
1617 style == SCE_COFFEESCRIPT_STRINGEOL);
1619 case SCLEX_VERILOG:
1620 return (style == SCE_V_STRING);
1622 case SCLEX_VHDL:
1623 return (style == SCE_VHDL_STRING ||
1624 style == SCE_VHDL_STRINGEOL);
1626 case SCLEX_CAML:
1627 return (style == SCE_CAML_CHAR ||
1628 style == SCE_CAML_STRING);
1630 case SCLEX_CSS:
1631 return (style == SCE_CSS_DOUBLESTRING ||
1632 style == SCE_CSS_SINGLESTRING);
1634 case SCLEX_ERLANG:
1635 return (style == SCE_ERLANG_STRING ||
1636 style == SCE_ERLANG_CHARACTER);
1638 case SCLEX_LISP:
1639 return (style == SCE_LISP_STRING ||
1640 style == SCE_LISP_STRINGEOL);
1642 case SCLEX_FORTH:
1643 return (style == SCE_FORTH_STRING);
1645 case SCLEX_POWERSHELL:
1646 return (style == SCE_POWERSHELL_STRING ||
1647 style == SCE_POWERSHELL_CHARACTER);
1649 case SCLEX_BATCH:
1650 case SCLEX_DIFF:
1651 case SCLEX_LATEX:
1652 case SCLEX_MAKEFILE:
1653 case SCLEX_MARKDOWN:
1654 case SCLEX_PROPERTIES:
1655 case SCLEX_TXT2TAGS:
1656 case SCLEX_YAML:
1657 /* there is no string type in those lexers, listing here just for completeness */
1658 return FALSE;
1660 case SCLEX_AU3:
1661 return (style == SCE_AU3_STRING);
1663 return FALSE;
1667 /** Checks whether the given style is a comment for the given lexer.
1669 * @param lexer Scintilla lexer type (@c SCLEX_*).
1670 * @param style Scintilla style (@c SCE_*).
1672 * @return @c TRUE if the style is a comment, @c FALSE otherwise.
1674 GEANY_API_SYMBOL
1675 gboolean highlighting_is_comment_style(gint lexer, gint style)
1677 switch (lexer)
1679 case SCLEX_COBOL:
1680 case SCLEX_CPP:
1681 return (style == SCE_C_COMMENT ||
1682 style == SCE_C_COMMENTLINE ||
1683 style == SCE_C_COMMENTDOC ||
1684 style == SCE_C_PREPROCESSORCOMMENT ||
1685 style == SCE_C_PREPROCESSORCOMMENTDOC ||
1686 style == SCE_C_COMMENTLINEDOC ||
1687 style == SCE_C_COMMENTDOCKEYWORD ||
1688 style == SCE_C_COMMENTDOCKEYWORDERROR ||
1689 style == SCE_C_TASKMARKER);
1691 case SCLEX_PASCAL:
1692 return (style == SCE_PAS_COMMENT ||
1693 style == SCE_PAS_COMMENT2 ||
1694 style == SCE_PAS_COMMENTLINE);
1696 case SCLEX_D:
1697 return (style == SCE_D_COMMENT ||
1698 style == SCE_D_COMMENTLINE ||
1699 style == SCE_D_COMMENTDOC ||
1700 style == SCE_D_COMMENTNESTED ||
1701 style == SCE_D_COMMENTLINEDOC ||
1702 style == SCE_D_COMMENTDOCKEYWORD ||
1703 style == SCE_D_COMMENTDOCKEYWORDERROR);
1705 case SCLEX_PYTHON:
1706 return (style == SCE_P_COMMENTLINE ||
1707 style == SCE_P_COMMENTBLOCK);
1709 case SCLEX_F77:
1710 case SCLEX_FORTRAN:
1711 return (style == SCE_F_COMMENT);
1713 case SCLEX_PERL:
1714 return (style == SCE_PL_COMMENTLINE);
1716 case SCLEX_RAKU:
1717 return (style == SCE_RAKU_COMMENTLINE ||
1718 style == SCE_RAKU_COMMENTEMBED ||
1719 style == SCE_RAKU_POD);
1721 case SCLEX_PROPERTIES:
1722 return (style == SCE_PROPS_COMMENT);
1724 case SCLEX_PO:
1725 return (style == SCE_PO_COMMENT ||
1726 style == SCE_PO_PROGRAMMER_COMMENT);
1728 case SCLEX_LATEX:
1729 return (style == SCE_L_COMMENT ||
1730 style == SCE_L_COMMENT2);
1732 case SCLEX_MAKEFILE:
1733 return (style == SCE_MAKE_COMMENT);
1735 case SCLEX_RUBY:
1736 return (style == SCE_RB_COMMENTLINE);
1738 case SCLEX_BASH:
1739 return (style == SCE_SH_COMMENTLINE);
1741 case SCLEX_R:
1742 return (style == SCE_R_COMMENT);
1744 case SCLEX_SQL:
1745 return (style == SCE_SQL_COMMENT ||
1746 style == SCE_SQL_COMMENTLINE ||
1747 style == SCE_SQL_COMMENTDOC ||
1748 style == SCE_SQL_COMMENTLINEDOC ||
1749 style == SCE_SQL_COMMENTDOCKEYWORD ||
1750 style == SCE_SQL_COMMENTDOCKEYWORDERROR);
1752 case SCLEX_TCL:
1753 return (style == SCE_TCL_COMMENT ||
1754 style == SCE_TCL_COMMENTLINE ||
1755 style == SCE_TCL_COMMENT_BOX ||
1756 style == SCE_TCL_BLOCK_COMMENT);
1758 case SCLEX_OCTAVE:
1759 return (style == SCE_MATLAB_COMMENT);
1761 case SCLEX_JULIA:
1762 return (style == SCE_JULIA_COMMENT);
1764 case SCLEX_LUA:
1765 return (style == SCE_LUA_COMMENT ||
1766 style == SCE_LUA_COMMENTLINE ||
1767 style == SCE_LUA_COMMENTDOC);
1769 case SCLEX_HASKELL:
1770 case SCLEX_LITERATEHASKELL:
1771 return (style == SCE_HA_COMMENTLINE ||
1772 style == SCE_HA_COMMENTBLOCK ||
1773 style == SCE_HA_COMMENTBLOCK2 ||
1774 style == SCE_HA_COMMENTBLOCK3 ||
1775 style == SCE_HA_LITERATE_COMMENT ||
1776 style == SCE_HA_LITERATE_CODEDELIM);
1778 case SCLEX_FREEBASIC:
1779 return (style == SCE_B_COMMENT ||
1780 style == SCE_B_COMMENTBLOCK ||
1781 style == SCE_B_DOCLINE ||
1782 style == SCE_B_DOCBLOCK ||
1783 style == SCE_B_DOCKEYWORD);
1785 case SCLEX_YAML:
1786 return (style == SCE_YAML_COMMENT);
1788 case SCLEX_XML:
1789 case SCLEX_HTML:
1790 case SCLEX_PHPSCRIPT:
1791 return (
1792 style == SCE_HBA_COMMENTLINE ||
1793 style == SCE_HB_COMMENTLINE ||
1794 style == SCE_H_COMMENT ||
1795 style == SCE_HJA_COMMENT ||
1796 style == SCE_HJA_COMMENTDOC ||
1797 style == SCE_HJA_COMMENTLINE ||
1798 style == SCE_HJ_COMMENT ||
1799 style == SCE_HJ_COMMENTDOC ||
1800 style == SCE_HJ_COMMENTLINE ||
1801 style == SCE_HPA_COMMENTLINE ||
1802 style == SCE_HP_COMMENTLINE ||
1803 style == SCE_HPHP_COMMENT ||
1804 style == SCE_HPHP_COMMENTLINE ||
1805 style == SCE_H_SGML_COMMENT);
1807 case SCLEX_CMAKE:
1808 return (style == SCE_CMAKE_COMMENT);
1810 case SCLEX_NSIS:
1811 return (style == SCE_NSIS_COMMENT ||
1812 style == SCE_NSIS_COMMENTBOX);
1814 case SCLEX_ADA:
1815 return (style == SCE_ADA_COMMENTLINE);
1817 case SCLEX_ABAQUS:
1818 return (style == SCE_ABAQUS_COMMENT ||
1819 style == SCE_ABAQUS_COMMENTBLOCK);
1821 case SCLEX_ASM:
1822 return (style == SCE_ASM_COMMENT ||
1823 style == SCE_ASM_COMMENTBLOCK ||
1824 style == SCE_ASM_COMMENTDIRECTIVE);
1826 case SCLEX_RUST:
1827 return (style == SCE_RUST_COMMENTBLOCK ||
1828 style == SCE_RUST_COMMENTLINE ||
1829 style == SCE_RUST_COMMENTBLOCKDOC ||
1830 style == SCE_RUST_COMMENTLINEDOC);
1832 case SCLEX_COFFEESCRIPT:
1833 return (style == SCE_COFFEESCRIPT_COMMENTLINE ||
1834 style == SCE_COFFEESCRIPT_COMMENTBLOCK ||
1835 style == SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT);
1837 case SCLEX_VERILOG:
1838 return (style == SCE_V_COMMENT ||
1839 style == SCE_V_COMMENTLINE ||
1840 style == SCE_V_COMMENTLINEBANG ||
1841 style == SCE_V_COMMENT_WORD);
1843 case SCLEX_VHDL:
1844 return (style == SCE_VHDL_COMMENT ||
1845 style == SCE_VHDL_COMMENTLINEBANG ||
1846 style == SCE_VHDL_BLOCK_COMMENT);
1848 case SCLEX_BATCH:
1849 return (style == SCE_BAT_COMMENT);
1851 case SCLEX_CAML:
1852 return (style == SCE_CAML_COMMENT ||
1853 style == SCE_CAML_COMMENT1 ||
1854 style == SCE_CAML_COMMENT2 ||
1855 style == SCE_CAML_COMMENT3);
1857 case SCLEX_ERLANG:
1858 return (style == SCE_ERLANG_COMMENT ||
1859 style == SCE_ERLANG_COMMENT_FUNCTION ||
1860 style == SCE_ERLANG_COMMENT_MODULE ||
1861 style == SCE_ERLANG_COMMENT_DOC ||
1862 style == SCE_ERLANG_COMMENT_DOC_MACRO);
1864 case SCLEX_FORTH:
1865 return (style == SCE_FORTH_COMMENT ||
1866 style == SCE_FORTH_COMMENT_ML);
1868 case SCLEX_CSS:
1869 return (style == SCE_CSS_COMMENT);
1871 case SCLEX_DIFF:
1872 return (style == SCE_DIFF_COMMENT);
1874 case SCLEX_LISP:
1875 return (style == SCE_LISP_COMMENT ||
1876 style == SCE_LISP_MULTI_COMMENT);
1878 case SCLEX_POWERSHELL:
1879 return (style == SCE_POWERSHELL_COMMENT ||
1880 style == SCE_POWERSHELL_COMMENTSTREAM ||
1881 style == SCE_POWERSHELL_COMMENTDOCKEYWORD);
1883 case SCLEX_TXT2TAGS:
1884 return (style == SCE_TXT2TAGS_COMMENT);
1886 case SCLEX_MARKDOWN:
1887 /* there is no comment type in those lexers, listing here just for completeness */
1888 return FALSE;
1890 case SCLEX_GDSCRIPT:
1891 return (style == SCE_GD_COMMENTLINE ||
1892 style == SCE_GD_COMMENTBLOCK);
1894 case SCLEX_AU3:
1895 return (style == SCE_AU3_COMMENT ||
1896 style == SCE_AU3_COMMENTBLOCK);
1898 return FALSE;
1902 /** Checks whether the given style is normal code (not string, comment, preprocessor, etc).
1904 * @param lexer Scintilla lexer type (@c SCLEX_*).
1905 * @param style Scintilla style (@c SCE_*).
1907 * @return @c TRUE if the style is code, @c FALSE otherwise.
1909 GEANY_API_SYMBOL
1910 gboolean highlighting_is_code_style(gint lexer, gint style)
1912 switch (lexer)
1914 case SCLEX_CPP:
1916 if (style == SCE_C_PREPROCESSOR)
1917 return FALSE;
1918 break;
1920 case SCLEX_HASKELL:
1921 case SCLEX_LITERATEHASKELL:
1923 if (style == SCE_HA_PREPROCESSOR)
1924 return FALSE;
1925 break;
1927 case SCLEX_VERILOG:
1929 if (style == SCE_V_PREPROCESSOR)
1930 return FALSE;
1931 break;
1934 return !(highlighting_is_comment_style(lexer, style) ||
1935 highlighting_is_string_style(lexer, style));