SF.net SVN: geany-plugins: [74] trunk/spellcheck
eht16 at users.sourceforge.net
eht16 at xxxxx
Thu Jun 19 21:34:54 UTC 2008
Revision: 74
http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=74&view=rev
Author: eht16
Date: 2008-06-19 14:34:52 -0700 (Thu, 19 Jun 2008)
Log Message:
-----------
Use enchant as spell check engine instead of Aspell.
Highlight only misspelled instead of whole the line.
Add Tools->Spellcheck sub menu to easily change the language to use for spell checking.
Add "check as you type" feature.
Change doc pointer usage.
Update Readme.
Modified Paths:
--------------
trunk/spellcheck/ChangeLog
trunk/spellcheck/README
trunk/spellcheck/configure.in
trunk/spellcheck/src/Makefile.am
trunk/spellcheck/src/spellcheck.c
Modified: trunk/spellcheck/ChangeLog
===================================================================
--- trunk/spellcheck/ChangeLog 2008-06-19 21:20:36 UTC (rev 73)
+++ trunk/spellcheck/ChangeLog 2008-06-19 21:34:52 UTC (rev 74)
@@ -1,3 +1,15 @@
+2008-06-19 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
+
+ * README, configure.in, src/Makefile.am, src/spellcheck.c:
+ Use enchant as spell check engine instead of Aspell.
+ Highlight only misspelled instead of whole the line.
+ Add Tools->Spellcheck sub menu to easily change the language
+ to use for spell checking.
+ Add "check as you type" feature.
+ Change doc pointer usage.
+ Update Readme.
+
+
2008-06-03 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
* src/spellcheck.c:
Modified: trunk/spellcheck/README
===================================================================
--- trunk/spellcheck/README 2008-06-19 21:20:36 UTC (rev 73)
+++ trunk/spellcheck/README 2008-06-19 21:34:52 UTC (rev 74)
@@ -1,34 +1,63 @@
Spell Check Plugin
-------------------
+==================
+.. contents::
+
About
-----
This plugin checks the content of the current document in Geany with the spell
-check program Aspell. You can also select a certain text passage, then the
+check library Enchant. You can also select a certain text passage, then the
plugin will only check the selected text. All lines with misspelled words
are highlighted with a red squiggly underline and the wrong words are printed
in the messages window at the bottom of Geany together with available
-suggestions. For the plugin to work at all, you need to have the Aspell
-library installed together with at least one dictionary.
+suggestions. For the plugin to work at all, you need to have the Enchant
+library installed together with at least one backend (Aspell, Myspell,
+Hunspell, ...).
The plugin's configure dialog lists all available languages/dictionaries
which can be used for the spell check.
+Downloads
+---------
+
+Spellcheck 0.1
+^^^^^^^^^^^^^^
+
+http://geany-plugins.sourceforge.net/spellcheck/spellcheck-0.1.tar.bz2
+
+http://geany-plugins.sourceforge.net/spellcheck/spellcheck-0.1.tar.bz2.sig (GPG-Signature)
+
+or
+
+http://geany-plugins.sourceforge.net/spellcheck/spellcheck-0.1.tar.gz
+
+http://geany-plugins.sourceforge.net/spellcheck/spellcheck-0.1.tar.gz.sig (GPG-Signature)
+
+
+Development Code
+^^^^^^^^^^^^^^^^
+
+Get the code from:
+
+ svn checkout http://geany-plugins.svn.sourceforge.net/svnroot/geany-plugins/trunk/spellcheck
+
+
Requirements
------------
For compiling the plugin yourself, you will need the GTK (>= 2.6.0) libraries
and header files. You will also need its dependency libraries and header
files, such as Pango, Glib and ATK. All these files are available at
http://www.gtk.org.
-Furthermore, you need to have installed libaspell with its development files.
+Furthermore, you need to have installed enchant with its development files
+(libenchant-dev or enchant-devel).
And obviously, you will need have Geany installed. If you have Geany installed
from the sources, you should be ready to go.
If you used a preprared package e.g. from your distribution you probably need
to install an additional package, this might be called geany-dev or geany-devel.
Please note that in order to compile and use this plugin, you need a current SVN
-version of Geany, at least SVN >= r2590.
+version of Geany, at least SVN >= 2715.
Furthermore you need, of course, a C compiler and the Make tool.
The GNU versions of these tools are recommended.
@@ -68,3 +97,4 @@
Ideas, questions, patches and bug reports
-----------------------------------------
Send it to me at enrico(dot)troeger(at)uvena(dot)de
+or report them at http://sourceforge.net/tracker/?group_id=222729.
Modified: trunk/spellcheck/configure.in
===================================================================
--- trunk/spellcheck/configure.in 2008-06-19 21:20:36 UTC (rev 73)
+++ trunk/spellcheck/configure.in 2008-06-19 21:34:52 UTC (rev 74)
@@ -16,20 +16,18 @@
# checking for Geany
PKG_CHECK_MODULES(GEANY, [geany >= 0.15])
-AC_SUBST(GTK_CFLAGS)
-AC_SUBST(GTK_LIBS)
+AC_SUBST(GEANY_CFLAGS)
+AC_SUBST(GEANY_LIBS)
+# checking for libenchant
+PKG_CHECK_MODULES(ENCHANT, [enchant >= 1.3])
+AC_SUBST(ENCHANT_CFLAGS)
+AC_SUBST(ENCHANT_LIBS)
+
GEANY_VERSION=`$PKG_CONFIG --modversion geany`
GTK_VERSION=`$PKG_CONFIG --modversion gtk+-2.0`
+ENCHANT_VERSION=`$PKG_CONFIG --modversion enchant`
-# checking for aspell
-AC_CHECK_HEADER(aspell.h, [AC_DEFINE(HAVE_ASPELL_H, 1,
- [Define to 1 if you have the <aspell.h> header file.] )],
- [AC_MSG_ERROR([You must have the aspell dev library installed to build the spellcheck plugin.]) ] )
-AC_CHECK_LIB(aspell, new_aspell_speller, SPELLER_LIB="-laspell",
- [AC_MSG_ERROR([You must have the aspell dev library installed to build the spellcheck plugin.]) ] )
-AC_SUBST(SPELLER_LIB)
-
# i18n
GETTEXT_PACKAGE=spellcheck
AC_SUBST(GETTEXT_PACKAGE)
@@ -65,6 +63,7 @@
echo "Install Spell Check files in : ${prefix}"
echo "Using Geany version : ${GEANY_VERSION}"
echo "Using GTK version : ${GTK_VERSION}"
+echo "Using libenchant version : ${ENCHANT_VERSION}"
echo ""
echo "Configuration is done OK."
echo ""
Modified: trunk/spellcheck/src/Makefile.am
===================================================================
--- trunk/spellcheck/src/Makefile.am 2008-06-19 21:20:36 UTC (rev 73)
+++ trunk/spellcheck/src/Makefile.am 2008-06-19 21:34:52 UTC (rev 74)
@@ -2,6 +2,6 @@
lib_LTLIBRARIES = spellcheck.la
spellcheck_la_SOURCES = spellcheck.c
spellcheck_la_LDFLAGS = -module -avoid-version
-spellcheck_la_LIBADD = @GEANY_LIBS@ $(INTLLIBS) @SPELLER_LIB@
+spellcheck_la_LIBADD = @GEANY_LIBS@ $(INTLLIBS) @ENCHANT_LIBS@
-AM_CFLAGS = @GEANY_CFLAGS@ -DLOCALEDIR=\""$(localedir)"\"
+AM_CFLAGS = @GEANY_CFLAGS@ @ENCHANT_CFLAGS@ -DLOCALEDIR=\""$(localedir)"\"
Modified: trunk/spellcheck/src/spellcheck.c
===================================================================
--- trunk/spellcheck/src/spellcheck.c 2008-06-19 21:20:36 UTC (rev 73)
+++ trunk/spellcheck/src/spellcheck.c 2008-06-19 21:34:52 UTC (rev 74)
@@ -35,7 +35,7 @@
#endif
#include <string.h>
-#include <aspell.h>
+#include <enchant.h>
#include "plugindata.h"
@@ -54,11 +54,24 @@
GeanyFunctions *geany_functions;
-PLUGIN_VERSION_CHECK(67)
+PLUGIN_VERSION_CHECK(71)
PLUGIN_SET_INFO(_("Spell Check"), _("Checks the spelling of the current document."), "0.2",
_("The Geany developer team"))
+typedef struct
+{
+ gchar *config_file;
+ gchar *default_language;
+ gboolean check_while_typing;
+ gulong signal_id;
+ GPtrArray *dicts;
+ EnchantBroker *broker;
+ EnchantDict *dict;
+} SpellCheck;
+static SpellCheck *sc;
+
+
/* Keybinding(s) */
enum
{
@@ -67,183 +80,260 @@
};
PLUGIN_KEY_GROUP(spellcheck, KB_COUNT)
-static gchar *config_file;
-static gchar *language;
+/* currently unused */
+#ifdef G_OS_WIN32
+#warning TODO check Windows support
/* On Windows we need to find the Aspell installation prefix via the Windows Registry
* and then set the prefix in the Aspell config object. */
static void set_up_aspell_prefix(AspellConfig *config)
{
-#ifdef G_OS_WIN32
char sTemp[1024];
HKEY hkey;
DWORD len = sizeof(sTemp);
-
+
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Aspell"), 0,
KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS)
return;
-
+
if (RegQueryValueEx(hkey, NULL, 0, NULL, (LPBYTE)sTemp, &len) == ERROR_SUCCESS)
aspell_config_replace(config, "prefix", sTemp);
RegCloseKey(hkey);
+}
#endif
+
+
+static void dict_describe(const gchar* const lang, const gchar* const name,
+ const gchar* const desc, const gchar* const file, void *target)
+{
+ gchar **result = (gchar**) target;
+ *result = g_strdup_printf("\"%s\" (%s)", lang, name);
}
-static void print_word_list(AspellSpeller *speller, GString *str, const AspellWordList *wl)
+static gint check_word(GeanyDocument *doc, gint line_number, GString *str, gint end_pos)
{
- if (wl == NULL)
+ gsize j;
+ gsize n_suggs = 0;
+ gchar **suggs;
+ gchar *word;
+
+ /* early out if the word is spelled correctly */
+ if (enchant_dict_check(sc->dict, str->str, -1) == 0)
+ return 0;
+
+ word = g_strdup(str->str);
+ g_string_erase(str, 0, str->len);
+ suggs = enchant_dict_suggest(sc->dict, word, -1, &n_suggs);
+
+ if (suggs != NULL)
{
- g_string_append_c(str, '?');
- }
- else
- {
- AspellStringEnumeration *els = aspell_word_list_elements(wl);
- const char *word;
+ g_string_append_printf(str, "line %d: %s | ", line_number + 1, word);
- while ((word = aspell_string_enumeration_next(els)) != 0)
+ g_string_append(str, _("Try: "));
+
+ /* Now find the misspellings in the line, limit suggestions to a maximum of 15 (for now) */
+ for (j = 0; j < MIN(n_suggs, 15); j++)
{
- g_string_append(str, word);
+ g_string_append(str, suggs[j]);
g_string_append_c(str, ' ');
}
- delete_aspell_string_enumeration(els);
+
+ p_editor->set_indicator(doc, end_pos - strlen(word), end_pos);
+ p_msgwindow->msg_add(COLOR_RED, line_number + 1, doc, "%s", str->str);
+
+ if (suggs != NULL && n_suggs)
+ enchant_dict_free_string_list(sc->dict, suggs);
}
+ g_free(word);
+
+ return n_suggs;
}
-static gint check_document(AspellSpeller *speller, gint idx)
+static gint process_line(GeanyDocument *doc, gint line_number, const gchar *line)
{
- AspellCanHaveError *ret;
- AspellDocumentChecker *checker;
- AspellToken token;
- gchar *word_begin;
+ gint end_pos, char_len;
+ gunichar c;
+ GString *str = g_string_sized_new(256);
+ gint suggestions_found = 0;
+
+ end_pos = p_sci->get_position_from_line(doc->sci, line_number);
+ /* split line into words */
+ while ((c = g_utf8_get_char_validated(line, -1)) != (gunichar) -1 && c != 0)
+ {
+ if (g_unichar_isalpha(c) || c == '\'')
+ {
+ /* part of a word */
+ g_string_append_unichar(str, c);
+ }
+ else if (str->len > 0)
+ {
+ g_string_append_c(str, '\0');
+ suggestions_found += check_word(doc, line_number, str, end_pos);
+ g_string_erase(str, 0, str->len);
+ }
+
+ /* calculate byte len of c and add skip these in line */
+ char_len = g_unichar_to_utf8(c, NULL);
+ line += char_len;
+ end_pos += char_len;
+ }
+ g_string_free(str, TRUE);
+
+ return suggestions_found;
+}
+
+
+static void check_document(GeanyDocument *doc)
+{
gchar *line;
- gint linewidth;
gint i;
gint first_line, last_line;
- gboolean suggestions_found = FALSE;
- GString *str = g_string_sized_new(1024);
+ gchar *dict_string = NULL;
+ gint suggestions_found = 0;
- if (! DOC_IDX_VALID(idx))
- return 1;
+ enchant_dict_describe(sc->dict, dict_describe, &dict_string);
- str = g_string_sized_new(1024);
- if (p_sci->can_copy(documents[idx]->sci))
+ if (p_sci->can_copy(doc->sci))
{
- first_line = p_sci->get_line_from_position(
- documents[idx]->sci, p_sci->get_selection_start(documents[idx]->sci));
- last_line = p_sci->get_line_from_position(
- documents[idx]->sci, p_sci->get_selection_end(documents[idx]->sci));
+ first_line = p_sci->get_line_from_position(doc->sci, p_sci->get_selection_start(doc->sci));
+ last_line = p_sci->get_line_from_position(doc->sci, p_sci->get_selection_end(doc->sci));
- p_msgwindow->msg_add(COLOR_BLUE, -1, -1,
- _("Checking file \"%s\" (lines %d to %d):"),
- DOC_FILENAME(idx), first_line + 1, last_line + 1);
+ p_msgwindow->msg_add(COLOR_BLUE, -1, NULL,
+ _("Checking file \"%s\" (lines %d to %d using %s):"),
+ DOC_FILENAME(doc), first_line + 1, last_line + 1, dict_string);
}
else
{
first_line = 0;
- last_line = p_sci->get_line_count(documents[idx]->sci);
- p_msgwindow->msg_add(COLOR_BLUE, -1, -1, _("Checking file \"%s\":"),
- DOC_FILENAME(idx));
+ last_line = p_sci->get_line_count(doc->sci);
+ p_msgwindow->msg_add(COLOR_BLUE, -1, NULL, _("Checking file \"%s\" (using %s):"),
+ DOC_FILENAME(doc), dict_string);
}
+ g_free(dict_string);
- /* Set up the document checker */
- ret = new_aspell_document_checker(speller);
- if (aspell_error(ret) != 0)
+ for (i = first_line; i < last_line; i++)
{
- g_warning("spellcheck: %s", aspell_error_message(ret));
- return 4;
- }
+ line = p_sci->get_line(doc->sci, i);
- checker = to_aspell_document_checker(ret);
+ suggestions_found += process_line(doc, i, line);
- for (i = first_line; i < last_line; i++)
- {
- line = p_sci->get_line(documents[idx]->sci, i);
- linewidth = strlen(line);
+ g_free(line);
+ }
- /* First process the line */
- aspell_document_checker_process(checker, line, -1);
+ if (suggestions_found == 0)
+ p_msgwindow->msg_add(COLOR_BLUE, -1, NULL, _("The checked text is spelled correctly."));
+}
- /* Now find the misspellings in the line */
- while (token = aspell_document_checker_next_misspelling(checker), token.len != 0)
- {
- p_editor->set_indicator_on_line(idx, i);
- /* Print out the misspelling and possible replacements */
- word_begin = line + token.offset;
- g_string_append_printf (str, "line %d: ", i + 1);
- g_string_append_len(str, word_begin, token.len);
+static void broker_init_failed()
+{
+ const gchar *err = enchant_broker_get_error(sc->broker);
+ p_dialogs->show_msgbox(GTK_MESSAGE_ERROR,
+ _("The Enchant library couldn't be initialized (%s)."),
+ (err != NULL) ? err : _("unknown error"));
+}
- g_string_append(str, " | ");
- g_string_append(str, _("Try: "));
- print_word_list(speller, str, aspell_speller_suggest(speller, word_begin, token.len));
- p_msgwindow->msg_add(COLOR_RED, i + 1, idx, "%s", str->str);
- g_string_erase(str, 0, str->len);
- suggestions_found = TRUE;
- }
+static void perform_check(GeanyDocument *doc)
+{
+ p_editor->clear_indicators(doc);
+ p_msgwindow->clear_tab(MSG_MESSAGE);
+ p_msgwindow->switch_tab(MSG_MESSAGE, FALSE);
- g_free(line);
- }
+ check_document(doc);
+}
- delete_aspell_document_checker(checker);
- g_string_free(str, TRUE);
+static void clear_indicators_on_line(GeanyDocument *doc, gint line_number)
+{
+ glong start_pos, length;
- if (! suggestions_found)
- p_msgwindow->msg_add(COLOR_BLUE, -1, -1, _("The checked text is spelled correctly."));
+ g_return_if_fail(doc != NULL);
- return 0;
+ start_pos = p_sci->get_position_from_line(doc->sci, line_number);
+ length = p_sci->get_line_length(doc->sci, line_number);
+ if (length > 0)
+ {
+ p_sci->send_message(doc->sci, SCI_STARTSTYLING, start_pos, INDIC2_MASK);
+ p_sci->send_message(doc->sci, SCI_SETSTYLING, length, 0);
+ }
}
-static void perform_check(gint idx)
+/* Checks only the last word before the current cursor position -> check as you type. */
+static gboolean on_key_release(GtkWidget *widget, GdkEventKey *ev, gpointer user_data)
{
- AspellCanHaveError *ret;
- AspellSpeller *speller;
- AspellConfig *config;
+ gint line_number;
+ GString *str = g_string_sized_new(256);
+ gchar *line;
+ GeanyDocument *doc;
+ static time_t time_prev = 0;
+ time_t time_now = time(NULL);
- if (! DOC_IDX_VALID(idx))
- return;
+ if (! sc->check_while_typing)
+ return FALSE;
+ /* check only once a second */
+ if (time_now == time_prev)
+ return FALSE;
+ /* set current time for the next key press */
+ time_prev = time_now;
- p_editor->clear_indicators(idx);
- p_msgwindow->clear_tab(MSG_MESSAGE);
- p_msgwindow->switch_tab(MSG_MESSAGE, FALSE);
+ doc = p_document->get_current();
+ if (doc == NULL)
+ return FALSE;
- config = new_aspell_config();
- aspell_config_replace(config, "lang", language);
- aspell_config_replace(config, "encoding", "utf-8");
- set_up_aspell_prefix(config);
+ if (ev->keyval == '\r' &&
+ p_sci->send_message(doc->sci, SCI_GETEOLMODE, 0, 0) == SC_EOL_CRLF)
+ { /* prevent double line checking */
+ return FALSE;
+ }
- ret = new_aspell_speller(config);
- delete_aspell_config(config);
- if (aspell_error(ret) != 0)
+ line_number = p_sci->get_current_line(doc->sci);
+ if (ev->keyval == '\n' || ev->keyval == '\r')
+ line_number--; /* check previous line if we start a new one */
+ line = p_sci->get_line(doc->sci, line_number);
+
+ clear_indicators_on_line(doc, line_number);
+ if (process_line(doc, line_number, line) != 0)
{
- delete_aspell_can_have_error(ret);
- return;
+ p_msgwindow->switch_tab(MSG_MESSAGE, FALSE);
}
- speller = to_aspell_speller(ret);
- check_document(speller, idx);
- delete_aspell_speller(speller);
+ g_string_free(str, TRUE);
+ g_free(line);
+
+ return FALSE;
}
-static void
-item_activate(GtkMenuItem *menuitem, gpointer gdata)
+static void on_menu_item_activate(GtkMenuItem *menuitem, gpointer gdata)
{
- gint idx = p_document->get_cur_idx();
+ GeanyDocument *doc = p_document->get_current();
- perform_check(idx);
+ /* Another language was chosen from the menu item, so make it default for this session. */
+ if (gdata != NULL)
+ setptr(sc->default_language, g_strdup(gdata));
+
+ /* Request new dict object */
+ enchant_broker_free_dict(sc->broker, sc->dict);
+ sc->dict = enchant_broker_request_dict(sc->broker, sc->default_language);
+ if (sc->dict == NULL)
+ {
+ broker_init_failed();
+ return;
+ }
+
+ perform_check(doc);
}
static void kb_activate(guint key_id)
{
- item_activate(NULL, NULL);
+ on_menu_item_activate(NULL, NULL);
}
@@ -259,7 +349,7 @@
#ifdef G_OS_WIN32
gchar *install_dir = g_win32_get_package_installation_directory("geany", NULL);
/* e.g. C:\Program Files\geany\lib\locale */
- locale_dir = g_strconcat(install_dir, "\\lib\\locale", NULL);
+ locale_dir = g_strconcat(install_dir, "\\share\\locale", NULL);
g_free(install_dir);
#else
locale_dir = g_strdup(LOCALEDIR);
@@ -285,34 +375,34 @@
}
else
lang = "en";
-
+
return lang;
}
-static void fill_dicts_combo(GtkComboBox *combo)
+static void 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)
{
- AspellConfig *config;
- AspellDictInfoList *dlist;
- AspellDictInfoEnumeration *dels;
- const AspellDictInfo *entry;
- guint i = 0;
+ guint i;
+ gchar *result = g_strdup(lang_tag);
- config = new_aspell_config();
- set_up_aspell_prefix(config);
- dlist = get_aspell_dict_info_list(config);
- delete_aspell_config(config);
+ /* sometimes dictionaries are named lang-LOCALE instead of lang_LOCALE, so replace the
+ * hyphen by a dash, enchant seems to not care about it. */
+ for (i = 0; i < strlen(result); i++)
+ {
+ if (result[i] == '-')
+ result[i] = '_';
+ }
- dels = aspell_dict_info_list_elements(dlist);
- while ((entry = aspell_dict_info_enumeration_next(dels)) != 0)
+ /* find duplicates and skip them */
+ for (i = 0; i < sc->dicts->len; i++)
{
- gtk_combo_box_append_text(combo, entry->name);
+ if (p_utils->str_equal(g_ptr_array_index(sc->dicts, i), result))
+ return;
+ }
- if (p_utils->str_equal(entry->name, language))
- gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i);
- i++;
- }
- delete_aspell_dict_info_enumeration(dels);
+ g_ptr_array_add(sc->dicts, result);
}
@@ -322,14 +412,18 @@
{
GKeyFile *config = g_key_file_new();
gchar *data;
- gchar *config_dir = g_path_get_dirname(config_file);
+ gchar *config_dir = g_path_get_dirname(sc->config_file);
- setptr(language, gtk_combo_box_get_active_text(GTK_COMBO_BOX(
+ setptr(sc->default_language, gtk_combo_box_get_active_text(GTK_COMBO_BOX(
g_object_get_data(G_OBJECT(dialog), "combo"))));
- g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL);
- g_key_file_set_string(config, "spellcheck", "language", language);
+ sc->check_while_typing = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ g_object_get_data(G_OBJECT(dialog), "check"))));
+ g_key_file_load_from_file(config, sc->config_file, G_KEY_FILE_NONE, NULL);
+ g_key_file_set_string(config, "spellcheck", "language", sc->default_language);
+ g_key_file_set_boolean(config, "spellcheck", "check_while_typing", sc->check_while_typing);
+
if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && p_utils->mkdir(config_dir, TRUE) != 0)
{
p_dialogs->show_msgbox(GTK_MESSAGE_ERROR,
@@ -339,7 +433,7 @@
{
/* write config to file */
data = g_key_file_to_data(config, NULL, NULL);
- p_utils->write_file(config_file, data);
+ p_utils->write_file(sc->config_file, data);
g_free(data);
}
g_free(config_dir);
@@ -348,28 +442,92 @@
}
+static gint sort_dicts(gconstpointer a, gconstpointer b)
+{ /* casting mania ;-) */
+ return strcmp((gchar*)((GPtrArray*)a)->pdata, (gchar*)((GPtrArray*)b)->pdata);
+}
+
+
+static void create_dicts_array()
+{
+ sc->dicts = g_ptr_array_new();
+
+ enchant_broker_list_dicts(sc->broker, add_dict_array, sc->dicts);
+
+ g_ptr_array_sort(sc->dicts, sort_dicts);
+}
+
+
+static GtkWidget *create_menu()
+{
+ GtkWidget *sp_item, *menu, *subitem;
+ guint i;
+
+ sp_item = gtk_menu_item_new_with_mnemonic(_("_Spell Check"));
+ gtk_container_add(GTK_CONTAINER(main_widgets->tools_menu), sp_item);
+
+ menu = gtk_menu_new();
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(sp_item), menu);
+
+ subitem = gtk_menu_item_new_with_mnemonic(_("Default"));
+ gtk_container_add(GTK_CONTAINER(menu), subitem);
+ g_signal_connect((gpointer) subitem, "activate", G_CALLBACK(on_menu_item_activate), NULL);
+
+ subitem = gtk_separator_menu_item_new();
+ gtk_container_add(GTK_CONTAINER(menu), subitem);
+
+ for (i = 0; i < sc->dicts->len; i++)
+ {
+ GtkWidget *menu_item;
+
+ menu_item = gtk_menu_item_new_with_label(g_ptr_array_index(sc->dicts, i));
+ gtk_container_add(GTK_CONTAINER(menu), menu_item);
+ g_signal_connect((gpointer) menu_item, "activate",
+ G_CALLBACK(on_menu_item_activate), g_ptr_array_index(sc->dicts, i));
+ }
+
+ return sp_item;
+}
+
+
void plugin_init(GeanyData *data)
{
GtkWidget *sp_item;
GKeyFile *config = g_key_file_new();
- config_file = g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "plugins", G_DIR_SEPARATOR_S,
+ sc = g_new0(SpellCheck, 1);
+
+ sc->config_file = g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "plugins", G_DIR_SEPARATOR_S,
"spellcheck", G_DIR_SEPARATOR_S, "spellcheck.conf", NULL);
- g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL);
- language = p_utils->get_setting_string(config, "spellcheck", "language", get_default_lang());
+ g_key_file_load_from_file(config, sc->config_file, G_KEY_FILE_NONE, NULL);
+ sc->default_language = p_utils->get_setting_string(config,
+ "spellcheck", "language", get_default_lang());
+ sc->check_while_typing = p_utils->get_setting_boolean(config,
+ "spellcheck", "check_while_typing", FALSE);
g_key_file_free(config);
locale_init();
- sp_item = gtk_menu_item_new_with_mnemonic(_("_Spell Check"));
- gtk_widget_show(sp_item);
- gtk_container_add(GTK_CONTAINER(main_widgets->tools_menu), sp_item);
- g_signal_connect(G_OBJECT(sp_item), "activate", G_CALLBACK(item_activate), NULL);
+ sc->broker = enchant_broker_init();
+ sc->dict = enchant_broker_request_dict(sc->broker, sc->default_language);
+ if (sc->dict == NULL)
+ {
+ broker_init_failed();
+ return;
+ }
+ create_dicts_array();
+
+ sp_item = create_menu();
+ gtk_widget_show_all(sp_item);
+
plugin_fields->menu_item = sp_item;
plugin_fields->flags = PLUGIN_IS_DOCUMENT_SENSITIVE;
+ sc->signal_id = g_signal_connect(main_widgets->window,
+ "key-release-event", G_CALLBACK(on_key_release), NULL);
+
/* setup keybindings */
p_keybindings->set_item(plugin_key_group, KB_SPELL_CHECK, kb_activate,
0, 0, "spell_check", _("Run Spell Check"), NULL);
@@ -378,7 +536,8 @@
GtkWidget *plugin_configure(GtkDialog *dialog)
{
- GtkWidget *label, *vbox, *combo;
+ GtkWidget *label, *vbox, *combo, *check;
+ guint i;
vbox = gtk_vbox_new(FALSE, 6);
@@ -387,12 +546,27 @@
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
combo = gtk_combo_box_new_text();
- fill_dicts_combo(GTK_COMBO_BOX(combo));
- gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(combo), 3);
+ for (i = 0; i < sc->dicts->len; i++)
+ {
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combo), g_ptr_array_index(sc->dicts, i));
+
+ if (p_utils->str_equal(g_ptr_array_index(sc->dicts, i), sc->default_language))
+ gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i);
+ }
+
+ if (sc->dicts->len > 20)
+ gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(combo), 3);
+ else if (sc->dicts->len > 10)
+ gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(combo), 2);
gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0);
+ check = gtk_check_button_new_with_label(_("Check spelling while typing"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), sc->check_while_typing);
+ gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0);
+
g_object_set_data(G_OBJECT(dialog), "combo", combo);
+ g_object_set_data(G_OBJECT(dialog), "check", check);
g_signal_connect(dialog, "response", G_CALLBACK(on_configure_response), NULL);
gtk_widget_show_all(vbox);
@@ -403,7 +577,20 @@
void plugin_cleanup(void)
{
- g_free(language);
- g_free(config_file);
+ guint i;
+ for (i = 0; i < sc->dicts->len; i++)
+ {
+ g_free(g_ptr_array_index(sc->dicts, i));
+ }
+ g_ptr_array_free(sc->dicts, TRUE);
+
+ g_signal_handler_disconnect(main_widgets->window, sc->signal_id);
+
+ enchant_broker_free_dict(sc->broker, sc->dict);
+ enchant_broker_free(sc->broker);
+
+ g_free(sc->default_language);
+ g_free(sc->config_file);
+ g_free(sc);
gtk_widget_destroy(plugin_fields->menu_item);
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the Plugins-Commits
mailing list