diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2013-01-31 19:40:41 +0100 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2013-01-31 19:40:41 +0100 |
commit | 6983d34e884bf21c72990a9ad4ab7cad35f0c555 (patch) | |
tree | 7de0fbe4516a39f438d791dc8671dc5335771062 /src/plugins | |
parent | 5d2382caab50d046a1a8abddeb34d7a545b9ea12 (diff) | |
download | weechat-6983d34e884bf21c72990a9ad4ab7cad35f0c555.zip |
aspell: optimization on spellers to improve speed (save state by buffer), add info "aspell_dict", add completion "aspell_dicts"
Two hashtables have been added to store the spellers currently used (in all
buffers) and info for each buffer: array with pointers to spellers and state of
aspell for this buffer.
Therefore the spellers are not destroyed and created again on each buffer switch,
or each time screen is refreshed when window is split.
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/aspell/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/plugins/aspell/Makefile.am | 6 | ||||
-rw-r--r-- | src/plugins/aspell/weechat-aspell-command.c | 410 | ||||
-rw-r--r-- | src/plugins/aspell/weechat-aspell-command.h | 25 | ||||
-rw-r--r-- | src/plugins/aspell/weechat-aspell-completion.c | 106 | ||||
-rw-r--r-- | src/plugins/aspell/weechat-aspell-completion.h | 25 | ||||
-rw-r--r-- | src/plugins/aspell/weechat-aspell-config.c | 40 | ||||
-rw-r--r-- | src/plugins/aspell/weechat-aspell-info.c | 89 | ||||
-rw-r--r-- | src/plugins/aspell/weechat-aspell-info.h | 25 | ||||
-rw-r--r-- | src/plugins/aspell/weechat-aspell-speller.c | 333 | ||||
-rw-r--r-- | src/plugins/aspell/weechat-aspell-speller.h | 25 | ||||
-rw-r--r-- | src/plugins/aspell/weechat-aspell.c | 669 | ||||
-rw-r--r-- | src/plugins/aspell/weechat-aspell.h | 5 |
13 files changed, 1110 insertions, 651 deletions
diff --git a/src/plugins/aspell/CMakeLists.txt b/src/plugins/aspell/CMakeLists.txt index 6b5248ecb..eadb701e1 100644 --- a/src/plugins/aspell/CMakeLists.txt +++ b/src/plugins/aspell/CMakeLists.txt @@ -21,7 +21,10 @@ ADD_LIBRARY(aspell MODULE weechat-aspell.c weechat-aspell.h weechat-aspell-bar-item.c weechat-aspell-bar-item.h +weechat-aspell-command.c weechat-aspell-command.h +weechat-aspell-completion.c weechat-aspell-completion.h weechat-aspell-config.c weechat-aspell-config.h +weechat-aspell-info.c weechat-aspell-info.h weechat-aspell-speller.c weechat-aspell-speller.h) SET_TARGET_PROPERTIES(aspell PROPERTIES PREFIX "") diff --git a/src/plugins/aspell/Makefile.am b/src/plugins/aspell/Makefile.am index 41679833f..c101d05a0 100644 --- a/src/plugins/aspell/Makefile.am +++ b/src/plugins/aspell/Makefile.am @@ -28,8 +28,14 @@ aspell_la_SOURCES = weechat-aspell.c \ weechat-aspell.h \ weechat-aspell-bar-item.c \ weechat-aspell-bar-item.h \ + weechat-aspell-command.c \ + weechat-aspell-command.h \ + weechat-aspell-completion.c \ + weechat-aspell-completion.h \ weechat-aspell-config.c \ weechat-aspell-config.h \ + weechat-aspell-info.c \ + weechat-aspell-info.h \ weechat-aspell-speller.c \ weechat-aspell-speller.h aspell_la_LDFLAGS = -module diff --git a/src/plugins/aspell/weechat-aspell-command.c b/src/plugins/aspell/weechat-aspell-command.c new file mode 100644 index 000000000..9ef908776 --- /dev/null +++ b/src/plugins/aspell/weechat-aspell-command.c @@ -0,0 +1,410 @@ +/* + * weechat-aspell-command.c - aspell commands + * + * Copyright (C) 2013 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "weechat-aspell.h" +#include "weechat-aspell-config.h" +#include "weechat-aspell-speller.h" + + +/* + * Converts an aspell ISO lang code in its English full name. + * + * Note: result must be freed after use. + */ + +char * +weechat_aspell_command_iso_to_lang (const char *code) +{ + int i; + + for (i = 0; aspell_langs[i].code; i++) + { + if (strcmp (aspell_langs[i].code, code) == 0) + return strdup (aspell_langs[i].name); + } + + /* lang code not found */ + return strdup ("Unknown"); +} + +/* + * Converts an aspell ISO country code in its English full name. + * + * Note: result must be freed after use. + */ + +char * +weechat_aspell_command_iso_to_country (const char *code) +{ + int i; + + for (i = 0; aspell_countries[i].code; i++) + { + if (strcmp (aspell_countries[i].code, code) == 0) + return strdup (aspell_countries[i].name); + } + + /* country code not found */ + return strdup ("Unknown"); +} + +/* + * Displays list of aspell dictionaries installed on system. + */ + +void +weechat_aspell_command_speller_list_dicts () +{ + char *country, *lang, *pos; + char str_dict[256], str_country[128]; + struct AspellConfig *config; + AspellDictInfoList *list; + AspellDictInfoEnumeration *elements; + const AspellDictInfo *dict; + + config = new_aspell_config(); + list = get_aspell_dict_info_list (config); + elements = aspell_dict_info_list_elements (list); + + weechat_printf (NULL, ""); + weechat_printf (NULL, + /* TRANSLATORS: "%s" is "aspell" */ + _( "%s dictionaries list:"), + ASPELL_PLUGIN_NAME); + + while ((dict = aspell_dict_info_enumeration_next (elements)) != NULL) + { + country = NULL; + pos = strchr (dict->code, '_'); + + if (pos) + { + pos[0] = '\0'; + lang = weechat_aspell_command_iso_to_lang ((char*)dict->code); + pos[0] = '_'; + country = weechat_aspell_command_iso_to_country (pos + 1); + } + else + lang = weechat_aspell_command_iso_to_lang ((char*)dict->code); + + str_country[0] = '\0'; + if (country || dict->jargon[0]) + { + snprintf (str_country, sizeof (str_country), " (%s%s%s)", + (country) ? country : dict->jargon, + (country && dict->jargon[0]) ? " - " : "", + (country && dict->jargon[0]) ? ((dict->jargon[0]) ? dict->jargon : country) : ""); + } + + snprintf (str_dict, sizeof (str_dict), "%-22s %s%s", + dict->name, lang, str_country); + + weechat_printf (NULL, " %s", str_dict); + + if (lang) + free (lang); + if (country) + free (country); + } + + delete_aspell_dict_info_enumeration (elements); + delete_aspell_config (config); +} + +/* + * Sets a list of dictionaries for a buffer. + */ + +void +weechat_aspell_command_set_dict (struct t_gui_buffer *buffer, const char *value) +{ + char *name; + + name = weechat_aspell_build_option_name (buffer); + if (!name) + return; + + if (weechat_aspell_config_set_dict (name, value) > 0) + { + if (value && value[0]) + weechat_printf (NULL, "%s: \"%s\" => %s", + ASPELL_PLUGIN_NAME, name, value); + else + weechat_printf (NULL, _("%s: \"%s\" removed"), + ASPELL_PLUGIN_NAME, name); + } + + free (name); +} + +/* + * Adds a word in personal dictionary. + */ + +void +weechat_aspell_command_add_word (struct t_gui_buffer *buffer, const char *dict, + const char *word) +{ + struct t_aspell_speller_buffer *ptr_speller_buffer; + AspellSpeller *new_speller, *ptr_speller; + + new_speller = NULL; + + if (dict) + { + ptr_speller = weechat_hashtable_get (weechat_aspell_spellers, dict); + if (!ptr_speller) + { + if (!weechat_aspell_speller_dict_supported (dict)) + { + weechat_printf (NULL, + _("%s: error: dictionary \"%s\" is not " + "available on your system"), + ASPELL_PLUGIN_NAME, dict); + return; + } + new_speller = weechat_aspell_speller_new (dict); + if (!new_speller) + return; + ptr_speller = new_speller; + } + } + else + { + ptr_speller_buffer = weechat_hashtable_get (weechat_aspell_speller_buffer, + buffer); + if (!ptr_speller_buffer) + ptr_speller_buffer = weechat_aspell_speller_buffer_new (buffer); + if (!ptr_speller_buffer) + goto error; + if (!ptr_speller_buffer->spellers || !ptr_speller_buffer->spellers[0]) + { + weechat_printf (NULL, + _("%s%s: no dictionary on this buffer for " + "adding word"), + weechat_prefix ("error"), + ASPELL_PLUGIN_NAME); + return; + } + else if (ptr_speller_buffer->spellers[1]) + { + weechat_printf (NULL, + _("%s%s: many dictionaries are defined for " + "this buffer, please specify dictionary"), + weechat_prefix ("error"), + ASPELL_PLUGIN_NAME); + return; + } + ptr_speller = ptr_speller_buffer->spellers[0]; + } + + if (aspell_speller_add_to_personal (ptr_speller, + word, + strlen (word)) == 1) + { + weechat_printf (NULL, + _("%s: word \"%s\" added to personal dictionary"), + ASPELL_PLUGIN_NAME, word); + } + else + goto error; + + goto end; + +error: + weechat_printf (NULL, + _("%s%s: failed to add word to personal " + "dictionary"), + weechat_prefix ("error"), ASPELL_PLUGIN_NAME); + +end: + if (new_speller) + weechat_hashtable_remove (weechat_aspell_spellers, dict); +} + +/* + * Callback for command "/aspell". + */ + +int +weechat_aspell_command_cb (void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + char *dicts; + const char *default_dict; + struct t_infolist *infolist; + int number; + + /* make C compiler happy */ + (void) data; + + if (argc == 1) + { + /* display aspell status */ + weechat_printf (NULL, ""); + weechat_printf (NULL, "%s", + (aspell_enabled) ? + _("Aspell is enabled") : _("Aspell is disabled")); + default_dict = weechat_config_string (weechat_aspell_config_check_default_dict); + weechat_printf (NULL, + _("Default dictionary: %s"), + (default_dict && default_dict[0]) ? + default_dict : _("(not set)")); + number = 0; + infolist = weechat_infolist_get ("option", NULL, "aspell.dict.*"); + if (infolist) + { + while (weechat_infolist_next (infolist)) + { + if (number == 0) + weechat_printf (NULL, _("Specific dictionaries on buffers:")); + number++; + weechat_printf (NULL, " %s: %s", + weechat_infolist_string (infolist, "option_name"), + weechat_infolist_string (infolist, "value")); + } + weechat_infolist_free (infolist); + } + return WEECHAT_RC_OK; + } + + /* enable aspell */ + if (weechat_strcasecmp (argv[1], "enable") == 0) + { + weechat_config_option_set (weechat_aspell_config_check_enabled, "1", 1); + weechat_printf (NULL, _("Aspell enabled")); + return WEECHAT_RC_OK; + } + + /* disable aspell */ + if (weechat_strcasecmp (argv[1], "disable") == 0) + { + weechat_config_option_set (weechat_aspell_config_check_enabled, "0", 1); + weechat_printf (NULL, _("Aspell disabled")); + return WEECHAT_RC_OK; + } + + /* toggle aspell */ + if (weechat_strcasecmp (argv[1], "toggle") == 0) + { + if (aspell_enabled) + { + weechat_config_option_set (weechat_aspell_config_check_enabled, "0", 1); + weechat_printf (NULL, _("Aspell disabled")); + } + else + { + weechat_config_option_set (weechat_aspell_config_check_enabled, "1", 1); + weechat_printf (NULL, _("Aspell enabled")); + } + return WEECHAT_RC_OK; + } + + /* list of dictionaries */ + if (weechat_strcasecmp (argv[1], "listdict") == 0) + { + weechat_aspell_command_speller_list_dicts (); + return WEECHAT_RC_OK; + } + + /* set dictionary for current buffer */ + if (weechat_strcasecmp (argv[1], "setdict") == 0) + { + if (argc > 2) + { + dicts = weechat_string_replace (argv_eol[2], " ", ""); + weechat_aspell_command_set_dict (buffer, + (dicts) ? dicts : argv[2]); + if (dicts) + free (dicts); + } + return WEECHAT_RC_OK; + } + + /* delete dictionary used on current buffer */ + if (weechat_strcasecmp (argv[1], "deldict") == 0) + { + weechat_aspell_command_set_dict (buffer, NULL); + return WEECHAT_RC_OK; + } + + /* add word to personal dictionary */ + if (weechat_strcasecmp (argv[1], "addword") == 0) + { + if (argc > 3) + weechat_aspell_command_add_word (buffer, argv[2], argv_eol[3]); + else + weechat_aspell_command_add_word (buffer, NULL, argv_eol[2]); + return WEECHAT_RC_OK; + } + + return WEECHAT_RC_ERROR; +} + +/* + * Hooks aspell command. + */ + +void +weechat_aspell_command_init () +{ + weechat_hook_command ("aspell", + N_("aspell plugin configuration"), + N_("enable|disable|toggle" + " || listdict" + " || setdict <dict>[,<dict>...]" + " || deldict" + " || addword [<dict>] <word>"), + N_(" enable: enable aspell\n" + " disable: disable aspell\n" + " toggle: toggle aspell\n" + "listdict: show installed dictionaries\n" + " setdict: set dictionary for current buffer " + "(multiple dictionaries can be separated by a " + "comma)\n" + " deldict: delete dictionary used on current " + "buffer\n" + " addword: add a word in personal aspell " + "dictionary\n" + "\n" + "Input line beginning with a '/' is not checked, " + "except for some commands (see /set " + "aspell.check.commands).\n\n" + "To enable aspell on all buffers, use option " + "\"default_dict\", then enable aspell, for " + "example:\n" + " /set aspell.check.default_dict \"en\"\n" + " /aspell enable\n\n" + "Default key to toggle aspell is alt-s."), + "enable" + " || disable" + " || toggle" + " || listdict" + " || setdict %(aspell_dicts)" + " || deldict" + " || addword", + &weechat_aspell_command_cb, NULL); +} diff --git a/src/plugins/aspell/weechat-aspell-command.h b/src/plugins/aspell/weechat-aspell-command.h new file mode 100644 index 000000000..f24bc7790 --- /dev/null +++ b/src/plugins/aspell/weechat-aspell-command.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_ASPELL_COMMAND_H +#define __WEECHAT_ASPELL_COMMAND_H 1 + +extern void weechat_aspell_command_init (); + +#endif /* __WEECHAT_ASPELL_COMMAND_H */ diff --git a/src/plugins/aspell/weechat-aspell-completion.c b/src/plugins/aspell/weechat-aspell-completion.c new file mode 100644 index 000000000..36ccf24f6 --- /dev/null +++ b/src/plugins/aspell/weechat-aspell-completion.c @@ -0,0 +1,106 @@ +/* + * weechat-aspell-completion.c - completion for aspell commands + * + * Copyright (C) 2013 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "weechat-aspell.h" + + +/* + * Adds aspell langs (all langs, even for dictionaries not installed) to + * completion list. + */ + +int +weechat_aspell_completion_langs_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + int i; + + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + for (i = 0; aspell_langs[i].code; i++) + { + weechat_hook_completion_list_add (completion, + aspell_langs[i].code, + 0, WEECHAT_LIST_POS_SORT); + } + + return WEECHAT_RC_OK; +} + +/* + * Adds aspell dictionaries (only installed dictionaries) to completion list. + */ + +int +weechat_aspell_completion_dicts_cb (void *data, + const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + struct AspellConfig *config; + AspellDictInfoList *list; + AspellDictInfoEnumeration *elements; + const AspellDictInfo *dict; + + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + config = new_aspell_config (); + list = get_aspell_dict_info_list (config); + elements = aspell_dict_info_list_elements (list); + + while ((dict = aspell_dict_info_enumeration_next (elements)) != NULL) + { + weechat_hook_completion_list_add (completion, dict->name, + 0, WEECHAT_LIST_POS_SORT); + } + + delete_aspell_dict_info_enumeration (elements); + delete_aspell_config (config); + + return WEECHAT_RC_OK; +} + +/* + * Hooks completion. + */ + +void +weechat_aspell_completion_init () +{ + weechat_hook_completion ("aspell_langs", + N_("list of all languages supported by aspell"), + &weechat_aspell_completion_langs_cb, NULL); + weechat_hook_completion ("aspell_dicts", + N_("list of aspell installed dictionaries"), + &weechat_aspell_completion_dicts_cb, NULL); +} diff --git a/src/plugins/aspell/weechat-aspell-completion.h b/src/plugins/aspell/weechat-aspell-completion.h new file mode 100644 index 000000000..96010a5aa --- /dev/null +++ b/src/plugins/aspell/weechat-aspell-completion.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_ASPELL_COMPLETION_H +#define __WEECHAT_ASPELL_COMPLETION_H 1 + +extern void weechat_aspell_completion_init (); + +#endif /* __WEECHAT_ASPELL_COMPLETION_H */ diff --git a/src/plugins/aspell/weechat-aspell-config.c b/src/plugins/aspell/weechat-aspell-config.c index c7a6e9a6a..2301f91a5 100644 --- a/src/plugins/aspell/weechat-aspell-config.c +++ b/src/plugins/aspell/weechat-aspell-config.c @@ -33,6 +33,8 @@ struct t_config_file *weechat_aspell_config_file = NULL; struct t_config_section *weechat_aspell_config_section_dict = NULL; +int weechat_aspell_config_loading = 0; + /* aspell config, look section */ struct t_config_option *weechat_aspell_config_look_color; @@ -110,7 +112,9 @@ weechat_aspell_config_change_default_dict (void *data, (void) data; (void) option; - weechat_aspell_create_spellers (weechat_current_buffer ()); + weechat_hashtable_remove_all (weechat_aspell_speller_buffer); + if (!weechat_aspell_config_loading) + weechat_aspell_speller_remove_unused (); } /* @@ -157,7 +161,9 @@ weechat_aspell_config_dict_change (void *data, (void) data; (void) option; - weechat_aspell_create_spellers (weechat_current_buffer ()); + weechat_hashtable_remove_all (weechat_aspell_speller_buffer); + if (!weechat_aspell_config_loading) + weechat_aspell_speller_remove_unused (); } /* @@ -177,7 +183,9 @@ weechat_aspell_config_dict_delete_option (void *data, weechat_config_option_free (option); - weechat_aspell_create_spellers (weechat_current_buffer ()); + weechat_hashtable_remove_all (weechat_aspell_speller_buffer); + if (!weechat_aspell_config_loading) + weechat_aspell_speller_remove_unused (); return WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED; } @@ -211,7 +219,7 @@ weechat_aspell_config_dict_create_option (void *data, if (ptr_option) { if (value && value[0]) - rc = weechat_config_option_set (ptr_option, value, 1); + rc = weechat_config_option_set (ptr_option, value, 0); else { weechat_config_option_free (ptr_option); @@ -246,7 +254,11 @@ weechat_aspell_config_dict_create_option (void *data, option_name, value); } else - weechat_aspell_create_spellers (weechat_current_buffer ()); + { + weechat_hashtable_remove_all (weechat_aspell_speller_buffer); + if (!weechat_aspell_config_loading) + weechat_aspell_speller_remove_unused (); + } return rc; } @@ -263,8 +275,9 @@ weechat_aspell_config_option_change (void *data, (void) data; (void) option; - weechat_aspell_speller_free_all (); - weechat_aspell_create_spellers (weechat_current_buffer ()); + weechat_hashtable_remove_all (weechat_aspell_speller_buffer); + if (!weechat_aspell_config_loading) + weechat_aspell_speller_remove_unused (); } /* @@ -284,8 +297,9 @@ weechat_aspell_config_option_delete_option (void *data, weechat_config_option_free (option); - weechat_aspell_speller_free_all (); - weechat_aspell_create_spellers (weechat_current_buffer ()); + weechat_hashtable_remove_all (weechat_aspell_speller_buffer); + if (!weechat_aspell_config_loading) + weechat_aspell_speller_remove_unused (); return WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED; } @@ -353,8 +367,9 @@ weechat_aspell_config_option_create_option (void *data, } else { - weechat_aspell_speller_free_all (); - weechat_aspell_create_spellers (weechat_current_buffer ()); + weechat_hashtable_remove_all (weechat_aspell_speller_buffer); + if (!weechat_aspell_config_loading) + weechat_aspell_speller_remove_unused (); } return rc; @@ -525,12 +540,15 @@ weechat_aspell_config_read () { int rc; + weechat_aspell_config_loading = 1; rc = weechat_config_read (weechat_aspell_config_file); + weechat_aspell_config_loading = 0; if (rc == WEECHAT_CONFIG_READ_OK) { weechat_aspell_config_change_commands (NULL, weechat_aspell_config_check_commands); } + weechat_aspell_speller_remove_unused (); return rc; } diff --git a/src/plugins/aspell/weechat-aspell-info.c b/src/plugins/aspell/weechat-aspell-info.c new file mode 100644 index 000000000..5b3614aa6 --- /dev/null +++ b/src/plugins/aspell/weechat-aspell-info.c @@ -0,0 +1,89 @@ +/* + * weechat-aspell-info.c - info for aspell plugin + * + * Copyright (C) 2013 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "weechat-aspell.h" + + +/* + * Returns aspell info. + */ + +const char * +weechat_aspell_info_get_info_cb (void *data, const char *info_name, + const char *arguments) +{ + int rc; + long unsigned int value; + struct t_gui_buffer *buffer; + const char *buffer_full_name; + + /* make C compiler happy */ + (void) data; + + if (weechat_strcasecmp (info_name, "aspell_dict") == 0) + { + if (arguments) + { + buffer_full_name = NULL; + if (strncmp (arguments, "0x", 2) == 0) + { + rc = sscanf (arguments, "%lx", &value); + if ((rc != EOF) && (rc != 0)) + { + buffer = (struct t_gui_buffer *)value; + if (buffer) + { + buffer_full_name = weechat_buffer_get_string (buffer, + "full_name"); + } + } + } + else + buffer_full_name = arguments; + + if (buffer_full_name) + return weechat_aspell_get_dict_with_buffer_name (buffer_full_name); + } + return NULL; + } + + return NULL; +} + +/* + * Hooks info for aspell plugin. + */ + +void +weechat_aspell_info_init () +{ + /* info hooks */ + weechat_hook_info ("aspell_dict", + N_("comma-separated list of dictionaries used in buffer"), + N_("buffer pointer (\"0x12345678\") or buffer full name " + "(\"irc.freenode.#weechat\")"), + &weechat_aspell_info_get_info_cb, NULL); +} diff --git a/src/plugins/aspell/weechat-aspell-info.h b/src/plugins/aspell/weechat-aspell-info.h new file mode 100644 index 000000000..aa0bcdf9c --- /dev/null +++ b/src/plugins/aspell/weechat-aspell-info.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_ASPELL_INFO_H +#define __WEECHAT_ASPELL_INFO_H 1 + +extern void weechat_aspell_info_init (); + +#endif /* __WEECHAT_ASPELL_INFO_H */ diff --git a/src/plugins/aspell/weechat-aspell-speller.c b/src/plugins/aspell/weechat-aspell-speller.c index bb12d9745..0b674b4b8 100644 --- a/src/plugins/aspell/weechat-aspell-speller.c +++ b/src/plugins/aspell/weechat-aspell-speller.c @@ -26,22 +26,32 @@ #include "../weechat-plugin.h" #include "weechat-aspell.h" #include "weechat-aspell-speller.h" +#include "weechat-aspell-config.h" -struct t_aspell_speller *weechat_aspell_spellers = NULL; -struct t_aspell_speller *last_weechat_aspell_speller = NULL; +/* + * spellers: one by dictionary (key is name of dictionary (eg: "fr"), value is + * pointer on AspellSpeller) + */ +struct t_hashtable *weechat_aspell_spellers = NULL; + +/* + * spellers by buffer (key is buffer pointer, value is pointer on + * struct t_aspell_speller_buffer) + */ +struct t_hashtable *weechat_aspell_speller_buffer = NULL; /* - * Checks if an aspell dictionary exists for a lang. + * Checks if an aspell dictionary is supported (installed on system). * * Returns: - * 1: aspell dict exists for the lang - * 0: aspell dict does not exist for the lang + * 1: aspell dict is supported + * 0: aspell dict is NOT supported */ int -weechat_aspell_speller_exists (const char *lang) +weechat_aspell_speller_dict_supported (const char *lang) { struct AspellConfig *config; AspellDictInfoList *list; @@ -90,7 +100,7 @@ weechat_aspell_speller_check_dictionaries (const char *dict_list) { for (i = 0; i < argc; i++) { - if (!weechat_aspell_speller_exists (argv[i])) + if (!weechat_aspell_speller_dict_supported (argv[i])) { weechat_printf (NULL, _("%s: warning: dictionary \"%s\" is not " @@ -104,39 +114,17 @@ weechat_aspell_speller_check_dictionaries (const char *dict_list) } /* - * Searches for a speller by lang. - * - * Returns pointer to speller found, NULL if not found. - */ - -struct t_aspell_speller * -weechat_aspell_speller_search (const char *lang) -{ - struct t_aspell_speller *ptr_speller; - - for (ptr_speller = weechat_aspell_spellers; ptr_speller; - ptr_speller = ptr_speller->next_speller) - { - if (strcmp (ptr_speller->lang, lang) == 0) - return ptr_speller; - } - - /* no speller found */ - return NULL; -} - -/* - * Creates and adds a new speller instance. + * Creates and adds a new speller instance in the hashtable. * - * Returns pointer to new speller, NULL if error. + * Returns pointer to new aspell speller, NULL if error. */ -struct t_aspell_speller * +AspellSpeller * weechat_aspell_speller_new (const char *lang) { - struct t_aspell_speller *new_speller; AspellConfig *config; AspellCanHaveError *ret; + AspellSpeller *new_speller; struct t_infolist *infolist; if (!lang) @@ -179,82 +167,269 @@ weechat_aspell_speller_new (const char *lang) return NULL; } - /* create and add a new speller cell */ - new_speller = malloc (sizeof (*new_speller)); - if (!new_speller) + new_speller = to_aspell_speller (ret); + weechat_hashtable_set (weechat_aspell_spellers, lang, new_speller); + + /* free configuration */ + delete_aspell_config (config); + + return new_speller; +} + +void +weechat_aspell_speller_add_dicts_to_hash (struct t_hashtable *hashtable, + const char *dict) +{ + char **dicts; + int num_dicts, i; + + if (!dict || !dict[0]) + return; + + dicts = weechat_string_split (dict, ",", 0, 0, &num_dicts); + if (dicts) { - weechat_printf (NULL, - _("%s%s: not enough memory to create new speller"), - weechat_prefix ("error"), ASPELL_PLUGIN_NAME); - return NULL; + for (i = 0; i < num_dicts; i++) + { + weechat_hashtable_set (hashtable, dicts[i], NULL); + } + weechat_string_free_split (dicts); } +} + +/* + * Removes a speller if it is NOT in hashtable "used_spellers". + */ - new_speller->speller = to_aspell_speller (ret); - new_speller->lang = strdup (lang); +void +weechat_aspell_speller_remove_unused_cb (void *data, + struct t_hashtable *hashtable, + const void *key, const void *value) +{ + struct t_hashtable *used_spellers; - /* add speller to list */ - new_speller->prev_speller = last_weechat_aspell_speller; - new_speller->next_speller = NULL; - if (weechat_aspell_spellers) - last_weechat_aspell_speller->next_speller = new_speller; - else - weechat_aspell_spellers = new_speller; - last_weechat_aspell_speller = new_speller; + /* make C compiler happy */ + (void) value; - /* free configuration */ - delete_aspell_config (config); + used_spellers = (struct t_hashtable *)data; - return new_speller; + /* if speller is not in "used_spellers", remove it (not used any more) */ + if (!weechat_hashtable_has_key (used_spellers, key)) + weechat_hashtable_remove (hashtable, key); } /* - * Removes a speller instance. + * Removes unused spellers from hashtable "weechat_aspell_spellers". */ void -weechat_aspell_speller_free (struct t_aspell_speller *speller) +weechat_aspell_speller_remove_unused () { - if (!speller) + struct t_hashtable *used_spellers; + struct t_infolist *infolist; + + if (weechat_aspell_plugin->debug) + { + weechat_printf (NULL, + "%s: removing unused spellers", + ASPELL_PLUGIN_NAME); + } + + /* create a hashtable that will contain all used spellers */ + used_spellers = weechat_hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + if (!used_spellers) return; + /* collect used spellers and store them in hashtable "used_spellers" */ + weechat_aspell_speller_add_dicts_to_hash (used_spellers, + weechat_config_string (weechat_aspell_config_check_default_dict)); + infolist = weechat_infolist_get ("option", NULL, "aspell.dict.*"); + if (infolist) + { + while (weechat_infolist_next (infolist)) + { + weechat_aspell_speller_add_dicts_to_hash (used_spellers, + weechat_infolist_string (infolist, "value")); + } + weechat_infolist_free (infolist); + } + + /* + * look at current spellers, and remove spellers that are not in hashtable + * "used_spellers" + */ + weechat_hashtable_map (weechat_aspell_spellers, + &weechat_aspell_speller_remove_unused_cb, + used_spellers); + + weechat_hashtable_free (used_spellers); +} + +/* + * Callback called when a key is removed in hashtable "weechat_aspell_spellers". + */ + +void +weechat_aspell_speller_free_value_cb (struct t_hashtable *hashtable, + const void *key, void *value) +{ + AspellSpeller *ptr_speller; + + /* make C compiler happy */ + (void) hashtable; + if (weechat_aspell_plugin->debug) { weechat_printf (NULL, "%s: removing speller for lang \"%s\"", - ASPELL_PLUGIN_NAME, speller->lang); + ASPELL_PLUGIN_NAME, (const char *)key); } - /* free data */ - if (speller->speller) + /* free aspell data */ + ptr_speller = (AspellSpeller *)value; + aspell_speller_save_all_word_lists (ptr_speller); + delete_aspell_speller (ptr_speller); +} + +/* + * Creates a structure for buffer speller info in hashtable + * "weechat_aspell_buffer_spellers". + */ + +struct t_aspell_speller_buffer * +weechat_aspell_speller_buffer_new (struct t_gui_buffer *buffer) +{ + const char *buffer_dicts; + char **dicts; + int num_dicts, i; + struct t_aspell_speller_buffer *new_speller_buffer; + AspellSpeller *ptr_speller; + + if (!buffer) + return NULL; + + weechat_hashtable_remove (weechat_aspell_speller_buffer, buffer); + + new_speller_buffer = malloc (sizeof (*new_speller_buffer)); + if (!new_speller_buffer) + return NULL; + + new_speller_buffer->spellers = NULL; + new_speller_buffer->modifier_string = NULL; + new_speller_buffer->input_pos = -1; + new_speller_buffer->modifier_result = NULL; + + buffer_dicts = weechat_aspell_get_dict (buffer); + if (buffer_dicts) { - aspell_speller_save_all_word_lists (speller->speller); - delete_aspell_speller (speller->speller); + dicts = weechat_string_split (buffer_dicts, ",", 0, 0, &num_dicts); + if (dicts && (num_dicts > 0)) + { + new_speller_buffer->spellers = + malloc ((num_dicts + 1) * sizeof (AspellSpeller *)); + if (new_speller_buffer->spellers) + { + for (i = 0; i < num_dicts; i++) + { + ptr_speller = weechat_hashtable_get (weechat_aspell_spellers, + dicts[i]); + if (!ptr_speller) + ptr_speller = weechat_aspell_speller_new (dicts[i]); + new_speller_buffer->spellers[i] = ptr_speller; + } + new_speller_buffer->spellers[num_dicts] = NULL; + } + } + if (dicts) + weechat_string_free_split (dicts); } - if (speller->lang) - free (speller->lang); - - /* remove speller from list */ - if (speller->prev_speller) - (speller->prev_speller)->next_speller = speller->next_speller; - if (speller->next_speller) - (speller->next_speller)->prev_speller = speller->prev_speller; - if (weechat_aspell_spellers == speller) - weechat_aspell_spellers = speller->next_speller; - if (last_weechat_aspell_speller == speller) - last_weechat_aspell_speller = speller->prev_speller; - - free (speller); + + weechat_hashtable_set (weechat_aspell_speller_buffer, + buffer, + new_speller_buffer); + + weechat_bar_item_update ("aspell_dict"); + + return new_speller_buffer; } /* - * Frees all spellers. + * Callback called when a key is removed in hashtable + * "weechat_aspell_speller_buffer". */ void -weechat_aspell_speller_free_all () +weechat_aspell_speller_buffer_free_value_cb (struct t_hashtable *hashtable, + const void *key, void *value) { - while (weechat_aspell_spellers) + struct t_aspell_speller_buffer *ptr_speller_buffer; + + /* make C compiler happy */ + (void) hashtable; + (void) key; + + ptr_speller_buffer = (struct t_aspell_speller_buffer *)value; + + if (ptr_speller_buffer->spellers) + free (ptr_speller_buffer->spellers); + if (ptr_speller_buffer->modifier_string) + free (ptr_speller_buffer->modifier_string); + if (ptr_speller_buffer->modifier_result) + free (ptr_speller_buffer->modifier_result); + + free (ptr_speller_buffer); +} + +/* + * Initializes spellers (creates hashtables). + * + * Returns: + * 1: OK (hashtables created) + * 0: error (not enough memory) + */ + +int +weechat_aspell_speller_init () +{ + weechat_aspell_spellers = weechat_hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_POINTER, + NULL, + NULL); + if (!weechat_aspell_spellers) + return 0; + weechat_hashtable_set_pointer (weechat_aspell_spellers, + "callback_free_value", + &weechat_aspell_speller_free_value_cb); + + weechat_aspell_speller_buffer = weechat_hashtable_new (32, + WEECHAT_HASHTABLE_POINTER, + WEECHAT_HASHTABLE_POINTER, + NULL, + NULL); + if (!weechat_aspell_speller_buffer) { - weechat_aspell_speller_free (weechat_aspell_spellers); + weechat_hashtable_free (weechat_aspell_spellers); + return 0; } + weechat_hashtable_set_pointer (weechat_aspell_speller_buffer, + "callback_free_value", + &weechat_aspell_speller_buffer_free_value_cb); + + return 1; +} + +/* + * Ends spellers (removes hashtables). + */ + +void +weechat_aspell_speller_end () +{ + weechat_hashtable_free (weechat_aspell_spellers); + weechat_hashtable_free (weechat_aspell_speller_buffer); } diff --git a/src/plugins/aspell/weechat-aspell-speller.h b/src/plugins/aspell/weechat-aspell-speller.h index 212be88b0..15c67564a 100644 --- a/src/plugins/aspell/weechat-aspell-speller.h +++ b/src/plugins/aspell/weechat-aspell-speller.h @@ -21,22 +21,23 @@ #ifndef __WEECHAT_ASPELL_SPELLER_H #define __WEECHAT_ASPELL_SPELLER_H 1 -struct t_aspell_speller +struct t_aspell_speller_buffer { - AspellSpeller *speller; /* aspell speller */ - char *lang; /* language */ - - struct t_aspell_speller *prev_speller; /* pointer to next speller */ - struct t_aspell_speller *next_speller; /* pointer to previous speller */ + AspellSpeller **spellers; /* pointer to spellers for buf. */ + char *modifier_string; /* last modifier string */ + int input_pos; /* position of cursor in input */ + char *modifier_result; /* last modifier result */ }; -extern struct t_aspell_speller *weechat_aspell_spellers; +extern struct t_hashtable *weechat_aspell_spellers; +extern struct t_hashtable *weechat_aspell_speller_buffer; -extern int weechat_aspell_speller_exists (const char *lang); -extern struct t_aspell_speller *weechat_aspell_speller_search (const char *lang); +extern int weechat_aspell_speller_dict_supported (const char *lang); extern void weechat_aspell_speller_check_dictionaries (const char *dict_list); -extern struct t_aspell_speller *weechat_aspell_speller_new (const char *lang); -extern void weechat_aspell_speller_free (struct t_aspell_speller *speller); -extern void weechat_aspell_speller_free_all (); +extern AspellSpeller *weechat_aspell_speller_new (const char *lang); +extern void weechat_aspell_speller_remove_unused (); +extern struct t_aspell_speller_buffer *weechat_aspell_speller_buffer_new (struct t_gui_buffer *buffer); +extern int weechat_aspell_speller_init (); +extern void weechat_aspell_speller_end (); #endif /* __WEECHAT_ASPELL_SPELLER_H */ diff --git a/src/plugins/aspell/weechat-aspell.c b/src/plugins/aspell/weechat-aspell.c index 9dd03f3a0..df50ffd92 100644 --- a/src/plugins/aspell/weechat-aspell.c +++ b/src/plugins/aspell/weechat-aspell.c @@ -30,7 +30,10 @@ #include "../weechat-plugin.h" #include "weechat-aspell.h" #include "weechat-aspell-bar-item.h" +#include "weechat-aspell-command.h" +#include "weechat-aspell-completion.h" #include "weechat-aspell-config.h" +#include "weechat-aspell-info.h" #include "weechat-aspell-speller.h" @@ -43,18 +46,13 @@ WEECHAT_PLUGIN_LICENSE(WEECHAT_LICENSE); struct t_weechat_plugin *weechat_aspell_plugin = NULL; int aspell_enabled = 0; -struct t_gui_buffer *aspell_buffer_spellers = NULL; - -char *aspell_last_modifier_string = NULL; /* last str. received by modifier */ -int aspell_last_buffer_input_pos = -1; /* last cursor position */ -char *aspell_last_modifier_result = NULL; /* last str. built by modifier */ /* - * aspell supported langs, updated on 2012-07-05 + * aspell supported languages, updated on 2012-07-05 * URL: ftp://ftp.gnu.org/gnu/aspell/dict/0index.html */ -struct t_aspell_code aspell_langs_avail[] = +struct t_aspell_code aspell_langs[] = { { "af", "Afrikaans" }, { "am", "Amharic" }, @@ -150,7 +148,7 @@ struct t_aspell_code aspell_langs_avail[] = { NULL, NULL} }; -struct t_aspell_code aspell_countries_avail[] = +struct t_aspell_code aspell_countries[] = { { "AT", "Austria" }, { "BR", "Brazil" }, @@ -201,19 +199,18 @@ weechat_aspell_build_option_name (struct t_gui_buffer *buffer) } /* - * Gets dictionary list for a buffer. + * Gets dictionary list for a name of buffer. * * First tries with all arguments, then removes one by one to find dict (from * specific to general dict). */ const char * -weechat_aspell_get_dict (struct t_gui_buffer *buffer) +weechat_aspell_get_dict_with_buffer_name (const char *name) { - char *name, *option_name, *ptr_end; + char *option_name, *ptr_end; struct t_config_option *ptr_option; - name = weechat_aspell_build_option_name (buffer); if (!name) return NULL; @@ -227,7 +224,6 @@ weechat_aspell_get_dict (struct t_gui_buffer *buffer) if (ptr_option) { free (option_name); - free (name); return weechat_config_string (ptr_option); } ptr_end--; @@ -241,297 +237,44 @@ weechat_aspell_get_dict (struct t_gui_buffer *buffer) ptr_option = weechat_aspell_config_get_dict (option_name); free (option_name); - free (name); if (ptr_option) return weechat_config_string (ptr_option); } - else - free (name); /* nothing found => return default dictionary (if set) */ if (weechat_config_string (weechat_aspell_config_check_default_dict) && weechat_config_string (weechat_aspell_config_check_default_dict)[0]) + { return weechat_config_string (weechat_aspell_config_check_default_dict); + } /* no default dictionary set */ return NULL; } /* - * Sets a list of dictionaries for a buffer. + * Gets dictionary list for a buffer. + * + * First tries with all arguments, then removes one by one to find dict (from + * specific to general dict). */ -void -weechat_aspell_set_dict (struct t_gui_buffer *buffer, const char *value) +const char * +weechat_aspell_get_dict (struct t_gui_buffer *buffer) { char *name; + const char *dict; name = weechat_aspell_build_option_name (buffer); if (!name) - return; + return NULL; - if (weechat_aspell_config_set_dict (name, value) > 0) - { - if (value && value[0]) - weechat_printf (NULL, "%s: \"%s\" => %s", - ASPELL_PLUGIN_NAME, name, value); - else - weechat_printf (NULL, _("%s: \"%s\" removed"), - ASPELL_PLUGIN_NAME, name); - } + dict = weechat_aspell_get_dict_with_buffer_name (name); free (name); -} - -/* - * Checks if current spellers are already OK. - * - * Returns: - * 1: already OK - * 0: spellers must be changed - */ - -int -weechat_aspell_spellers_already_ok (const char *dict_list) -{ - char **argv; - int argc, rc, i; - struct t_aspell_speller *ptr_speller; - - if (!dict_list && !weechat_aspell_spellers) - return 1; - - if (!dict_list || !weechat_aspell_spellers) - return 0; - - rc = 1; - - argv = weechat_string_split (dict_list, ",", 0, 0, &argc); - if (argv) - { - ptr_speller = weechat_aspell_spellers; - for (i = 0; i < argc; i++) - { - if (!ptr_speller) - { - rc = 0; - break; - } - if (strcmp (ptr_speller->lang, argv[i]) != 0) - { - rc = 0; - break; - } - ptr_speller = ptr_speller->next_speller; - } - if (ptr_speller) - rc = 0; - weechat_string_free_split (argv); - } - - return rc; -} - -/* - * Creates spellers for a buffer. - */ - -void -weechat_aspell_create_spellers (struct t_gui_buffer *buffer) -{ - const char *dict_list; - char **argv; - int argc, i; - - if (!buffer) - return; - - dict_list = weechat_aspell_get_dict (buffer); - if (!weechat_aspell_spellers_already_ok (dict_list)) - { - weechat_aspell_speller_free_all (); - if (dict_list) - { - argv = weechat_string_split (dict_list, ",", 0, 0, &argc); - if (argv) - { - for (i = 0; i < argc; i++) - { - weechat_aspell_speller_new (argv[i]); - } - weechat_string_free_split (argv); - } - } - weechat_bar_item_update ("aspell_dict"); - } -} - -/* - * Converts an aspell ISO lang code in its English full name. - * - * Note: result must be freed after use. - */ - -char * -weechat_aspell_iso_to_lang (const char *code) -{ - int i; - - for (i = 0; aspell_langs_avail[i].code; i++) - { - if (strcmp (aspell_langs_avail[i].code, code) == 0) - return strdup (aspell_langs_avail[i].name); - } - - /* lang code not found */ - return strdup ("Unknown"); -} - -/* - * Converts an aspell ISO country code in its English full name. - * - * Note: result must be freed after use. - */ - -char * -weechat_aspell_iso_to_country (const char *code) -{ - int i; - - for (i = 0; aspell_countries_avail[i].code; i++) - { - if (strcmp (aspell_countries_avail[i].code, code) == 0) - return strdup (aspell_countries_avail[i].name); - } - - /* country code not found */ - return strdup ("Unknown"); -} - -/* - * Displays list of aspell dictionaries installed on system. - */ - -void -weechat_aspell_speller_list_dicts () -{ - char *country, *lang, *pos; - char buffer[192]; - struct AspellConfig *config; - AspellDictInfoList *list; - AspellDictInfoEnumeration *elements; - const AspellDictInfo *dict; - - config = new_aspell_config(); - list = get_aspell_dict_info_list (config); - elements = aspell_dict_info_list_elements (list); - - weechat_printf (NULL, ""); - weechat_printf (NULL, - /* TRANSLATORS: "%s" is "aspell" */ - _( "%s dictionaries list:"), - ASPELL_PLUGIN_NAME); - - while ((dict = aspell_dict_info_enumeration_next (elements)) != NULL) - { - country = NULL; - pos = strchr (dict->code, '_'); - - if (pos) - { - pos[0] = '\0'; - lang = weechat_aspell_iso_to_lang ((char*)dict->code); - pos[0] = '_'; - country = weechat_aspell_iso_to_country (pos + 1); - } - else - lang = weechat_aspell_iso_to_lang ((char*)dict->code); - - if (strlen (dict->jargon) == 0) - { - if (pos) - { - snprintf (buffer, sizeof (buffer), "%-22s %s (%s)", - dict->name, lang, country); - } - else - { - snprintf (buffer, sizeof (buffer), "%-22s %s", - dict->name, lang); - } - } - else - { - if (pos) - { - snprintf (buffer, sizeof (buffer), "%-22s %s (%s - %s)", - dict->name, lang, country, dict->jargon); - } - else - { - snprintf (buffer, sizeof (buffer), "%-22s %s (%s)", - dict->name, lang, dict->jargon); - } - } - - weechat_printf (NULL, " %s", buffer); - - if (lang) - free (lang); - if (country) - free (country); - } - delete_aspell_dict_info_enumeration (elements); - delete_aspell_config (config); -} - -/* - * Adds a word in personal dictionary. - */ - -void -weechat_aspell_add_word (const char *lang, const char *word) -{ - struct t_aspell_speller *new_speller, *ptr_speller; - - new_speller = NULL; - ptr_speller = weechat_aspell_speller_search (lang); - if (!ptr_speller) - { - if (!weechat_aspell_speller_exists (lang)) - { - weechat_printf (NULL, - _("%s: error: dictionary \"%s\" is not " - "available on your system"), - ASPELL_PLUGIN_NAME, lang); - return; - } - new_speller = weechat_aspell_speller_new (lang); - if (!new_speller) - return; - ptr_speller = new_speller; - } - - if (aspell_speller_add_to_personal (ptr_speller->speller, - word, - strlen (word)) == 1) - { - weechat_printf (NULL, - _("%s: word \"%s\" added to personal dictionary"), - ASPELL_PLUGIN_NAME, word); - } - else - { - weechat_printf (NULL, - _("%s%s: failed to add word to personal " - "dictionary"), - weechat_prefix ("error"), ASPELL_PLUGIN_NAME); - } - - if (new_speller) - weechat_aspell_speller_free (new_speller); + return dict; } /* @@ -628,10 +371,12 @@ weechat_aspell_string_is_simili_number (const char *word) */ int -weechat_aspell_check_word (struct t_gui_buffer *buffer, const char *word) +weechat_aspell_check_word (struct t_gui_buffer *buffer, + struct t_aspell_speller_buffer *speller_buffer, + const char *word) { const char *buffer_type, *buffer_nick, *buffer_channel; - struct t_aspell_speller *ptr_speller; + int i; /* word too small? then do not check word */ if ((weechat_config_integer (weechat_aspell_config_check_word_min_length) > 0) @@ -661,12 +406,12 @@ weechat_aspell_check_word (struct t_gui_buffer *buffer, const char *word) } /* check word with all spellers for this buffer (order is important) */ - for (ptr_speller = weechat_aspell_spellers; ptr_speller; - ptr_speller = ptr_speller->next_speller) + if (speller_buffer->spellers) { - if (aspell_speller_check (ptr_speller->speller, word, -1) == 1) + for (i = 0; speller_buffer->spellers[i]; i++) { - return 1; + if (aspell_speller_check (speller_buffer->spellers[i], word, -1) == 1) + return 1; } } @@ -683,10 +428,10 @@ weechat_aspell_check_word (struct t_gui_buffer *buffer, const char *word) */ char * -weechat_aspell_get_suggestions (const char *word) +weechat_aspell_get_suggestions (struct t_aspell_speller_buffer *speller_buffer, + const char *word) { - struct t_aspell_speller *ptr_speller; - int size, max_suggestions, num_suggestions; + int i, size, max_suggestions, num_suggestions; char *suggestions, *suggestions2; const char *ptr_word; const AspellWordList *list; @@ -702,33 +447,35 @@ weechat_aspell_get_suggestions (const char *word) return NULL; suggestions[0] = '\0'; - for (ptr_speller = weechat_aspell_spellers; ptr_speller; - ptr_speller = ptr_speller->next_speller) + if (speller_buffer->spellers) { - list = aspell_speller_suggest (ptr_speller->speller, word, -1); - if (list) + for (i = 0; speller_buffer->spellers[i]; i++) { - elements = aspell_word_list_elements (list); - num_suggestions = 0; - while ((ptr_word = aspell_string_enumeration_next (elements)) != NULL) + list = aspell_speller_suggest (speller_buffer->spellers[i], word, -1); + if (list) { - size += strlen (ptr_word) + ((suggestions[0]) ? 1 : 0); - suggestions2 = realloc (suggestions, size); - if (!suggestions2) + elements = aspell_word_list_elements (list); + num_suggestions = 0; + while ((ptr_word = aspell_string_enumeration_next (elements)) != NULL) { - free (suggestions); - delete_aspell_string_enumeration (elements); - return NULL; + size += strlen (ptr_word) + ((suggestions[0]) ? 1 : 0); + suggestions2 = realloc (suggestions, size); + if (!suggestions2) + { + free (suggestions); + delete_aspell_string_enumeration (elements); + return NULL; + } + suggestions = suggestions2; + if (suggestions[0]) + strcat (suggestions, (num_suggestions == 0) ? "/" : ","); + strcat (suggestions, ptr_word); + num_suggestions++; + if ((max_suggestions >= 0) && (num_suggestions == max_suggestions)) + break; } - suggestions = suggestions2; - if (suggestions[0]) - strcat (suggestions, (num_suggestions == 0) ? "/" : ","); - strcat (suggestions, ptr_word); - num_suggestions++; - if ((max_suggestions >= 0) && (num_suggestions == max_suggestions)) - break; + delete_aspell_string_enumeration (elements); } - delete_aspell_string_enumeration (elements); } } @@ -752,11 +499,12 @@ weechat_aspell_modifier_cb (void *data, const char *modifier, { long unsigned int value; struct t_gui_buffer *buffer; + struct t_aspell_speller_buffer *ptr_speller_buffer; char *result, *ptr_string, *pos_space, *ptr_end, save_end; char *word_for_suggestions, *old_suggestions, *suggestions; char *word_and_suggestions; const char *color_normal, *color_error, *ptr_suggestions; - int buffer_has_changed, utf8_char_int, char_size; + int utf8_char_int, char_size; int length, index_result, length_word, word_ok; int length_color_normal, length_color_error, rc; int input_pos, current_pos, word_start_pos, word_end_pos; @@ -777,54 +525,54 @@ weechat_aspell_modifier_cb (void *data, const char *modifier, buffer = (struct t_gui_buffer *)value; - buffer_has_changed = 0; - if (buffer != aspell_buffer_spellers) - { - weechat_aspell_create_spellers (buffer); - aspell_buffer_spellers = buffer; - buffer_has_changed = 1; - } - - if (!weechat_aspell_spellers) - return NULL; - - /* check text search only if option is enabled */ + /* check text during search only if option is enabled */ if (weechat_buffer_get_integer (buffer, "text_search") && !weechat_config_boolean (weechat_aspell_config_check_during_search)) return NULL; + /* get structure with speller info for buffer */ + ptr_speller_buffer = weechat_hashtable_get (weechat_aspell_speller_buffer, + buffer); + if (!ptr_speller_buffer) + { + ptr_speller_buffer = weechat_aspell_speller_buffer_new (buffer); + if (!ptr_speller_buffer) + return NULL; + } + if (!ptr_speller_buffer->spellers) + return NULL; + /* * for performance: return last string built if input string is the - * same and cursor position is the same (only if suggestions are enabled) + * same (and cursor position is the same, if suggestions are enabled) */ input_pos = weechat_buffer_get_integer (buffer, "input_pos"); - if (!buffer_has_changed - && aspell_last_modifier_string - && (strcmp (string, aspell_last_modifier_string) == 0) + if (ptr_speller_buffer->modifier_string + && (strcmp (string, ptr_speller_buffer->modifier_string) == 0) && ((weechat_config_integer (weechat_aspell_config_check_suggestions) < 0) - || (input_pos == aspell_last_buffer_input_pos))) + || (input_pos == ptr_speller_buffer->input_pos))) { - return (aspell_last_modifier_result) ? - strdup (aspell_last_modifier_result) : NULL; + return (ptr_speller_buffer->modifier_result) ? + strdup (ptr_speller_buffer->modifier_result) : NULL; } /* free last modifier string and result */ - if (aspell_last_modifier_string) + if (ptr_speller_buffer->modifier_string) { - free (aspell_last_modifier_string); - aspell_last_modifier_string = NULL; + free (ptr_speller_buffer->modifier_string); + ptr_speller_buffer->modifier_string = NULL; } - if (aspell_last_modifier_result) + if (ptr_speller_buffer->modifier_result) { - free (aspell_last_modifier_result); - aspell_last_modifier_result = NULL; + free (ptr_speller_buffer->modifier_result); + ptr_speller_buffer->modifier_result = NULL; } word_for_suggestions = NULL; /* save last modifier string received */ - aspell_last_modifier_string = strdup (string); - aspell_last_buffer_input_pos = input_pos; + ptr_speller_buffer->modifier_string = strdup (string); + ptr_speller_buffer->input_pos = input_pos; color_normal = weechat_color ("bar_fg"); length_color_normal = strlen (color_normal); @@ -838,7 +586,7 @@ weechat_aspell_modifier_cb (void *data, const char *modifier, { result[0] = '\0'; - ptr_string = aspell_last_modifier_string; + ptr_string = ptr_speller_buffer->modifier_string; index_result = 0; /* check if string is a command */ @@ -865,7 +613,9 @@ weechat_aspell_modifier_cb (void *data, const char *modifier, free (result); return NULL; } - memcpy (result + index_result, aspell_last_modifier_string, char_size); + memcpy (result + index_result, + ptr_speller_buffer->modifier_string, + char_size); index_result += char_size; strcpy (result + index_result, ptr_string); index_result += strlen (ptr_string); @@ -939,7 +689,9 @@ weechat_aspell_modifier_cb (void *data, const char *modifier, if ((save_end != '\0') || (weechat_config_integer (weechat_aspell_config_check_real_time))) { - word_ok = weechat_aspell_check_word (buffer, ptr_string); + word_ok = weechat_aspell_check_word (buffer, + ptr_speller_buffer, + ptr_string); if (!word_ok && (input_pos >= word_start_pos)) { /* @@ -992,7 +744,8 @@ weechat_aspell_modifier_cb (void *data, const char *modifier, /* if there is a misspelled word, get suggestions and set them in buffer */ if (word_for_suggestions) { - suggestions = weechat_aspell_get_suggestions (word_for_suggestions); + suggestions = weechat_aspell_get_suggestions (ptr_speller_buffer, + word_for_suggestions); if (suggestions) { length = strlen (word_for_suggestions) + 1 /* ":" */ @@ -1044,182 +797,38 @@ weechat_aspell_modifier_cb (void *data, const char *modifier, if (!result) return NULL; - aspell_last_modifier_result = strdup (result); + ptr_speller_buffer->modifier_result = strdup (result); return result; } /* - * Callback for command "/aspell". - */ - -int -weechat_aspell_command_cb (void *data, struct t_gui_buffer *buffer, - int argc, char **argv, char **argv_eol) -{ - char *dicts; - const char *default_dict; - struct t_infolist *infolist; - int number; - - /* make C compiler happy */ - (void) data; - - if (argc == 1) - { - /* display aspell status */ - weechat_printf (NULL, ""); - weechat_printf (NULL, "%s", - (aspell_enabled) ? - _("Aspell is enabled") : _("Aspell is disabled")); - default_dict = weechat_config_string (weechat_aspell_config_check_default_dict); - weechat_printf (NULL, - _("Default dictionary: %s"), - (default_dict && default_dict[0]) ? - default_dict : _("(not set)")); - number = 0; - infolist = weechat_infolist_get ("option", NULL, "aspell.dict.*"); - if (infolist) - { - while (weechat_infolist_next (infolist)) - { - if (number == 0) - weechat_printf (NULL, _("Specific dictionaries on buffers:")); - number++; - weechat_printf (NULL, " %s: %s", - weechat_infolist_string (infolist, "option_name"), - weechat_infolist_string (infolist, "value")); - } - weechat_infolist_free (infolist); - } - return WEECHAT_RC_OK; - } - - /* enable aspell */ - if (weechat_strcasecmp (argv[1], "enable") == 0) - { - weechat_config_option_set (weechat_aspell_config_check_enabled, "1", 1); - weechat_printf (NULL, _("Aspell enabled")); - return WEECHAT_RC_OK; - } - - /* disable aspell */ - if (weechat_strcasecmp (argv[1], "disable") == 0) - { - weechat_config_option_set (weechat_aspell_config_check_enabled, "0", 1); - weechat_printf (NULL, _("Aspell disabled")); - return WEECHAT_RC_OK; - } - - /* toggle aspell */ - if (weechat_strcasecmp (argv[1], "toggle") == 0) - { - if (aspell_enabled) - { - weechat_config_option_set (weechat_aspell_config_check_enabled, "0", 1); - weechat_printf (NULL, _("Aspell disabled")); - } - else - { - weechat_config_option_set (weechat_aspell_config_check_enabled, "1", 1); - weechat_printf (NULL, _("Aspell enabled")); - } - return WEECHAT_RC_OK; - } - - /* list of dictionaries */ - if (weechat_strcasecmp (argv[1], "listdict") == 0) - { - weechat_aspell_speller_list_dicts (); - return WEECHAT_RC_OK; - } - - /* set dictionary for current buffer */ - if (weechat_strcasecmp (argv[1], "setdict") == 0) - { - if (argc > 2) - { - dicts = weechat_string_replace (argv_eol[2], " ", ""); - weechat_aspell_set_dict (buffer, - (dicts) ? dicts : argv[2]); - if (dicts) - free (dicts); - } - return WEECHAT_RC_OK; - } - - /* delete dictionary used on current buffer */ - if (weechat_strcasecmp (argv[1], "deldict") == 0) - { - weechat_aspell_set_dict (buffer, NULL); - return WEECHAT_RC_OK; - } - - /* add word to personal dictionary */ - if (weechat_strcasecmp (argv[1], "addword") == 0) - { - if (argc > 3) - weechat_aspell_add_word (argv[2], argv_eol[3]); - else - { - if (!weechat_aspell_spellers) - { - weechat_printf (NULL, - _("%s%s: no dictionary on this buffer for " - "adding word"), - weechat_prefix ("error"), - ASPELL_PLUGIN_NAME); - } - else if (weechat_aspell_spellers->next_speller) - { - weechat_printf (NULL, - _("%s%s: many dictionaries are defined for " - "this buffer, please specify dictionary"), - weechat_prefix ("error"), - ASPELL_PLUGIN_NAME); - } - else - weechat_aspell_add_word (weechat_aspell_spellers->lang, - argv_eol[2]); - } - return WEECHAT_RC_OK; - } - - return WEECHAT_RC_ERROR; -} - -/* - * Adds aspell langs to completion list. + * Refreshes bar items on signal "buffer_switch". */ int -weechat_aspell_completion_langs_cb (void *data, const char *completion_item, - struct t_gui_buffer *buffer, - struct t_gui_completion *completion) +weechat_aspell_buffer_switch_cb (void *data, const char *signal, + const char *type_data, void *signal_data) { - int i; - /* make C compiler happy */ (void) data; - (void) completion_item; - (void) buffer; + (void) signal; + (void) type_data; + (void) signal_data; - for (i = 0; aspell_langs_avail[i].code; i++) - { - weechat_hook_completion_list_add (completion, - aspell_langs_avail[i].code, - 0, WEECHAT_LIST_POS_SORT); - } + /* refresh bar items (for root bars) */ + weechat_bar_item_update ("aspell_dict"); + weechat_bar_item_update ("aspell_suggest"); return WEECHAT_RC_OK; } /* - * Refreshes bar items on signal "buffer_switch". + * Refreshes bar items on signal "window_switch". */ int -weechat_aspell_buffer_switch_cb (void *data, const char *signal, +weechat_aspell_window_switch_cb (void *data, const char *signal, const char *type_data, void *signal_data) { /* make C compiler happy */ @@ -1236,22 +845,20 @@ weechat_aspell_buffer_switch_cb (void *data, const char *signal, } /* - * Refreshes bar items on signal "window_switch". + * Removes struct for buffer in hashtable "weechat_aspell_speller_buffer" on + * signal "buffer_closed". */ int -weechat_aspell_window_switch_cb (void *data, const char *signal, +weechat_aspell_buffer_closed_cb (void *data, const char *signal, const char *type_data, void *signal_data) { /* make C compiler happy */ (void) data; (void) signal; (void) type_data; - (void) signal_data; - /* refresh bar items (for root bars) */ - weechat_bar_item_update ("aspell_dict"); - weechat_bar_item_update ("aspell_suggest"); + weechat_hashtable_remove (weechat_aspell_speller_buffer, signal_data); return WEECHAT_RC_OK; } @@ -1269,50 +876,18 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) weechat_plugin = plugin; + if (!weechat_aspell_speller_init ()) + return WEECHAT_RC_ERROR; + if (!weechat_aspell_config_init ()) return WEECHAT_RC_ERROR; if (weechat_aspell_config_read () < 0) return WEECHAT_RC_ERROR; - /* command /aspell */ - weechat_hook_command ("aspell", - N_("aspell plugin configuration"), - N_("enable|disable|toggle" - " || listdict" - " || setdict <lang>" - " || deldict" - " || addword [<lang>] <word>"), - N_(" enable: enable aspell\n" - " disable: disable aspell\n" - " toggle: toggle aspell\n" - "listdict: show installed dictionaries\n" - " setdict: set dictionary for current buffer\n" - " deldict: delete dictionary used on current " - "buffer\n" - " addword: add a word in personal aspell " - "dictionary\n" - "\n" - "Input line beginning with a '/' is not checked, " - "except for some commands (see /set " - "aspell.check.commands).\n\n" - "To enable aspell on all buffers, use option " - "\"default_dict\", then enable aspell, for " - "example:\n" - " /set aspell.check.default_dict \"en\"\n" - " /aspell enable\n\n" - "Default key to toggle aspell is alt-s."), - "enable" - " || disable" - " || toggle" - " || listdict" - " || setdict %(aspell_langs)" - " || deldict" - " || addword", - &weechat_aspell_command_cb, NULL); - weechat_hook_completion ("aspell_langs", - N_("list of supported langs for aspell"), - &weechat_aspell_completion_langs_cb, NULL); + weechat_aspell_command_init (); + + weechat_aspell_completion_init (); /* * callback for spell checking input text @@ -1324,10 +899,14 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) weechat_aspell_bar_item_init (); + weechat_aspell_info_init (); + weechat_hook_signal ("buffer_switch", &weechat_aspell_buffer_switch_cb, NULL); weechat_hook_signal ("window_switch", &weechat_aspell_window_switch_cb, NULL); + weechat_hook_signal ("buffer_closed", + &weechat_aspell_buffer_closed_cb, NULL); return WEECHAT_RC_OK; } @@ -1343,15 +922,9 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) (void) plugin; weechat_aspell_config_write (); - - weechat_aspell_speller_free_all (); - - if (aspell_last_modifier_string) - free (aspell_last_modifier_string); - if (aspell_last_modifier_result) - free (aspell_last_modifier_result); - weechat_aspell_config_free (); + weechat_aspell_speller_end (); + return WEECHAT_RC_OK; } diff --git a/src/plugins/aspell/weechat-aspell.h b/src/plugins/aspell/weechat-aspell.h index 072818103..7f26608fd 100644 --- a/src/plugins/aspell/weechat-aspell.h +++ b/src/plugins/aspell/weechat-aspell.h @@ -34,8 +34,11 @@ struct t_aspell_code extern struct t_weechat_plugin *weechat_aspell_plugin; extern int aspell_enabled; +extern struct t_aspell_code aspell_langs[]; +extern struct t_aspell_code aspell_countries[]; -extern void weechat_aspell_create_spellers (struct t_gui_buffer *buffer); +extern char *weechat_aspell_build_option_name (struct t_gui_buffer *buffer); +extern const char *weechat_aspell_get_dict_with_buffer_name (const char *name); extern const char *weechat_aspell_get_dict (struct t_gui_buffer *buffer); #endif /* __WEECHAT_ASPELL_H */ |