- LFUN_SPELLING_IGNORE ("spelling-ignore").
+- LFUN_SPELLING_REMOVE ("spelling-remove").
+
- LFUN_PREVIEW_INSERT ("preview-insert").
- LFUN_FORWARD_SEARCH ("forward-search").
~Private();
+ SpellChecker::Result toResult(SpellCheckResult status);
+ string toString(SpellCheckResult status);
+
/// the speller
AppleSpeller speller;
};
}
+SpellChecker::Result AppleSpellChecker::Private::toResult(SpellCheckResult status)
+{
+ return status == SPELL_CHECK_FAILED ? UNKNOWN_WORD :
+ status == SPELL_CHECK_LEARNED ? LEARNED_WORD : WORD_OK ;
+}
+
+
+string AppleSpellChecker::Private::toString(SpellCheckResult status)
+{
+ return status == SPELL_CHECK_FAILED ? "FAILED" :
+ status == SPELL_CHECK_LEARNED ? "LEARNED" : "OK";
+}
+
+
SpellChecker::Result AppleSpellChecker::check(WordLangTuple const & word)
{
string const word_str = to_utf8(word.word());
- int const word_ok = checkAppleSpeller(d->speller, word_str.c_str(), word.lang()->code().c_str());
- return (word_ok) ? OK : UNKNOWN_WORD;
+ SpellCheckResult result = checkAppleSpeller(d->speller, word_str.c_str(), word.lang()->code().c_str());
+ LYXERR(Debug::GUI, "spellCheck: \"" << word.word() << "\" = " << d->toString(result)) ;
+ return d->toResult(result);
}
{
string const word_str = to_utf8(word.word());
learnAppleSpeller(d->speller, word_str.c_str());
+ LYXERR(Debug::GUI, "learn word: \"" << word.word() << "\"") ;
+}
+
+
+// remove from personal dictionary
+void AppleSpellChecker::remove(WordLangTuple const & word)
+{
+ string const word_str = to_utf8(word.word());
+ unlearnAppleSpeller(d->speller, word_str.c_str());
+ LYXERR(Debug::GUI, "unlearn word: \"" << word.word() << "\"") ;
}
enum Result check(WordLangTuple const &);
void suggest(WordLangTuple const &, docstring_list &);
void insert(WordLangTuple const &);
+ void remove(WordLangTuple const &);
void accept(WordLangTuple const &);
bool hasDictionary(Language const * lang) const;
docstring const error();
d->speller(word.lang()->code(), word.lang()->variety());
if (!m)
- return OK;
+ return WORD_OK;
if (word.word().empty())
// MSVC compiled Aspell doesn't like it.
- return OK;
+ return WORD_OK;
string const word_str = to_utf8(word.word());
int const word_ok = aspell_speller_check(m, word_str.c_str(), -1);
LASSERT(word_ok != -1, /**/);
- return (word_ok) ? OK : UNKNOWN_WORD;
+ return (word_ok) ? WORD_OK : UNKNOWN_WORD;
}
enum Result check(WordLangTuple const &);
void suggest(WordLangTuple const &, docstring_list &);
void insert(WordLangTuple const &);
+ void remove(WordLangTuple const &) {};
void accept(WordLangTuple const &);
bool hasDictionary(Language const * lang) const;
docstring const error();
if (from == end)
break;
to = from;
- if (from.paragraph().spellCheck(from.pos(), to.pos(), wl, suggestions)) {
+ SpellChecker::Result res = from.paragraph().spellCheck(from.pos(), to.pos(), wl, suggestions);
+ if (SpellChecker::misspelled(res)) {
word_lang = wl;
break;
}
enchant::Dict * m = d->speller(word.lang()->code());
if (!m)
- return OK;
+ return WORD_OK;
string utf8word = to_utf8(word.word());
if (m->check(utf8word))
- return OK;
+ return WORD_OK;
return UNKNOWN_WORD;
}
enum Result check(WordLangTuple const &);
void suggest(WordLangTuple const &, docstring_list &);
void insert(WordLangTuple const &);
+ void remove(WordLangTuple const &) {};
void accept(WordLangTuple const &);
bool hasDictionary(Language const * lang) const;
docstring const error();
LFUN_SPELLING_ADD, // spitz 20100118
LFUN_SPELLING_IGNORE, // spitz 20100118
// 345
+ LFUN_SPELLING_REMOVE, // switt 20100728
LFUN_PREVIEW_INSERT, // vfr, 20100328
LFUN_FORWARD_SEARCH,
LFUN_INSET_COPY_AS, // vfr, 20100419
SpellChecker::Result HunspellChecker::check(WordLangTuple const & wl)
{
if (d->isIgnored(wl))
- return OK;
+ return WORD_OK;
Hunspell * h = d->speller(wl.lang()->code());
if (!h)
- return OK;
+ return WORD_OK;
int info;
string const encoding = h->get_dic_encoding();
string const word_to_check = to_iconv_encoding(wl.word(), encoding);
if (h->spell(word_to_check.c_str(), &info))
- return OK;
+ return WORD_OK;
if (info & SPELL_COMPOUND) {
// FIXME: What to do with that?
enum Result check(WordLangTuple const &);
void suggest(WordLangTuple const &, docstring_list &);
void insert(WordLangTuple const &);
+ void remove(WordLangTuple const &) {};
void accept(WordLangTuple const &);
bool hasDictionary(Language const * lang) const;
docstring const error();
* \endvar
*/
{ LFUN_SPELLING_IGNORE, "spelling-ignore", ReadOnly, Edit },
+/*!
+ * \var lyx::FuncCode lyx::LFUN_SPELLING_REMOVE
+ * \li Action: Remove the word under the cursor from the respective
+ * spell checker dictionary.
+ * \li Syntax: spelling-remove [<STRING>] [<LANG>]
+ * \li Params: <WORD>: word to remove
+ <LANG>: language name (see file languages)
+ * \li Origin: SWitt, 28 July 2010
+ * \endvar
+ */
+ { LFUN_SPELLING_REMOVE, "spelling-remove", ReadOnly, Edit },
/*!
* \var lyx::FuncCode lyx::LFUN_THESAURUS_ENTRY
* \li Action: Look up thesaurus entries with respect to the word under the cursor.
}
-bool Paragraph::spellCheck(pos_type & from, pos_type & to, WordLangTuple & wl,
+SpellChecker::Result Paragraph::spellCheck(pos_type & from, pos_type & to, WordLangTuple & wl,
docstring_list & suggestions, bool do_suggestion) const
{
SpellChecker * speller = theSpellChecker();
if (!speller)
- return false;
+ return SpellChecker::WORD_OK;
if (!d->layout_->spellcheck || !inInset().allowSpellCheck())
- return false;
+ return SpellChecker::WORD_OK;
locateWord(from, to, WHOLE_WORD);
if (from == to || from >= pos_type(d->text_.size()))
- return false;
+ return SpellChecker::WORD_OK;
docstring word = asString(from, to, AS_STR_INSETS);
// Ignore words with digits
}
wl = WordLangTuple(word, lang);
SpellChecker::Result res = ignored ?
- SpellChecker::OK : speller->check(wl);
-#if 0
-// FIXME: the code below makes aspell abort if a word in an unknown
-// language is checked.
- // Just ignore any error that the spellchecker reports.
- // FIXME: we should through out an exception and catch it in the GUI to
- // display the error.
- if (!speller->error().empty())
- return false;
-#endif
+ SpellChecker::WORD_OK : speller->check(wl);
- bool const misspelled = res != SpellChecker::OK
- && res != SpellChecker::IGNORED_WORD;
+ bool const misspelled_ = SpellChecker::misspelled(res) ;
if (lyxrc.spellcheck_continuously)
- d->fontlist_.setMisspelled(from, to, misspelled);
+ d->fontlist_.setMisspelled(from, to, misspelled_);
- if (misspelled && do_suggestion)
+ if (misspelled_ && do_suggestion)
speller->suggest(wl, suggestions);
else
suggestions.clear();
- return misspelled;
+ return res;
}
pos_type to = pos;
WordLangTuple wl;
docstring_list suggestions;
- return spellCheck(from, to, wl, suggestions, false);
+ SpellChecker::Result res = spellCheck(from, to, wl, suggestions, false);
+ return SpellChecker::misspelled(res) ;
}
#define PARAGRAPH_H
#include "FontEnums.h"
+#include "SpellChecker.h"
#include "insets/InsetCode.h"
/// Spellcheck word at position \p from and fill in found misspelled word
/// and \p suggestions if \p do_suggestion is true.
- /// \return true if pointed word is misspelled.
- bool spellCheck(pos_type & from, pos_type & to, WordLangTuple & wl,
+ /// \return result from spell checker, SpellChecker::UNKNOWN_WORD when misspelled.
+ SpellChecker::Result spellCheck(pos_type & from, pos_type & to, WordLangTuple & wl,
docstring_list & suggestions, bool do_suggestion = true) const;
/// Spellcheck word at position \p pos.
/// the result from checking a single word
enum Result {
/// word is correct
- OK = 1,
+ WORD_OK = 1,
/// root of given word was found
- ROOT,
+ ROOT_FOUND,
/// word found through compound formation
COMPOUND_WORD,
/// word not found
UNKNOWN_WORD,
/// number of other ignored "word"
- IGNORED_WORD
+ IGNORED_WORD,
+ /// number of personal dictionary "word"
+ LEARNED_WORD
};
virtual ~SpellChecker() {}
+ /// does the spell check failed
+ static bool misspelled(Result res) {
+ return res != SpellChecker::WORD_OK
+ && res != SpellChecker::IGNORED_WORD
+ && res != SpellChecker::LEARNED_WORD; }
+
/// check the given word of the given lang code and return the result
virtual enum Result check(WordLangTuple const &) = 0;
/// insert the given word into the personal dictionary
virtual void insert(WordLangTuple const &) = 0;
+ /// remove the given word from the personal dictionary
+ virtual void remove(WordLangTuple const &) = 0;
+
/// accept the given word temporarily
virtual void accept(WordLangTuple const &) = 0;
break;
}
+ case LFUN_SPELLING_REMOVE: {
+ docstring word = from_utf8(cmd.getArg(0));
+ Language * lang;
+ if (word.empty()) {
+ word = cur.selectionAsString(false);
+ // FIXME
+ if (word.size() > 100 || word.empty()) {
+ // Get word or selection
+ selectWordWhenUnderCursor(cur, WHOLE_WORD);
+ word = cur.selectionAsString(false);
+ }
+ lang = const_cast<Language *>(cur.getFont().language());
+ } else
+ lang = const_cast<Language *>(languages.getLanguage(cmd.getArg(1)));
+ WordLangTuple wl(word, lang);
+ theSpellChecker()->remove(wl);
+ break;
+ }
+
case LFUN_PARAGRAPH_PARAMS_APPLY: {
// Given data, an encoding of the ParagraphParameters
// generated in the Paragraph dialog, this function sets
case LFUN_SPELLING_ADD:
case LFUN_SPELLING_IGNORE:
+ case LFUN_SPELLING_REMOVE:
enable = theSpellChecker();
break;
#include "Paragraph.h"
#include "ParIterator.h"
#include "Session.h"
+#include "SpellChecker.h"
#include "TextClass.h"
#include "TocBackend.h"
#include "Toolbars.h"
void MenuDefinition::expandSpellingSuggestions(BufferView const * bv)
{
- if (!bv || !lyxrc.spellcheck_continuously)
+ if (!bv)
return;
WordLangTuple wl;
docstring_list suggestions;
pos_type from = bv->cursor().pos();
pos_type to = from;
Paragraph const & par = bv->cursor().paragraph();
- if (!par.spellCheck(from, to, wl, suggestions))
- return;
- LYXERR(Debug::GUI, "Misspelled Word! Suggested Words = ");
- size_t i = 0;
- MenuItem item(MenuItem::Submenu, qt_("More Spelling Suggestions"));
- item.setSubmenu(MenuDefinition(qt_("More Spelling Suggestions")));
- for (; i != suggestions.size(); ++i) {
- docstring const & suggestion = suggestions[i];
- LYXERR(Debug::GUI, suggestion);
- MenuItem w(MenuItem::Command, toqstr(suggestion),
- FuncRequest(LFUN_WORD_REPLACE, suggestion));
- if (i < 10)
- add(w);
- else
- item.submenu().add(w);
+ SpellChecker::Result res = par.spellCheck(from, to, wl, suggestions);
+ switch (res) {
+ case SpellChecker::UNKNOWN_WORD:
+ if (lyxrc.spellcheck_continuously) {
+ LYXERR(Debug::GUI, "Misspelled Word! Suggested Words = ");
+ size_t i = 0;
+ MenuItem item(MenuItem::Submenu, qt_("More Spelling Suggestions"));
+ item.setSubmenu(MenuDefinition(qt_("More Spelling Suggestions")));
+ for (; i != suggestions.size(); ++i) {
+ docstring const & suggestion = suggestions[i];
+ LYXERR(Debug::GUI, suggestion);
+ MenuItem w(MenuItem::Command, toqstr(suggestion),
+ FuncRequest(LFUN_WORD_REPLACE, suggestion));
+ if (i < 10)
+ add(w);
+ else
+ item.submenu().add(w);
+ }
+ if (i >= 10)
+ add(item);
+ if (i > 0)
+ add(MenuItem(MenuItem::Separator));
+ docstring const arg = wl.word() + " " + from_ascii(wl.lang()->lang());
+ add(MenuItem(MenuItem::Command, qt_("Add to personal dictionary|c"),
+ FuncRequest(LFUN_SPELLING_ADD, arg)));
+ add(MenuItem(MenuItem::Command, qt_("Ignore all|I"),
+ FuncRequest(LFUN_SPELLING_IGNORE, arg)));
+ }
+ break;
+ case SpellChecker::LEARNED_WORD: {
+ LYXERR(Debug::GUI, "Learned Word.");
+ docstring const arg = wl.word() + " " + from_ascii(wl.lang()->lang());
+ add(MenuItem(MenuItem::Command, qt_("Remove from personal dictionary|r"),
+ FuncRequest(LFUN_SPELLING_REMOVE, arg)));
+ }
+ break;
+ case SpellChecker::WORD_OK:
+ case SpellChecker::COMPOUND_WORD:
+ case SpellChecker::ROOT_FOUND:
+ case SpellChecker::IGNORED_WORD:
+ break;
}
- if (i >= 10)
- add(item);
- if (i > 0)
- add(MenuItem(MenuItem::Separator));
- docstring const arg = wl.word() + " " + from_ascii(wl.lang()->lang());
- add(MenuItem(MenuItem::Command, qt_("Add to personal dictionary|c"),
- FuncRequest(LFUN_SPELLING_ADD, arg)));
- add(MenuItem(MenuItem::Command, qt_("Ignore all|I"),
- FuncRequest(LFUN_SPELLING_IGNORE, arg)));
-
}
struct sortLanguageByName {
extern "C" {
#endif
+typedef enum SpellCheckResult {
+ SPELL_CHECK_FAILED,
+ SPELL_CHECK_OK,
+ SPELL_CHECK_IGNORED,
+ SPELL_CHECK_LEARNED
+} SpellCheckResult ;
+
typedef struct AppleSpellerRec * AppleSpeller ;
AppleSpeller newAppleSpeller(void);
void freeAppleSpeller(AppleSpeller speller);
-int checkAppleSpeller(AppleSpeller speller, const char * word, const char * lang);
+SpellCheckResult checkAppleSpeller(AppleSpeller speller, const char * word, const char * lang);
void ignoreAppleSpeller(AppleSpeller speller, const char * word);
size_t makeSuggestionAppleSpeller(AppleSpeller speller, const char * word, const char * lang);
const char * getSuggestionAppleSpeller(AppleSpeller speller, size_t pos);
void learnAppleSpeller(AppleSpeller speller, const char * word);
+void unlearnAppleSpeller(AppleSpeller speller, const char * word);
int hasLanguageAppleSpeller(AppleSpeller speller, const char * lang);
#ifdef __cplusplus
}
-int checkAppleSpeller(AppleSpeller speller, const char * word, const char * lang)
+SpellCheckResult checkAppleSpeller(AppleSpeller speller, const char * word, const char * lang)
{
if (!speller->checker || !lang || !word)
- return 0;
+ return SPELL_CHECK_FAILED;
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString * word_ = toString(word);
NSString * lang_ = toString(lang);
- NSRange result = [speller->checker
+ NSRange match = [speller->checker
checkSpellingOfString:word_
startingAt:0
language:lang_
inSpellDocumentWithTag:speller->doctag
wordCount:NULL];
+ SpellCheckResult result = match.length == 0 ? SPELL_CHECK_OK : SPELL_CHECK_FAILED;
+ if (result == SPELL_CHECK_OK && [NSSpellChecker instancesRespondToSelector:@selector(hasLearnedWord:)]) {
+ if ([speller->checker hasLearnedWord:word_])
+ result = SPELL_CHECK_LEARNED;
+ }
+
[word_ release];
[lang_ release];
[pool release];
- return (result.length ? 0 : 1);
+ return result;
}
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString * word_ = toString(word);
- if ([NSSpellChecker instancesRespondToSelector:@selector(learnWord)])
+ if ([NSSpellChecker instancesRespondToSelector:@selector(learnWord:)])
[speller->checker learnWord:word_];
[word_ release];
}
+
+void unlearnAppleSpeller(AppleSpeller speller, const char * word)
+{
+#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSString * word_ = toString(word);
+
+ if ([NSSpellChecker instancesRespondToSelector:@selector(unlearnWord:)])
+ [speller->checker unlearnWord:word_];
+
+ [word_ release];
+ [pool release];
+#endif
+}
+
+
int hasLanguageAppleSpeller(AppleSpeller speller, const char * lang)
{
BOOL result = NO;
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString * lang_ = toString(lang);
- if ([NSSpellChecker instancesRespondToSelector:@selector(availableLanguages)]) {
+ if ([NSSpellChecker instancesRespondToSelector:@selector(availableLanguages:)]) {
NSArray * languages = [speller->checker availableLanguages];
for (NSString *element in languages) {