⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spellchk.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Purple - Replace certain misspelled words with their correct form. * * Signification changes were made by Benjamin Kahn ("xkahn") and * Richard Laager ("rlaager") in April 2005--you may want to contact * them if you have questions. * * Pidgin is the legal property of its developers, whose names are too numerous * to list here.  Please refer to the COPYRIGHT file distributed with this * source distribution. * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * *//* * A lot of this code (especially the config code) was taken directly * or nearly directly from xchat, version 1.4.2 by Peter Zelezny and others. */#include "internal.h"#include "pidgin.h"#include "debug.h"#include "notify.h"#include "signals.h"#include "util.h"#include "version.h"#include "gtkplugin.h"#include "gtkprefs.h"#include "gtkutils.h"#include <stdio.h>#include <string.h>#ifndef _WIN32#include <strings.h>#endif#include <sys/types.h>#include <sys/stat.h>#define SPELLCHECK_PLUGIN_ID "gtk-spellcheck"#define SPELLCHK_OBJECT_KEY "spellchk"enum {	BAD_COLUMN,	GOOD_COLUMN,	WORD_ONLY_COLUMN,	CASE_SENSITIVE_COLUMN,	N_COLUMNS};struct _spellchk {	GtkTextView *view;	GtkTextMark *mark_insert_start;	GtkTextMark *mark_insert_end;	const gchar *word;	gboolean inserting;	gboolean ignore_correction;	gboolean ignore_correction_on_send;	gint pos;};typedef struct _spellchk spellchk;static GtkListStore *model;static gbooleanis_word_uppercase(const gchar *word){	for (; word[0] != '\0'; word = g_utf8_find_next_char (word, NULL)) {		gunichar c = g_utf8_get_char(word);		if (!(g_unichar_isupper(c) ||		      g_unichar_ispunct(c) ||		      g_unichar_isspace(c)))			return FALSE;	}	return TRUE;}static gbooleanis_word_lowercase(const gchar *word){	for (; word[0] != '\0'; word = g_utf8_find_next_char(word, NULL)) {		gunichar c = g_utf8_get_char(word);		if (!(g_unichar_islower(c) ||		      g_unichar_ispunct(c) ||		      g_unichar_isspace(c)))			return FALSE;	}	return TRUE;}static gbooleanis_word_proper(const gchar *word){	if (word[0] == '\0')		return FALSE;	if (!g_unichar_isupper(g_utf8_get_char_validated(word, -1)))		return FALSE;	return is_word_lowercase(g_utf8_offset_to_pointer(word, 1));}static gchar *make_word_proper(const gchar *word){	char buf[7];	gchar *lower = g_utf8_strdown(word, -1);	gint bytes;	gchar *ret;	bytes = g_unichar_to_utf8(g_unichar_toupper(g_utf8_get_char(word)), buf);	buf[MIN(bytes, sizeof(buf) - 1)] = '\0';	ret = g_strconcat(buf, g_utf8_offset_to_pointer(lower, 1), NULL);	g_free(lower);	return ret;}static gbooleansubstitute_simple_buffer(GtkTextBuffer *buffer){	GtkTextIter start;	GtkTextIter end;	GtkTreeIter treeiter;	gchar *text = NULL;	gtk_text_buffer_get_iter_at_offset(buffer, &start, 0);	gtk_text_buffer_get_iter_at_offset(buffer, &end, 0);	gtk_text_iter_forward_to_end(&end);	text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &treeiter) && text) {		do {			GValue val1;			const gchar *bad;			gchar *cursor;			glong char_pos;			val1.g_type = 0;			gtk_tree_model_get_value(GTK_TREE_MODEL(model), &treeiter, WORD_ONLY_COLUMN, &val1);			if (g_value_get_boolean(&val1))			{				g_value_unset(&val1);				continue;			}			g_value_unset(&val1);			gtk_tree_model_get_value(GTK_TREE_MODEL(model), &treeiter, BAD_COLUMN, &val1);			bad = g_value_get_string(&val1);			/* using g_utf8_* to get /character/ offsets instead of byte offsets for buffer */			if ((cursor = g_strrstr(text, bad)))			{				GValue val2;				const gchar *good;				val2.g_type = 0;				gtk_tree_model_get_value(GTK_TREE_MODEL(model), &treeiter, GOOD_COLUMN, &val2);				good = g_value_get_string(&val2);				char_pos = g_utf8_pointer_to_offset(text, cursor);				gtk_text_buffer_get_iter_at_offset(buffer, &start, char_pos);				gtk_text_buffer_get_iter_at_offset(buffer, &end, char_pos + g_utf8_strlen(bad, -1));				gtk_text_buffer_delete(buffer, &start, &end);				gtk_text_buffer_get_iter_at_offset(buffer, &start, char_pos);				gtk_text_buffer_insert(buffer, &start, good, -1);				g_value_unset(&val2);				g_free(text);				g_value_unset(&val1);				return TRUE;			}			g_value_unset(&val1);		} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &treeiter));	}	g_free(text);	return FALSE;}static gchar *substitute_word(gchar *word){	GtkTreeIter iter;	gchar *outword;	gchar *lowerword;	gchar *foldedword;	if (word == NULL)		return NULL;	lowerword = g_utf8_strdown(word, -1);	foldedword = g_utf8_casefold(word, -1);	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) {		do {			GValue val1;			gboolean case_sensitive;			const char *bad;			gchar *tmpbad = NULL;			val1.g_type = 0;			gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, WORD_ONLY_COLUMN, &val1);			if (!g_value_get_boolean(&val1)) {				g_value_unset(&val1);				continue;			}			g_value_unset(&val1);			gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, CASE_SENSITIVE_COLUMN, &val1);			case_sensitive = g_value_get_boolean(&val1);			g_value_unset(&val1);			gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, BAD_COLUMN, &val1);			bad = g_value_get_string(&val1);			if ((case_sensitive && !strcmp(bad, word)) ||			    (!case_sensitive && (!strcmp(bad, lowerword) ||			                        (!is_word_lowercase(bad) &&			                         !strcmp((tmpbad = g_utf8_casefold(bad, -1)), foldedword)))))			{				GValue val2;				const char *good;				g_free(tmpbad);				val2.g_type = 0;				gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, GOOD_COLUMN, &val2);				good = g_value_get_string(&val2);				if (!case_sensitive && is_word_lowercase(bad) && is_word_lowercase(good))				{					if (is_word_uppercase(word))						outword = g_utf8_strup(good, -1);					else if (is_word_proper(word))						outword = make_word_proper(good);					else						outword = g_strdup(good);				}				else					outword = g_strdup(good);				g_value_unset(&val1);				g_value_unset(&val2);				g_free(foldedword);				return outword;			}			g_value_unset(&val1);			g_free(tmpbad);		} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter));	}	g_free(foldedword);	return NULL;}static voidspellchk_free(spellchk *spell){	GtkTextBuffer *buffer;	g_return_if_fail(spell != NULL);	buffer = gtk_text_view_get_buffer(spell->view);	g_signal_handlers_disconnect_matched(buffer,			G_SIGNAL_MATCH_DATA,			0, 0, NULL, NULL,			spell);	g_free(spell);}/* Pango doesn't know about the "'" character.  Let's fix that. */static gbooleanspellchk_inside_word(GtkTextIter *iter){	gunichar ucs4_char = gtk_text_iter_get_char(iter);	gchar *utf8_str;	gchar c = 0;	utf8_str = g_ucs4_to_utf8(&ucs4_char, 1, NULL, NULL, NULL);	if (utf8_str != NULL)	{		c = utf8_str[0];		g_free(utf8_str);	}	/* Hack because otherwise typing things like U.S. gets difficult	 * if you have 'u' -> 'you' set as a correction...	 *	 * Part 1 of 2: This marks . as being an inside-word character. */	if (c == '.')		return TRUE;	/* Avoid problems with \r, for example (SF #1289031). */	if (c == '\\')		return TRUE;	if (gtk_text_iter_inside_word (iter) == TRUE)		return TRUE;	if (c == '\'') {		gboolean result = gtk_text_iter_backward_char(iter);		gboolean output = gtk_text_iter_inside_word(iter);		if (result)		{			/*			 * Hack so that "u'll" will correct correctly.			 */			ucs4_char = gtk_text_iter_get_char(iter);			utf8_str = g_ucs4_to_utf8(&ucs4_char, 1, NULL, NULL, NULL);			if (utf8_str != NULL)			{				c = utf8_str[0];				g_free(utf8_str);				if (c == 'u' || c == 'U')				{					gtk_text_iter_forward_char(iter);					return FALSE;				}			}			gtk_text_iter_forward_char(iter);		}		return output;	}	else if (c == '&')		return TRUE;	return FALSE;}static gbooleanspellchk_backward_word_start(GtkTextIter *iter){	int output;	int result;	output = gtk_text_iter_backward_word_start(iter);	/* It didn't work...  */	if (!output)		return FALSE;	while (spellchk_inside_word(iter)) {		result = gtk_text_iter_backward_char(iter);		/* We can't go backwards anymore?  We're at the beginning of the word. */		if (!result)			return TRUE;		if (!spellchk_inside_word(iter)) {			gtk_text_iter_forward_char(iter);			return TRUE;		}		output = gtk_text_iter_backward_word_start(iter);		if (!output)			return FALSE;	}	return TRUE;}static gbooleancheck_range(spellchk *spell, GtkTextBuffer *buffer,				GtkTextIter start, GtkTextIter end, gboolean sending){	gboolean replaced;	gboolean result;	gchar *tmp;	int period_count = 0;	gchar *word;	GtkTextMark *mark;	GtkTextIter pos;	if ((replaced = substitute_simple_buffer(buffer)))	{		mark = gtk_text_buffer_get_insert(buffer);		gtk_text_buffer_get_iter_at_mark(buffer, &pos, mark);		spell->pos = gtk_text_iter_get_offset(&pos);		gtk_text_buffer_get_iter_at_mark(buffer, &start, mark);		gtk_text_buffer_get_iter_at_mark(buffer, &end, mark);	}	if (!sending)	{		/* We need to go backwords to find out if we are inside a word or not. */		gtk_text_iter_backward_char(&end);		if (spellchk_inside_word(&end))		{			gtk_text_iter_forward_char(&end);			return replaced;  /* We only pay attention to whole words. */		}	}	/* We could be in the middle of a whitespace block.  Check for that. */	result = gtk_text_iter_backward_char(&end);	if (!spellchk_inside_word(&end))	{		if (result)			gtk_text_iter_forward_char(&end);		return replaced;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -