1 /*
2 * speller.c - this file is part of Spellcheck, a Geany plugin
3 *
4 * Copyright 2008-2011 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5 * Copyright 2008-2010 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
6 *
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.
11 *
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.
16 *
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,
20 * MA 02110-1301, USA.
21 *
22 * $Id$
23 */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <geanyplugin.h>
30 #include <scintilla/SciLexer.h>
31
32 #include <string.h>
33 #include <ctype.h>
34 #include <enchant.h>
35
36 #include "speller.h"
37 #include "scplugin.h"
38
39
40
41 static EnchantBroker *sc_speller_broker = NULL;
42 static EnchantDict *sc_speller_dict = NULL;
43
44
45
dict_describe(const gchar * const lang,const gchar * const name,const gchar * const desc,const gchar * const file,void * target)46 static void dict_describe(const gchar* const lang, const gchar* const name,
47 const gchar* const desc, const gchar* const file, void *target)
48 {
49 gchar **result = (gchar**) target;
50 *result = g_strdup_printf("\"%s\" (%s)", lang, name);
51 }
52
53
is_word_sep(gunichar c)54 static gboolean is_word_sep(gunichar c)
55 {
56 return g_unichar_isspace(c) || g_unichar_ispunct(c);
57 }
58
59
60 /* Strip punctuation and white space, more or less Unicode-safe.
61 * The offset of the start of the word is stored in offset if non-NULL. */
strip_word(const gchar * word_to_check,gint * result_offset)62 static gchar *strip_word(const gchar *word_to_check, gint *result_offset)
63 {
64 gunichar c;
65 gchar *word = g_strdup(word_to_check);
66 gchar *word_start = word;
67 gchar *word_end;
68 gint offset = 0;
69 gint word_len;
70 gint new_word_len;
71
72 /* strip from the left */
73 do
74 {
75 c = g_utf8_get_char_validated(word, -1);
76 if (is_word_sep(c))
77 { /* skip this character */
78 word = g_utf8_next_char(word);
79 }
80 else
81 break;
82 } while (c != (gunichar) -1 && c != 0 && *word != '\0');
83 word_len = strlen(word_to_check);
84 offset = word - word_start;
85 new_word_len = word_len - offset;
86
87 if (new_word_len <= 0)
88 { /* empty or only punctuation in input string */
89 *result_offset = 0;
90 g_free(word_start);
91 return NULL;
92 }
93 /* move the string in-place and truncate it */
94 g_memmove(word_start, word, new_word_len);
95 word = word_start;
96 word[new_word_len] = '\0';
97 if (EMPTY(word))
98 {
99 g_free(word);
100 return NULL;
101 }
102 /* strip from the right */
103 word_end = word + strlen(word);
104 do
105 {
106 word_end = g_utf8_prev_char(word_end);
107 c = g_utf8_get_char_validated(word_end, -1);
108 if (is_word_sep(c))
109 { /* skip this character */
110 *word_end = '\0';
111 }
112 else
113 break;
114 } while (c != (gunichar) -1 && word_end >= word);
115
116 if (result_offset != NULL)
117 *result_offset = offset;
118
119 return word;
120 }
121
122
sc_speller_check_word(GeanyDocument * doc,gint line_number,const gchar * word,gint start_pos,gint end_pos)123 static gint sc_speller_check_word(GeanyDocument *doc, gint line_number, const gchar *word,
124 gint start_pos, gint end_pos)
125 {
126 gsize n_suggs = 0;
127 gchar *word_to_check;
128 gint offset;
129
130 g_return_val_if_fail(sc_speller_dict != NULL, 0);
131 g_return_val_if_fail(doc != NULL, 0);
132 g_return_val_if_fail(word != NULL, 0);
133 g_return_val_if_fail(start_pos >= 0 && end_pos >= 0, 0);
134
135 if (EMPTY(word))
136 return 0;
137
138 /* ignore numbers or words starting with digits */
139 if (isdigit(*word))
140 return 0;
141
142 /* ignore non-text */
143 if (! sc_speller_is_text(doc, start_pos))
144 return 0;
145
146 /* strip punctuation and white space */
147 word_to_check = strip_word(word, &offset);
148 if (EMPTY(word_to_check))
149 {
150 g_free(word_to_check);
151 return 0;
152 }
153
154 /* recalculate start_pos and end_pos */
155 start_pos += offset;
156 end_pos = start_pos + strlen(word_to_check);
157
158 /* early out if the word is spelled correctly */
159 if (enchant_dict_check(sc_speller_dict, word_to_check, -1) == 0)
160 {
161 g_free(word_to_check);
162 return 0;
163 }
164
165 editor_indicator_set_on_range(doc->editor, GEANY_INDICATOR_ERROR, start_pos, end_pos);
166
167 if (sc_info->use_msgwin && line_number != -1)
168 {
169 gsize j;
170 gchar **suggs;
171 GString *str;
172
173 str = g_string_sized_new(256);
174 suggs = enchant_dict_suggest(sc_speller_dict, word_to_check, -1, &n_suggs);
175 if (suggs != NULL)
176 {
177 g_string_append_printf(str, "line %d: %s | ", line_number + 1, word_to_check);
178
179 g_string_append(str, _("Try: "));
180
181 /* Now find the misspellings in the line, limit suggestions to a maximum of 15 (for now) */
182 for (j = 0; j < MIN(n_suggs, 15); j++)
183 {
184 g_string_append(str, suggs[j]);
185 g_string_append_c(str, ' ');
186 }
187
188 msgwin_msg_add(COLOR_RED, line_number + 1, doc, "%s", str->str);
189
190 if (suggs != NULL && n_suggs > 0)
191 enchant_dict_free_string_list(sc_speller_dict, suggs);
192 }
193 g_string_free(str, TRUE);
194 }
195
196 g_free(word_to_check);
197 return n_suggs;
198 }
199
200
sc_speller_process_line(GeanyDocument * doc,gint line_number)201 gint sc_speller_process_line(GeanyDocument *doc, gint line_number)
202 {
203 gint pos_start, pos_end;
204 gint wstart, wend;
205 gint suggestions_found = 0;
206 gint wordchars_len;
207 gchar *wordchars;
208 gchar *underscore_in_wordchars = NULL;
209 gboolean wordchars_modified = FALSE;
210
211 g_return_val_if_fail(sc_speller_dict != NULL, 0);
212 g_return_val_if_fail(doc != NULL, 0);
213
214 if (! DOC_VALID(doc))
215 return 0; /* current document has been closed */
216
217 /* add ' (single quote) temporarily to wordchars
218 * to be able to check for "doesn't", "isn't" and similar */
219 wordchars_len = scintilla_send_message(doc->editor->sci, SCI_GETWORDCHARS, 0, 0);
220 wordchars = g_malloc0(wordchars_len + 2); /* 2 = temporarily added "'" and "\0" */
221 scintilla_send_message(doc->editor->sci, SCI_GETWORDCHARS, 0, (sptr_t)wordchars);
222 if (! strchr(wordchars, '\''))
223 {
224 /* temporarily add "'" to the wordchars */
225 wordchars[wordchars_len] = '\'';
226 wordchars_modified = TRUE;
227 }
228 underscore_in_wordchars = strchr(wordchars, '_');
229 if (underscore_in_wordchars != NULL)
230 {
231 /* Temporarily remove underscore from the wordchars to treat
232 * it as a word seperator. Replace it by a "'" which we added already above. */
233 *underscore_in_wordchars = '\'';
234 wordchars_modified = TRUE;
235 }
236 if (wordchars_modified)
237 {
238 /* apply previously changed WORDCHARS setting */
239 scintilla_send_message(doc->editor->sci, SCI_SETWORDCHARS, 0, (sptr_t)wordchars);
240 }
241 pos_start = sci_get_position_from_line(doc->editor->sci, line_number);
242 pos_end = sci_get_position_from_line(doc->editor->sci, line_number + 1);
243
244 while (pos_start < pos_end)
245 {
246 gchar *word;
247
248 wstart = scintilla_send_message(doc->editor->sci, SCI_WORDSTARTPOSITION, pos_start, TRUE);
249 wend = scintilla_send_message(doc->editor->sci, SCI_WORDENDPOSITION, wstart, FALSE);
250 if (wstart == wend)
251 break;
252
253 word = sci_get_contents_range(doc->editor->sci, wstart, wend);
254
255 suggestions_found += sc_speller_check_word(doc, line_number, word, wstart, wend);
256
257 pos_start = wend + 1;
258
259 g_free(word);
260 }
261
262 if (wordchars_modified)
263 {
264 if (underscore_in_wordchars != NULL)
265 /* re-add underscore if we removed it above */
266 *underscore_in_wordchars = '_';
267 /* reset wordchars for the current document */
268 wordchars[wordchars_len] = '\0';
269 scintilla_send_message(doc->editor->sci, SCI_SETWORDCHARS, 0, (sptr_t)wordchars);
270 }
271 g_free(wordchars);
272 return suggestions_found;
273 }
274
275
sc_speller_check_document(GeanyDocument * doc)276 void sc_speller_check_document(GeanyDocument *doc)
277 {
278 gint i;
279 gint first_line, last_line;
280 gchar *dict_string = NULL;
281 gint suggestions_found = 0;
282
283 g_return_if_fail(sc_speller_dict != NULL);
284 g_return_if_fail(doc != NULL);
285
286 ui_progress_bar_start(_("Checking"));
287
288 enchant_dict_describe(sc_speller_dict, dict_describe, &dict_string);
289
290 if (sci_has_selection(doc->editor->sci))
291 {
292 first_line = sci_get_line_from_position(
293 doc->editor->sci, sci_get_selection_start(doc->editor->sci));
294 last_line = sci_get_line_from_position(
295 doc->editor->sci, sci_get_selection_end(doc->editor->sci));
296
297 if (sc_info->use_msgwin)
298 msgwin_msg_add(COLOR_BLUE, -1, NULL,
299 _("Checking file \"%s\" (lines %d to %d using %s):"),
300 DOC_FILENAME(doc), first_line + 1, last_line + 1, dict_string);
301 g_message("Checking file \"%s\" (lines %d to %d using %s):",
302 DOC_FILENAME(doc), first_line + 1, last_line + 1, dict_string);
303 }
304 else
305 {
306 first_line = 0;
307 last_line = sci_get_line_count(doc->editor->sci);
308 if (sc_info->use_msgwin)
309 msgwin_msg_add(COLOR_BLUE, -1, NULL, _("Checking file \"%s\" (using %s):"),
310 DOC_FILENAME(doc), dict_string);
311 g_message("Checking file \"%s\" (using %s):", DOC_FILENAME(doc), dict_string);
312 }
313 g_free(dict_string);
314
315 if (first_line == last_line)
316 {
317 suggestions_found += sc_speller_process_line(doc, first_line);
318 }
319 else
320 {
321 for (i = first_line; i < last_line; i++)
322 {
323 if (! DOC_VALID(doc))
324 { /* current document has been closed (might happen while checking large files) */
325 ui_progress_bar_stop();
326 return;
327 }
328 suggestions_found += sc_speller_process_line(doc, i);
329
330 /* process other GTK events to keep the GUI being responsive */
331 while (g_main_context_iteration(NULL, FALSE));
332 }
333 }
334 if (suggestions_found == 0 && sc_info->use_msgwin)
335 msgwin_msg_add(COLOR_BLUE, -1, NULL, _("The checked text is spelled correctly."));
336
337 ui_progress_bar_stop();
338 }
339
340
broker_init_failed(void)341 static void broker_init_failed(void)
342 {
343 const gchar *err = enchant_broker_get_error(sc_speller_broker);
344 gchar *msg = g_strdup_printf(
345 _("The Enchant library couldn't be initialized (%s)."),
346 (err != NULL) ? err : _("unknown error (maybe the chosen language is not available)"));
347
348 msgwin_status_add("%s", msg);
349 if (main_is_realized())
350 /* show dialog only after Geany has been loaded already, i.e. not while starting up */
351 dialogs_show_msgbox(GTK_MESSAGE_ERROR, "%s", msg);
352
353 g_free(msg);
354 }
355
356
dict_compare(gpointer data,gpointer user_data)357 static void dict_compare(gpointer data, gpointer user_data)
358 {
359 gboolean *supported = user_data;
360
361 if (utils_str_equal(sc_info->default_language, data))
362 *supported = TRUE;
363 }
364
365
check_default_lang(void)366 static gboolean check_default_lang(void)
367 {
368 gboolean supported = FALSE;
369
370 g_ptr_array_foreach(sc_info->dicts, dict_compare, &supported);
371
372 return supported;
373 }
374
375
sc_speller_get_default_lang(void)376 gchar *sc_speller_get_default_lang(void)
377 {
378 const gchar *lang = g_getenv("LANG");
379 gchar *result = NULL;
380
381 if (! EMPTY(lang))
382 {
383 if (*lang == 'C' || *lang == 'c')
384 lang = "en";
385 else
386 { /* if we have something like de_DE.UTF-8, strip everything from the period to the end */
387 gchar *period = strchr(lang, '.');
388 if (period != NULL)
389 result = g_strndup(lang, period - lang);
390 }
391 }
392 else
393 lang = "en";
394
395 return (result != NULL) ? result : g_strdup(lang);
396 }
397
398
add_dict_array(const gchar * const lang_tag,const gchar * const provider_name,const gchar * const provider_desc,const gchar * const provider_file,gpointer user_data)399 static void add_dict_array(const gchar* const lang_tag, const gchar* const provider_name,
400 const gchar* const provider_desc, const gchar* const provider_file,
401 gpointer user_data)
402 {
403 guint i;
404 gchar *result = g_strdup(lang_tag);
405
406 /* sometimes dictionaries are named lang-LOCALE instead of lang_LOCALE, so replace the
407 * hyphen by a dash, enchant seems to not care about it. */
408 for (i = 0; i < strlen(result); i++)
409 {
410 if (result[i] == '-')
411 result[i] = '_';
412 }
413
414 /* find duplicates and skip them */
415 for (i = 0; i < sc_info->dicts->len; i++)
416 {
417 if (utils_str_equal(g_ptr_array_index(sc_info->dicts, i), result))
418 {
419 g_free(result);
420 return;
421 }
422 }
423
424 g_ptr_array_add(sc_info->dicts, result);
425 }
426
427
sort_dicts(gconstpointer a,gconstpointer b)428 static gint sort_dicts(gconstpointer a, gconstpointer b)
429 { /* casting mania ;-) */
430 return strcmp((gchar*)((GPtrArray*)a)->pdata, (gchar*)((GPtrArray*)b)->pdata);
431 }
432
433
sc_speller_dicts_free(void)434 static void sc_speller_dicts_free(void)
435 {
436 guint i;
437 if (sc_info->dicts != NULL)
438 {
439 for (i = 0; i < sc_info->dicts->len; i++)
440 {
441 g_free(g_ptr_array_index(sc_info->dicts, i));
442 }
443 g_ptr_array_free(sc_info->dicts, TRUE);
444 }
445 }
446
447
create_dicts_array(void)448 static void create_dicts_array(void)
449 {
450 sc_speller_dicts_free();
451
452 sc_info->dicts = g_ptr_array_new();
453
454 enchant_broker_list_dicts(sc_speller_broker, add_dict_array, sc_info->dicts);
455
456 g_ptr_array_sort(sc_info->dicts, sort_dicts);
457 }
458
459
sc_speller_dict_free_string_list(gchar ** tmp_suggs)460 void sc_speller_dict_free_string_list(gchar **tmp_suggs)
461 {
462 g_return_if_fail(sc_speller_dict != NULL);
463
464 enchant_dict_free_string_list(sc_speller_dict, tmp_suggs);
465 }
466
467
sc_speller_add_word(const gchar * word)468 void sc_speller_add_word(const gchar *word)
469 {
470 g_return_if_fail(sc_speller_dict != NULL);
471 g_return_if_fail(word != NULL);
472
473 #ifdef HAVE_ENCHANT_1_5
474 /* enchant_dict_add() is available since Enchant 1.4 */
475 enchant_dict_add(sc_speller_dict, word, -1);
476 #else
477 enchant_dict_add_to_pwl(sc_speller_dict, word, -1);
478 #endif
479 }
480
sc_speller_dict_check(const gchar * word)481 gboolean sc_speller_dict_check(const gchar *word)
482 {
483 g_return_val_if_fail(sc_speller_dict != NULL, FALSE);
484 g_return_val_if_fail(word != NULL, FALSE);
485
486 return enchant_dict_check(sc_speller_dict, word, -1);
487 }
488
489
sc_speller_dict_suggest(const gchar * word,gsize * n_suggs)490 gchar **sc_speller_dict_suggest(const gchar *word, gsize *n_suggs)
491 {
492 g_return_val_if_fail(sc_speller_dict != NULL, NULL);
493 g_return_val_if_fail(word != NULL, NULL);
494
495 return enchant_dict_suggest(sc_speller_dict, word, -1, n_suggs);
496 }
497
498
sc_speller_add_word_to_session(const gchar * word)499 void sc_speller_add_word_to_session(const gchar *word)
500 {
501 g_return_if_fail(sc_speller_dict != NULL);
502 g_return_if_fail(word != NULL);
503
504 enchant_dict_add_to_session(sc_speller_dict, word, -1);
505 }
506
507
sc_speller_store_replacement(const gchar * old_word,const gchar * new_word)508 void sc_speller_store_replacement(const gchar *old_word, const gchar *new_word)
509 {
510 g_return_if_fail(sc_speller_dict != NULL);
511 g_return_if_fail(old_word != NULL);
512 g_return_if_fail(new_word != NULL);
513
514 enchant_dict_store_replacement(sc_speller_dict, old_word, -1, new_word, -1);
515 }
516
517
sc_speller_reinit_enchant_dict(void)518 void sc_speller_reinit_enchant_dict(void)
519 {
520 const gchar *lang = sc_info->default_language;
521
522 /* Release a previous dict object */
523 if (sc_speller_dict != NULL)
524 enchant_broker_free_dict(sc_speller_broker, sc_speller_dict);
525
526 #ifdef HAVE_ENCHANT_2_0
527 #define ENCHANT_CONFIG_ENV_NAME "ENCHANT_CONFIG_DIR"
528 /* set custom configuration path for enchant (Enchant will look for dictionaries there) */
529 if (! EMPTY(sc_info->dictionary_dir))
530 {
531 g_setenv(ENCHANT_CONFIG_ENV_NAME, sc_info->dictionary_dir, TRUE);
532 }
533 else
534 {
535 g_unsetenv(ENCHANT_CONFIG_ENV_NAME);
536 }
537 #elif HAVE_ENCHANT_1_5
538 {
539 const gchar *old_path;
540 gchar *new_path;
541
542 /* add custom dictionary path for myspell (primarily used on Windows) */
543 old_path = enchant_broker_get_param(sc_speller_broker, "enchant.myspell.dictionary.path");
544 if (old_path != NULL)
545 new_path = g_strconcat(
546 old_path, G_SEARCHPATH_SEPARATOR_S, sc_info->dictionary_dir, NULL);
547 else
548 new_path = sc_info->dictionary_dir;
549
550 enchant_broker_set_param(sc_speller_broker, "enchant.myspell.dictionary.path", new_path);
551 if (new_path != sc_info->dictionary_dir)
552 g_free(new_path);
553 }
554 #endif
555 create_dicts_array();
556
557 /* Check if the stored default dictionary is (still) available, fall back to the first
558 * one in the list if not */
559 if (EMPTY(lang) || ! check_default_lang())
560 {
561 if (sc_info->dicts->len > 0)
562 {
563 lang = g_ptr_array_index(sc_info->dicts, 0);
564 g_warning("Stored language ('%s') could not be loaded. Falling back to '%s'",
565 sc_info->default_language, lang);
566 }
567 else
568 g_warning("Stored language ('%s') could not be loaded.", sc_info->default_language);
569 }
570
571 /* Request new dict object */
572 if (! EMPTY(lang))
573 sc_speller_dict = enchant_broker_request_dict(sc_speller_broker, lang);
574 else
575 sc_speller_dict = NULL;
576 if (sc_speller_dict == NULL)
577 {
578 broker_init_failed();
579 gtk_widget_set_sensitive(sc_info->menu_item, FALSE);
580 }
581 else
582 {
583 gtk_widget_set_sensitive(sc_info->menu_item, TRUE);
584 }
585 }
586
587
log_enchant_version(void)588 static void log_enchant_version(void)
589 {
590 #ifdef HAVE_ENCHANT_2_0
591 const gchar *enchant_version = enchant_get_version();
592 #else
593 const gchar *enchant_version = "1.6 or older";
594 #endif
595
596 g_debug("Initializing Enchant library version %s", enchant_version);
597 }
598
599
sc_speller_init(void)600 void sc_speller_init(void)
601 {
602 log_enchant_version();
603 sc_speller_broker = enchant_broker_init();
604
605 sc_speller_reinit_enchant_dict();
606 }
607
608
sc_speller_free(void)609 void sc_speller_free(void)
610 {
611 sc_speller_dicts_free();
612 if (sc_speller_dict != NULL)
613 enchant_broker_free_dict(sc_speller_broker, sc_speller_dict);
614 enchant_broker_free(sc_speller_broker);
615 }
616
617
sc_speller_is_text(GeanyDocument * doc,gint pos)618 gboolean sc_speller_is_text(GeanyDocument *doc, gint pos)
619 {
620 gint lexer, style;
621
622 g_return_val_if_fail(doc != NULL, FALSE);
623 g_return_val_if_fail(pos >= 0, FALSE);
624
625 style = sci_get_style_at(doc->editor->sci, pos);
626 /* early out for the default style */
627 if (style == STYLE_DEFAULT)
628 return TRUE;
629
630 lexer = scintilla_send_message(doc->editor->sci, SCI_GETLEXER, 0, 0);
631 switch (lexer)
632 {
633 case SCLEX_ABAQUS:
634 {
635 switch (style)
636 {
637 case SCE_ABAQUS_DEFAULT:
638 case SCE_ABAQUS_COMMENT:
639 case SCE_ABAQUS_COMMENTBLOCK:
640 case SCE_ABAQUS_STRING:
641 return TRUE;
642 default:
643 return FALSE;
644 }
645 break;
646 }
647 case SCLEX_ADA:
648 {
649 switch (style)
650 {
651 case SCE_ADA_DEFAULT:
652 case SCE_ADA_COMMENTLINE:
653 case SCE_ADA_STRING:
654 case SCE_ADA_STRINGEOL:
655 case SCE_ADA_CHARACTER:
656 case SCE_ADA_CHARACTEREOL:
657 return TRUE;
658 default:
659 return FALSE;
660 }
661 break;
662 }
663 case SCLEX_ASM:
664 {
665 switch (style)
666 {
667 case SCE_ASM_DEFAULT:
668 case SCE_ASM_COMMENT:
669 case SCE_ASM_COMMENTBLOCK:
670 case SCE_ASM_STRING:
671 case SCE_ASM_STRINGEOL:
672 case SCE_ASM_CHARACTER:
673 return TRUE;
674 default:
675 return FALSE;
676 }
677 break;
678 }
679 case SCLEX_BASH:
680 {
681 switch (style)
682 {
683 case SCE_SH_DEFAULT:
684 case SCE_SH_COMMENTLINE:
685 case SCE_SH_STRING:
686 case SCE_SH_CHARACTER:
687 return TRUE;
688 default:
689 return FALSE;
690 }
691 break;
692 }
693 case SCLEX_BATCH:
694 {
695 switch (style)
696 {
697 case SCE_BAT_DEFAULT:
698 case SCE_BAT_COMMENT:
699 return TRUE;
700 default:
701 return FALSE;
702 }
703 break;
704 }
705 case SCLEX_CAML:
706 {
707 switch (style)
708 {
709 case SCE_CAML_DEFAULT:
710 case SCE_CAML_COMMENT:
711 case SCE_CAML_COMMENT1:
712 case SCE_CAML_COMMENT2:
713 case SCE_CAML_COMMENT3:
714 case SCE_CAML_STRING:
715 case SCE_CAML_CHAR:
716 return TRUE;
717 default:
718 return FALSE;
719 }
720 break;
721 }
722 case SCLEX_CMAKE:
723 {
724 switch (style)
725 {
726 case SCE_CMAKE_DEFAULT:
727 case SCE_CMAKE_COMMENT:
728 case SCE_CMAKE_STRINGDQ:
729 case SCE_CMAKE_STRINGLQ:
730 case SCE_CMAKE_STRINGRQ:
731 return TRUE;
732 default:
733 return FALSE;
734 }
735 break;
736 }
737 #ifdef SCE_PAS_DEFAULT
738 case SCLEX_PASCAL:
739 {
740 switch (style)
741 {
742 case SCE_PAS_DEFAULT:
743 case SCE_PAS_COMMENT:
744 case SCE_PAS_COMMENT2:
745 case SCE_PAS_COMMENTLINE:
746 case SCE_PAS_STRING:
747 case SCE_PAS_CHARACTER:
748 return TRUE;
749 default:
750 return FALSE;
751 }
752 break;
753 }
754 #else
755 case SCLEX_PASCAL:
756 #endif
757 case SCLEX_COBOL:
758 case SCLEX_CPP:
759 {
760 switch (style)
761 {
762 case SCE_C_DEFAULT:
763 case SCE_C_COMMENT:
764 case SCE_C_COMMENTLINE:
765 case SCE_C_COMMENTDOC:
766 case SCE_C_STRING:
767 case SCE_C_CHARACTER:
768 case SCE_C_STRINGEOL:
769 case SCE_C_COMMENTLINEDOC:
770 return TRUE;
771 default:
772 return FALSE;
773 }
774 break;
775 }
776 case SCLEX_COFFEESCRIPT:
777 {
778 switch (style)
779 {
780 case SCE_COFFEESCRIPT_CHARACTER:
781 case SCE_COFFEESCRIPT_COMMENTBLOCK:
782 case SCE_COFFEESCRIPT_COMMENTDOCKEYWORD:
783 case SCE_COFFEESCRIPT_COMMENTDOCKEYWORDERROR:
784 case SCE_COFFEESCRIPT_COMMENTLINEDOC:
785 case SCE_COFFEESCRIPT_STRING:
786 case SCE_COFFEESCRIPT_STRINGEOL:
787 case SCE_COFFEESCRIPT_STRINGRAW:
788 return TRUE;
789 default:
790 return FALSE;
791 }
792 break;
793 }
794 case SCLEX_CSS:
795 {
796 switch (style)
797 {
798 case SCE_CSS_DEFAULT:
799 case SCE_CSS_COMMENT:
800 return TRUE;
801 default:
802 return FALSE;
803 }
804 break;
805 }
806 case SCLEX_D:
807 {
808 switch (style)
809 {
810 case SCE_D_DEFAULT:
811 case SCE_D_COMMENT:
812 case SCE_D_COMMENTLINE:
813 case SCE_D_COMMENTDOC:
814 case SCE_D_COMMENTNESTED:
815 case SCE_D_STRING:
816 case SCE_D_STRINGEOL:
817 case SCE_D_CHARACTER:
818 case SCE_D_COMMENTLINEDOC:
819 return TRUE;
820 default:
821 return FALSE;
822 }
823 break;
824 }
825 case SCLEX_DIFF:
826 {
827 switch (style)
828 {
829 case SCE_DIFF_DEFAULT:
830 case SCE_DIFF_COMMENT:
831 case SCE_DIFF_HEADER:
832 return TRUE;
833 default:
834 return FALSE;
835 }
836 break;
837 }
838 case SCLEX_ERLANG:
839 {
840 switch (style)
841 {
842 case SCE_ERLANG_DEFAULT:
843 case SCE_ERLANG_COMMENT:
844 case SCE_ERLANG_STRING:
845 case SCE_ERLANG_CHARACTER:
846 case SCE_ERLANG_COMMENT_FUNCTION:
847 case SCE_ERLANG_COMMENT_MODULE:
848 case SCE_ERLANG_COMMENT_DOC:
849 case SCE_ERLANG_COMMENT_DOC_MACRO:
850 return TRUE;
851 default:
852 return FALSE;
853 }
854 break;
855 }
856 case SCLEX_F77:
857 case SCLEX_FORTRAN:
858 {
859 switch (style)
860 {
861 case SCE_F_DEFAULT:
862 case SCE_F_COMMENT:
863 case SCE_F_STRING1:
864 case SCE_F_STRING2:
865 case SCE_F_STRINGEOL:
866 return TRUE;
867 default:
868 return FALSE;
869 }
870 break;
871 }
872 case SCLEX_FORTH:
873 {
874 switch (style)
875 {
876 case SCE_FORTH_DEFAULT:
877 case SCE_FORTH_COMMENT:
878 case SCE_FORTH_COMMENT_ML:
879 case SCE_FORTH_STRING:
880 case SCE_FORTH_LOCALE:
881 return TRUE;
882 default:
883 return FALSE;
884 }
885 break;
886 }
887 case SCLEX_FREEBASIC:
888 {
889 switch (style)
890 {
891 case SCE_B_DEFAULT:
892 case SCE_B_COMMENT:
893 case SCE_B_STRING:
894 case SCE_B_STRINGEOL:
895 case SCE_B_CONSTANT:
896 return TRUE;
897 default:
898 return FALSE;
899 }
900 break;
901 }
902 case SCLEX_HASKELL:
903 {
904 switch (style)
905 {
906 case SCE_HA_DEFAULT:
907 case SCE_HA_COMMENTLINE:
908 case SCE_HA_COMMENTBLOCK:
909 case SCE_HA_COMMENTBLOCK2:
910 case SCE_HA_COMMENTBLOCK3:
911 case SCE_HA_STRING:
912 case SCE_HA_CHARACTER:
913 case SCE_HA_DATA:
914 return TRUE;
915 default:
916 return FALSE;
917 }
918 break;
919 }
920 case SCLEX_HTML:
921 case SCLEX_PHPSCRIPT:
922 case SCLEX_XML:
923 {
924 switch (style)
925 {
926 case SCE_H_DEFAULT:
927 case SCE_H_TAGUNKNOWN:
928 case SCE_H_ATTRIBUTEUNKNOWN:
929 case SCE_H_DOUBLESTRING:
930 case SCE_H_SINGLESTRING:
931 case SCE_H_COMMENT:
932 case SCE_H_CDATA:
933 case SCE_H_VALUE: /* really? */
934 case SCE_H_SGML_DEFAULT:
935 case SCE_H_SGML_COMMENT:
936 case SCE_H_SGML_DOUBLESTRING:
937 case SCE_H_SGML_SIMPLESTRING:
938 case SCE_H_SGML_1ST_PARAM_COMMENT:
939 case SCE_HJ_COMMENT:
940 case SCE_HJ_COMMENTLINE:
941 case SCE_HJ_COMMENTDOC:
942 case SCE_HJ_DOUBLESTRING:
943 case SCE_HJ_SINGLESTRING:
944 case SCE_HJ_STRINGEOL:
945 case SCE_HB_COMMENTLINE:
946 case SCE_HB_STRING:
947 case SCE_HB_STRINGEOL:
948 case SCE_HBA_COMMENTLINE:
949 case SCE_HBA_STRING:
950 case SCE_HBA_STRINGEOL:
951 case SCE_HJA_COMMENT:
952 case SCE_HJA_COMMENTLINE:
953 case SCE_HJA_COMMENTDOC:
954 case SCE_HJA_DOUBLESTRING:
955 case SCE_HJA_SINGLESTRING:
956 case SCE_HJA_STRINGEOL:
957 case SCE_HP_COMMENTLINE:
958 case SCE_HP_STRING:
959 case SCE_HP_CHARACTER:
960 case SCE_HP_TRIPLE:
961 case SCE_HP_TRIPLEDOUBLE:
962 case SCE_HPA_COMMENTLINE:
963 case SCE_HPA_STRING:
964 case SCE_HPA_CHARACTER:
965 case SCE_HPA_TRIPLE:
966 case SCE_HPA_TRIPLEDOUBLE:
967 case SCE_HPHP_SIMPLESTRING:
968 case SCE_HPHP_HSTRING:
969 case SCE_HPHP_COMMENT:
970 case SCE_HPHP_COMMENTLINE:
971 return TRUE;
972 default:
973 return FALSE;
974 }
975 break;
976 }
977 case SCLEX_LATEX:
978 {
979 switch (style)
980 {
981 case SCE_L_DEFAULT:
982 case SCE_L_COMMENT:
983 return TRUE;
984 default:
985 return FALSE;
986 }
987 break;
988 }
989 case SCLEX_LISP:
990 {
991 switch (style)
992 {
993 case SCE_LISP_DEFAULT:
994 case SCE_LISP_COMMENT:
995 case SCE_LISP_STRING:
996 case SCE_LISP_STRINGEOL:
997 case SCE_LISP_MULTI_COMMENT:
998 return TRUE;
999 default:
1000 return FALSE;
1001 }
1002 break;
1003 }
1004 case SCLEX_LUA:
1005 {
1006 switch (style)
1007 {
1008 case SCE_LUA_DEFAULT:
1009 case SCE_LUA_COMMENT:
1010 case SCE_LUA_COMMENTLINE:
1011 case SCE_LUA_COMMENTDOC:
1012 case SCE_LUA_STRING:
1013 case SCE_LUA_CHARACTER:
1014 case SCE_LUA_LITERALSTRING:
1015 case SCE_LUA_STRINGEOL:
1016 return TRUE;
1017 default:
1018 return FALSE;
1019 }
1020 break;
1021 }
1022 case SCLEX_MAKEFILE:
1023 {
1024 switch (style)
1025 {
1026 case SCE_MAKE_DEFAULT:
1027 case SCE_MAKE_COMMENT:
1028 return TRUE;
1029 default:
1030 return FALSE;
1031 }
1032 break;
1033 }
1034 case SCLEX_MARKDOWN:
1035 {
1036 return TRUE;
1037 break;
1038 }
1039 case SCLEX_MATLAB:
1040 case SCLEX_OCTAVE:
1041 {
1042 switch (style)
1043 {
1044 case SCE_MATLAB_DEFAULT:
1045 case SCE_MATLAB_COMMENT:
1046 case SCE_MATLAB_STRING:
1047 case SCE_MATLAB_DOUBLEQUOTESTRING:
1048 return TRUE;
1049 default:
1050 return FALSE;
1051 }
1052 break;
1053 }
1054 case SCLEX_NSIS:
1055 {
1056 switch (style)
1057 {
1058 case SCE_NSIS_DEFAULT:
1059 case SCE_NSIS_COMMENT:
1060 case SCE_NSIS_STRINGDQ:
1061 case SCE_NSIS_STRINGLQ:
1062 case SCE_NSIS_STRINGRQ:
1063 case SCE_NSIS_STRINGVAR:
1064 case SCE_NSIS_COMMENTBOX:
1065 return TRUE;
1066 default:
1067 return FALSE;
1068 }
1069 break;
1070 }
1071 case SCLEX_PERL:
1072 {
1073 switch (style)
1074 {
1075 case SCE_PL_DEFAULT:
1076 case SCE_PL_COMMENTLINE:
1077 case SCE_PL_STRING:
1078 case SCE_PL_CHARACTER:
1079 case SCE_PL_POD:
1080 case SCE_PL_POD_VERB:
1081 case SCE_PL_LONGQUOTE:
1082 /* do we want SCE_PL_STRING_* too? */
1083 return TRUE;
1084 default:
1085 return FALSE;
1086 }
1087 break;
1088 }
1089 case SCLEX_PO:
1090 {
1091 switch (style)
1092 {
1093 case SCE_PO_DEFAULT:
1094 case SCE_PO_COMMENT:
1095 case SCE_PO_MSGID_TEXT:
1096 case SCE_PO_MSGSTR_TEXT:
1097 case SCE_PO_MSGCTXT_TEXT:
1098 return TRUE;
1099 default:
1100 return FALSE;
1101 }
1102 break;
1103 }
1104 case SCLEX_POWERSHELL:
1105 {
1106 switch (style)
1107 {
1108 case SCE_POWERSHELL_DEFAULT:
1109 case SCE_POWERSHELL_COMMENT:
1110 case SCE_POWERSHELL_STRING:
1111 case SCE_POWERSHELL_COMMENTSTREAM:
1112 case SCE_POWERSHELL_COMMENTDOCKEYWORD:
1113 return TRUE;
1114 default:
1115 return FALSE;
1116 }
1117 break;
1118 }
1119 case SCLEX_PROPERTIES:
1120 {
1121 switch (style)
1122 {
1123 case SCE_PROPS_DEFAULT:
1124 case SCE_PROPS_COMMENT:
1125 return TRUE;
1126 default:
1127 return FALSE;
1128 }
1129 break;
1130 }
1131 case SCLEX_PYTHON:
1132 {
1133 switch (style)
1134 {
1135 case SCE_P_DEFAULT:
1136 case SCE_P_COMMENTLINE:
1137 case SCE_P_STRING:
1138 case SCE_P_CHARACTER:
1139 case SCE_P_TRIPLE:
1140 case SCE_P_TRIPLEDOUBLE:
1141 case SCE_P_COMMENTBLOCK:
1142 case SCE_P_STRINGEOL:
1143 return TRUE;
1144 default:
1145 return FALSE;
1146 }
1147 break;
1148 }
1149 case SCLEX_R:
1150 {
1151 switch (style)
1152 {
1153 case SCE_R_DEFAULT:
1154 case SCE_R_COMMENT:
1155 case SCE_R_STRING:
1156 case SCE_R_STRING2:
1157 return TRUE;
1158 default:
1159 return FALSE;
1160 }
1161 break;
1162 }
1163 case SCLEX_RUBY:
1164 {
1165 switch (style)
1166 {
1167 case SCE_RB_DEFAULT:
1168 case SCE_RB_COMMENTLINE:
1169 case SCE_RB_STRING:
1170 case SCE_RB_CHARACTER:
1171 case SCE_RB_POD:
1172 return TRUE;
1173 default:
1174 return FALSE;
1175 }
1176 break;
1177 }
1178 case SCLEX_RUST:
1179 {
1180 switch (style)
1181 {
1182 case SCE_RUST_DEFAULT:
1183 case SCE_RUST_COMMENTBLOCK:
1184 case SCE_RUST_COMMENTBLOCKDOC:
1185 case SCE_RUST_COMMENTLINE:
1186 case SCE_RUST_COMMENTLINEDOC:
1187 case SCE_RUST_STRING:
1188 case SCE_RUST_STRINGR:
1189 case SCE_RUST_BYTESTRING:
1190 case SCE_RUST_BYTESTRINGR:
1191 case SCE_RUST_LEXERROR:
1192 return TRUE;
1193 default:
1194 return FALSE;
1195 }
1196 break;
1197 }
1198 case SCLEX_SQL:
1199 {
1200 switch (style)
1201 {
1202 case SCE_SQL_DEFAULT:
1203 case SCE_SQL_COMMENT:
1204 case SCE_SQL_COMMENTLINE:
1205 case SCE_SQL_COMMENTDOC:
1206 case SCE_SQL_STRING:
1207 case SCE_SQL_CHARACTER:
1208 case SCE_SQL_SQLPLUS_COMMENT:
1209 return TRUE;
1210 default:
1211 return FALSE;
1212 }
1213 break;
1214 }
1215 case SCLEX_TCL:
1216 {
1217 switch (style)
1218 {
1219 case SCE_TCL_DEFAULT:
1220 case SCE_TCL_COMMENT:
1221 case SCE_TCL_COMMENTLINE:
1222 case SCE_TCL_IN_QUOTE:
1223 return TRUE;
1224 default:
1225 return FALSE;
1226 }
1227 break;
1228 }
1229 case SCLEX_TXT2TAGS:
1230 {
1231 return TRUE;
1232 break;
1233 }
1234 case SCLEX_VERILOG:
1235 {
1236 switch (style)
1237 {
1238 case SCE_V_DEFAULT:
1239 case SCE_V_COMMENT:
1240 case SCE_V_COMMENTLINE:
1241 case SCE_V_COMMENTLINEBANG:
1242 case SCE_V_STRING:
1243 case SCE_V_STRINGEOL:
1244 return TRUE;
1245 default:
1246 return FALSE;
1247 }
1248 break;
1249 }
1250 case SCLEX_VHDL:
1251 {
1252 switch (style)
1253 {
1254 case SCE_VHDL_DEFAULT:
1255 case SCE_VHDL_COMMENT:
1256 case SCE_VHDL_COMMENTLINEBANG:
1257 case SCE_VHDL_STRING:
1258 case SCE_VHDL_STRINGEOL:
1259 return TRUE;
1260 default:
1261 return FALSE;
1262 }
1263 break;
1264 }
1265 case SCLEX_YAML:
1266 {
1267 switch (style)
1268 {
1269 case SCE_YAML_DEFAULT:
1270 case SCE_YAML_COMMENT:
1271 case SCE_YAML_TEXT:
1272 return TRUE;
1273 default:
1274 return FALSE;
1275 }
1276 break;
1277 }
1278 }
1279 /* if the current lexer was not handled, let's say the passed position contains
1280 * valid text to not ignore more than we want */
1281 return TRUE;
1282 }
1283