[LyX/master] Add way to remove items from document dictionary

Juergen Spitzmueller spitz at lyx.org
Sun Mar 7 17:18:46 UTC 2021


commit c8feef2e2316978b60d6cef0a5513f80966990b7
Author: Juergen Spitzmueller <spitz at lyx.org>
Date:   Sun Mar 7 18:23:07 2021 +0100

    Add way to remove items from document dictionary
---
 lib/RELEASE-NOTES          |    3 +++
 src/AppleSpellChecker.cpp  |    2 +-
 src/AspellChecker.cpp      |    2 +-
 src/EnchantChecker.cpp     |    2 +-
 src/FuncCode.h             |    1 +
 src/HunspellChecker.cpp    |   23 +++++++++++------------
 src/LyXAction.cpp          |   13 +++++++++++++
 src/Paragraph.cpp          |    4 ++--
 src/SpellChecker.h         |    5 ++++-
 src/Text3.cpp              |   43 +++++++++++++++++++++++++++++++++++++++++--
 src/frontends/qt/Menus.cpp |    7 +++++++
 11 files changed, 85 insertions(+), 20 deletions(-)

diff --git a/lib/RELEASE-NOTES b/lib/RELEASE-NOTES
index 638d5a9..11c3503 100644
--- a/lib/RELEASE-NOTES
+++ b/lib/RELEASE-NOTES
@@ -119,6 +119,9 @@
 * spelling-add-local adds words for a given language to the document's local spelling
   dictionary.
 
+* spelling-remove-local removes words for a given language from the document's local
+  spelling dictionary.
+
 * inset-split is a new convenience function that splits an inset into two at the given
   cursor position. This is only implemented for text insets currently.
 
diff --git a/src/AppleSpellChecker.cpp b/src/AppleSpellChecker.cpp
index 763b809..0a82d38 100644
--- a/src/AppleSpellChecker.cpp
+++ b/src/AppleSpellChecker.cpp
@@ -92,7 +92,7 @@ SpellChecker::Result AppleSpellChecker::check(WordLangTuple const & word,
 		if (it->lang()->code() != word.lang()->code())
 			continue;
 		if (it->word() == word.word())
-			return LEARNED_WORD;
+			return DOCUMENT_LEARNED_WORD;
 	}
 
 	SpellCheckResult result =
diff --git a/src/AspellChecker.cpp b/src/AspellChecker.cpp
index d7392d2..a5c54d8 100644
--- a/src/AspellChecker.cpp
+++ b/src/AspellChecker.cpp
@@ -445,7 +445,7 @@ SpellChecker::Result AspellChecker::check(WordLangTuple const & word,
 		if (it->lang()->code() != word.lang()->code())
 			continue;
 		if (it->word() == word.word())
-			return LEARNED_WORD;
+			return DOCUMENT_LEARNED_WORD;
 	}
 	SpellChecker::Result rc = d->check(m, word);
 	return (rc == WORD_OK && d->learned(word)) ? LEARNED_WORD : rc;
diff --git a/src/EnchantChecker.cpp b/src/EnchantChecker.cpp
index 8eaea83..5b42f33 100644
--- a/src/EnchantChecker.cpp
+++ b/src/EnchantChecker.cpp
@@ -139,7 +139,7 @@ SpellChecker::Result EnchantChecker::check(WordLangTuple const & word,
 		if (it->lang()->code() != word.lang()->code())
 			continue;
 		if (it->word() == word.word())
-			return LEARNED_WORD;
+			return DOCUMENT_LEARNED_WORD;
 	}
 
 	return UNKNOWN_WORD;
diff --git a/src/FuncCode.h b/src/FuncCode.h
index 4fceed8..391232b 100644
--- a/src/FuncCode.h
+++ b/src/FuncCode.h
@@ -499,6 +499,7 @@ enum FuncCode
 	LFUN_FONT_NO_SPELLCHECK,        // jspitzm 20210305
 	LFUN_SPELLING_ADD_LOCAL,        // jspitzm 20210306
 	// 390
+	LFUN_SPELLING_REMOVE_LOCAL,     // jspitzm 20210307
 	LFUN_LASTACTION                 // end of the table
 };
 
diff --git a/src/HunspellChecker.cpp b/src/HunspellChecker.cpp
index 06349c6..1cac9ad 100644
--- a/src/HunspellChecker.cpp
+++ b/src/HunspellChecker.cpp
@@ -70,8 +70,7 @@ struct HunspellChecker::Private
 	Hunspell * speller(Language const * lang);
 	Hunspell * lookup(Language const * lang);
 	/// ignored words
-	bool isIgnored(WordLangTuple const & wl,
-		       std::vector<WordLangTuple> const & docdict) const;
+	bool isIgnored(WordLangTuple const & wl) const;
 	/// personal word list interface
 	void remove(WordLangTuple const & wl);
 	void insert(WordLangTuple const & wl);
@@ -282,8 +281,7 @@ int HunspellChecker::Private::numDictionaries() const
 }
 
 
-bool HunspellChecker::Private::isIgnored(WordLangTuple const & wl,
-					 vector<WordLangTuple> const & docdict) const
+bool HunspellChecker::Private::isIgnored(WordLangTuple const & wl) const
 {
 	IgnoreList::const_iterator it = ignored_.begin();
 	for (; it != ignored_.end(); ++it) {
@@ -292,13 +290,6 @@ bool HunspellChecker::Private::isIgnored(WordLangTuple const & wl,
 		if (it->word() == wl.word())
 			return true;
 	}
-	it = docdict.begin();
-	for (; it != docdict.end(); ++it) {
-		if (it->lang()->code() != wl.lang()->code())
-			continue;
-		if (it->word() == wl.word())
-			return true;
-	}
 	return false;
 }
 
@@ -356,9 +347,17 @@ HunspellChecker::~HunspellChecker()
 SpellChecker::Result HunspellChecker::check(WordLangTuple const & wl,
 					    vector<WordLangTuple> const & docdict)
 {
-	if (d->isIgnored(wl, docdict))
+	if (d->isIgnored(wl))
 		return WORD_OK;
 
+	IgnoreList::const_iterator it = docdict.begin();
+	for (; it != docdict.end(); ++it) {
+		if (it->lang()->code() != wl.lang()->code())
+			continue;
+		if (it->word() == wl.word())
+			return DOCUMENT_LEARNED_WORD;
+	}
+
 	Hunspell * h = d->speller(wl.lang());
 	if (!h)
 		return NO_DICTIONARY;
diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp
index 5badfc9..8933e3d 100644
--- a/src/LyXAction.cpp
+++ b/src/LyXAction.cpp
@@ -3807,6 +3807,19 @@ void LyXAction::init()
 		{ LFUN_SPELLING_ADD_LOCAL, "spelling-add-local", Noop, Edit },
 
 /*!
+ * \var lyx::FuncCode lyx::LFUN_SPELLING_REMOVE_LOCAL
+ * \li Action: Remove the word under the cursor from the document's local
+ *             spell checker dictionary.
+ *             The default for the language is retrieved from the cursor position.
+ * \li Syntax: spelling-remove-local [<STRING>] [<LANG>]
+ * \li Params: <WORD>: word to remove
+	       <LANG>: language name (see file languages)
+ * \li Origin: spitz, 7 Mar 2021
+ * \endvar
+ */
+		{ LFUN_SPELLING_REMOVE_LOCAL, "spelling-remove-local", Noop, Edit },
+
+/*!
  * \var lyx::FuncCode lyx::LFUN_SPELLING_CONTINUOUSLY
  * \li Action: Toggle continuous spell checking.
  * \li Syntax: spelling-continuously
diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp
index e4ebf8b..9bfa3b8 100644
--- a/src/Paragraph.cpp
+++ b/src/Paragraph.cpp
@@ -4961,11 +4961,11 @@ void Paragraph::Private::markMisspelledWords(
 		WordLangTuple const candidate(word.substr(wstart, wlen), lang);
 		SpellChecker::Result actresult = result;
 		if (inset_owner_->buffer().params().spellignored(candidate))
-			actresult = SpellChecker::WORD_OK;
+			actresult = SpellChecker::DOCUMENT_LEARNED_WORD;
 		numskipped += countSkips(it, et, snext);
 		/// mark the range of misspelling
 		setMisspelled(wstart, snext, actresult);
-		if (actresult == SpellChecker::WORD_OK)
+		if (actresult == SpellChecker::DOCUMENT_LEARNED_WORD)
 			LYXERR(Debug::GUI, "local dictionary word: \"" <<
 				   candidate.word() << "\" [" <<
 				   wstart << ".." << (snext-1) << "]");
diff --git a/src/SpellChecker.h b/src/SpellChecker.h
index 7a5dbac..58e5de6 100644
--- a/src/SpellChecker.h
+++ b/src/SpellChecker.h
@@ -44,6 +44,8 @@ public:
 		IGNORED_WORD,
 		/// number of personal dictionary "word"
 		LEARNED_WORD,
+		/// number of document dictionary "word"
+		DOCUMENT_LEARNED_WORD,
 		/// missing dictionary for language
 		NO_DICTIONARY
 	};
@@ -57,7 +59,8 @@ public:
 		return res != WORD_OK
 			&& res != IGNORED_WORD
 			&& res != NO_DICTIONARY
-			&& res != LEARNED_WORD; }
+			&& res != LEARNED_WORD
+			&& res != DOCUMENT_LEARNED_WORD; }
 
 	/// check the given word of the given lang code and return the result
 	virtual enum Result check(WordLangTuple const &,
diff --git a/src/Text3.cpp b/src/Text3.cpp
index 9ff7150..26d6d71 100644
--- a/src/Text3.cpp
+++ b/src/Text3.cpp
@@ -2745,8 +2745,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 			}
 		}
 		WordLangTuple wl(word, language);
-		bool const has_item = bv->buffer().params().spellignored(wl);
-		if (!has_item) {
+		if (!bv->buffer().params().spellignored(wl)) {
 			cur.recordUndoBufferParams();
 			bv->buffer().params().spellignore().push_back(wl);
 			cur.recordUndo();
@@ -2761,6 +2760,45 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 		break;
 	}
 
+	case LFUN_SPELLING_REMOVE_LOCAL: {
+		Language const * language = getLanguage(cur, cmd.getArg(1));
+		docstring word = from_utf8(cmd.getArg(0));
+		if (word.empty()) {
+			word = cur.selectionAsString(false);
+			if (word.size() > 100)
+				break;
+			if (word.empty()) {
+				// Get word or selection
+				selectWordWhenUnderCursor(cur, WHOLE_WORD);
+				word = cur.selectionAsString(false);
+			}
+		}
+		WordLangTuple wl(word, language);
+		bool has_item = false;
+		vector<WordLangTuple>::const_iterator it = bv->buffer().params().spellignore().begin();
+		for (; it != bv->buffer().params().spellignore().end(); ++it) {
+			if (it->lang()->code() != wl.lang()->code())
+				continue;
+			if (it->word() == wl.word()) {
+				has_item = true;
+				break;
+			}
+		}
+		if (has_item) {
+			cur.recordUndoBufferParams();
+			bv->buffer().params().spellignore().erase(it);
+			cur.recordUndo();
+			// trigger re-check
+			WordLangTuple wl;
+			docstring_list suggestions;
+			Paragraph const & par = cur.paragraph();
+			pos_type from = cur.pos();
+			pos_type to = from;
+			par.spellCheck(from, to, wl, suggestions, true, true);
+		}
+		break;
+	}
+
 
 	case LFUN_SPELLING_IGNORE: {
 		Language const * language = getLanguage(cur, cmd.getArg(1));
@@ -3492,6 +3530,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
 
 	case LFUN_SPELLING_ADD:
 	case LFUN_SPELLING_ADD_LOCAL:
+	case LFUN_SPELLING_REMOVE_LOCAL:
 	case LFUN_SPELLING_IGNORE:
 	case LFUN_SPELLING_REMOVE:
 		enable = theSpellChecker() != nullptr;
diff --git a/src/frontends/qt/Menus.cpp b/src/frontends/qt/Menus.cpp
index df5586e..3b7bde0 100644
--- a/src/frontends/qt/Menus.cpp
+++ b/src/frontends/qt/Menus.cpp
@@ -878,6 +878,13 @@ void MenuDefinition::expandSpellingSuggestions(BufferView const * bv)
 					FuncRequest(LFUN_SPELLING_REMOVE, arg)));
 		}
 		break;
+	case SpellChecker::DOCUMENT_LEARNED_WORD: {
+			LYXERR(Debug::GUI, "Document-Learned Word.");
+			docstring const arg = wl.word() + " " + from_ascii(wl.lang()->lang());
+			add(MenuItem(MenuItem::Command, qt_("Remove from document dictionary|r"),
+					FuncRequest(LFUN_SPELLING_REMOVE_LOCAL, arg)));
+		}
+		break;
 	case SpellChecker::NO_DICTIONARY:
 		LYXERR(Debug::GUI, "No dictionary for language " + from_ascii(wl.lang()->lang()));
 		// FALLTHROUGH


More information about the lyx-cvs mailing list