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.
22 * @file highlighting.h
23 * Syntax highlighting for the different filetypes, using the Scintilla lexers.
30 #include "highlighting.h"
31 #include "highlightingmappings.h"
37 #include "filetypesprivate.h"
38 #include "sciwrappers.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
;
64 gsize count
; /* number of styles */
65 GeanyLexerStyle
*styling
; /* array of styles, NULL if not used or uninitialised */
67 gchar
*wordchars
; /* NULL used for style sets with no styles */
68 gchar
**property_keys
;
69 gchar
**property_values
;
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 */
82 GCS_MARGIN_LINENUMBER
,
84 GCS_FOLD_SYMBOL_HIGHLIGHT
,
89 GCS_LINE_WRAP_VISUALS
,
95 GCS_MARKER_TRANSLUCENCY
,
104 GeanyLexerStyle styling
[GCS_MAX
];
106 /* icon style, 1-4 */
108 /* vertical line style, 0-2 */
110 /* horizontal line when folded, 0-2 */
114 } common_style_set
= { { { 0 } }, 0, 0, 0, NULL
};
117 /* For filetypes.common [named_styles] section.
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
)
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
)
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
, ",");
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
);
200 style
->bold
= !style
->bold
;
202 style
->italic
= !style
->italic
;
206 *style
= gsd_default
;
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
)
219 gchar
*named_color
= NULL
;
221 g_return_if_fail(clr
!= NULL
);
223 if (G_UNLIKELY(EMPTY(str
)))
226 named_color
= g_key_file_get_string(kf
, "named_colors", str
, NULL
);
230 c
= utils_parse_color_to_bgr(str
);
232 geany_debug("Bad color '%s'", str
);
240 static void parse_keyfile_style(GKeyFile
*kf
, gchar
**list
,
241 const GeanyLexerStyle
*default_style
, GeanyLexerStyle
*style
)
245 g_return_if_fail(default_style
);
246 g_return_if_fail(style
);
248 *style
= *default_style
;
253 len
= g_strv_length(list
);
258 gchar
**items
= g_strsplit(list
[0], ",", 0);
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]);
270 else if (strchr(list
[0], ',') != NULL
)
272 geany_debug("Unknown named style '%s'", items
[0]);
284 style
->italic
= utils_atob(list
[3]);
287 style
->bold
= utils_atob(list
[2]);
290 parse_color(kf
, list
[1], &style
->background
);
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
)
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
);
312 list
= g_key_file_get_string_list(config
, "styling", key_name
, &len
, NULL
);
313 parse_keyfile_style(config
, list
, &gsd_default
, style
);
316 parse_keyfile_style(configh
, list
, &gsd_default
, style
);
322 static void convert_int(const gchar
*int_str
, gint
*val
)
325 gint v
= strtol(int_str
, &end
, 10);
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
)
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
);
348 list
= g_key_file_get_string_list(config
, section
, key
, &len
, NULL
);
356 convert_int(list
[0], &style
->foreground
);
359 convert_int(list
[1], &style
->background
);
366 /* first or second can be NULL. */
367 static void get_keyfile_ints(GKeyFile
*config
, GKeyFile
*configh
, const gchar
*section
,
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
);
376 *first
= tmp_style
.foreground
;
378 *second
= tmp_style
.background
;
382 static guint
invert(guint icolour
)
384 if (interface_prefs
.highlighting_invert_all
)
385 return 0xffffff - 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
];
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)
425 for (i
= 0; i
< filetypes_array
->len
; i
++)
428 if (named_style_hash
)
429 g_hash_table_destroy(named_style_hash
);
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";
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
);
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
);
473 const gchar
*key
= *ptr
;
478 /* don't replace already read default style with system one */
479 if (!g_str_equal(key
, "default"))
480 add_named_style(config
, key
);
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
);
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
);
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
);
520 /* if color scheme is missing, use default */
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
);
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
);
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
];
606 SSM(sci
, SCI_SETWHITESPACECHARS
, 0, (sptr_t
) 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);
626 SSM(sci
, SCI_SETCARETSTYLE
, CARETSTYLE_LINE
, 0);
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
)
687 SSM(sci
, SCI_SETFOLDFLAGS
, 4, 0);
692 SSM(sci
, SCI_SETFOLDFLAGS
, 16, 0);
697 SSM(sci
, SCI_SETFOLDFLAGS
, 0, 0);
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
)
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
);
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
);
720 SSM(sci
, SCI_MARKERDEFINE
, SC_MARKNUM_FOLDEROPEN
, SC_MARK_ARROWDOWN
);
721 SSM(sci
, SCI_MARKERDEFINE
, SC_MARKNUM_FOLDER
, SC_MARK_ARROW
);
724 SSM(sci
, SCI_MARKERDEFINE
, SC_MARKNUM_FOLDEROPEN
, SC_MARK_MINUS
);
725 SSM(sci
, SCI_MARKERDEFINE
, SC_MARKNUM_FOLDER
, SC_MARK_PLUS
);
729 /* choose the folding style - straight or curved, I prefer straight, so it is default ;-) */
730 switch (common_style_set
.fold_lines
)
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
);
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
);
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
);
750 SC_MARKNUM_FOLDEROPEN
,
752 SC_MARKNUM_FOLDERSUB
,
753 SC_MARKNUM_FOLDERTAIL
,
754 SC_MARKNUM_FOLDEREND
,
755 SC_MARKNUM_FOLDEROPENMID
,
756 SC_MARKNUM_FOLDERMIDTAIL
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
];
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);
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
)
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
);
845 style_sets
[ft_id
].keywords
= NULL
;
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
)
864 g_assert(ft_id
!= GEANY_FILETYPES_NONE
);
867 sci_set_lexer(sci
, lexer
);
870 styleset_common(sci
, ft_id
);
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
);
884 foreach_range(i
, n_keywords
)
886 if (keywords
[i
].merge
)
887 merge_type_keywords(sci
, ft_id
, i
);
889 sci_set_keywords(sci
, keywords
[i
].id
, style_sets
[ft_id
].keywords
[i
]);
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
)
914 gchar
*str
= g_key_file_get_string(config
, group
, *keys
, NULL
);
917 SETPTR(*values
, str
);
925 static void read_properties(GeanyFiletype
*ft
, GKeyFile
*config
, GKeyFile
*configh
)
927 gchar group
[] = "lexer_properties";
929 gchar
**keysh
= g_key_file_get_keys(configh
, group
, NULL
, NULL
);
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
);
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
);
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)); \
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
);
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
);
990 /* None filetype handled specially */
991 if (filetype_idx
== GEANY_FILETYPES_NONE
)
993 styleset_common_init(config
, configh
);
996 /* All stylesets depend on filetypes.common */
997 filetypes_load_config(GEANY_FILETYPES_NONE
, FALSE
);
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(RUBY
);
1047 init_styleset_case(RUST
);
1048 init_styleset_case(SH
);
1049 init_styleset_case(SMALLTALK
);
1050 init_styleset_case(SQL
);
1051 init_styleset_case(TCL
);
1052 init_styleset_case(TXT2TAGS
);
1053 init_styleset_case(VHDL
);
1054 init_styleset_case(VERILOG
);
1055 init_styleset_case(XML
);
1056 init_styleset_case(YAML
);
1057 init_styleset_case(ZEPHIR
);
1059 if (ft
->lexer_filetype
)
1060 geany_debug("Filetype %s has a recursive lexer_filetype %s set!",
1061 ft
->name
, ft
->lexer_filetype
->name
);
1064 /* should be done in filetypes.c really: */
1065 get_keyfile_wordchars(config
, configh
, &style_sets
[filetype_idx
].wordchars
,
1066 common_style_set
.wordchars
);
1070 #define styleset_case(LANG_NAME) \
1071 case (GEANY_FILETYPES_##LANG_NAME): \
1072 styleset_from_mapping(sci, ft->id, highlighting_lexer_##LANG_NAME, \
1073 highlighting_styles_##LANG_NAME, \
1074 HL_N_ENTRIES(highlighting_styles_##LANG_NAME), \
1075 highlighting_keywords_##LANG_NAME, \
1076 HL_N_ENTRIES(highlighting_keywords_##LANG_NAME), \
1077 highlighting_properties_##LANG_NAME, \
1078 HL_N_ENTRIES(highlighting_properties_##LANG_NAME)); \
1081 /** Sets up highlighting and other visual settings.
1082 * @param sci Scintilla widget.
1083 * @param ft Filetype settings to use. */
1085 void highlighting_set_styles(ScintillaObject
*sci
, GeanyFiletype
*ft
)
1087 guint lexer_id
= get_lexer_filetype(ft
);
1089 filetypes_load_config(ft
->id
, FALSE
); /* load filetypes.ext */
1093 styleset_case(ABAQUS
);
1095 styleset_case(ASCIIDOC
);
1098 styleset_case(BASIC
);
1099 styleset_case(BATCH
);
1101 styleset_case(CAML
);
1102 styleset_case(CMAKE
);
1103 styleset_case(COBOL
);
1104 styleset_case(COFFEESCRIPT
);
1105 styleset_case(CONF
);
1108 styleset_case(DIFF
);
1109 styleset_case(LISP
);
1110 styleset_case(ERLANG
);
1111 styleset_case(DOCBOOK
);
1113 styleset_case(FORTH
);
1114 styleset_case(FORTRAN
);
1115 styleset_case(GDSCRIPT
);
1117 styleset_case(HASKELL
);
1118 styleset_case(HAXE
);
1120 styleset_case(HTML
);
1121 styleset_case(JAVA
);
1123 styleset_case(JULIA
);
1124 styleset_case(LATEX
);
1126 styleset_case(MAKE
);
1127 styleset_case(MARKDOWN
);
1128 styleset_case(MATLAB
);
1129 styleset_case(NSIS
);
1130 styleset_case(OBJECTIVEC
);
1131 styleset_case(PASCAL
);
1132 styleset_case(PERL
);
1135 styleset_case(POWERSHELL
);
1136 styleset_case(PYTHON
);
1138 styleset_case(RUBY
);
1139 styleset_case(RUST
);
1141 styleset_case(SMALLTALK
);
1144 styleset_case(TXT2TAGS
);
1145 styleset_case(VHDL
);
1146 styleset_case(VERILOG
);
1148 styleset_case(YAML
);
1149 styleset_case(ZEPHIR
);
1150 case GEANY_FILETYPES_NONE
:
1152 styleset_default(sci
, ft
->id
);
1154 /* [lexer_properties] settings */
1155 if (style_sets
[ft
->id
].property_keys
)
1157 gchar
**prop
= style_sets
[ft
->id
].property_keys
;
1158 gchar
**val
= style_sets
[ft
->id
].property_values
;
1162 sci_set_property(sci
, *prop
, *val
);
1170 /** Retrieves a style @a style_id for the filetype @a ft_id.
1171 * If the style was not already initialised
1172 * (e.g. by by opening a file of this type), it will be initialised. The returned pointer is
1173 * owned by Geany and must not be freed.
1174 * @param ft_id Filetype ID, e.g. @c GEANY_FILETYPES_DIFF.
1175 * @param style_id A Scintilla lexer style, e.g. @c SCE_DIFF_ADDED. See scintilla/lexilla/include/SciLexer.h.
1176 * @return A pointer to the style struct.
1177 * @see Scintilla messages @c SCI_STYLEGETFORE, etc, for use with scintilla_send_message(). */
1179 const GeanyLexerStyle
*highlighting_get_style(gint ft_id
, gint style_id
)
1181 g_return_val_if_fail(ft_id
>= 0 && (guint
) ft_id
< filetypes_array
->len
, NULL
);
1182 g_return_val_if_fail(style_id
>= 0, NULL
);
1184 /* ensure filetype loaded */
1185 filetypes_load_config((guint
) ft_id
, FALSE
);
1187 /* TODO: style_id might not be the real array index (Scintilla styles are not always synced
1188 * with array indices) */
1189 return get_style((guint
) ft_id
, (guint
) style_id
);
1200 static void on_color_scheme_changed(GtkTreeSelection
*treesel
, gpointer dummy
)
1202 GtkTreeModel
*model
;
1207 if (!gtk_tree_selection_get_selected(treesel
, &model
, &iter
))
1209 gtk_tree_model_get(model
, &iter
, SCHEME_FILE
, &fname
, -1);
1211 /* check if default item */
1214 SETPTR(editor_prefs
.color_scheme
, NULL
);
1218 SETPTR(fname
, utils_get_locale_from_utf8(fname
));
1220 /* fname is just the basename from the menu item, so prepend the custom files path */
1221 path
= g_build_path(G_DIR_SEPARATOR_S
, app
->configdir
, GEANY_COLORSCHEMES_SUBDIR
, fname
, NULL
);
1222 if (!g_file_test(path
, G_FILE_TEST_EXISTS
))
1224 /* try the system path */
1226 path
= g_build_path(G_DIR_SEPARATOR_S
, app
->datadir
, GEANY_COLORSCHEMES_SUBDIR
, fname
, NULL
);
1228 if (g_file_test(path
, G_FILE_TEST_EXISTS
))
1230 SETPTR(editor_prefs
.color_scheme
, fname
);
1236 SETPTR(fname
, utils_get_utf8_from_locale(fname
));
1237 ui_set_statusbar(TRUE
, _("Could not find file '%s'."), fname
);
1244 static gchar
*utils_get_setting_locale_string(GKeyFile
*keyfile
,
1245 const gchar
*group
, const gchar
*key
, const gchar
*default_value
)
1247 gchar
*result
= g_key_file_get_locale_string(keyfile
, group
, key
, NULL
, NULL
);
1249 return FALLBACK(result
, g_strdup(default_value
));
1253 static void add_color_scheme_item(GtkListStore
*store
,
1254 gchar
*name
, gchar
*desc
, const gchar
*fn
, GtkTreeIter
*current_iter
)
1259 /* reuse parameters */
1260 name
= g_markup_escape_text(name
, -1);
1261 desc
= g_markup_escape_text(desc
, -1);
1262 markup
= g_strdup_printf("<big><b>%s</b></big>\n%s", name
, desc
);
1266 gtk_list_store_append(store
, &iter
);
1267 gtk_list_store_set(store
, &iter
, SCHEME_MARKUP
, markup
,
1268 SCHEME_FILE
, fn
, -1);
1271 /* select the current iter if the the color scheme matches, or if it's the
1272 * default (fn == NULL), in case of bad config file. the default theme is
1273 * first anyway so if a later scheme matches it will override default */
1274 if ((! fn
|| utils_str_equal(fn
, editor_prefs
.color_scheme
)) && current_iter
)
1275 *current_iter
= iter
;
1279 static void add_color_scheme_file(GtkListStore
*store
, const gchar
*fname
, GtkTreeIter
*current_iter
)
1281 GKeyFile
*hkeyfile
, *skeyfile
;
1282 gchar
*path
, *theme_name
, *theme_desc
;
1283 gchar
*theme_fn
= utils_get_utf8_from_locale(fname
);
1285 path
= g_build_filename(app
->configdir
, GEANY_COLORSCHEMES_SUBDIR
, fname
, NULL
);
1286 hkeyfile
= utils_key_file_new(path
);
1287 SETPTR(path
, g_build_filename(app
->datadir
, GEANY_COLORSCHEMES_SUBDIR
, fname
, NULL
));
1288 skeyfile
= utils_key_file_new(path
);
1290 theme_name
= utils_get_setting(locale_string
, hkeyfile
, skeyfile
, "theme_info", "name", theme_fn
);
1291 theme_desc
= utils_get_setting(locale_string
, hkeyfile
, skeyfile
, "theme_info", "description", NULL
);
1292 add_color_scheme_item(store
, theme_name
, theme_desc
, theme_fn
, current_iter
);
1298 g_key_file_free(hkeyfile
);
1299 g_key_file_free(skeyfile
);
1303 static gboolean
add_color_scheme_items(GtkListStore
*store
, GtkTreeIter
*current_iter
)
1305 GSList
*list
, *node
;
1307 add_color_scheme_item(store
, _("Default"), _("Default"), NULL
, current_iter
);
1308 list
= utils_get_config_files(GEANY_COLORSCHEMES_SUBDIR
);
1310 foreach_slist(node
, list
)
1312 gchar
*fname
= node
->data
;
1314 if (g_str_has_suffix(fname
, ".conf"))
1315 add_color_scheme_file(store
, fname
, current_iter
);
1320 return list
!= NULL
;
1324 static void on_color_scheme_dialog_response(GtkWidget
*dialog
,
1325 gint response
, gpointer
*dialog_ptr
)
1328 gtk_widget_destroy(dialog
);
1332 void highlighting_show_color_scheme_dialog(void)
1334 static GtkWidget
*dialog
= NULL
;
1335 GtkListStore
*store
= gtk_list_store_new(SCHEME_COLUMNS
,
1336 G_TYPE_STRING
, G_TYPE_STRING
);
1337 GtkCellRenderer
*text_renderer
;
1338 GtkTreeViewColumn
*column
;
1339 GtkTreeSelection
*treesel
;
1340 GtkTreeIter current_iter
;
1342 GtkWidget
*vbox
, *swin
, *tree
;
1345 doc
= document_get_current();
1346 if (doc
&& doc
->file_type
->priv
->warn_color_scheme
)
1347 dialogs_show_msgbox_with_secondary(GTK_MESSAGE_WARNING
,
1348 _("The current filetype overrides the default style."),
1349 _("This may cause color schemes to display incorrectly."));
1351 tree
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
1352 g_object_unref(store
);
1353 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree
), TRUE
);
1354 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree
), FALSE
);
1356 text_renderer
= gtk_cell_renderer_text_new();
1357 g_object_set(text_renderer
, "wrap-mode", PANGO_WRAP_WORD
, NULL
);
1358 column
= gtk_tree_view_column_new_with_attributes(
1359 NULL
, text_renderer
, "markup", SCHEME_MARKUP
, NULL
);
1360 gtk_tree_view_append_column(GTK_TREE_VIEW(tree
), column
);
1362 add_color_scheme_items(store
, ¤t_iter
);
1364 treesel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(tree
));
1365 gtk_tree_selection_select_iter(treesel
, ¤t_iter
);
1366 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(store
), ¤t_iter
);
1367 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tree
), path
, NULL
, FALSE
, 0, 0);
1368 gtk_tree_path_free(path
);
1369 g_signal_connect(treesel
, "changed", G_CALLBACK(on_color_scheme_changed
), NULL
);
1371 /* old dialog may still be showing */
1373 gtk_widget_destroy(dialog
);
1374 dialog
= gtk_dialog_new_with_buttons(_("Color Schemes"),
1375 GTK_WINDOW(main_widgets
.window
), GTK_DIALOG_DESTROY_WITH_PARENT
,
1376 GTK_STOCK_CLOSE
, GTK_RESPONSE_CLOSE
, NULL
);
1377 vbox
= ui_dialog_vbox_new(GTK_DIALOG(dialog
));
1378 gtk_box_set_spacing(GTK_BOX(vbox
), 6);
1379 gtk_widget_set_name(dialog
, "GeanyDialog");
1380 gtk_window_set_default_size(GTK_WINDOW(dialog
),
1381 GEANY_DEFAULT_DIALOG_HEIGHT
* 7/4, GEANY_DEFAULT_DIALOG_HEIGHT
);
1383 swin
= gtk_scrolled_window_new(NULL
, NULL
);
1384 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swin
), GTK_SHADOW_IN
);
1385 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin
),
1386 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1387 gtk_container_add(GTK_CONTAINER(swin
), tree
);
1388 gtk_box_pack_start(GTK_BOX(vbox
), swin
, TRUE
, TRUE
, 0);
1389 g_signal_connect(dialog
, "response", G_CALLBACK(on_color_scheme_dialog_response
), &dialog
);
1390 gtk_widget_show_all(dialog
);
1394 /** Checks whether the given style is a string for the given lexer.
1396 * @param lexer Scintilla lexer type (@c SCLEX_*).
1397 * @param style Scintilla style (@c SCE_*).
1399 * @return @c TRUE if the style is a string, @c FALSE otherwise.
1402 gboolean
highlighting_is_string_style(gint lexer
, gint style
)
1404 /* Don't forget STRINGEOL, to prevent completion whilst typing a string with no closing char. */
1409 return (style
== SCE_C_CHARACTER
||
1410 style
== SCE_C_STRING
||
1411 style
== SCE_C_STRINGEOL
||
1412 style
== SCE_C_STRINGRAW
||
1413 style
== SCE_C_VERBATIM
||
1414 style
== SCE_C_USERLITERAL
||
1415 style
== SCE_C_TRIPLEVERBATIM
||
1416 style
== SCE_C_REGEX
||
1417 style
== SCE_C_HASHQUOTEDSTRING
||
1418 style
== SCE_C_ESCAPESEQUENCE
);
1421 return (style
== SCE_PAS_CHARACTER
||
1422 style
== SCE_PAS_STRING
||
1423 style
== SCE_PAS_STRINGEOL
);
1426 return (style
== SCE_D_STRING
||
1427 style
== SCE_D_STRINGEOL
||
1428 style
== SCE_D_CHARACTER
||
1429 style
== SCE_D_STRINGB
||
1430 style
== SCE_D_STRINGR
);
1433 return (style
== SCE_P_STRING
||
1434 style
== SCE_P_TRIPLE
||
1435 style
== SCE_P_TRIPLEDOUBLE
||
1436 style
== SCE_P_CHARACTER
||
1437 style
== SCE_P_FSTRING
||
1438 style
== SCE_P_FCHARACTER
||
1439 style
== SCE_P_FTRIPLE
||
1440 style
== SCE_P_FTRIPLEDOUBLE
||
1441 style
== SCE_P_STRINGEOL
);
1443 case SCLEX_GDSCRIPT
:
1444 return (style
== SCE_GD_STRING
||
1445 style
== SCE_GD_TRIPLE
||
1446 style
== SCE_GD_TRIPLEDOUBLE
||
1447 style
== SCE_GD_CHARACTER
||
1448 style
== SCE_GD_STRINGEOL
);
1452 return (style
== SCE_F_STRING1
||
1453 style
== SCE_F_STRING2
||
1454 style
== SCE_F_STRINGEOL
);
1457 return (style
== SCE_PL_STRING
||
1458 style
== SCE_PL_CHARACTER
||
1459 style
== SCE_PL_HERE_DELIM
||
1460 style
== SCE_PL_HERE_Q
||
1461 style
== SCE_PL_HERE_QQ
||
1462 style
== SCE_PL_HERE_QX
||
1463 style
== SCE_PL_POD
||
1464 style
== SCE_PL_STRING_Q
||
1465 style
== SCE_PL_STRING_QQ
||
1466 style
== SCE_PL_STRING_QX
||
1467 style
== SCE_PL_STRING_QR
||
1468 style
== SCE_PL_STRING_QW
||
1469 style
== SCE_PL_POD_VERB
||
1470 style
== SCE_PL_REGEX
||
1471 style
== SCE_PL_REGEX_VAR
||
1472 style
== SCE_PL_XLAT
1473 /* we don't include any STRING_*_VAR for autocompletion */);
1476 return (style
== SCE_PO_MSGCTXT_TEXT
||
1477 style
== SCE_PO_MSGCTXT_TEXT_EOL
||
1478 style
== SCE_PO_MSGID_TEXT
||
1479 style
== SCE_PO_MSGID_TEXT_EOL
||
1480 style
== SCE_PO_MSGSTR_TEXT
||
1481 style
== SCE_PO_MSGSTR_TEXT_EOL
);
1484 return (style
== SCE_R_STRING
);
1487 return (style
== SCE_RB_CHARACTER
||
1488 style
== SCE_RB_STRING
||
1489 style
== SCE_RB_HERE_DELIM
||
1490 style
== SCE_RB_HERE_Q
||
1491 style
== SCE_RB_HERE_QQ
||
1492 style
== SCE_RB_HERE_QX
||
1493 style
== SCE_RB_REGEX
||
1494 style
== SCE_RB_STRING_Q
||
1495 style
== SCE_RB_STRING_QQ
||
1496 style
== SCE_RB_STRING_QX
||
1497 style
== SCE_RB_STRING_QR
||
1498 style
== SCE_RB_STRING_QW
||
1499 style
== SCE_RB_POD
);
1502 return (style
== SCE_SH_STRING
);
1505 return (style
== SCE_SQL_STRING
);
1508 return (style
== SCE_TCL_IN_QUOTE
);
1511 return (style
== SCE_LUA_LITERALSTRING
||
1512 style
== SCE_LUA_CHARACTER
||
1513 style
== SCE_LUA_STRINGEOL
||
1514 style
== SCE_LUA_STRING
);
1517 case SCLEX_LITERATEHASKELL
:
1518 return (style
== SCE_HA_CHARACTER
||
1519 style
== SCE_HA_STRINGEOL
||
1520 style
== SCE_HA_STRING
);
1522 case SCLEX_FREEBASIC
:
1523 return (style
== SCE_B_STRING
||
1524 style
== SCE_B_STRINGEOL
);
1527 return (style
== SCE_MATLAB_STRING
||
1528 style
== SCE_MATLAB_DOUBLEQUOTESTRING
);
1531 return (style
== SCE_JULIA_CHAR
||
1532 style
== SCE_JULIA_STRING
||
1533 style
== SCE_JULIA_DOCSTRING
||
1534 style
== SCE_JULIA_COMMAND
||
1535 style
== SCE_JULIA_STRINGINTERP
);
1539 case SCLEX_PHPSCRIPT
:
1541 style
== SCE_HBA_STRING
||
1542 style
== SCE_HBA_STRINGEOL
||
1543 style
== SCE_HB_STRING
||
1544 style
== SCE_HB_STRINGEOL
||
1545 style
== SCE_H_CDATA
||
1546 style
== SCE_H_DOUBLESTRING
||
1547 style
== SCE_HJA_DOUBLESTRING
||
1548 style
== SCE_HJA_SINGLESTRING
||
1549 style
== SCE_HJA_STRINGEOL
||
1550 style
== SCE_HJA_REGEX
||
1551 style
== SCE_HJ_DOUBLESTRING
||
1552 style
== SCE_HJ_SINGLESTRING
||
1553 style
== SCE_HJ_STRINGEOL
||
1554 style
== SCE_HJ_REGEX
||
1555 style
== SCE_HPA_CHARACTER
||
1556 style
== SCE_HPA_STRING
||
1557 style
== SCE_HPA_TRIPLE
||
1558 style
== SCE_HPA_TRIPLEDOUBLE
||
1559 style
== SCE_HP_CHARACTER
||
1560 style
== SCE_HPHP_HSTRING
|| /* HSTRING is a heredoc */
1561 style
== SCE_HPHP_HSTRING_VARIABLE
||
1562 style
== SCE_HPHP_SIMPLESTRING
||
1563 style
== SCE_HP_STRING
||
1564 style
== SCE_HP_TRIPLE
||
1565 style
== SCE_HP_TRIPLEDOUBLE
||
1566 style
== SCE_H_SGML_DOUBLESTRING
||
1567 style
== SCE_H_SGML_SIMPLESTRING
||
1568 style
== SCE_H_SINGLESTRING
);
1571 return (style
== SCE_CMAKE_STRINGDQ
||
1572 style
== SCE_CMAKE_STRINGLQ
||
1573 style
== SCE_CMAKE_STRINGRQ
||
1574 style
== SCE_CMAKE_STRINGVAR
);
1577 return (style
== SCE_NSIS_STRINGDQ
||
1578 style
== SCE_NSIS_STRINGLQ
||
1579 style
== SCE_NSIS_STRINGRQ
||
1580 style
== SCE_NSIS_STRINGVAR
);
1583 return (style
== SCE_ADA_CHARACTER
||
1584 style
== SCE_ADA_STRING
||
1585 style
== SCE_ADA_CHARACTEREOL
||
1586 style
== SCE_ADA_STRINGEOL
);
1589 return (style
== SCE_ABAQUS_STRING
);
1592 return (style
== SCE_RUST_CHARACTER
||
1593 style
== SCE_RUST_BYTECHARACTER
||
1594 style
== SCE_RUST_STRING
||
1595 style
== SCE_RUST_STRINGR
||
1596 style
== SCE_RUST_BYTESTRING
||
1597 style
== SCE_RUST_BYTESTRINGR
||
1598 style
== SCE_RUST_LEXERROR
);
1600 case SCLEX_COFFEESCRIPT
:
1601 return (style
== SCE_COFFEESCRIPT_CHARACTER
||
1602 style
== SCE_COFFEESCRIPT_STRING
||
1603 style
== SCE_COFFEESCRIPT_REGEX
||
1604 style
== SCE_COFFEESCRIPT_VERBOSE_REGEX
||
1605 style
== SCE_COFFEESCRIPT_STRINGEOL
);
1608 return (style
== SCE_V_STRING
);
1611 return (style
== SCE_VHDL_STRING
||
1612 style
== SCE_VHDL_STRINGEOL
);
1615 return (style
== SCE_CAML_CHAR
||
1616 style
== SCE_CAML_STRING
);
1619 return (style
== SCE_CSS_DOUBLESTRING
||
1620 style
== SCE_CSS_SINGLESTRING
);
1623 return (style
== SCE_ERLANG_STRING
||
1624 style
== SCE_ERLANG_CHARACTER
);
1627 return (style
== SCE_LISP_STRING
||
1628 style
== SCE_LISP_STRINGEOL
);
1631 return (style
== SCE_FORTH_STRING
);
1633 case SCLEX_POWERSHELL
:
1634 return (style
== SCE_POWERSHELL_STRING
||
1635 style
== SCE_POWERSHELL_CHARACTER
);
1640 case SCLEX_MAKEFILE
:
1641 case SCLEX_MARKDOWN
:
1642 case SCLEX_PROPERTIES
:
1643 case SCLEX_TXT2TAGS
:
1645 /* there is no string type in those lexers, listing here just for completeness */
1649 return (style
== SCE_AU3_STRING
);
1655 /** Checks whether the given style is a comment for the given lexer.
1657 * @param lexer Scintilla lexer type (@c SCLEX_*).
1658 * @param style Scintilla style (@c SCE_*).
1660 * @return @c TRUE if the style is a comment, @c FALSE otherwise.
1663 gboolean
highlighting_is_comment_style(gint lexer
, gint style
)
1669 return (style
== SCE_C_COMMENT
||
1670 style
== SCE_C_COMMENTLINE
||
1671 style
== SCE_C_COMMENTDOC
||
1672 style
== SCE_C_PREPROCESSORCOMMENT
||
1673 style
== SCE_C_PREPROCESSORCOMMENTDOC
||
1674 style
== SCE_C_COMMENTLINEDOC
||
1675 style
== SCE_C_COMMENTDOCKEYWORD
||
1676 style
== SCE_C_COMMENTDOCKEYWORDERROR
||
1677 style
== SCE_C_TASKMARKER
);
1680 return (style
== SCE_PAS_COMMENT
||
1681 style
== SCE_PAS_COMMENT2
||
1682 style
== SCE_PAS_COMMENTLINE
);
1685 return (style
== SCE_D_COMMENT
||
1686 style
== SCE_D_COMMENTLINE
||
1687 style
== SCE_D_COMMENTDOC
||
1688 style
== SCE_D_COMMENTNESTED
||
1689 style
== SCE_D_COMMENTLINEDOC
||
1690 style
== SCE_D_COMMENTDOCKEYWORD
||
1691 style
== SCE_D_COMMENTDOCKEYWORDERROR
);
1694 return (style
== SCE_P_COMMENTLINE
||
1695 style
== SCE_P_COMMENTBLOCK
);
1699 return (style
== SCE_F_COMMENT
);
1702 return (style
== SCE_PL_COMMENTLINE
);
1704 case SCLEX_PROPERTIES
:
1705 return (style
== SCE_PROPS_COMMENT
);
1708 return (style
== SCE_PO_COMMENT
||
1709 style
== SCE_PO_PROGRAMMER_COMMENT
);
1712 return (style
== SCE_L_COMMENT
||
1713 style
== SCE_L_COMMENT2
);
1715 case SCLEX_MAKEFILE
:
1716 return (style
== SCE_MAKE_COMMENT
);
1719 return (style
== SCE_RB_COMMENTLINE
);
1722 return (style
== SCE_SH_COMMENTLINE
);
1725 return (style
== SCE_R_COMMENT
);
1728 return (style
== SCE_SQL_COMMENT
||
1729 style
== SCE_SQL_COMMENTLINE
||
1730 style
== SCE_SQL_COMMENTDOC
||
1731 style
== SCE_SQL_COMMENTLINEDOC
||
1732 style
== SCE_SQL_COMMENTDOCKEYWORD
||
1733 style
== SCE_SQL_COMMENTDOCKEYWORDERROR
);
1736 return (style
== SCE_TCL_COMMENT
||
1737 style
== SCE_TCL_COMMENTLINE
||
1738 style
== SCE_TCL_COMMENT_BOX
||
1739 style
== SCE_TCL_BLOCK_COMMENT
);
1742 return (style
== SCE_MATLAB_COMMENT
);
1745 return (style
== SCE_JULIA_COMMENT
);
1748 return (style
== SCE_LUA_COMMENT
||
1749 style
== SCE_LUA_COMMENTLINE
||
1750 style
== SCE_LUA_COMMENTDOC
);
1753 case SCLEX_LITERATEHASKELL
:
1754 return (style
== SCE_HA_COMMENTLINE
||
1755 style
== SCE_HA_COMMENTBLOCK
||
1756 style
== SCE_HA_COMMENTBLOCK2
||
1757 style
== SCE_HA_COMMENTBLOCK3
||
1758 style
== SCE_HA_LITERATE_COMMENT
||
1759 style
== SCE_HA_LITERATE_CODEDELIM
);
1761 case SCLEX_FREEBASIC
:
1762 return (style
== SCE_B_COMMENT
||
1763 style
== SCE_B_COMMENTBLOCK
||
1764 style
== SCE_B_DOCLINE
||
1765 style
== SCE_B_DOCBLOCK
||
1766 style
== SCE_B_DOCKEYWORD
);
1769 return (style
== SCE_YAML_COMMENT
);
1773 case SCLEX_PHPSCRIPT
:
1775 style
== SCE_HBA_COMMENTLINE
||
1776 style
== SCE_HB_COMMENTLINE
||
1777 style
== SCE_H_COMMENT
||
1778 style
== SCE_HJA_COMMENT
||
1779 style
== SCE_HJA_COMMENTDOC
||
1780 style
== SCE_HJA_COMMENTLINE
||
1781 style
== SCE_HJ_COMMENT
||
1782 style
== SCE_HJ_COMMENTDOC
||
1783 style
== SCE_HJ_COMMENTLINE
||
1784 style
== SCE_HPA_COMMENTLINE
||
1785 style
== SCE_HP_COMMENTLINE
||
1786 style
== SCE_HPHP_COMMENT
||
1787 style
== SCE_HPHP_COMMENTLINE
||
1788 style
== SCE_H_SGML_COMMENT
);
1791 return (style
== SCE_CMAKE_COMMENT
);
1794 return (style
== SCE_NSIS_COMMENT
||
1795 style
== SCE_NSIS_COMMENTBOX
);
1798 return (style
== SCE_ADA_COMMENTLINE
);
1801 return (style
== SCE_ABAQUS_COMMENT
||
1802 style
== SCE_ABAQUS_COMMENTBLOCK
);
1805 return (style
== SCE_ASM_COMMENT
||
1806 style
== SCE_ASM_COMMENTBLOCK
||
1807 style
== SCE_ASM_COMMENTDIRECTIVE
);
1810 return (style
== SCE_RUST_COMMENTBLOCK
||
1811 style
== SCE_RUST_COMMENTLINE
||
1812 style
== SCE_RUST_COMMENTBLOCKDOC
||
1813 style
== SCE_RUST_COMMENTLINEDOC
);
1815 case SCLEX_COFFEESCRIPT
:
1816 return (style
== SCE_COFFEESCRIPT_COMMENTLINE
||
1817 style
== SCE_COFFEESCRIPT_COMMENTBLOCK
||
1818 style
== SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT
);
1821 return (style
== SCE_V_COMMENT
||
1822 style
== SCE_V_COMMENTLINE
||
1823 style
== SCE_V_COMMENTLINEBANG
||
1824 style
== SCE_V_COMMENT_WORD
);
1827 return (style
== SCE_VHDL_COMMENT
||
1828 style
== SCE_VHDL_COMMENTLINEBANG
||
1829 style
== SCE_VHDL_BLOCK_COMMENT
);
1832 return (style
== SCE_BAT_COMMENT
);
1835 return (style
== SCE_CAML_COMMENT
||
1836 style
== SCE_CAML_COMMENT1
||
1837 style
== SCE_CAML_COMMENT2
||
1838 style
== SCE_CAML_COMMENT3
);
1841 return (style
== SCE_ERLANG_COMMENT
||
1842 style
== SCE_ERLANG_COMMENT_FUNCTION
||
1843 style
== SCE_ERLANG_COMMENT_MODULE
||
1844 style
== SCE_ERLANG_COMMENT_DOC
||
1845 style
== SCE_ERLANG_COMMENT_DOC_MACRO
);
1848 return (style
== SCE_FORTH_COMMENT
||
1849 style
== SCE_FORTH_COMMENT_ML
);
1852 return (style
== SCE_CSS_COMMENT
);
1855 return (style
== SCE_DIFF_COMMENT
);
1858 return (style
== SCE_LISP_COMMENT
||
1859 style
== SCE_LISP_MULTI_COMMENT
);
1861 case SCLEX_POWERSHELL
:
1862 return (style
== SCE_POWERSHELL_COMMENT
||
1863 style
== SCE_POWERSHELL_COMMENTSTREAM
||
1864 style
== SCE_POWERSHELL_COMMENTDOCKEYWORD
);
1866 case SCLEX_TXT2TAGS
:
1867 return (style
== SCE_TXT2TAGS_COMMENT
);
1869 case SCLEX_MARKDOWN
:
1870 /* there is no comment type in those lexers, listing here just for completeness */
1873 case SCLEX_GDSCRIPT
:
1874 return (style
== SCE_GD_COMMENTLINE
||
1875 style
== SCE_GD_COMMENTBLOCK
);
1878 return (style
== SCE_AU3_COMMENT
||
1879 style
== SCE_AU3_COMMENTBLOCK
);
1885 /** Checks whether the given style is normal code (not string, comment, preprocessor, etc).
1887 * @param lexer Scintilla lexer type (@c SCLEX_*).
1888 * @param style Scintilla style (@c SCE_*).
1890 * @return @c TRUE if the style is code, @c FALSE otherwise.
1893 gboolean
highlighting_is_code_style(gint lexer
, gint style
)
1899 if (style
== SCE_C_PREPROCESSOR
)
1904 case SCLEX_LITERATEHASKELL
:
1906 if (style
== SCE_HA_PREPROCESSOR
)
1912 if (style
== SCE_V_PREPROCESSOR
)
1917 return !(highlighting_is_comment_style(lexer
, style
) ||
1918 highlighting_is_string_style(lexer
, style
));