From 15b337d3f4caa3fa71160dc93b7caf4f2c098b06 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Tue, 26 Nov 2024 16:55:51 +0300 Subject: fixes #4692 (SpellChecker to use the native Windows speller if present) --- plugins/SpellChecker/spellchecker.vcxproj | 1 + plugins/SpellChecker/spellchecker.vcxproj.filters | 3 + plugins/SpellChecker/src/dictionary.cpp | 45 ++++--- plugins/SpellChecker/src/dictionary.h | 8 +- plugins/SpellChecker/src/hunspell.cpp | 29 ----- plugins/SpellChecker/src/native.cpp | 145 ++++++++++++++++++++++ plugins/SpellChecker/src/spellchecker.cpp | 1 + plugins/SpellChecker/src/stdafx.h | 1 - plugins/SpellChecker/src/version.h | 6 +- 9 files changed, 178 insertions(+), 61 deletions(-) create mode 100644 plugins/SpellChecker/src/native.cpp (limited to 'plugins') diff --git a/plugins/SpellChecker/spellchecker.vcxproj b/plugins/SpellChecker/spellchecker.vcxproj index 570332771c..ebafe54ef1 100644 --- a/plugins/SpellChecker/spellchecker.vcxproj +++ b/plugins/SpellChecker/spellchecker.vcxproj @@ -33,6 +33,7 @@ + diff --git a/plugins/SpellChecker/spellchecker.vcxproj.filters b/plugins/SpellChecker/spellchecker.vcxproj.filters index d53fe3bae2..6140ec504f 100644 --- a/plugins/SpellChecker/spellchecker.vcxproj.filters +++ b/plugins/SpellChecker/spellchecker.vcxproj.filters @@ -32,6 +32,9 @@ Source Files + + Source Files + diff --git a/plugins/SpellChecker/src/dictionary.cpp b/plugins/SpellChecker/src/dictionary.cpp index 83bbefd5ce..de8464eb98 100644 --- a/plugins/SpellChecker/src/dictionary.cpp +++ b/plugins/SpellChecker/src/dictionary.cpp @@ -57,7 +57,7 @@ static aditionalLanguages[] = { ///////////////////////////////////////////////////////////////////////////////////////// // To get the names of the languages -void Dictionary::GetInfo() +bool Dictionary::GetInfo() { for (auto &it : g_plugin.locales) { if (mir_wstrcmpi(language, it.first.c_str()) == 0) { @@ -82,35 +82,34 @@ void Dictionary::GetInfo() mir_wstrncpy(localized_name, TranslateW(localName), _countof(localized_name)); } - if (localized_name[0] != 0) - mir_snwprintf(full_name, L"%s [%s]", localized_name, language); - - break; + mir_snwprintf(full_name, L"%s [%s]", localized_name, language); + return true; } } - if (full_name[0] == '\0') { - DBVARIANT dbv; + DBVARIANT dbv; - char lang[128]; - WideCharToMultiByte(CP_ACP, 0, language, -1, lang, sizeof(lang), nullptr, nullptr); - if (!g_plugin.getWString(lang, &dbv)) { - mir_wstrncpy(localized_name, dbv.pwszVal, _countof(localized_name)); - db_free(&dbv); - } + char lang[128]; + WideCharToMultiByte(CP_ACP, 0, language, -1, lang, sizeof(lang), nullptr, nullptr); + if (!g_plugin.getWString(lang, &dbv)) { + mir_wstrncpy(localized_name, dbv.pwszVal, _countof(localized_name)); + db_free(&dbv); + } - if (localized_name[0] == '\0') { - for (auto &it : aditionalLanguages) { - if (!mir_wstrcmp(it.language, language)) { - mir_wstrncpy(localized_name, TranslateW(it.localized_name), _countof(localized_name)); - break; - } + if (localized_name[0] == '\0') { + for (auto &it : aditionalLanguages) { + if (!mir_wstrcmp(it.language, language)) { + mir_wstrncpy(localized_name, TranslateW(it.localized_name), _countof(localized_name)); + break; } } + } - if (localized_name[0] != '\0') - mir_snwprintf(full_name, L"%s [%s]", localized_name, language); - else - mir_wstrncpy(full_name, language, _countof(full_name)); + if (localized_name[0] != '\0') { + mir_snwprintf(full_name, L"%s [%s]", localized_name, language); + return true; } + + mir_wstrncpy(full_name, language, _countof(full_name)); + return false; } diff --git a/plugins/SpellChecker/src/dictionary.h b/plugins/SpellChecker/src/dictionary.h index 8ba9ee2acf..daad917ddc 100644 --- a/plugins/SpellChecker/src/dictionary.h +++ b/plugins/SpellChecker/src/dictionary.h @@ -38,7 +38,7 @@ struct Dictionary Dictionary(const wchar_t *aLanguage, const wchar_t *aSource); virtual ~Dictionary(); - void GetInfo(); + bool GetInfo(); // Return TRUE if the word is correct virtual BOOL spell(const wchar_t *word) = 0; @@ -46,9 +46,6 @@ struct Dictionary // Return a list of suggestions to a word virtual Suggestions suggest(const wchar_t *word) = 0; - // Return a list of auto suggestions to a word - virtual Suggestions autoSuggest(const wchar_t *word) = 0; - // Return a auto suggestions to a word // You have to free the item virtual wchar_t* autoSuggestOne(const wchar_t *word) = 0; @@ -71,5 +68,6 @@ struct Dictionary // Return a list of avaible languages void GetAvaibleDictionaries(OBJLIST &dicts, wchar_t *path, wchar_t *user_path); - +void GetNativeDictionaries(OBJLIST &dicts); + #endif // __DICTIONARY_H__ diff --git a/plugins/SpellChecker/src/hunspell.cpp b/plugins/SpellChecker/src/hunspell.cpp index ebf76d5c88..d5e953dc32 100644 --- a/plugins/SpellChecker/src/hunspell.cpp +++ b/plugins/SpellChecker/src/hunspell.cpp @@ -589,35 +589,6 @@ public: return ret; } - // Return a list of auto suggestions to a word - virtual Suggestions autoSuggest(const wchar_t * word) - { - Suggestions ret; - - load(); - if (loaded != LANGUAGE_LOADED) - return ret; - - char hunspell_word[1024]; - toHunspell(hunspell_word, word, _countof(hunspell_word)); - - char **words; - int count = hunspell->suggest(&words, hunspell_word); - if (count <= 0) - return ret; - - // Oki, lets make our array - for (int i = 0; i < count; i++) { - auto *p = fromHunspell(words[i]); - ret.push_back(p); - free(p); - free(words[i]); - } - free(words); - - return ret; - } - // Return a list of auto suggestions to a word // You have to free the list AND each item virtual wchar_t * autoSuggestOne(const wchar_t * word) diff --git a/plugins/SpellChecker/src/native.cpp b/plugins/SpellChecker/src/native.cpp new file mode 100644 index 0000000000..b80ab78ea5 --- /dev/null +++ b/plugins/SpellChecker/src/native.cpp @@ -0,0 +1,145 @@ +/* +Copyright (C) 2006-2010 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" + +struct NativeDictionary : public Dictionary +{ + CComPtr m_speller; + + NativeDictionary(const wchar_t *wszLanguage) : + Dictionary(wszLanguage, 0) + { + if (auto *p = wcschr(language, '-')) + *p = '_'; + + g_plugin.m_spellFactory->CreateSpellChecker(wszLanguage, &m_speller); + + if (!GetInfo()) + if (auto *p = wcschr(full_name, '_')) + *p = '-'; + } + + virtual ~NativeDictionary() + { + } + + // Return TRUE if the word is correct + virtual BOOL spell(const wchar_t *word) + { + CComPtr error; + if (FAILED(m_speller->Check(word, &error))) + return FALSE; + + CComPtr err; + if (FAILED(error->Next(&err))) + return FALSE; + + return err == nullptr; + } + + // Return a list of suggestions to a word + virtual Suggestions suggest(const wchar_t *word) + { + Suggestions ret; + + CComPtr suggestions; + if (SUCCEEDED(m_speller->Suggest(word, &suggestions))) { + wchar_t *ws; + ULONG fetched; + while (true) { + suggestions->Next(1, &ws, &fetched); + if (fetched == 0) + break; + ret.push_back(ws); + } + } + return ret; + } + + // Return a list of auto suggestions to a word + // You have to free the list AND each item + virtual wchar_t* autoSuggestOne(const wchar_t * word) + { + CComPtr suggestions; + if (SUCCEEDED(m_speller->Suggest(word, &suggestions))) { + wchar_t *ws; + ULONG fetched; + suggestions->Next(1, &ws, &fetched); + if (fetched) { + wchar_t *p = (wchar_t *)malloc(sizeof(wchar_t) * (mir_wstrlen(ws) + 1)); + mir_wstrcpy(p, ws); + return p; + } + } + return nullptr; + } + + // Return TRUE if the char is a word char + virtual BOOL isWordChar(wchar_t c) + { + if (c == 0) + return FALSE; + + return iswalpha(c); + } + + // Assert that all needed data is loaded + virtual void load() + { + } + + virtual BOOL isLoaded() + { + return TRUE; + } + + // Add a word to the user custom dict + virtual void addWord(const wchar_t *word) + { + m_speller->Add(word); + } + + // Add a word to the list of ignored words + virtual void ignoreWord(const wchar_t * word) + { + m_speller->Ignore(word); + } +}; + +// Return a list of avaible languages +void GetNativeDictionaries(OBJLIST &dicts) +{ + CComPtr ptr; + g_plugin.m_spellFactory->get_SupportedLanguages(&ptr); + + ULONG fetched; + wchar_t *ws; + while (true) { + ptr->Next(1, &ws, &fetched); + if (fetched == 0) + break; + + auto *pNew = new NativeDictionary(ws); + if (!mir_wstrcmpi(ws, pNew->full_name)) + delete pNew; + else + dicts.insert(pNew); + } +} diff --git a/plugins/SpellChecker/src/spellchecker.cpp b/plugins/SpellChecker/src/spellchecker.cpp index 16213bc425..deeadb0bcf 100644 --- a/plugins/SpellChecker/src/spellchecker.cpp +++ b/plugins/SpellChecker/src/spellchecker.cpp @@ -104,6 +104,7 @@ static int ModulesLoaded(WPARAM, LPARAM) } else flagsDllFolder = Utils_ReplaceVarsW(FLAGS_DLL_FOLDER); + GetNativeDictionaries(languages); GetAvaibleDictionaries(languages, dictionariesFolder, customDictionariesFolder); LoadOptions(); diff --git a/plugins/SpellChecker/src/stdafx.h b/plugins/SpellChecker/src/stdafx.h index 57eeba34e8..a7ff2b119e 100644 --- a/plugins/SpellChecker/src/stdafx.h +++ b/plugins/SpellChecker/src/stdafx.h @@ -83,7 +83,6 @@ struct CMPlugin : public PLUGIN std::map locales; - CComPtr m_speller; CComPtr m_spellFactory; int Load() override; diff --git a/plugins/SpellChecker/src/version.h b/plugins/SpellChecker/src/version.h index dcc16f666f..78946dccd1 100644 --- a/plugins/SpellChecker/src/version.h +++ b/plugins/SpellChecker/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 -#define __MINOR_VERSION 2 -#define __RELEASE_NUM 6 -#define __BUILD_NUM 6 +#define __MINOR_VERSION 3 +#define __RELEASE_NUM 1 +#define __BUILD_NUM 0 #include -- cgit v1.2.3