#include "support/lassert.h"
#include "support/debug.h"
+#include "support/lstrings.h"
#include "support/docstring_list.h"
#include "support/filetools.h"
#include "support/Package.h"
#include "support/FileName.h"
-#include "support/Path.h"
+#include "support/PathChanger.h"
#include <aspell.h>
struct Speller {
AspellConfig * config;
AspellCanHaveError * e_speller;
+ bool accept_compound;
docstring_list ignored_words_;
};
typedef std::map<std::string, Speller> Spellers;
typedef map<std::string, PersonalWordList *> LangPersonalWordList;
-} // anon namespace
+} // namespace
struct AspellChecker::Private
{
- Private() {}
+ Private()
+ {}
~Private();
bool isValidDictionary(AspellConfig * config,
string const & lang, string const & variety);
+ int numDictionaries() const;
bool checkAspellData(AspellConfig * config,
string const & basepath, string const & datapath, string const & dictpath,
string const & lang, string const & variety);
AspellConfig * getConfig(string const & lang, string const & variety);
+ string toAspellWord(docstring const & word) const;
+
SpellChecker::Result check(AspellSpeller * m,
- string const & word) const;
+ WordLangTuple const & word) const;
void initSessionDictionary(Speller const & speller, PersonalWordList * pd);
+ void addToSession(AspellCanHaveError * speller, docstring const & word);
void insert(WordLangTuple const & word);
void remove(WordLangTuple const & word);
bool learned(WordLangTuple const & word);
/// the location below system/user directory
/// there the rws files lookup will happen
- const string dictDirectory(void) { return "dicts"; }
+ const string dictDirectory(void)
+ {
+ return "dicts";
+ }
/// there the dat+cmap files lookup will happen
- const string dataDirectory(void) { return "data"; }
+ const string dataDirectory(void)
+ {
+ return "data";
+ }
/// os package directory constants
/// macports on Mac OS X or
/// aspell rpms on Linux
- const string osPackageBase(void) {
+ const string osPackageBase(void)
+ {
#ifdef USE_MACOSX_PACKAGING
return "/opt/local";
#else
return "/usr";
#endif
}
- const string osPackageDictDirectory(void) {
+ const string osPackageDictDirectory(void)
+ {
#ifdef USE_MACOSX_PACKAGING
return "/share/aspell";
#else
return "/lib/aspell-0.60";
#endif
}
- const string osPackageDataDirectory(void) { return "/lib/aspell-0.60"; }
-
+ const string osPackageDataDirectory(void)
+ {
+ return "/lib/aspell-0.60";
+ }
};
LangPersonalWordList::const_iterator pdit = personal_.begin();
LangPersonalWordList::const_iterator pdet = personal_.end();
-
+
for (; pdit != pdet; ++pdit) {
- if ( 0 == pdit->second)
+ if (0 == pdit->second)
continue;
PersonalWordList * pd = pdit->second;
pd->save();
string const & lang, string const & variety)
{
FileName base(basepath);
- bool have_dict = base.isDirectory() ;
+ bool have_dict = base.isDirectory();
if (have_dict) {
FileName data(addPath(base.absFileName(), datapath));
have_dict = isValidDictionary(config, lang, variety);
}
}
- return have_dict ;
+ return have_dict;
}
{
AspellConfig * config = new_aspell_config();
bool have_dict = false;
- string const sysdir = lyx::support::package().system_support().absFileName() ;
- string const userdir = lyx::support::package().user_support().absFileName() ;
+ string const sysdir = lyx::support::package().system_support().absFileName();
+ string const userdir = lyx::support::package().user_support().absFileName();
LYXERR(Debug::FILES, "aspell user dir: " << userdir);
have_dict = checkAspellData(config, userdir, dataDirectory(), dictDirectory(), lang, variety);
}
if (!have_dict) {
// check for package data of OS installation
- have_dict = checkAspellData(config, osPackageBase(), osPackageDataDirectory(), osPackageDictDirectory(), lang, variety);
+ checkAspellData(config, osPackageBase(), osPackageDataDirectory(), osPackageDictDirectory(), lang, variety);
}
- return config ;
+ return config;
+}
+
+
+void AspellChecker::Private::addToSession(AspellCanHaveError * speller, docstring const & word)
+{
+ string const word_to_add = toAspellWord(word);
+ if (1 != aspell_speller_add_to_session(to_aspell_speller(speller), word_to_add.c_str(), -1))
+ LYXERR(Debug::GUI, "aspell add to session: " << aspell_error_message(speller));
}
docstring_list::const_iterator it = pd->begin();
docstring_list::const_iterator et = pd->end();
for (; it != et; ++it) {
- string const word_to_add = to_utf8(*it);
- aspell_speller_add_to_session(aspell, word_to_add.c_str(), -1);
+ addToSession(speller.e_speller, *it);
}
it = speller.ignored_words_.begin();
et = speller.ignored_words_.end();
for (; it != et; ++it) {
- string const word_to_add = to_utf8(*it);
- aspell_speller_add_to_session(aspell, word_to_add.c_str(), -1);
+ addToSession(speller.e_speller, *it);
}
}
// Report run-together words as errors
aspell_config_replace(m.config, "run-together", "false");
+ m.accept_compound = lyxrc.spellchecker_accept_compound;
m.e_speller = new_aspell_speller(m.config);
if (aspell_error_number(m.e_speller) != 0) {
// FIXME: We should indicate somehow that this language is not supported.
personal_[lang->lang()] = pd;
initSessionDictionary(m, pd);
}
-
+
spellers_[lang->lang()] = m;
return m.e_speller ? to_aspell_speller(m.e_speller) : 0;
}
AspellSpeller * AspellChecker::Private::speller(Language const * lang)
{
Spellers::iterator it = spellers_.find(lang->lang());
- if (it != spellers_.end())
- return to_aspell_speller(it->second.e_speller);
-
+ if (it != spellers_.end()) {
+ Speller aspell = it->second;
+ if (lyxrc.spellchecker_accept_compound != aspell.accept_compound) {
+ // spell checker setting changed... adjust run-together
+ aspell.accept_compound = lyxrc.spellchecker_accept_compound;
+ if (aspell.accept_compound)
+ // Consider run-together words as legal compounds
+ aspell_config_replace(aspell.config, "run-together", "true");
+ else
+ // Report run-together words as errors
+ aspell_config_replace(aspell.config, "run-together", "false");
+ AspellCanHaveError * e_speller = aspell.e_speller;
+ aspell.e_speller = new_aspell_speller(aspell.config);
+ delete_aspell_speller(to_aspell_speller(e_speller));
+ spellers_[lang->lang()] = aspell;
+ }
+ return to_aspell_speller(aspell.e_speller);
+ }
+
return addSpeller(lang);
}
+int AspellChecker::Private::numDictionaries() const
+{
+ int result = 0;
+ Spellers::const_iterator it = spellers_.begin();
+ Spellers::const_iterator et = spellers_.end();
+
+ for (; it != et; ++it) {
+ Speller aspell = it->second;
+ result += aspell.e_speller != 0;
+ }
+ return result;
+}
+
+
+string AspellChecker::Private::toAspellWord(docstring const & word) const
+{
+ size_t mpos;
+ string word_str = to_utf8(word);
+ while ((mpos = word_str.find('-')) != word_str.npos) {
+ word_str.erase(mpos, 1);
+ }
+ return word_str;
+}
+
+
SpellChecker::Result AspellChecker::Private::check(
- AspellSpeller * m, string const & word)
+ AspellSpeller * m, WordLangTuple const & word)
const
{
- int const word_ok = aspell_speller_check(m, word.c_str(), -1);
- LASSERT(word_ok != -1, /**/);
+ SpellChecker::Result result = WORD_OK;
+ docstring w1;
+ LYXERR(Debug::GUI, "spellCheck: \"" <<
+ word.word() << "\", lang = " << word.lang()->lang()) ;
+ docstring rest = split(word.word(), w1, '-');
+ for (; result == WORD_OK;) {
+ string const word_str = toAspellWord(w1);
+ int const word_ok = aspell_speller_check(m, word_str.c_str(), -1);
+ LASSERT(word_ok != -1, return UNKNOWN_WORD);
+ result = (word_ok) ? WORD_OK : UNKNOWN_WORD;
+ if (rest.empty())
+ break;
+ rest = split(rest, w1, '-');
+ }
+ if (result == WORD_OK)
+ return result;
+ string const word_str = toAspellWord(word.word());
+ int const word_ok = aspell_speller_check(m, word_str.c_str(), -1);
+ LASSERT(word_ok != -1, return UNKNOWN_WORD);
return (word_ok) ? WORD_OK : UNKNOWN_WORD;
}
}
}
-
+
void AspellChecker::Private::insert(WordLangTuple const & word)
{
Spellers::iterator it = spellers_.find(word.lang()->lang());
if (it != spellers_.end()) {
- AspellSpeller * speller = to_aspell_speller(it->second.e_speller);
- aspell_speller_add_to_session(speller, to_utf8(word.word()).c_str(), -1);
+ addToSession(it->second.e_speller, word.word());
PersonalWordList * pd = personal_[word.lang()->lang()];
if (!pd)
return;
}
-AspellChecker::AspellChecker(): d(new Private)
-{
-}
+AspellChecker::AspellChecker()
+ : d(new Private)
+{}
AspellChecker::~AspellChecker()
}
-SpellChecker::Result AspellChecker::check(WordLangTuple const & word)
+SpellChecker::Result AspellChecker::check(WordLangTuple const & word,
+ vector<WordLangTuple> const & docdict)
{
-
AspellSpeller * m = d->speller(word.lang());
if (!m)
- return WORD_OK;
+ return NO_DICTIONARY;
if (word.word().empty())
// MSVC compiled Aspell doesn't like it.
return WORD_OK;
- string const word_str = to_utf8(word.word());
- SpellChecker::Result rc = d->check(m, word_str);
+ vector<WordLangTuple>::const_iterator it = docdict.begin();
+ for (; it != docdict.end(); ++it) {
+ if (it->lang()->code() != word.lang()->code())
+ continue;
+ if (it->word() == word.word())
+ return DOCUMENT_LEARNED_WORD;
+ }
+ SpellChecker::Result rc = d->check(m, word);
return (rc == WORD_OK && d->learned(word)) ? LEARNED_WORD : rc;
}
{
Spellers::iterator it = d->spellers_.find(word.lang()->lang());
if (it != d->spellers_.end()) {
- AspellSpeller * speller = to_aspell_speller(it->second.e_speller);
- aspell_speller_add_to_session(speller, to_utf8(word.word()).c_str(), -1);
+ d->addToSession(it->second.e_speller, word.word());
d->accept(it->second, word);
advanceChangeNumber();
}
if (!m)
return;
+ string const word = d->toAspellWord(wl.word());
AspellWordList const * sugs =
- aspell_speller_suggest(m, to_utf8(wl.word()).c_str(), -1);
- LASSERT(sugs != 0, /**/);
+ aspell_speller_suggest(m, word.c_str(), -1);
+ LASSERT(sugs != 0, return);
AspellStringEnumeration * els = aspell_word_list_elements(sugs);
if (!els || aspell_word_list_empty(sugs))
return;
delete_aspell_string_enumeration(els);
}
+
void AspellChecker::remove(WordLangTuple const & word)
{
d->remove(word);
advanceChangeNumber();
}
+
bool AspellChecker::hasDictionary(Language const * lang) const
{
bool have = false;
}
+int AspellChecker::numDictionaries() const
+{
+ return d->numDictionaries();
+}
+
+
docstring const AspellChecker::error()
{
Spellers::iterator it = d->spellers_.begin();