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... */