Mercurial > ~mikael > mcabber > hg
comparison mcabber/mcabber/screen.c @ 2170:282531385f34
Multilanguage spell checking
author | Dmitry Potapov <potapov.d@gmail.com> |
---|---|
date | Sun, 15 Feb 2015 16:23:30 +0100 |
parents | db6ca1e1e082 |
children | 46d1182d45be |
comparison
equal
deleted
inserted
replaced
2169:4889f429fdd0 | 2170:282531385f34 |
---|---|
184 inline void scr_update_buddy_window(void); | 184 inline void scr_update_buddy_window(void); |
185 inline void scr_set_chatmode(int enable); | 185 inline void scr_set_chatmode(int enable); |
186 | 186 |
187 #define SPELLBADCHAR 5 | 187 #define SPELLBADCHAR 5 |
188 | 188 |
189 #if defined(WITH_ENCHANT) || defined(WITH_ASPELL) | |
190 typedef struct { | |
189 #ifdef WITH_ENCHANT | 191 #ifdef WITH_ENCHANT |
190 EnchantBroker *spell_broker; | 192 EnchantBroker *broker; |
191 EnchantDict *spell_checker; | 193 EnchantDict *checker; |
192 #endif | 194 #endif |
193 | |
194 #ifdef WITH_ASPELL | 195 #ifdef WITH_ASPELL |
195 AspellConfig *spell_config; | 196 AspellConfig *config; |
196 AspellSpeller *spell_checker; | 197 AspellSpeller *checker; |
198 #endif | |
199 } spell_checker; | |
200 | |
201 GSList* spell_checkers = NULL; | |
197 #endif | 202 #endif |
198 | 203 |
199 typedef struct { | 204 typedef struct { |
200 int color_pair; | 205 int color_pair; |
201 int color_attrib; | 206 int color_attrib; |
4478 } | 4483 } |
4479 return; | 4484 return; |
4480 } | 4485 } |
4481 | 4486 |
4482 #if defined(WITH_ENCHANT) || defined(WITH_ASPELL) | 4487 #if defined(WITH_ENCHANT) || defined(WITH_ASPELL) |
4483 // initialization | 4488 static void spell_checker_free(gpointer data) |
4484 void spellcheck_init(void) | 4489 { |
4485 { | 4490 spell_checker* sc = data; |
4486 int spell_enable = settings_opt_get_int("spell_enable"); | 4491 #ifdef WITH_ENCHANT |
4487 const char *spell_lang = settings_opt_get("spell_lang"); | 4492 enchant_broker_free_dict(sc->broker, sc->checker); |
4493 enchant_broker_free(sc->broker); | |
4494 #endif | |
4495 #ifdef WITH_ASPELL | |
4496 delete_aspell_speller(sc->checker); | |
4497 delete_aspell_config(sc->config); | |
4498 #endif | |
4499 g_free(sc); | |
4500 } | |
4501 | |
4502 static spell_checker* new_spell_checker(const char* spell_lang) | |
4503 { | |
4504 spell_checker* sc = g_new(spell_checker, 1); | |
4488 #ifdef WITH_ASPELL | 4505 #ifdef WITH_ASPELL |
4489 const char *spell_encoding = settings_opt_get("spell_encoding"); | 4506 const char *spell_encoding = settings_opt_get("spell_encoding"); |
4490 AspellCanHaveError *possible_err; | 4507 AspellCanHaveError *possible_err; |
4508 sc->config = new_aspell_config(); | |
4509 if (spell_encoding) | |
4510 aspell_config_replace(sc->config, "encoding", spell_encoding); | |
4511 aspell_config_replace(sc->config, "lang", spell_lang); | |
4512 possible_err = new_aspell_speller(sc->config); | |
4513 | |
4514 if (aspell_error_number(possible_err) != 0) { | |
4515 delete_aspell_config(sc->config); | |
4516 g_free(sc); | |
4517 sc = NULL; | |
4518 } else { | |
4519 sc->checker = to_aspell_speller(possible_err); | |
4520 } | |
4491 #endif | 4521 #endif |
4522 #ifdef WITH_ENCHANT | |
4523 sc->broker = enchant_broker_init(); | |
4524 sc->checker = enchant_broker_request_dict(sc->broker, spell_lang); | |
4525 if (!sc->checker) { | |
4526 enchant_broker_free(sc->broker); | |
4527 g_free(sc); | |
4528 sc = NULL; | |
4529 } | |
4530 #endif | |
4531 return sc; | |
4532 } | |
4533 | |
4534 // initialization | |
4535 void spellcheck_init(void) | |
4536 { | |
4537 int spell_enable = settings_opt_get_int("spell_enable"); | |
4538 const char *spell_lang = settings_opt_get("spell_lang"); | |
4539 gchar** langs; | |
4540 gchar** lang_iter; | |
4541 spell_checker* sc; | |
4492 | 4542 |
4493 if (!spell_enable) | 4543 if (!spell_enable) |
4494 return; | 4544 return; |
4495 | 4545 |
4496 #ifdef WITH_ENCHANT | 4546 spellcheck_deinit(); |
4497 if (spell_checker) { | |
4498 enchant_broker_free_dict(spell_broker, spell_checker); | |
4499 enchant_broker_free(spell_broker); | |
4500 spell_checker = NULL; | |
4501 spell_broker = NULL; | |
4502 } | |
4503 #endif | |
4504 #ifdef WITH_ASPELL | |
4505 if (spell_checker) { | |
4506 delete_aspell_speller(spell_checker); | |
4507 delete_aspell_config(spell_config); | |
4508 spell_checker = NULL; | |
4509 spell_config = NULL; | |
4510 } | |
4511 #endif | |
4512 | 4547 |
4513 if (!spell_lang) { // Cannot initialize: language not specified | 4548 if (!spell_lang) { // Cannot initialize: language not specified |
4514 scr_LogPrint(LPRINT_LOGNORM, "Error: Cannot initialize spell checker, language not specified."); | 4549 scr_LogPrint(LPRINT_LOGNORM, "Error: Cannot initialize spell checker, language not specified."); |
4515 scr_LogPrint(LPRINT_LOGNORM, "Please set the 'spell_lang' variable."); | 4550 scr_LogPrint(LPRINT_LOGNORM, "Please set the 'spell_lang' variable."); |
4516 return; | 4551 return; |
4517 } | 4552 } |
4518 | 4553 |
4519 #ifdef WITH_ENCHANT | 4554 langs = g_strsplit(spell_lang, " ", -1); |
4520 spell_broker = enchant_broker_init(); | 4555 for (lang_iter = langs; *lang_iter; ++lang_iter) { |
4521 spell_checker = enchant_broker_request_dict(spell_broker, spell_lang); | 4556 if (**lang_iter) { // Skip empty strings |
4522 #endif | 4557 sc = new_spell_checker(*lang_iter); |
4523 | 4558 if (sc) { |
4524 #ifdef WITH_ASPELL | 4559 spell_checkers = g_slist_append(spell_checkers, sc); |
4525 spell_config = new_aspell_config(); | 4560 } |
4526 if (spell_encoding) | 4561 } |
4527 aspell_config_replace(spell_config, "encoding", spell_encoding); | 4562 } |
4528 aspell_config_replace(spell_config, "lang", spell_lang); | 4563 g_strfreev(langs); |
4529 possible_err = new_aspell_speller(spell_config); | |
4530 | |
4531 if (aspell_error_number(possible_err) != 0) { | |
4532 spell_checker = NULL; | |
4533 delete_aspell_config(spell_config); | |
4534 spell_config = NULL; | |
4535 } else { | |
4536 spell_checker = to_aspell_speller(possible_err); | |
4537 } | |
4538 #endif | |
4539 } | 4564 } |
4540 | 4565 |
4541 // Deinitialization of spellchecker | 4566 // Deinitialization of spellchecker |
4542 void spellcheck_deinit(void) | 4567 void spellcheck_deinit(void) |
4543 { | 4568 { |
4544 if (spell_checker) { | 4569 g_slist_free_full(spell_checkers, spell_checker_free); |
4570 spell_checkers = NULL; | |
4571 } | |
4572 | |
4573 typedef struct { | |
4574 const char* str; | |
4575 int len; | |
4576 } spell_substring; | |
4577 | |
4578 static int spellcheckword(gconstpointer sc_ptr, gconstpointer substr_ptr) | |
4579 { | |
4580 spell_checker* sc = (spell_checker*) sc_ptr; | |
4581 spell_substring* substr = (spell_substring*) substr_ptr; | |
4545 #ifdef WITH_ENCHANT | 4582 #ifdef WITH_ENCHANT |
4546 enchant_broker_free_dict(spell_broker, spell_checker); | 4583 // enchant_dict_check will return 0 on good word |
4584 return enchant_dict_check(sc->checker, substr->str, substr->len); | |
4547 #endif | 4585 #endif |
4548 #ifdef WITH_ASPELL | 4586 #ifdef WITH_ASPELL |
4549 delete_aspell_speller(spell_checker); | 4587 // aspell_speller_check will return 1 on good word, so we need to make it 0 |
4588 return aspell_speller_check(sc->checker, substr->str, substr->len) - 1; | |
4550 #endif | 4589 #endif |
4551 spell_checker = NULL; | 4590 return 0; // Keep compiler happy |
4552 } | |
4553 | |
4554 #ifdef WITH_ENCHANT | |
4555 if (spell_broker) { | |
4556 enchant_broker_free(spell_broker); | |
4557 spell_broker = NULL; | |
4558 } | |
4559 #endif | |
4560 #ifdef WITH_ASPELL | |
4561 if (spell_config) { | |
4562 delete_aspell_config(spell_config); | |
4563 spell_config = NULL; | |
4564 } | |
4565 #endif | |
4566 } | 4591 } |
4567 | 4592 |
4568 #define spell_isalpha(c) (utf8_mode ? iswalpha(get_char(c)) : isalpha(*c)) | 4593 #define spell_isalpha(c) (utf8_mode ? iswalpha(get_char(c)) : isalpha(*c)) |
4569 | 4594 |
4570 // Spell checking function | 4595 // Spell checking function |
4571 static void spellcheck(char *line, char *checked) | 4596 static void spellcheck(char *line, char *checked) |
4572 { | 4597 { |
4573 const char *start, *line_start; | 4598 const char *start, *line_start; |
4599 spell_substring substr; | |
4574 | 4600 |
4575 if (inputLine[0] == 0 || inputLine[0] == COMMAND_CHAR) | 4601 if (inputLine[0] == 0 || inputLine[0] == COMMAND_CHAR) |
4576 return; | 4602 return; |
4577 | 4603 |
4578 line_start = line; | 4604 line_start = line; |
4605 start = line; | 4631 start = line; |
4606 | 4632 |
4607 while (spell_isalpha(line)) | 4633 while (spell_isalpha(line)) |
4608 line = next_char(line); | 4634 line = next_char(line); |
4609 | 4635 |
4610 if (spell_checker && | 4636 substr.str = start; |
4611 #ifdef WITH_ENCHANT | 4637 substr.len = line - start; |
4612 enchant_dict_check(spell_checker, start, line - start) != 0 | 4638 if (!g_slist_find_custom(spell_checkers, &substr, spellcheckword)) |
4639 memset(&checked[start - line_start], SPELLBADCHAR, line - start); | |
4640 } | |
4641 } | |
4613 #endif | 4642 #endif |
4614 #ifdef WITH_ASPELL | |
4615 aspell_speller_check(spell_checker, start, line - start) == 0 | |
4616 #endif | |
4617 ) | |
4618 memset(&checked[start - line_start], SPELLBADCHAR, line - start); | |
4619 } | |
4620 } | |
4621 #endif | |
4622 | 4643 |
4623 /* vim: set et cindent cinoptions=>2\:2(0 ts=2 sw=2: For Vim users... */ | 4644 /* vim: set et cindent cinoptions=>2\:2(0 ts=2 sw=2: For Vim users... */ |