soc.2008.finch: 93ec1e7f: Added spell checking support to GntEntry...

queueram at soc.pidgin.im queueram at soc.pidgin.im
Sun Jun 1 20:01:09 EDT 2008


-----------------------------------------------------------------
Revision: 93ec1e7fbb0cac754ce4524688069369e4afb5a0
Ancestor: 4604a1b4f5a0af87939613abf115bb25b4a7c97f
Author: queueram at soc.pidgin.im
Date: 2008-06-01T23:55:59
Branch: im.pidgin.soc.2008.finch
URL: http://d.pidgin.im/viewmtn/revision/info/93ec1e7fbb0cac754ce4524688069369e4afb5a0

Modified files:
        finch/libgnt/gntentry.c finch/libgnt/gntentry.h

ChangeLog: 

Added spell checking support to GntEntry using Enchant.
Note: need to pull #define USE_ENCHANT into configure.ac

-------------- next part --------------
============================================================
--- finch/libgnt/gntentry.c	d10788925442d949ed37c71dcfe1ea114c70c0d1
+++ finch/libgnt/gntentry.c	2a7faafbed24ce6dee19090a192190f6d424ba12
@@ -30,6 +30,10 @@
 #include "gnttree.h"
 #include "gntutils.h"
 
+#ifdef USE_ENCHANT
+#include <enchant/enchant.h>
+#endif
+
 enum
 {
 	SIG_TEXT_CHANGED,
@@ -54,6 +58,15 @@ struct _GntEntryKillRing
 	GntEntryAction last;
 };
 
+/* XXX: put #ifdef around the struct? */
+struct _GntEntryEnchant
+{
+#ifdef USE_ENCHANT
+	EnchantBroker *broker;
+	EnchantDict *dict;
+#endif
+};
+
 static guint signals[SIGS] = { 0 };
 
 static GntWidgetClass *parent_class = NULL;
@@ -265,6 +278,85 @@ show_suggest_dropdown(GntEntry *entry)
 	return TRUE;
 }
 
+#ifdef USE_ENCHANT
+/* copy of get_beginning_of_word, but not GntEntry specific
+ * TODO: refactor with get_beginning_of_word
+ */
+static char *
+get_beginning_of_prev_word(char *here, char *start)
+{
+	char *s = here;
+	while (s > start)
+	{
+		char *t = g_utf8_find_prev_char(start, s);
+		if (g_unichar_isspace(*t) || g_unichar_ispunct(*t))
+			break;
+		s = t;
+	}
+	return s;
+}
+
+static char *
+get_beginning_of_next_word(char *here, char *end)
+{
+	char *s = here;
+	char *t;
+	gboolean got_space;
+
+	got_space = g_unichar_isspace(*s) || g_unichar_ispunct(*s);
+	while (s < end && !got_space) {
+		t = g_utf8_find_next_char(s, end);
+		if (g_unichar_isspace(*t) || g_unichar_ispunct(*t))
+			got_space = TRUE;
+		s = t;
+	}
+	if(got_space) {
+		while (s < end) {
+			t = g_utf8_find_next_char(s, end);
+			s = t;
+			if(!t)
+				break;
+			if (!g_unichar_isspace(*t) && !g_unichar_ispunct(*t))
+				break;
+		}
+	} else {
+		s = NULL;
+	}
+	return s;
+}
+
+static char *
+get_end_of_word(char *here, char *end)
+{
+	char *s = here;
+	char *t;
+
+	while (s < end) {
+		t = g_utf8_find_next_char(s, end);
+		if (!t || g_unichar_isspace(*t) || g_unichar_ispunct(*t))
+			break;
+		s = t;
+	}
+	return s;
+}
+
+static gboolean
+check_word(GntEntry *entry, char *start, char *end) {
+	gboolean retval = TRUE;
+
+	if (!entry->enchant->dict)
+		return FALSE;
+
+	if (g_unichar_isdigit(*start) == FALSE) { /* don't check numbers */
+		if (enchant_dict_check(entry->enchant->dict, start, end - start + 1) != 0) {
+			retval = FALSE;
+		}
+	}
+
+	return retval;
+}
+#endif
+
 static void
 gnt_entry_draw(GntWidget *widget)
 {
@@ -282,9 +374,86 @@ gnt_entry_draw(GntWidget *widget)
 		mvwhline(widget->window, 0, 0, gnt_ascii_only() ? '*' : ACS_BULLET,
 				g_utf8_pointer_to_offset(entry->scroll, entry->end));
 	}
-	else
+	else {
+#ifdef USE_ENCHANT
+		/* TODO: maybe want to move this to a different location and use some
+		 * sort of tags to indicate areas of misspellings and then print the tags
+		 * out here so the spellchecking isn't always performed for each word on
+		 * a gnt_entry_draw */
+		char *s, *e;
+		char *str;
+		/* don't try anything if the box is empty */
+		if(entry->start != entry->end) {
+			wmove(widget->window, 0, 0);
+			/* if scroll starts on a non-letter, find the next word */
+			if(g_unichar_isspace(*entry->scroll) || g_unichar_ispunct(*entry->scroll)) {
+				s = get_beginning_of_next_word(entry->scroll, entry->end);
+				if(!s) {
+					s = entry->end;
+				}
+				str = g_strndup(entry->scroll, s - entry->scroll);
+				waddstr(widget->window, str);
+				g_free(str);
+			} else {
+				s = get_beginning_of_prev_word(entry->scroll, entry->start);
+			}
+			e = get_end_of_word(s, entry->end);
+
+			/* TODO: pick better attribute for misspelled words */
+			if(!check_word(entry, s, e)) {
+				wattron(widget->window, A_REVERSE);
+			} else {
+				wattroff(widget->window, A_REVERSE);
+			}
+			/* first word might be special case if scroll is in middle of word */
+			if(s < entry->scroll) {
+				str = g_strndup(entry->scroll, e - entry->scroll + 1);
+			} else {
+				str = g_strndup(s, e - s + 1);
+			}
+			waddstr(widget->window, str);
+			g_free(str);
+
+			s = g_utf8_find_next_char(e, entry->end);
+			while(s) {
+				/* print the whitespace and punctuation characters */
+				wattroff(widget->window, A_REVERSE);
+				e = get_beginning_of_next_word(s, entry->end);
+				if(!e && s < entry->end) {
+					/* the end is all non-letter characters */
+					str = g_strndup(s, entry->end - s + 1);
+					waddstr(widget->window, str);
+					g_free(str);
+					break;
+				} else if (e) {
+					/* there are more words */
+					str = g_strndup(s, e - s);
+					waddstr(widget->window, str);
+					g_free(str);
+					s = e;
+					e = get_end_of_word(s, entry->end);
+
+					/* TODO: pick better attribute for misspelled words */
+					if(!check_word(entry, s, e)) {
+						wattron(widget->window, A_REVERSE);
+					} else {
+						wattroff(widget->window, A_REVERSE);
+					}
+					str = g_strndup(s, e - s + 1);
+					waddstr(widget->window, str);
+					g_free(str);
+					s = g_utf8_find_next_char(e, entry->end);
+				} else {
+					break;
+				}
+			}
+		}
+#else
 		mvwprintw(widget->window, 0, 0, "%s", entry->scroll);
+#endif
+	}
 
+	wattroff(widget->window, A_REVERSE);
 	stop = gnt_util_onscreen_width(entry->scroll, entry->end);
 	if (stop < widget->priv.width)
 		mvwhline(widget->window, 0, stop, ENTRY_CHAR, widget->priv.width - stop);
@@ -944,6 +1113,46 @@ new_killring(void)
 	return kr;
 }
 
+static GntEntryEnchant *
+new_enchant(void)
+{
+	GntEntryEnchant *e = NULL;
+#ifdef USE_ENCHANT
+    const char *err;
+	const char *lang;
+
+	e = g_new0(GntEntryEnchant, 1);
+	e->broker = enchant_broker_init();
+	if (e->broker == NULL) {
+		g_warning("GntEntry: error enchant_broker_init()\n");
+	} else {
+		lang = g_getenv("LANG");
+		if (lang) {
+			if (g_strncasecmp(lang, "C", 1) == 0)
+				lang = NULL;
+			else if (lang[0] == 0)
+				lang = NULL;
+		}
+
+		if (!lang) {
+			lang = "en";
+		}
+
+		e->dict = enchant_broker_request_dict(e->broker, lang);
+
+		if (e->dict == NULL) {
+			err = enchant_broker_get_error(e->broker);
+			if(err != NULL) {
+				g_warning("GntEntry: couldn't get dictionary for %s: %s\n", lang, err);
+			} else {
+				g_warning("GntEntry: couldn't get dictionary for %s\n", lang);
+			}
+		}
+	}
+#endif
+	return e;
+}
+
 static void
 gnt_entry_init(GTypeInstance *instance, gpointer class)
 {
@@ -960,6 +1169,7 @@ gnt_entry_init(GTypeInstance *instance, 
 	entry->always = FALSE;
 	entry->suggests = NULL;
 	entry->killring = new_killring();
+	entry->enchant = new_enchant();
 
 	GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry),
 			GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW | GNT_WIDGET_CAN_TAKE_FOCUS);
============================================================
--- finch/libgnt/gntentry.h	4be38f89219eec94a088a7993c20eafaf2ae46ae
+++ finch/libgnt/gntentry.h	bf6fe730cfed94c9f43cc128893e56cf88dd6402
@@ -45,10 +45,14 @@
 
 #define	ENTRY_CHAR		'_'			/* The character to use to fill in the blank places */
 
+/* XXX: HACK */
+#define USE_ENCHANT
+
 typedef struct _GntEntry			GntEntry;
 typedef struct _GntEntryPriv		GntEntryPriv;
 typedef struct _GntEntryClass	GntEntryClass;
 typedef struct _GntEntryKillRing    GntEntryKillRing;
+typedef struct _GntEntryEnchant	GntEntryEnchant;
 
 typedef enum
 {
@@ -86,6 +90,9 @@ struct _GntEntry
 	gboolean always;    /* Should the list of suggestions show at all times, or only on tab-press? */
 	GntWidget *ddown;   /* The dropdown with the suggested list */
 	GntEntryKillRing *killring; /**< @since 2.3.0 */
+#ifdef USE_ENCHANT
+	GntEntryEnchant *enchant; /**< holds Enchant info for spell checking */
+#endif
 };
 
 struct _GntEntryClass


More information about the Commits mailing list