Support normal and abbreviated HTML hex triplets in color schemes
[geany-mirror.git] / src / highlighting.c
blobb48712d71515cae76c63379fe2e6a307b4421705
1 /*
2 * highlighting.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2005-2011 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5 * Copyright 2006-2011 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 /**
23 * @file highlighting.h
24 * Syntax highlighting for the different filetypes, using the Scintilla lexers.
27 #include "geany.h"
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <string.h>
33 #include "SciLexer.h"
34 #include "highlighting.h"
35 #include "editor.h"
36 #include "utils.h"
37 #include "filetypes.h"
38 #include "symbols.h"
39 #include "ui_utils.h"
40 #include "utils.h"
41 #include "main.h"
42 #include "support.h"
43 #include "sciwrappers.h"
45 #include "highlightingmappings.h"
48 #define GEANY_COLORSCHEMES_SUBDIR "colorschemes"
50 /* Whitespace has to be set after setting wordchars. */
51 #define GEANY_WHITESPACE_CHARS " \t" "!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~"
54 static gchar *whitespace_chars;
57 typedef struct
59 gsize count; /* number of styles */
60 GeanyLexerStyle *styling; /* array of styles, NULL if not used or uninitialised */
61 gchar **keywords;
62 gchar *wordchars; /* NULL used for style sets with no styles */
63 gchar **property_keys;
64 gchar **property_values;
65 } StyleSet;
67 /* each filetype has a styleset but GEANY_FILETYPES_NONE uses common_style_set for styling */
68 static StyleSet *style_sets = NULL;
71 enum /* Geany common styling */
73 GCS_DEFAULT,
74 GCS_SELECTION,
75 GCS_BRACE_GOOD,
76 GCS_BRACE_BAD,
77 GCS_MARGIN_LINENUMBER,
78 GCS_MARGIN_FOLDING,
79 GCS_FOLD_SYMBOL_HIGHLIGHT,
80 GCS_CURRENT_LINE,
81 GCS_CARET,
82 GCS_INDENT_GUIDE,
83 GCS_WHITE_SPACE,
84 GCS_LINE_WRAP_VISUALS,
85 GCS_LINE_WRAP_INDENT,
86 GCS_TRANSLUCENCY,
87 GCS_MARKER_LINE,
88 GCS_MARKER_SEARCH,
89 GCS_MARKER_MARK,
90 GCS_MARKER_TRANSLUCENCY,
91 GCS_LINE_HEIGHT,
92 GCS_CALLTIPS,
93 GCS_MAX
96 static struct
98 GeanyLexerStyle styling[GCS_MAX];
100 /* icon style, 1-4 */
101 gint fold_marker;
102 /* vertical line style, 0-2 */
103 gint fold_lines;
104 /* horizontal line when folded, 0-2 */
105 gint fold_draw_line;
107 gchar *wordchars;
108 } common_style_set;
111 /* For filetypes.common [named_styles] section.
112 * 0xBBGGRR format.
113 * e.g. "comment" => &GeanyLexerStyle{0x0000d0, 0xffffff, FALSE, FALSE} */
114 static GHashTable *named_style_hash = NULL;
116 /* 0xBBGGRR format, set by "default" named style. */
117 static GeanyLexerStyle gsd_default = {0x000000, 0xffffff, FALSE, FALSE};
120 /* Note: use sciwrappers.h instead where possible.
121 * Do not use SSM in files unrelated to scintilla. */
122 #define SSM(s, m, w, l) scintilla_send_message(s, m, w, l)
124 /* filetypes should use the filetypes.foo [lexer_properties] group instead of hardcoding */
125 static void sci_set_property(ScintillaObject *sci, const gchar *name, const gchar *value)
127 SSM(sci, SCI_SETPROPERTY, (uptr_t) name, (sptr_t) value);
131 static void new_styleset(guint file_type_id, gsize styling_count)
133 StyleSet *set = &style_sets[file_type_id];
135 set->count = styling_count;
136 set->styling = g_new0(GeanyLexerStyle, styling_count);
140 static void free_styleset(guint file_type_id)
142 StyleSet *style_ptr;
143 style_ptr = &style_sets[file_type_id];
145 style_ptr->count = 0;
146 g_free(style_ptr->styling);
147 style_ptr->styling = NULL;
148 g_strfreev(style_ptr->keywords);
149 style_ptr->keywords = NULL;
150 g_free(style_ptr->wordchars);
151 style_ptr->wordchars = NULL;
152 g_strfreev(style_ptr->property_keys);
153 style_ptr->property_keys = NULL;
154 g_strfreev(style_ptr->property_values);
155 style_ptr->property_values = NULL;
159 static void get_keyfile_keywords(GKeyFile *config, GKeyFile *configh,
160 const gchar *key, guint ft_id, guint pos)
162 style_sets[ft_id].keywords[pos] =
163 utils_get_setting(string, configh, config, "keywords", key, "");
167 static void get_keyfile_wordchars(GKeyFile *config, GKeyFile *configh, gchar **wordchars)
169 *wordchars = utils_get_setting(string, configh, config,
170 "settings", "wordchars", GEANY_WORDCHARS);
174 static gboolean read_named_style(const gchar *named_style, GeanyLexerStyle *style)
176 GeanyLexerStyle *cs;
177 gchar *comma, *name = NULL;
178 const gchar *bold = NULL;
179 const gchar *italic = NULL;
181 g_return_val_if_fail(named_style, FALSE);
182 name = utils_strdupa(named_style); /* named_style must not be written to, may be a static string */
184 comma = strstr(name, ",");
185 if (comma)
187 bold = strstr(comma, ",bold");
188 italic = strstr(comma, ",italic");
189 *comma = '\0'; /* terminate name to make lookup work */
191 cs = g_hash_table_lookup(named_style_hash, name);
193 if (cs)
195 *style = *cs;
196 if (bold)
197 style->bold = !style->bold;
198 if (italic)
199 style->italic = !style->italic;
201 else
203 *style = gsd_default;
205 return (cs != NULL);
209 /* Parses a color in `str` which can be an HTML color (ex. #0099cc),
210 * an abbreviated HTML color (ex. #09c) or a hex string color
211 * (ex. 0x0099cc). The result of the conversion is stored into the
212 * location pointed to by `clr`. */
213 static void parse_color(const gchar *str, gint *clr)
215 gint c;
216 gchar hex_clr[9] = { 0 };
217 const gchar *start;
219 g_return_if_fail(clr != NULL);
221 if (G_UNLIKELY(! NZV(str)))
222 return;
224 if (str[0] == '#')
225 start = str + 1;
226 else if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
227 start = str + 2;
228 else
229 start = str;
231 if (strlen(start) == 3)
233 snprintf(hex_clr, 9, "0x%c%c%c%c%c%c", start[0], start[0],
234 start[1], start[1], start[2], start[2]);
236 else
237 snprintf(hex_clr, 9, "0x%s", start);
239 c = utils_strtod(hex_clr, NULL, FALSE);
241 if (c > -1)
243 *clr = c;
244 return;
246 geany_debug("Bad color '%s'", str);
250 static void parse_keyfile_style(gchar **list,
251 const GeanyLexerStyle *default_style, GeanyLexerStyle *style)
253 gsize len;
254 gchar *str;
256 g_return_if_fail(default_style);
257 g_return_if_fail(style);
259 *style = *default_style;
261 if (!list)
262 return;
264 len = g_strv_length(list);
266 str = list[0];
267 if (len == 1 && isalpha(str[0]))
269 if (!read_named_style(str, style))
270 geany_debug(
271 "No named style '%s'! Check filetype styles or %s color scheme.",
272 str, NVL(editor_prefs.color_scheme, "filetypes.common"));
274 else
276 switch (len)
278 case 4:
279 style->italic = utils_atob(list[3]);
280 case 3:
281 style->bold = utils_atob(list[2]);
282 case 2:
283 parse_color(list[1], &style->background);
284 case 1:
285 parse_color(list[0], &style->foreground);
291 static void get_keyfile_style(GKeyFile *config, GKeyFile *configh,
292 const gchar *key_name, GeanyLexerStyle *style)
294 gchar **list;
295 gsize len;
297 g_return_if_fail(config);
298 g_return_if_fail(configh);
299 g_return_if_fail(key_name);
300 g_return_if_fail(style);
302 list = g_key_file_get_string_list(configh, "styling", key_name, &len, NULL);
303 if (list == NULL)
304 list = g_key_file_get_string_list(config, "styling", key_name, &len, NULL);
306 parse_keyfile_style(list, &gsd_default, style);
307 g_strfreev(list);
311 /* Convert 0xRRGGBB to 0xBBGGRR, which scintilla expects. */
312 static gint rotate_rgb(gint color)
314 return ((color & 0xFF0000) >> 16) +
315 (color & 0x00FF00) +
316 ((color & 0x0000FF) << 16);
320 static void convert_int(const gchar *int_str, gint *val)
322 gchar *end;
323 gint v = strtol(int_str, &end, 10);
325 if (int_str != end)
326 *val = v;
330 /* Get first and second integer numbers, store in foreground and background fields of @a style. */
331 static void get_keyfile_int(GKeyFile *config, GKeyFile *configh, const gchar *section,
332 const gchar *key, gint fdefault_val, gint sdefault_val,
333 GeanyLexerStyle *style)
335 gchar **list;
336 gsize len;
337 GeanyLexerStyle def = {fdefault_val, sdefault_val, FALSE, FALSE};
339 g_return_if_fail(config);
340 g_return_if_fail(configh);
341 g_return_if_fail(section);
342 g_return_if_fail(key);
344 list = g_key_file_get_string_list(configh, section, key, &len, NULL);
345 if (list == NULL)
346 list = g_key_file_get_string_list(config, section, key, &len, NULL);
348 *style = def;
349 if (!list)
350 return;
352 if (list[0])
354 convert_int(list[0], &style->foreground);
355 if (list[1])
357 convert_int(list[1], &style->background);
360 g_strfreev(list);
364 /* first or second can be NULL. */
365 static void get_keyfile_ints(GKeyFile *config, GKeyFile *configh, const gchar *section,
366 const gchar *key,
367 gint fdefault_val, gint sdefault_val,
368 gint *first, gint *second)
370 GeanyLexerStyle tmp_style;
372 get_keyfile_int(config, configh, section, key, fdefault_val, sdefault_val, &tmp_style);
373 if (first)
374 *first = tmp_style.foreground;
375 if (second)
376 *second = tmp_style.background;
380 static guint invert(guint icolour)
382 if (interface_prefs.highlighting_invert_all)
383 return utils_invert_color(icolour);
385 return icolour;
389 static GeanyLexerStyle *get_style(guint ft_id, guint styling_index)
391 g_assert(ft_id < filetypes_array->len);
393 if (G_UNLIKELY(ft_id == GEANY_FILETYPES_NONE))
395 g_assert(styling_index < GCS_MAX);
396 return &common_style_set.styling[styling_index];
398 else
400 StyleSet *set = &style_sets[ft_id];
402 g_assert(styling_index < set->count);
403 return &set->styling[styling_index];
408 static void set_sci_style(ScintillaObject *sci, guint style, guint ft_id, guint styling_index)
410 GeanyLexerStyle *style_ptr = get_style(ft_id, styling_index);
412 SSM(sci, SCI_STYLESETFORE, style, invert(style_ptr->foreground));
413 SSM(sci, SCI_STYLESETBACK, style, invert(style_ptr->background));
414 SSM(sci, SCI_STYLESETBOLD, style, style_ptr->bold);
415 SSM(sci, SCI_STYLESETITALIC, style, style_ptr->italic);
419 void highlighting_free_styles()
421 guint i;
423 for (i = 0; i < filetypes_array->len; i++)
424 free_styleset(i);
426 if (named_style_hash)
427 g_hash_table_destroy(named_style_hash);
429 g_free(style_sets);
433 static GString *get_global_typenames(gint lang)
435 GString *s = NULL;
437 if (app->tm_workspace)
439 GPtrArray *tags_array = app->tm_workspace->global_tags;
441 if (tags_array)
443 s = symbols_find_tags_as_string(tags_array, TM_GLOBAL_TYPE_MASK, lang);
446 return s;
450 static gchar*
451 get_keyfile_whitespace_chars(GKeyFile *config, GKeyFile *configh)
453 return utils_get_setting(string, configh, config,
454 "settings", "whitespace_chars", GEANY_WHITESPACE_CHARS);
458 static void add_named_style(GKeyFile *config, const gchar *key)
460 const gchar group[] = "named_styles";
461 gchar **list;
462 gsize len;
464 list = g_key_file_get_string_list(config, group, key, &len, NULL);
465 /* we allow a named style to reference another style above it */
466 if (list && len >= 1)
468 GeanyLexerStyle *style = g_new0(GeanyLexerStyle, 1);
470 parse_keyfile_style(list, &gsd_default, style);
471 g_hash_table_insert(named_style_hash, g_strdup(key), style);
473 g_strfreev(list);
477 static void get_named_styles(GKeyFile *config)
479 const gchar group[] = "named_styles";
480 gchar **keys = g_key_file_get_keys(config, group, NULL, NULL);
481 gchar **ptr = keys;
483 if (!ptr)
484 return;
486 while (1)
488 const gchar *key = *ptr;
490 if (!key)
491 break;
493 /* don't replace already read default style with system one */
494 if (!g_str_equal(key, "default"))
495 add_named_style(config, key);
497 ptr++;
499 g_strfreev(keys);
503 static GKeyFile *utils_key_file_new(const gchar *filename)
505 GKeyFile *config = g_key_file_new();
507 g_key_file_load_from_file(config, filename, G_KEY_FILE_KEEP_COMMENTS, NULL);
508 return config;
512 static void load_named_styles(GKeyFile *config, GKeyFile *config_home)
514 const gchar *scheme = editor_prefs.color_scheme;
515 gboolean free_kf = FALSE;
517 if (named_style_hash)
518 g_hash_table_destroy(named_style_hash); /* reloading */
520 named_style_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
522 if (NZV(scheme))
524 gchar *path, *path_home;
526 path = g_build_path(G_DIR_SEPARATOR_S, app->datadir, GEANY_COLORSCHEMES_SUBDIR, scheme, NULL);
527 path_home = g_build_path(G_DIR_SEPARATOR_S, app->configdir, GEANY_COLORSCHEMES_SUBDIR, scheme, NULL);
529 if (g_file_test(path, G_FILE_TEST_EXISTS) || g_file_test(path_home, G_FILE_TEST_EXISTS))
531 config = utils_key_file_new(path);
532 config_home = utils_key_file_new(path_home);
533 free_kf = TRUE;
535 /* if color scheme is missing, use default */
536 g_free(path);
537 g_free(path_home);
539 /* first set default to the "default" named style */
540 add_named_style(config, "default");
541 read_named_style("default", &gsd_default); /* in case user overrides but not with both colors */
542 add_named_style(config_home, "default");
543 read_named_style("default", &gsd_default);
545 get_named_styles(config);
546 /* home overrides any system named style */
547 get_named_styles(config_home);
549 if (free_kf)
551 g_key_file_free(config);
552 g_key_file_free(config_home);
557 static void styleset_common_init(guint ft_id, GKeyFile *config, GKeyFile *config_home)
559 load_named_styles(config, config_home);
561 get_keyfile_style(config, config_home, "default", &common_style_set.styling[GCS_DEFAULT]);
562 get_keyfile_style(config, config_home, "selection", &common_style_set.styling[GCS_SELECTION]);
563 get_keyfile_style(config, config_home, "brace_good", &common_style_set.styling[GCS_BRACE_GOOD]);
564 get_keyfile_style(config, config_home, "brace_bad", &common_style_set.styling[GCS_BRACE_BAD]);
565 get_keyfile_style(config, config_home, "margin_linenumber", &common_style_set.styling[GCS_MARGIN_LINENUMBER]);
566 get_keyfile_style(config, config_home, "margin_folding", &common_style_set.styling[GCS_MARGIN_FOLDING]);
567 get_keyfile_style(config, config_home, "fold_symbol_highlight", &common_style_set.styling[GCS_FOLD_SYMBOL_HIGHLIGHT]);
568 get_keyfile_style(config, config_home, "current_line", &common_style_set.styling[GCS_CURRENT_LINE]);
569 get_keyfile_style(config, config_home, "caret", &common_style_set.styling[GCS_CARET]);
570 get_keyfile_style(config, config_home, "indent_guide", &common_style_set.styling[GCS_INDENT_GUIDE]);
571 get_keyfile_style(config, config_home, "white_space", &common_style_set.styling[GCS_WHITE_SPACE]);
572 get_keyfile_style(config, config_home, "marker_line", &common_style_set.styling[GCS_MARKER_LINE]);
573 get_keyfile_style(config, config_home, "marker_search", &common_style_set.styling[GCS_MARKER_SEARCH]);
574 get_keyfile_style(config, config_home, "marker_mark", &common_style_set.styling[GCS_MARKER_MARK]);
575 get_keyfile_style(config, config_home, "calltips", &common_style_set.styling[GCS_CALLTIPS]);
577 get_keyfile_ints(config, config_home, "styling", "folding_style",
578 1, 1, &common_style_set.fold_marker, &common_style_set.fold_lines);
579 get_keyfile_ints(config, config_home, "styling", "folding_horiz_line",
580 2, 0, &common_style_set.fold_draw_line, NULL);
581 get_keyfile_ints(config, config_home, "styling", "caret_width",
582 1, 0, &common_style_set.styling[GCS_CARET].background, NULL); /* caret.foreground used earlier */
583 get_keyfile_int(config, config_home, "styling", "line_wrap_visuals",
584 3, 0, &common_style_set.styling[GCS_LINE_WRAP_VISUALS]);
585 get_keyfile_int(config, config_home, "styling", "line_wrap_indent",
586 0, 0, &common_style_set.styling[GCS_LINE_WRAP_INDENT]);
587 get_keyfile_int(config, config_home, "styling", "translucency",
588 256, 256, &common_style_set.styling[GCS_TRANSLUCENCY]);
589 get_keyfile_int(config, config_home, "styling", "marker_translucency",
590 256, 256, &common_style_set.styling[GCS_MARKER_TRANSLUCENCY]);
591 get_keyfile_int(config, config_home, "styling", "line_height",
592 0, 0, &common_style_set.styling[GCS_LINE_HEIGHT]);
594 get_keyfile_wordchars(config, config_home, &common_style_set.wordchars);
595 whitespace_chars = get_keyfile_whitespace_chars(config, config_home);
599 static void styleset_common(ScintillaObject *sci, guint ft_id)
601 SSM(sci, SCI_STYLECLEARALL, 0, 0);
603 SSM(sci, SCI_SETWORDCHARS, 0, (sptr_t) (ft_id == GEANY_FILETYPES_NONE ?
604 common_style_set.wordchars : style_sets[ft_id].wordchars));
605 /* have to set whitespace after setting wordchars */
606 SSM(sci, SCI_SETWHITESPACECHARS, 0, (sptr_t) whitespace_chars);
608 /* caret colour, style and width */
609 SSM(sci, SCI_SETCARETFORE, invert(common_style_set.styling[GCS_CARET].foreground), 0);
610 SSM(sci, SCI_SETCARETWIDTH, common_style_set.styling[GCS_CARET].background, 0);
611 if (common_style_set.styling[GCS_CARET].bold)
612 SSM(sci, SCI_SETCARETSTYLE, CARETSTYLE_BLOCK, 0);
613 else
614 SSM(sci, SCI_SETCARETSTYLE, CARETSTYLE_LINE, 0);
616 /* line height */
617 SSM(sci, SCI_SETEXTRAASCENT, common_style_set.styling[GCS_LINE_HEIGHT].foreground, 0);
618 SSM(sci, SCI_SETEXTRADESCENT, common_style_set.styling[GCS_LINE_HEIGHT].background, 0);
620 /* colourise the current line */
621 SSM(sci, SCI_SETCARETLINEBACK, invert(common_style_set.styling[GCS_CURRENT_LINE].background), 0);
622 /* bold=enable current line */
623 SSM(sci, SCI_SETCARETLINEVISIBLE, common_style_set.styling[GCS_CURRENT_LINE].bold, 0);
625 /* Translucency for current line and selection */
626 SSM(sci, SCI_SETCARETLINEBACKALPHA, common_style_set.styling[GCS_TRANSLUCENCY].foreground, 0);
627 SSM(sci, SCI_SETSELALPHA, common_style_set.styling[GCS_TRANSLUCENCY].background, 0);
629 /* line wrapping visuals */
630 SSM(sci, SCI_SETWRAPVISUALFLAGS,
631 common_style_set.styling[GCS_LINE_WRAP_VISUALS].foreground, 0);
632 SSM(sci, SCI_SETWRAPVISUALFLAGSLOCATION,
633 common_style_set.styling[GCS_LINE_WRAP_VISUALS].background, 0);
634 SSM(sci, SCI_SETWRAPSTARTINDENT, common_style_set.styling[GCS_LINE_WRAP_INDENT].foreground, 0);
635 SSM(sci, SCI_SETWRAPINDENTMODE, common_style_set.styling[GCS_LINE_WRAP_INDENT].background, 0);
637 /* Error indicator */
638 SSM(sci, SCI_INDICSETSTYLE, GEANY_INDICATOR_ERROR, INDIC_SQUIGGLE);
639 SSM(sci, SCI_INDICSETFORE, GEANY_INDICATOR_ERROR, invert(rotate_rgb(0xff0000)));
641 /* Search indicator, used for 'Mark' matches */
642 SSM(sci, SCI_INDICSETSTYLE, GEANY_INDICATOR_SEARCH, INDIC_ROUNDBOX);
643 SSM(sci, SCI_INDICSETFORE, GEANY_INDICATOR_SEARCH,
644 invert(common_style_set.styling[GCS_MARKER_SEARCH].background));
645 SSM(sci, SCI_INDICSETALPHA, GEANY_INDICATOR_SEARCH, 60);
647 /* define marker symbols
648 * 0 -> line marker */
649 SSM(sci, SCI_MARKERDEFINE, 0, SC_MARK_SHORTARROW);
650 SSM(sci, SCI_MARKERSETFORE, 0, invert(common_style_set.styling[GCS_MARKER_LINE].foreground));
651 SSM(sci, SCI_MARKERSETBACK, 0, invert(common_style_set.styling[GCS_MARKER_LINE].background));
652 SSM(sci, SCI_MARKERSETALPHA, 0, common_style_set.styling[GCS_MARKER_TRANSLUCENCY].foreground);
654 /* 1 -> user marker */
655 SSM(sci, SCI_MARKERDEFINE, 1, SC_MARK_PLUS);
656 SSM(sci, SCI_MARKERSETFORE, 1, invert(common_style_set.styling[GCS_MARKER_MARK].foreground));
657 SSM(sci, SCI_MARKERSETBACK, 1, invert(common_style_set.styling[GCS_MARKER_MARK].background));
658 SSM(sci, SCI_MARKERSETALPHA, 1, common_style_set.styling[GCS_MARKER_TRANSLUCENCY].background);
660 /* 2 -> folding marker, other folding settings */
661 SSM(sci, SCI_SETMARGINTYPEN, 2, SC_MARGIN_SYMBOL);
662 SSM(sci, SCI_SETMARGINMASKN, 2, SC_MASK_FOLDERS);
664 /* drawing a horizontal line when text if folded */
665 switch (common_style_set.fold_draw_line)
667 case 1:
669 SSM(sci, SCI_SETFOLDFLAGS, 4, 0);
670 break;
672 case 2:
674 SSM(sci, SCI_SETFOLDFLAGS, 16, 0);
675 break;
677 default:
679 SSM(sci, SCI_SETFOLDFLAGS, 0, 0);
680 break;
684 /* choose the folding style - boxes or circles, I prefer boxes, so it is default ;-) */
685 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND, SC_MARK_EMPTY);
686 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_EMPTY);
687 switch (common_style_set.fold_marker)
689 case 2:
690 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS);
691 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS);
692 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND, SC_MARK_CIRCLEPLUSCONNECTED);
693 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_CIRCLEMINUSCONNECTED);
694 break;
695 default:
696 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS);
697 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS);
698 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED);
699 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED);
700 break;
701 case 3:
702 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_ARROWDOWN);
703 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_ARROW);
704 break;
705 case 4:
706 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_MINUS);
707 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_PLUS);
708 break;
711 /* choose the folding style - straight or curved, I prefer straight, so it is default ;-) */
712 switch (common_style_set.fold_lines)
714 case 2:
715 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE);
716 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE);
717 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
718 break;
719 default:
720 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER);
721 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER);
722 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
723 break;
724 case 0:
725 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_EMPTY);
726 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_EMPTY);
727 SSM(sci, SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_EMPTY);
728 break;
731 gint markers[] = {
732 SC_MARKNUM_FOLDEROPEN,
733 SC_MARKNUM_FOLDER,
734 SC_MARKNUM_FOLDERSUB,
735 SC_MARKNUM_FOLDERTAIL,
736 SC_MARKNUM_FOLDEREND,
737 SC_MARKNUM_FOLDEROPENMID,
738 SC_MARKNUM_FOLDERMIDTAIL
740 guint i;
742 foreach_range(i, G_N_ELEMENTS(markers))
744 SSM(sci, SCI_MARKERSETFORE, markers[i],
745 invert(common_style_set.styling[GCS_FOLD_SYMBOL_HIGHLIGHT].foreground));
746 SSM(sci, SCI_MARKERSETBACK, markers[i],
747 invert(common_style_set.styling[GCS_MARGIN_FOLDING].foreground));
751 /* set some common defaults */
752 sci_set_property(sci, "fold", "1");
753 sci_set_property(sci, "fold.compact", "0");
754 sci_set_property(sci, "fold.comment", "1");
755 sci_set_property(sci, "fold.preprocessor", "1");
756 sci_set_property(sci, "fold.at.else", "1");
758 /* bold (3rd argument) is whether to override default foreground selection */
759 if (common_style_set.styling[GCS_SELECTION].bold)
760 SSM(sci, SCI_SETSELFORE, 1, invert(common_style_set.styling[GCS_SELECTION].foreground));
761 /* italic (4th argument) is whether to override default background selection */
762 if (common_style_set.styling[GCS_SELECTION].italic)
763 SSM(sci, SCI_SETSELBACK, 1, invert(common_style_set.styling[GCS_SELECTION].background));
765 SSM(sci, SCI_SETSTYLEBITS, SSM(sci, SCI_GETSTYLEBITSNEEDED, 0, 0), 0);
767 SSM(sci, SCI_SETFOLDMARGINCOLOUR, 1, invert(common_style_set.styling[GCS_MARGIN_FOLDING].background));
768 SSM(sci, SCI_SETFOLDMARGINHICOLOUR, 1, invert(common_style_set.styling[GCS_MARGIN_FOLDING].background));
769 set_sci_style(sci, STYLE_LINENUMBER, GEANY_FILETYPES_NONE, GCS_MARGIN_LINENUMBER);
770 set_sci_style(sci, STYLE_BRACELIGHT, GEANY_FILETYPES_NONE, GCS_BRACE_GOOD);
771 set_sci_style(sci, STYLE_BRACEBAD, GEANY_FILETYPES_NONE, GCS_BRACE_BAD);
772 set_sci_style(sci, STYLE_INDENTGUIDE, GEANY_FILETYPES_NONE, GCS_INDENT_GUIDE);
774 /* bold = common whitespace settings enabled */
775 SSM(sci, SCI_SETWHITESPACEFORE, common_style_set.styling[GCS_WHITE_SPACE].bold,
776 invert(common_style_set.styling[GCS_WHITE_SPACE].foreground));
777 SSM(sci, SCI_SETWHITESPACEBACK, common_style_set.styling[GCS_WHITE_SPACE].italic,
778 invert(common_style_set.styling[GCS_WHITE_SPACE].background));
780 if (common_style_set.styling[GCS_CALLTIPS].bold)
781 SSM(sci, SCI_CALLTIPSETFORE, invert(common_style_set.styling[GCS_CALLTIPS].foreground), 1);
782 if (common_style_set.styling[GCS_CALLTIPS].italic)
783 SSM(sci, SCI_CALLTIPSETBACK, invert(common_style_set.styling[GCS_CALLTIPS].background), 1);
787 /* Merge & assign global typedefs and user secondary keywords.
788 * keyword_idx is used for both style_sets[].keywords and scintilla keyword style number */
789 static void merge_type_keywords(ScintillaObject *sci, guint ft_id, guint keyword_idx)
791 const gchar *user_words = style_sets[ft_id].keywords[keyword_idx];
792 GString *s;
794 s = get_global_typenames(filetypes[ft_id]->lang);
795 if (G_UNLIKELY(s == NULL))
796 s = g_string_sized_new(200);
797 else
798 g_string_append_c(s, ' '); /* append a space as delimiter to the existing list of words */
800 g_string_append(s, user_words);
802 sci_set_keywords(sci, keyword_idx, s->str);
803 g_string_free(s, TRUE);
807 static void styleset_init_from_mapping(guint ft_id, GKeyFile *config, GKeyFile *config_home,
808 const HLStyle *styles, gsize n_styles,
809 const HLKeyword *keywords, gsize n_keywords)
811 gsize i;
813 /* styles */
814 new_styleset(ft_id, n_styles);
815 foreach_range(i, n_styles)
817 GeanyLexerStyle *style = &style_sets[ft_id].styling[i];
819 get_keyfile_style(config, config_home, styles[i].name, style);
822 /* keywords */
823 if (n_keywords < 1)
824 style_sets[ft_id].keywords = NULL;
825 else
827 style_sets[ft_id].keywords = g_new(gchar*, n_keywords + 1);
828 foreach_range(i, n_keywords)
829 get_keyfile_keywords(config, config_home, keywords[i].key, ft_id, i);
830 style_sets[ft_id].keywords[i] = NULL;
835 /* STYLE_DEFAULT will be set to match the first style. */
836 static void styleset_from_mapping(ScintillaObject *sci, guint ft_id, guint lexer,
837 const HLStyle *styles, gsize n_styles,
838 const HLKeyword *keywords, gsize n_keywords,
839 const HLProperty *properties, gsize n_properties)
841 gsize i;
843 g_assert(ft_id != GEANY_FILETYPES_NONE);
845 /* lexer */
846 SSM(sci, SCI_SETLEXER, lexer, 0);
848 /* styles */
849 styleset_common(sci, ft_id);
850 if (n_styles > 0)
852 /* first style is also default one */
853 set_sci_style(sci, STYLE_DEFAULT, ft_id, 0);
854 foreach_range(i, n_styles)
856 if (styles[i].fill_eol)
857 SSM(sci, SCI_STYLESETEOLFILLED, styles[i].style, TRUE);
858 set_sci_style(sci, styles[i].style, ft_id, i);
862 /* keywords */
863 foreach_range(i, n_keywords)
865 if (keywords[i].merge)
866 merge_type_keywords(sci, ft_id, i);
867 else
868 sci_set_keywords(sci, keywords[i].id, style_sets[ft_id].keywords[i]);
871 /* properties */
872 foreach_range(i, n_properties)
873 sci_set_property(sci, properties[i].property, properties[i].value);
878 static void styleset_default(ScintillaObject *sci, guint ft_id)
880 SSM(sci, SCI_SETLEXER, SCLEX_NULL, 0);
882 /* we need to set STYLE_DEFAULT before we call SCI_STYLECLEARALL in styleset_common() */
883 set_sci_style(sci, STYLE_DEFAULT, GEANY_FILETYPES_NONE, GCS_DEFAULT);
885 styleset_common(sci, ft_id);
889 static void get_key_values(GKeyFile *config, const gchar *group, gchar **keys, gchar **values)
891 while (*keys)
893 gchar *str = g_key_file_get_string(config, group, *keys, NULL);
895 if (str)
896 setptr(*values, str);
898 keys++;
899 values++;
904 static void read_properties(GeanyFiletype *ft, GKeyFile *config, GKeyFile *configh)
906 gchar group[] = "lexer_properties";
907 gchar **keys;
908 gchar **keysh = g_key_file_get_keys(configh, group, NULL, NULL);
909 gchar **ptr;
911 /* remove overridden keys from system keyfile */
912 foreach_strv(ptr, keysh)
913 g_key_file_remove_key(config, group, *ptr, NULL);
915 /* merge sys and user keys */
916 keys = g_key_file_get_keys(config, group, NULL, NULL);
917 keys = utils_strv_join(keys, keysh);
919 if (keys)
921 gchar **values = g_new0(gchar*, g_strv_length(keys) + 1);
923 style_sets[ft->id].property_keys = keys;
924 style_sets[ft->id].property_values = values;
926 get_key_values(config, group, keys, values);
927 get_key_values(configh, group, keys, values);
932 static guint get_lexer_filetype(GeanyFiletype *ft)
934 ft = NVL(ft->lexer_filetype, ft);
935 return ft->id;
939 #define init_styleset_case(LANG_NAME) \
940 case (GEANY_FILETYPES_##LANG_NAME): \
941 styleset_init_from_mapping(filetype_idx, config, configh, \
942 highlighting_styles_##LANG_NAME, \
943 HL_N_ENTRIES(highlighting_styles_##LANG_NAME), \
944 highlighting_keywords_##LANG_NAME, \
945 HL_N_ENTRIES(highlighting_keywords_##LANG_NAME)); \
946 break
948 /* Called by filetypes_load_config(). */
949 void highlighting_init_styles(guint filetype_idx, GKeyFile *config, GKeyFile *configh)
951 GeanyFiletype *ft = filetypes[filetype_idx];
952 guint lexer_id = get_lexer_filetype(ft);
954 if (!style_sets)
955 style_sets = g_new0(StyleSet, filetypes_array->len);
957 /* Clear old information if necessary - e.g. when reloading config */
958 free_styleset(filetype_idx);
960 read_properties(ft, config, configh);
962 /* None filetype handled specially */
963 if (filetype_idx == GEANY_FILETYPES_NONE)
965 styleset_common_init(GEANY_FILETYPES_NONE, config, configh);
966 return;
968 /* All stylesets depend on filetypes.common */
969 filetypes_load_config(GEANY_FILETYPES_NONE, FALSE);
971 switch (lexer_id)
973 init_styleset_case(ADA);
974 init_styleset_case(ASM);
975 init_styleset_case(BASIC);
976 init_styleset_case(C);
977 init_styleset_case(CAML);
978 init_styleset_case(CMAKE);
979 init_styleset_case(COBOL);
980 init_styleset_case(CONF);
981 init_styleset_case(CSS);
982 init_styleset_case(D);
983 init_styleset_case(DIFF);
984 init_styleset_case(LISP);
985 init_styleset_case(ERLANG);
986 init_styleset_case(DOCBOOK);
987 init_styleset_case(FERITE);
988 init_styleset_case(F77);
989 init_styleset_case(FORTH);
990 init_styleset_case(FORTRAN);
991 init_styleset_case(HASKELL);
992 init_styleset_case(HAXE);
993 init_styleset_case(AS);
994 init_styleset_case(HTML);
995 init_styleset_case(JAVA);
996 init_styleset_case(JS);
997 init_styleset_case(LATEX);
998 init_styleset_case(LUA);
999 init_styleset_case(MAKE);
1000 init_styleset_case(MATLAB);
1001 init_styleset_case(MARKDOWN);
1002 init_styleset_case(NSIS);
1003 init_styleset_case(OBJECTIVEC);
1004 init_styleset_case(PASCAL);
1005 init_styleset_case(PERL);
1006 init_styleset_case(PHP);
1007 init_styleset_case(PO);
1008 init_styleset_case(PYTHON);
1009 init_styleset_case(R);
1010 init_styleset_case(RUBY);
1011 init_styleset_case(SH);
1012 init_styleset_case(SQL);
1013 init_styleset_case(TCL);
1014 init_styleset_case(TXT2TAGS);
1015 init_styleset_case(VHDL);
1016 init_styleset_case(VERILOG);
1017 init_styleset_case(XML);
1018 init_styleset_case(YAML);
1019 default:
1020 if (ft->lexer_filetype)
1021 geany_debug("Filetype %s has a recursive lexer_filetype %s set!",
1022 ft->name, ft->lexer_filetype->name);
1025 /* should be done in filetypes.c really: */
1026 get_keyfile_wordchars(config, configh, &style_sets[filetype_idx].wordchars);
1030 #define styleset_case(LANG_NAME) \
1031 case (GEANY_FILETYPES_##LANG_NAME): \
1032 styleset_from_mapping(sci, ft->id, highlighting_lexer_##LANG_NAME, \
1033 highlighting_styles_##LANG_NAME, \
1034 HL_N_ENTRIES(highlighting_styles_##LANG_NAME), \
1035 highlighting_keywords_##LANG_NAME, \
1036 HL_N_ENTRIES(highlighting_keywords_##LANG_NAME), \
1037 highlighting_properties_##LANG_NAME, \
1038 HL_N_ENTRIES(highlighting_properties_##LANG_NAME)); \
1039 break
1041 /** Sets up highlighting and other visual settings.
1042 * @param sci Scintilla widget.
1043 * @param ft Filetype settings to use. */
1044 void highlighting_set_styles(ScintillaObject *sci, GeanyFiletype *ft)
1046 guint lexer_id = get_lexer_filetype(ft);
1048 filetypes_load_config(ft->id, FALSE); /* load filetypes.ext */
1050 switch (lexer_id)
1052 styleset_case(ADA);
1053 styleset_case(ASM);
1054 styleset_case(BASIC);
1055 styleset_case(C);
1056 styleset_case(CAML);
1057 styleset_case(CMAKE);
1058 styleset_case(COBOL);
1059 styleset_case(CONF);
1060 styleset_case(CSS);
1061 styleset_case(D);
1062 styleset_case(DIFF);
1063 styleset_case(LISP);
1064 styleset_case(ERLANG);
1065 styleset_case(DOCBOOK);
1066 styleset_case(FERITE);
1067 styleset_case(F77);
1068 styleset_case(FORTH);
1069 styleset_case(FORTRAN);
1070 styleset_case(HASKELL);
1071 styleset_case(HAXE);
1072 styleset_case(AS);
1073 styleset_case(HTML);
1074 styleset_case(JAVA);
1075 styleset_case(JS);
1076 styleset_case(LATEX);
1077 styleset_case(LUA);
1078 styleset_case(MAKE);
1079 styleset_case(MARKDOWN);
1080 styleset_case(MATLAB);
1081 styleset_case(NSIS);
1082 styleset_case(OBJECTIVEC);
1083 styleset_case(PASCAL);
1084 styleset_case(PERL);
1085 styleset_case(PHP);
1086 styleset_case(PO);
1087 styleset_case(PYTHON);
1088 styleset_case(R);
1089 styleset_case(RUBY);
1090 styleset_case(SH);
1091 styleset_case(SQL);
1092 styleset_case(TCL);
1093 styleset_case(TXT2TAGS);
1094 styleset_case(VHDL);
1095 styleset_case(VERILOG);
1096 styleset_case(XML);
1097 styleset_case(YAML);
1098 case GEANY_FILETYPES_NONE:
1099 default:
1100 styleset_default(sci, ft->id);
1102 /* [lexer_properties] settings */
1103 if (style_sets[ft->id].property_keys)
1105 gchar **prop = style_sets[ft->id].property_keys;
1106 gchar **val = style_sets[ft->id].property_values;
1108 while (*prop)
1110 sci_set_property(sci, *prop, *val);
1111 prop++;
1112 val++;
1118 /** Retrieves a style @a style_id for the filetype @a ft_id.
1119 * If the style was not already initialised
1120 * (e.g. by by opening a file of this type), it will be initialised. The returned pointer is
1121 * owned by Geany and must not be freed.
1122 * @param ft_id Filetype ID, e.g. @c GEANY_FILETYPES_DIFF.
1123 * @param style_id A Scintilla lexer style, e.g. @c SCE_DIFF_ADDED. See scintilla/include/SciLexer.h.
1124 * @return A pointer to the style struct.
1125 * @see Scintilla messages @c SCI_STYLEGETFORE, etc, for use with scintilla_send_message(). */
1126 const GeanyLexerStyle *highlighting_get_style(gint ft_id, gint style_id)
1128 g_return_val_if_fail(ft_id >= 0 && (guint) ft_id < filetypes_array->len, NULL);
1129 g_return_val_if_fail(style_id >= 0, NULL);
1131 /* ensure filetype loaded */
1132 filetypes_load_config((guint) ft_id, FALSE);
1134 /* TODO: style_id might not be the real array index (Scintilla styles are not always synced
1135 * with array indices) */
1136 return get_style((guint) ft_id, (guint) style_id);
1140 static void
1141 on_color_scheme_clicked(GtkMenuItem *menuitem, gpointer user_data)
1143 gchar *fname;
1144 gchar *path;
1146 /* prevent callback on setting initial value */
1147 if (!GTK_WIDGET_MAPPED(menuitem))
1148 return;
1150 /* check if default item */
1151 if (!user_data)
1153 setptr(editor_prefs.color_scheme, NULL);
1154 filetypes_reload();
1155 return;
1157 fname = g_strdup(g_object_get_data(G_OBJECT(menuitem), "colorscheme_file"));
1158 setptr(fname, utils_get_locale_from_utf8(fname));
1160 /* fname is just the basename from the menu item, so prepend the custom files path */
1161 path = g_build_path(G_DIR_SEPARATOR_S, app->configdir, GEANY_COLORSCHEMES_SUBDIR, fname, NULL);
1162 if (!g_file_test(path, G_FILE_TEST_EXISTS))
1164 /* try the system path */
1165 g_free(path);
1166 path = g_build_path(G_DIR_SEPARATOR_S, app->datadir, GEANY_COLORSCHEMES_SUBDIR, fname, NULL);
1168 if (g_file_test(path, G_FILE_TEST_EXISTS))
1170 setptr(editor_prefs.color_scheme, fname);
1171 fname = NULL;
1172 filetypes_reload();
1174 else
1176 setptr(fname, utils_get_utf8_from_locale(fname));
1177 ui_set_statusbar(TRUE, _("Could not find file '%s'."), fname);
1179 g_free(path);
1180 g_free(fname);
1184 static gchar *utils_get_setting_locale_string(GKeyFile *keyfile,
1185 const gchar *group, const gchar *key, const gchar *default_value)
1187 gchar *result = g_key_file_get_locale_string(keyfile, group, key, NULL, NULL);
1189 return NVL(result, g_strdup(default_value));
1193 static void add_color_scheme_item(GtkWidget *menu, const gchar *fname)
1195 static GSList *group = NULL;
1196 GtkWidget *item;
1198 if (!fname)
1200 item = gtk_radio_menu_item_new_with_mnemonic(group, _("_Default"));
1202 else
1204 GKeyFile *hkeyfile, *skeyfile;
1205 gchar *path, *theme_name, *tooltip;
1206 gchar *theme_fn = utils_get_utf8_from_locale(fname);
1208 path = utils_build_path(app->configdir, GEANY_COLORSCHEMES_SUBDIR, fname, NULL);
1209 hkeyfile = utils_key_file_new(path);
1210 setptr(path, utils_build_path(app->datadir, GEANY_COLORSCHEMES_SUBDIR, fname, NULL));
1211 skeyfile = utils_key_file_new(path);
1213 theme_name = utils_get_setting(locale_string, hkeyfile, skeyfile, "theme_info", "name", theme_fn);
1214 item = gtk_radio_menu_item_new_with_label(group, theme_name);
1215 g_object_set_data_full(G_OBJECT(item), "colorscheme_file", theme_fn, g_free);
1217 tooltip = utils_get_setting(locale_string, hkeyfile, skeyfile, "theme_info", "description", NULL);
1218 if (tooltip != NULL)
1220 gtk_widget_set_tooltip_text(item, tooltip);
1221 g_free(tooltip);
1223 g_free(path);
1224 g_free(theme_name);
1225 g_key_file_free(hkeyfile);
1226 g_key_file_free(skeyfile);
1229 group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
1230 if (utils_str_equal(editor_prefs.color_scheme, fname))
1231 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1233 gtk_widget_show(item);
1234 gtk_container_add(GTK_CONTAINER(menu), item);
1235 g_signal_connect(item, "activate",
1236 G_CALLBACK(on_color_scheme_clicked), GINT_TO_POINTER(fname != NULL));
1240 static gboolean add_color_scheme_items(GtkWidget *menu)
1242 GSList *list, *node;
1244 g_return_val_if_fail(menu, FALSE);
1246 add_color_scheme_item(menu, NULL);
1247 list = utils_get_config_files(GEANY_COLORSCHEMES_SUBDIR);
1249 foreach_slist(node, list)
1251 gchar *fname = node->data;
1253 if (g_str_has_suffix(fname, ".conf"))
1254 add_color_scheme_item(menu, fname);
1256 g_free(fname);
1258 g_slist_free(list);
1259 return list != NULL;
1263 static void create_color_scheme_menu(void)
1265 GtkWidget *item, *menu, *root;
1267 menu = ui_lookup_widget(main_widgets.window, "menu_view_editor1_menu");
1268 item = ui_image_menu_item_new(GTK_STOCK_SELECT_COLOR, _("_Color Schemes"));
1269 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), item);
1270 root = item;
1272 menu = gtk_menu_new();
1273 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1275 add_color_scheme_items(menu);
1276 gtk_widget_show_all(root);
1280 void highlighting_init(void)
1282 create_color_scheme_menu();
1286 /** Checks whether the given style is a string for the given lexer.
1288 * @param lexer Scintilla lexer type (@c SCLEX_*).
1289 * @param style Scintilla style (@c SCE_*).
1291 * @return @c TRUE if the style is a string, @c FALSE otherwise.
1293 gboolean highlighting_is_string_style(gint lexer, gint style)
1295 /* Don't forget STRINGEOL, to prevent completion whilst typing a string with no closing char. */
1297 switch (lexer)
1299 case SCLEX_CPP:
1300 return (style == SCE_C_CHARACTER ||
1301 style == SCE_C_STRING ||
1302 style == SCE_C_STRINGEOL ||
1303 style == SCE_C_STRINGRAW ||
1304 style == SCE_C_VERBATIM ||
1305 style == SCE_C_TRIPLEVERBATIM);
1307 case SCLEX_PASCAL:
1308 return (style == SCE_PAS_CHARACTER ||
1309 style == SCE_PAS_STRING ||
1310 style == SCE_PAS_STRINGEOL);
1312 case SCLEX_D:
1313 return (style == SCE_D_STRING ||
1314 style == SCE_D_STRINGEOL ||
1315 style == SCE_D_CHARACTER ||
1316 style == SCE_D_STRINGB ||
1317 style == SCE_D_STRINGR);
1319 case SCLEX_PYTHON:
1320 return (style == SCE_P_STRING ||
1321 style == SCE_P_TRIPLE ||
1322 style == SCE_P_TRIPLEDOUBLE ||
1323 style == SCE_P_CHARACTER ||
1324 style == SCE_P_STRINGEOL);
1326 case SCLEX_F77:
1327 case SCLEX_FORTRAN:
1328 return (style == SCE_F_STRING1 ||
1329 style == SCE_F_STRING2 ||
1330 style == SCE_F_STRINGEOL);
1332 case SCLEX_PERL:
1333 return (style == SCE_PL_STRING ||
1334 style == SCE_PL_CHARACTER ||
1335 style == SCE_PL_HERE_DELIM ||
1336 style == SCE_PL_HERE_Q ||
1337 style == SCE_PL_HERE_QQ ||
1338 style == SCE_PL_HERE_QX ||
1339 style == SCE_PL_POD ||
1340 style == SCE_PL_STRING_Q ||
1341 style == SCE_PL_STRING_QQ ||
1342 style == SCE_PL_STRING_QX ||
1343 style == SCE_PL_STRING_QR ||
1344 style == SCE_PL_STRING_QW ||
1345 style == SCE_PL_POD_VERB ||
1346 style == SCE_PL_XLAT
1347 /* we don't include any STRING_*_VAR for autocompletion */);
1349 case SCLEX_R:
1350 return (style == SCE_R_STRING);
1352 case SCLEX_RUBY:
1353 return (style == SCE_RB_CHARACTER ||
1354 style == SCE_RB_STRING ||
1355 style == SCE_RB_HERE_DELIM ||
1356 style == SCE_RB_HERE_Q ||
1357 style == SCE_RB_HERE_QQ ||
1358 style == SCE_RB_HERE_QX ||
1359 style == SCE_RB_POD);
1361 case SCLEX_BASH:
1362 return (style == SCE_SH_STRING);
1364 case SCLEX_SQL:
1365 return (style == SCE_SQL_STRING);
1367 case SCLEX_TCL:
1368 return (style == SCE_TCL_IN_QUOTE);
1370 case SCLEX_LUA:
1371 return (style == SCE_LUA_LITERALSTRING ||
1372 style == SCE_LUA_CHARACTER ||
1373 style == SCE_LUA_STRINGEOL ||
1374 style == SCE_LUA_STRING);
1376 case SCLEX_HASKELL:
1377 return (style == SCE_HA_CHARACTER ||
1378 style == SCE_HA_STRING);
1380 case SCLEX_FREEBASIC:
1381 return (style == SCE_B_STRING ||
1382 style == SCE_B_STRINGEOL);
1384 case SCLEX_OCTAVE:
1385 return (style == SCE_MATLAB_STRING ||
1386 style == SCE_MATLAB_DOUBLEQUOTESTRING);
1388 case SCLEX_HTML:
1389 return (
1390 style == SCE_HBA_STRING ||
1391 style == SCE_HBA_STRINGEOL ||
1392 style == SCE_HB_STRING ||
1393 style == SCE_HB_STRINGEOL ||
1394 style == SCE_H_CDATA ||
1395 style == SCE_H_DOUBLESTRING ||
1396 style == SCE_HJA_DOUBLESTRING ||
1397 style == SCE_HJA_SINGLESTRING ||
1398 style == SCE_HJA_STRINGEOL ||
1399 style == SCE_HJ_DOUBLESTRING ||
1400 style == SCE_HJ_SINGLESTRING ||
1401 style == SCE_HJ_STRINGEOL ||
1402 style == SCE_HPA_CHARACTER ||
1403 style == SCE_HPA_STRING ||
1404 style == SCE_HPA_TRIPLE ||
1405 style == SCE_HPA_TRIPLEDOUBLE ||
1406 style == SCE_HP_CHARACTER ||
1407 style == SCE_HPHP_HSTRING || /* HSTRING is a heredoc */
1408 style == SCE_HPHP_HSTRING_VARIABLE ||
1409 style == SCE_HPHP_SIMPLESTRING ||
1410 style == SCE_HP_STRING ||
1411 style == SCE_HP_TRIPLE ||
1412 style == SCE_HP_TRIPLEDOUBLE ||
1413 style == SCE_H_SGML_DOUBLESTRING ||
1414 style == SCE_H_SGML_SIMPLESTRING ||
1415 style == SCE_H_SINGLESTRING);
1417 case SCLEX_CMAKE:
1418 return (style == SCE_CMAKE_STRINGDQ ||
1419 style == SCE_CMAKE_STRINGLQ ||
1420 style == SCE_CMAKE_STRINGRQ ||
1421 style == SCE_CMAKE_STRINGVAR);
1423 case SCLEX_NSIS:
1424 return (style == SCE_NSIS_STRINGDQ ||
1425 style == SCE_NSIS_STRINGLQ ||
1426 style == SCE_NSIS_STRINGRQ ||
1427 style == SCE_NSIS_STRINGVAR);
1429 case SCLEX_ADA:
1430 return (style == SCE_ADA_CHARACTER ||
1431 style == SCE_ADA_STRING ||
1432 style == SCE_ADA_CHARACTEREOL ||
1433 style == SCE_ADA_STRINGEOL);
1435 return FALSE;
1439 /** Checks whether the given style is a comment for the given lexer.
1441 * @param lexer Scintilla lexer type (@c SCLEX_*).
1442 * @param style Scintilla style (@c SCE_*).
1444 * @return @c TRUE if the style is a comment, @c FALSE otherwise.
1446 gboolean highlighting_is_comment_style(gint lexer, gint style)
1448 switch (lexer)
1450 case SCLEX_COBOL:
1451 case SCLEX_CPP:
1452 return (style == SCE_C_COMMENT ||
1453 style == SCE_C_COMMENTLINE ||
1454 style == SCE_C_COMMENTDOC ||
1455 style == SCE_C_COMMENTLINEDOC ||
1456 style == SCE_C_COMMENTDOCKEYWORD ||
1457 style == SCE_C_COMMENTDOCKEYWORDERROR);
1459 case SCLEX_PASCAL:
1460 return (style == SCE_PAS_COMMENT ||
1461 style == SCE_PAS_COMMENT2 ||
1462 style == SCE_PAS_COMMENTLINE);
1464 case SCLEX_D:
1465 return (style == SCE_D_COMMENT ||
1466 style == SCE_D_COMMENTLINE ||
1467 style == SCE_D_COMMENTDOC ||
1468 style == SCE_D_COMMENTNESTED ||
1469 style == SCE_D_COMMENTLINEDOC ||
1470 style == SCE_D_COMMENTDOCKEYWORD ||
1471 style == SCE_D_COMMENTDOCKEYWORDERROR);
1473 case SCLEX_PYTHON:
1474 return (style == SCE_P_COMMENTLINE ||
1475 style == SCE_P_COMMENTBLOCK);
1477 case SCLEX_F77:
1478 case SCLEX_FORTRAN:
1479 return (style == SCE_F_COMMENT);
1481 case SCLEX_PERL:
1482 return (style == SCE_PL_COMMENTLINE);
1484 case SCLEX_PROPERTIES:
1485 return (style == SCE_PROPS_COMMENT);
1487 case SCLEX_PO:
1488 return (style == SCE_PO_COMMENT);
1490 case SCLEX_LATEX:
1491 return (style == SCE_L_COMMENT ||
1492 style == SCE_L_COMMENT2);
1494 case SCLEX_MAKEFILE:
1495 return (style == SCE_MAKE_COMMENT);
1497 case SCLEX_RUBY:
1498 return (style == SCE_RB_COMMENTLINE);
1500 case SCLEX_BASH:
1501 return (style == SCE_SH_COMMENTLINE);
1503 case SCLEX_R:
1504 return (style == SCE_R_COMMENT);
1506 case SCLEX_SQL:
1507 return (style == SCE_SQL_COMMENT ||
1508 style == SCE_SQL_COMMENTLINE ||
1509 style == SCE_SQL_COMMENTDOC ||
1510 style == SCE_SQL_COMMENTLINEDOC ||
1511 style == SCE_SQL_COMMENTDOCKEYWORD ||
1512 style == SCE_SQL_COMMENTDOCKEYWORDERROR);
1514 case SCLEX_TCL:
1515 return (style == SCE_TCL_COMMENT ||
1516 style == SCE_TCL_COMMENTLINE ||
1517 style == SCE_TCL_COMMENT_BOX ||
1518 style == SCE_TCL_BLOCK_COMMENT);
1520 case SCLEX_OCTAVE:
1521 return (style == SCE_MATLAB_COMMENT);
1523 case SCLEX_LUA:
1524 return (style == SCE_LUA_COMMENT ||
1525 style == SCE_LUA_COMMENTLINE ||
1526 style == SCE_LUA_COMMENTDOC);
1528 case SCLEX_HASKELL:
1529 return (style == SCE_HA_COMMENTLINE ||
1530 style == SCE_HA_COMMENTBLOCK ||
1531 style == SCE_HA_COMMENTBLOCK2 ||
1532 style == SCE_HA_COMMENTBLOCK3);
1534 case SCLEX_FREEBASIC:
1535 return (style == SCE_B_COMMENT);
1537 case SCLEX_YAML:
1538 return (style == SCE_YAML_COMMENT);
1540 case SCLEX_HTML:
1541 return (
1542 style == SCE_HBA_COMMENTLINE ||
1543 style == SCE_HB_COMMENTLINE ||
1544 style == SCE_H_COMMENT ||
1545 style == SCE_HJA_COMMENT ||
1546 style == SCE_HJA_COMMENTDOC ||
1547 style == SCE_HJA_COMMENTLINE ||
1548 style == SCE_HJ_COMMENT ||
1549 style == SCE_HJ_COMMENTDOC ||
1550 style == SCE_HJ_COMMENTLINE ||
1551 style == SCE_HPA_COMMENTLINE ||
1552 style == SCE_HP_COMMENTLINE ||
1553 style == SCE_HPHP_COMMENT ||
1554 style == SCE_HPHP_COMMENTLINE ||
1555 style == SCE_H_SGML_COMMENT);
1557 case SCLEX_CMAKE:
1558 return (style == SCE_CMAKE_COMMENT);
1560 case SCLEX_NSIS:
1561 return (style == SCE_NSIS_COMMENT ||
1562 style == SCE_NSIS_COMMENTBOX);
1564 case SCLEX_ADA:
1565 return (style == SCE_ADA_COMMENTLINE ||
1566 style == SCE_NSIS_COMMENTBOX);
1568 case SCLEX_ASM:
1569 return (style == SCE_ASM_COMMENT ||
1570 style == SCE_ASM_COMMENTBLOCK ||
1571 style == SCE_ASM_COMMENTDIRECTIVE);
1573 return FALSE;
1577 /** Checks whether the given style is normal code (not string, comment, preprocessor, etc).
1579 * @param lexer Scintilla lexer type (@c SCLEX_*).
1580 * @param style Scintilla style (@c SCE_*).
1582 * @return @c TRUE if the style is code, @c FALSE otherwise.
1584 gboolean highlighting_is_code_style(gint lexer, gint style)
1586 switch (lexer)
1588 case SCLEX_CPP:
1589 if (style == SCE_C_PREPROCESSOR)
1590 return FALSE;
1591 break;
1593 return !(highlighting_is_comment_style(lexer, style) ||
1594 highlighting_is_string_style(lexer, style));