]> git.lyx.org Git - lyx.git/blobdiff - src/AspellChecker.cpp
Disable CheckTeX while buffer is processed
[lyx.git] / src / AspellChecker.cpp
index 7772bb70d6d49c33ef395d4808d36db7ea825c76..8e41765e3d70bb302adc14504a4582935f17466c 100644 (file)
 
 #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>
 
@@ -41,17 +42,19 @@ namespace {
 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();
 
@@ -63,6 +66,7 @@ struct AspellChecker::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);
@@ -88,28 +92,38 @@ struct AspellChecker::Private
 
        /// 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";
+       }
 };
 
 
@@ -129,9 +143,9 @@ AspellChecker::Private::~Private()
 
        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();
@@ -171,7 +185,7 @@ bool AspellChecker::Private::checkAspellData(AspellConfig * config,
        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));
@@ -185,7 +199,7 @@ bool AspellChecker::Private::checkAspellData(AspellConfig * config,
                        have_dict = isValidDictionary(config, lang, variety);
                }
        }
-       return have_dict ;
+       return have_dict;
 }
 
 
@@ -193,8 +207,8 @@ AspellConfig * AspellChecker::Private::getConfig(string const & lang, string con
 {
        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);
@@ -204,16 +218,16 @@ AspellConfig * AspellChecker::Private::getConfig(string const & lang, string con
        }
        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))
+       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));
 }
 
@@ -264,6 +278,7 @@ AspellSpeller * AspellChecker::Private::addSpeller(Language const * lang)
                // 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.
@@ -278,7 +293,7 @@ AspellSpeller * AspellChecker::Private::addSpeller(Language const * lang)
                personal_[lang->lang()] = pd;
                initSessionDictionary(m, pd);
        }
-       
+
        spellers_[lang->lang()] = m;
        return m.e_speller ? to_aspell_speller(m.e_speller) : 0;
 }
@@ -287,26 +302,77 @@ AspellSpeller * AspellChecker::Private::addSpeller(Language const * lang)
 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
 {
-       return to_utf8(word);
+       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, WordLangTuple const & word) 
+       AspellSpeller * m, WordLangTuple const & word)
        const
 {
+       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, /**/);
+       LASSERT(word_ok != -1, return UNKNOWN_WORD);
        return (word_ok) ? WORD_OK : UNKNOWN_WORD;
 }
 
@@ -329,7 +395,7 @@ void AspellChecker::Private::remove(WordLangTuple const & word)
        }
 }
 
-               
+
 void AspellChecker::Private::insert(WordLangTuple const & word)
 {
        Spellers::iterator it = spellers_.find(word.lang()->lang());
@@ -351,9 +417,9 @@ bool AspellChecker::Private::learned(WordLangTuple const & word)
 }
 
 
-AspellChecker::AspellChecker(): d(new Private)
-{
-}
+AspellChecker::AspellChecker()
+       : d(new Private)
+{}
 
 
 AspellChecker::~AspellChecker()
@@ -364,11 +430,10 @@ AspellChecker::~AspellChecker()
 
 SpellChecker::Result AspellChecker::check(WordLangTuple const & word)
 {
-  
        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.
@@ -415,7 +480,7 @@ void AspellChecker::suggest(WordLangTuple const & wl,
        string const word = d->toAspellWord(wl.word());
        AspellWordList const * sugs =
                aspell_speller_suggest(m, word.c_str(), -1);
-       LASSERT(sugs != 0, /**/);
+       LASSERT(sugs != 0, return);
        AspellStringEnumeration * els = aspell_word_list_elements(sugs);
        if (!els || aspell_word_list_empty(sugs))
                return;
@@ -430,12 +495,14 @@ void AspellChecker::suggest(WordLangTuple const & wl,
        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;
@@ -456,6 +523,12 @@ bool AspellChecker::hasDictionary(Language const * lang) const
 }
 
 
+int AspellChecker::numDictionaries() const
+{
+       return d->numDictionaries();
+}
+
+
 docstring const AspellChecker::error()
 {
        Spellers::iterator it = d->spellers_.begin();