+ if (!d->layout_->spellcheck || !inInset().allowSpellCheck())
+ return result;
+
+ locateWord(from, to, WHOLE_WORD);
+ if (from == to || from >= size())
+ return result;
+
+ docstring word = asString(from, to, AS_STR_INSETS + AS_STR_SKIPDELETE);
+ Language * lang = d->getSpellLanguage(from);
+
+ wl = WordLangTuple(word, lang);
+
+ if (!word.size())
+ return result;
+
+ if (needsSpellCheck() || check_learned) {
+ // Ignore words with digits
+ // FIXME: make this customizable
+ // (note that some checkers ignore words with digits by default)
+ if (!hasDigit(word)) {
+ bool const trailing_dot = to < size() && d->text_[to] == '.';
+ result = speller->check(wl);
+ if (SpellChecker::misspelled(result) && trailing_dot) {
+ wl = WordLangTuple(word.append(from_ascii(".")), lang);
+ result = speller->check(wl);
+ if (!SpellChecker::misspelled(result)) {
+ LYXERR(Debug::GUI, "misspelled word is correct with dot: \"" <<
+ word << "\" [" <<
+ from << ".." << to << "]");
+ }
+ }
+ }
+ d->setMisspelled(from, to, result);
+ } else {
+ result = d->speller_state_.getState(from);
+ }
+
+ bool const misspelled_ = SpellChecker::misspelled(result) ;
+ if (misspelled_ && do_suggestion)
+ speller->suggest(wl, suggestions);
+ else if (misspelled_)
+ LYXERR(Debug::GUI, "misspelled word: \"" <<
+ word << "\" [" <<
+ from << ".." << to << "]");
+ else
+ suggestions.clear();
+
+ return result;
+}
+
+
+void Paragraph::Private::markMisspelledWords(
+ pos_type const & first, pos_type const & last,
+ SpellChecker::Result result,
+ docstring const & word,
+ SkipPositions const & skips)
+{
+ if (!SpellChecker::misspelled(result)) {
+ setMisspelled(first, last, SpellChecker::WORD_OK);
+ return;
+ }
+ int snext = first;
+ SpellChecker * speller = theSpellChecker();
+ // locate and enumerate the error positions
+ int nerrors = speller->numMisspelledWords();
+ int numskipped = 0;
+ SkipPositionsIterator it = skips.begin();
+ SkipPositionsIterator et = skips.end();
+ for (int index = 0; index < nerrors; ++index) {
+ int wstart;
+ int wlen = 0;
+ speller->misspelledWord(index, wstart, wlen);
+ /// should not happen if speller supports range checks
+ if (!wlen) continue;
+ docstring const misspelled = word.substr(wstart, wlen);
+ wstart += first + numskipped;
+ if (snext < wstart) {
+ /// mark the range of correct spelling
+ numskipped += countSkips(it, et, wstart);
+ setMisspelled(snext,
+ wstart - 1, SpellChecker::WORD_OK);
+ }
+ snext = wstart + wlen;
+ numskipped += countSkips(it, et, snext);
+ /// mark the range of misspelling
+ setMisspelled(wstart, snext, result);
+ LYXERR(Debug::GUI, "misspelled word: \"" <<
+ misspelled << "\" [" <<
+ wstart << ".." << (snext-1) << "]");
+ ++snext;
+ }
+ if (snext <= last) {
+ /// mark the range of correct spelling at end
+ setMisspelled(snext, last, SpellChecker::WORD_OK);
+ }
+}
+
+
+void Paragraph::spellCheck() const
+{
+ SpellChecker * speller = theSpellChecker();
+ if (!speller || !size() ||!needsSpellCheck())
+ return;
+ pos_type start;
+ pos_type endpos;
+ d->rangeOfSpellCheck(start, endpos);
+ if (speller->canCheckParagraph()) {
+ // loop until we leave the range
+ for (pos_type first = start; first < endpos; ) {
+ pos_type last = endpos;
+ Private::SkipPositions skips;
+ Language * lang = d->locateSpellRange(first, last, skips);
+ if (first >= endpos)
+ break;
+ // start the spell checker on the unit of meaning
+ docstring word = asString(first, last, AS_STR_INSETS + AS_STR_SKIPDELETE);
+ WordLangTuple wl = WordLangTuple(word, lang);
+ SpellChecker::Result result = word.size() ?
+ speller->check(wl) : SpellChecker::WORD_OK;
+ d->markMisspelledWords(first, last, result, word, skips);
+ first = ++last;
+ }
+ } else {
+ static docstring_list suggestions;
+ pos_type to = endpos;
+ while (start < endpos) {
+ WordLangTuple wl;
+ spellCheck(start, to, wl, suggestions, false);
+ start = to + 1;
+ }
+ }
+ d->readySpellCheck();
+}
+
+
+bool Paragraph::isMisspelled(pos_type pos) const
+{
+ return SpellChecker::misspelled(d->speller_state_.getState(pos));
+}
+
+
+string Paragraph::magicLabel() const
+{
+ stringstream ss;
+ ss << "magicparlabel-" << id();
+ return ss.str();