]> git.lyx.org Git - lyx.git/blobdiff - src/Paragraph.cpp
Remove indentation on screen after a plain separator inset
[lyx.git] / src / Paragraph.cpp
index 09874a005ee02cfbe4edab91d185d413017baad2..c43421b3764c36cda14988eb442427156aba0f3f 100644 (file)
@@ -1094,16 +1094,21 @@ void Paragraph::Private::latexInset(BufferParams const & bparams,
        odocstream::pos_type const len = os.os().tellp();
 
        if (inset->forceLTR(runparams)
+           // babel with Xe/LuaTeX does not need a switch
+           // and \L is not defined there.
+           && (!runparams.isFullUnicode() || !runparams.use_babel)
            && running_font.isRightToLeft()
            // ERT is an exception, it should be output with no
            // decorations at all
            && inset->lyxCode() != ERT_CODE) {
-               if (runparams.use_polyglossia) {
+               if (runparams.use_polyglossia)
+                       // (lua)bidi
                        os << "\\LRE{";
-               else if (running_font.language()->lang() == "farsi"
-                          || running_font.language()->lang() == "arabic_arabi")
+               else if (running_font.language()->lang() == "farsi"
+                        || running_font.language()->lang() == "arabic_arabi")
                        os << "\\textLR{" << termcmd;
                else
+                       // babel classic
                        os << "\\L{";
                close = true;
        }
@@ -1209,26 +1214,41 @@ void Paragraph::Private::latexSpecialChar(otexstream & os,
 {
        char_type const c = owner_->getUChar(bparams, runparams, i);
 
-       if (style.pass_thru || runparams.pass_thru || (runparams.for_searchAdv != OutputParams::NoSearch)
+       if (style.pass_thru || runparams.pass_thru || runparams.find_effective()
            || contains(style.pass_thru_chars, c)
            || contains(runparams.pass_thru_chars, c)) {
-               if (runparams.for_searchAdv != OutputParams::NoSearch) {
-                       if (c == '\\')
+               if (runparams.find_effective()) {
+                       switch (c) {
+                       case '\\':
                                os << "\\\\";
-                       else if (c == '{')
+                               return;
+                       case '{':
                                os << "\\braceleft ";
-                       else if (c == '}')
+                               return;
+                       case '}':
                                os << "\\braceright ";
-                       else if (c != '\0')
+                               return;
+                       case '$':
+                               os << "\\lyxdollar ";
+                               return;
+                       case '~':
+                               os << "\\lyxtilde ";
+                               return;
+                       case ' ':
+                       case '\0':
+                               break;
+                       default:
                                os.put(c);
+                               return;
+                       }
                }
                else if (c != '\0') {
                        Encoding const * const enc = runparams.encoding;
                        if (enc && !enc->encodable(c))
                                throw EncodingException(c);
                        os.put(c);
+                       return;
                }
-               return;
        }
 
        // TIPA uses its own T3 encoding
@@ -1240,7 +1260,7 @@ void Paragraph::Private::latexSpecialChar(otexstream & os,
        //       non-standard font encoding. If we are using such a language,
        //       we do not output special T1 chars.
        if (!runparams.inIPA && !running_font.language()->internalFontEncoding()
-           && !runparams.isFullUnicode() && bparams.main_font_encoding() == "T1"
+           && !runparams.isFullUnicode() && runparams.main_fontenc == "T1"
            && latexSpecialT1(c, os, i, column))
                return;
        // NOTE: "fontspec" (non-TeX fonts) sets the font encoding to "TU" (untill 2017 "EU1" or "EU2")
@@ -1532,12 +1552,12 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const
                if (c == 0x0022) {
                        if (features.runparams().isFullUnicode() && bp.useNonTeXFonts)
                                features.require("textquotedblp");
-                       else if (bp.main_font_encoding() != "T1"
+                       else if (features.runparams().main_fontenc != "T1"
                                 || ((&owner_->getFontSettings(bp, i))->language()->internalFontEncoding()))
                                features.require("textquotedbl");
-               } else if (ci.textfeature() && contains(ci.textpreamble(), '=')) {
+               } else if (ci.textFeature() && contains(ci.textPreamble(), '=')) {
                        // features that depend on the font or input encoding
-                       string feats = ci.textpreamble();
+                       string feats = ci.textPreamble();
                        string fontenc = (&owner_->getFontSettings(bp, i))->language()->fontenc(bp);
                        if (fontenc.empty())
                                fontenc = features.runparams().main_fontenc;
@@ -1731,16 +1751,34 @@ void Paragraph::write(ostream & os, BufferParams const & bparams,
                        column = 0;
                        break;
                case '.':
+               case '!':
+               case '?':
+               case ':':
+               case ';':
+               case ',':
+               case 0x061F:  // ؟ U+061F  ARABIC QUESTION MARK
+               case 0x061B:  // ؛ U+061B  ARABIC SEMICOLON
+               case 0x060C:  // ، U+060C  ARABIC COMMA
                        flushString(os, write_buffer);
                        if (i + 1 < size() && d->text_[i + 1] == ' ') {
-                               os << ".\n";
+                               os << to_utf8(docstring(1, c)) << '\n';
                                column = 0;
                        } else
-                               os << '.';
+                               os << to_utf8(docstring(1, c));
+                       break;
+               case 0x2014:  // — U+2014  EM DASH
+               case 0x3002:  // 。 U+3002  IDEOGRAPHIC FULL STOP
+               case 0xFF01:  // ! U+FF01  FULLWIDTH EXCLAMATION MARK
+               case 0xFF1F:  // ? U+FF1F  FULLWIDTH QUESTION MARK
+               case 0xFF1A:  // : U+FF1A  FULLWIDTH COLON
+               case 0xFF1B:  // ; U+FF1B  FULLWIDTH SEMICOLON
+               case 0xFF0C:  // , U+FF0C  FULLWIDTH COMMA
+                       flushString(os, write_buffer);
+                       os << to_utf8(docstring(1, c)) << '\n';
+                       column = 0;
                        break;
                default:
-                       if ((column > 70 && c == ' ')
-                           || column > 79) {
+                       if (column > 500) {
                                flushString(os, write_buffer);
                                os << '\n';
                                column = 0;
@@ -1912,7 +1950,8 @@ FontSpan Paragraph::fontSpan(pos_type pos) const
 
        // This should not happen, but if so, we take no chances.
        LYXERR0("Paragraph::fontSpan: position not found in fontinfo table!");
-       LASSERT(false, return FontSpan(pos, pos));
+       LASSERT(false, /**/);
+       return FontSpan(pos, pos);
 }
 
 
@@ -1988,9 +2027,11 @@ char_type Paragraph::getUChar(BufferParams const & bparams,
        char_type c = d->text_[pos];
 
        // Return unchanged character in LTR languages
-       // or if we use poylglossia/bidi (XeTeX).
-       if (rp.useBidiPackage()
-           || !getFontSettings(bparams, pos).isRightToLeft())
+       // or if we use poylglossia/bidi (XeTeX)
+       // or with babel and Xe/LuaTeX.
+       if (!getFontSettings(bparams, pos).isRightToLeft()
+           || rp.useBidiPackage()
+           || (rp.use_babel && rp.isFullUnicode()))
                return c;
 
        // Without polyglossia/bidi, we need to account for some special cases.
@@ -2268,6 +2309,22 @@ bool Paragraph::isPassThru() const
        return inInset().isPassThru() || d->layout_->pass_thru;
 }
 
+
+bool Paragraph::parbreakIsNewline() const
+{
+       return inInset().getLayout().parbreakIsNewline() || d->layout_->parbreak_is_newline;
+}
+
+
+bool Paragraph::isPartOfTextSequence() const
+{
+       for (pos_type i = 0; i < size(); ++i) {
+               if (!isInset(i) || getInset(i)->isPartOfTextSequence())
+                       return true;
+       }
+       return false;
+}
+
 namespace {
 
 // paragraphs inside floats need different alignment tags to avoid
@@ -2339,13 +2396,31 @@ int Paragraph::Private::startTeXParParams(BufferParams const & bparams,
                        (layout_->toggle_indent != ITOGGLE_NEVER) :
                        (layout_->toggle_indent == ITOGGLE_ALWAYS);
 
-       if (canindent && params_.noindent() && !layout_->pass_thru) {
-               os << "\\noindent ";
-               column += 10;
-       }
-
        LyXAlignment const curAlign = params_.align();
 
+       // Do not output \\noindent for paragraphs
+       // 1. that cannot have indentation or are indented always,
+       // 2. that are not part of the immediate text sequence (e.g., contain only floats),
+       // 3. that are PassThru,
+       // 4. or that are centered.
+       if (canindent && params_.noindent()
+           && owner_->isPartOfTextSequence()
+           && !layout_->pass_thru
+           && curAlign != LYX_ALIGN_CENTER) {
+               if (!owner_->empty()
+                   && owner_->getInset(0)
+                   && owner_->getInset(0)->lyxCode() == VSPACE_CODE)
+                       // If the paragraph starts with a vspace, the \\noindent
+                       // needs to come after that (as it leaves vmode).
+                       // If the paragraph consists only of the vspace,
+                       // \\noindent is not needed at all.
+                       runparams.need_noindent = owner_->size() > 1;
+               else {
+                       os << "\\noindent" << termcmd;
+                       column += 10;
+               }
+       }
+
        if (curAlign == layout_->align)
                return column;
 
@@ -2476,7 +2551,7 @@ void Paragraph::latex(BufferParams const & bparams,
        OutputParams const & runparams,
        int start_pos, int end_pos, bool force) const
 {
-       LYXERR(Debug::LATEX, "Paragraph::latex...     " << this);
+       LYXERR(Debug::OUTFILE, "Paragraph::latex...     " << this);
 
        // FIXME This check should not be needed. Perhaps issue an
        // error if it triggers.
@@ -2505,10 +2580,10 @@ void Paragraph::latex(BufferParams const & bparams,
        pos_type body_pos = beginOfBody();
        unsigned int column = 0;
 
-       // If we are inside an non inheritFont() inset, the real outerfont is local_font
-       Font const real_outerfont = (!inInset().inheritFont()
-                                    && runparams.local_font != nullptr)
-                       ? Font(runparams.local_font->fontInfo()) : outerfont;
+       // If we are inside an non inheritFont() inset,
+       // the outerfont is the buffer's main font
+       Font const real_outerfont =
+               inInset().inheritFont() ? outerfont : Font(bparams.getFont());
 
        if (body_pos > 0) {
                // the optional argument is kept in curly brackets in
@@ -2576,7 +2651,7 @@ void Paragraph::latex(BufferParams const & bparams,
                                                runparams);
                                runningChange = Change(Change::UNCHANGED);
 
-                               os << (isEnvSeparator(i) ? "}]~" : "}] ");
+                               os << ((isEnvSeparator(i) && !runparams.find_effective()) ? "}]~" : "}] ");
                                column +=3;
                        }
                        // For InTitle commands, we have already opened a group
@@ -2606,10 +2681,10 @@ void Paragraph::latex(BufferParams const & bparams,
 
                // Check whether a display math inset follows
                bool output_changes;
-               if (runparams.for_searchAdv == OutputParams::NoSearch)
+               if (!runparams.find_effective())
                        output_changes = bparams.output_changes;
                else
-                       output_changes = (runparams.for_searchAdv == OutputParams::SearchWithDeleted);
+                       output_changes = runparams.find_with_deleted();
                if (c == META_INSET
                    && i >= start_pos && (end_pos == -1 || i < end_pos)) {
                        if (isDeleted(i))
@@ -2739,9 +2814,11 @@ void Paragraph::latex(BufferParams const & bparams,
                                os << '}';
                                column += 1;
                        }
-                       if (closeLanguage)
+                       if (closeLanguage) {
                                // Force language closing
                                current_font.setLanguage(basefont.language());
+                               langClosed = true;
+                       }
                        Font const nextfont = (i == body_pos-1) ? basefont : current_font;
                        bool needPar = false;
                        column += running_font.latexWriteEndChanges(
@@ -2754,12 +2831,12 @@ void Paragraph::latex(BufferParams const & bparams,
                                column += Changes::latexMarkChange(os, bparams,
                                        Change(Change::UNCHANGED), Change(Change::DELETED), rp);
                        }
-                       open_font = false;
                        // Has the language been closed in the latexWriteEndChanges() call above?
-                       langClosed = running_font.language() != basefont.language()
+                       langClosed |= running_font.language() != basefont.language()
                                        && running_font.language() != nextfont.language()
                                        && (running_font.language()->encoding()->package() != Encoding::CJK);
                        running_font = basefont;
+                       open_font &= !langClosed;
                }
 
                // if necessary, close language environment before opening CJK
@@ -2772,7 +2849,8 @@ void Paragraph::latex(BufferParams const & bparams,
                        string end_tag = subst(lang_end_command, "$$lang", running_lang);
                        os << from_ascii(end_tag);
                        column += end_tag.length();
-                       popLanguageName();
+                       if (!languageStackEmpty())
+                               popLanguageName();
                }
 
                // Switch file encoding if necessary (and allowed)
@@ -2858,9 +2936,14 @@ void Paragraph::latex(BufferParams const & bparams,
                                        column += Changes::latexMarkChange(os, bparams,
                                                Change(Change::UNCHANGED), change, rp);
                                }
-                       } else {
+                       } else {// if fontswitch_inset
+                               if (current_font != running_font || !langClosed)
+                                       // font is still open in fontswitch_insets if we have
+                                       // a non-lang font difference or if the language
+                                       // is the only difference but has not been forcedly
+                                       // closed meanwhile
+                                       open_font = true;
                                running_font = current_font;
-                               open_font = !langClosed;
                        }
                }
 
@@ -2929,7 +3012,7 @@ void Paragraph::latex(BufferParams const & bparams,
                                d->latexInset(bparams, os, rp, running_font,
                                                basefont, real_outerfont, open_font,
                                                runningChange, style, i, column, fontswitch_inset,
-                                               closeLanguage, lang_switched_at_inset);
+                                               closeLanguage, (lang_switched_at_inset || langClosed));
                                if (fontswitch_inset) {
                                        if (open_font) {
                                                bool needPar = false;
@@ -3092,7 +3175,7 @@ void Paragraph::latex(BufferParams const & bparams,
                os << setEncoding(prev_encoding->iconvName());
        }
 
-       LYXERR(Debug::LATEX, "Paragraph::latex... done " << this);
+       LYXERR(Debug::OUTFILE, "Paragraph::latex... done " << this);
 }
 
 
@@ -3447,9 +3530,12 @@ std::tuple<std::vector<docstring>, std::vector<docstring>, std::vector<docstring
                                                       bool is_last_par,
                                                       bool ignore_fonts) const
 {
-       std::vector<docstring> prependedParagraphs;
-       std::vector<docstring> generatedParagraphs;
-       std::vector<docstring> appendedParagraphs;
+       // Return values: segregation of the content of this paragraph.
+       std::vector<docstring> prependedParagraphs; // Anything that must be output before the main tag of this paragraph.
+       std::vector<docstring> generatedParagraphs; // The main content of the paragraph.
+       std::vector<docstring> appendedParagraphs;  // Anything that must be output after the main tag of this paragraph.
+
+       // Internal string stream to store the output before being added to one of the previous lists.
        odocstringstream os;
 
        // If there is an argument that must be output before the main tag, do it before handling the rest of the paragraph.
@@ -3476,16 +3562,16 @@ std::tuple<std::vector<docstring>, std::vector<docstring>, std::vector<docstring
     // State variables for the main loop.
     auto xs = new XMLStream(os); // XMLStream has no copy constructor: to create a new object, the only solution
     // is to hold a pointer to the XMLStream (xs = XMLStream(os) is not allowed once the first object is built).
-    std::vector<char_type> delayedChars; // When a font tag ends with a space, output it after the closing font tag.
+    std::vector<docstring> delayedChars; // When a font tag ends with a space, output it after the closing font tag.
     // This requires to store delayed characters at some point.
 
-    DocBookFontState fs; // Track whether we have opened font tags
+       // Track whether we have opened font tags
+    DocBookFontState fs;
     DocBookFontState old_fs = fs;
 
     Layout const & style = *d->layout_;
-    FontInfo font_old = style.labeltype == LABEL_MANUAL ? style.labelfont : style.font;
-    string const default_family = buf.masterBuffer()->params().fonts_default_family;
 
+       // Conversion of the font opening/closing into DocBook tags.
     vector<xml::FontTag> tagsToOpen;
     vector<xml::EndFontTag> tagsToClose;
 
@@ -3508,7 +3594,7 @@ std::tuple<std::vector<docstring>, std::vector<docstring>, std::vector<docstring
                        // Output one paragraph (i.e. one string entry in generatedParagraphs).
                        generatedParagraphs.push_back(os.str());
 
-                       // Create a new XMLStream for the new paragraph, completely independent from the previous one. This implies
+                       // Create a new XMLStream for the new paragraph, completely independent of the previous one. This implies
                        // that the string stream must be reset.
                        os.str(from_ascii(""));
                        delete xs;
@@ -3516,14 +3602,17 @@ std::tuple<std::vector<docstring>, std::vector<docstring>, std::vector<docstring
 
                        // Restore the fonts for the new paragraph, so that the right tags are opened for the new entry.
                        if (!ignore_fonts_i) {
-                               font_old = outerfont.fontInfo();
                                fs = old_fs;
                        }
                }
 
                // Determine which tags should be opened or closed regarding fonts.
+               FontInfo const font_old = (i == 0 ?
+                               (style.labeltype == LABEL_MANUAL ? style.labelfont : style.font) :
+                               getFont(buf.masterBuffer()->params(), i - 1, outerfont).fontInfo());
                Font const font = getFont(buf.masterBuffer()->params(), i, outerfont);
-        tie(tagsToOpen, tagsToClose) = computeDocBookFontSwitch(font_old, font, default_family, fs);
+        tie(tagsToOpen, tagsToClose) = computeDocBookFontSwitch(
+                               font_old, font, buf.masterBuffer()->params().fonts_default_family, fs);
 
                if (!ignore_fonts_i) {
             vector<xml::EndFontTag>::const_iterator cit = tagsToClose.begin();
@@ -3534,8 +3623,8 @@ std::tuple<std::vector<docstring>, std::vector<docstring>, std::vector<docstring
 
         // Deal with the delayed characters *after* closing font tags.
         if (!delayedChars.empty()) {
-            for (char_type c: delayedChars)
-                *xs << c;
+            for (const docstring& c: delayedChars)
+                *xs << XMLStream::ESCAPE_NONE << c;
             delayedChars.clear();
         }
 
@@ -3566,12 +3655,19 @@ std::tuple<std::vector<docstring>, std::vector<docstring>, std::vector<docstring
                        }
                } else {
                        char_type c = getUChar(buf.masterBuffer()->params(), rp, i);
-                       if (lyx::isSpace(c) && !ignore_fonts)
-                               delayedChars.push_back(c);
-                       else
-                               *xs << c;
+                       if (lyx::isSpace(c) && !ignore_fonts) { // Delay spaces *after* the font-tag closure for cleaner output.
+                               if (c == ' ' && (style.free_spacing || rp.free_spacing)) {
+                                       delayedChars.push_back(from_ascii("&#160;"));
+                               } else {
+                                       delayedChars.emplace_back(1, c);
+                               }
+                       } else { // No need to delay the character.
+                               if (c == '\'' && !ignore_fonts)
+                                       *xs << XMLStream::ESCAPE_NONE << "&#8217;";
+                               else
+                                       *xs << c;
+                       }
                }
-               font_old = font.fontInfo();
        }
 
        // FIXME, this code is just imported from XHTML
@@ -3581,9 +3677,11 @@ std::tuple<std::vector<docstring>, std::vector<docstring>, std::vector<docstring
                xs->closeFontTags();
 
        // Deal with the delayed characters *after* closing font tags.
-       if (!delayedChars.empty())
-               for (char_type c: delayedChars)
-                       *xs << c;
+       if (!delayedChars.empty()) {
+               for (const docstring &c: delayedChars)
+                       *xs << XMLStream::ESCAPE_NONE << c;
+               delayedChars.clear();
+       }
 
        // In listings, new lines (i.e. \n characters in the output) are very important. Avoid generating one for the
        // last line to get a clean output.
@@ -3933,16 +4031,10 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf,
                // FIXME XHTML
                // Other such tags? What about the other text ranges?
 
-               vector<xml::EndFontTag>::const_iterator cit = tagsToClose.begin();
-               vector<xml::EndFontTag>::const_iterator cen = tagsToClose.end();
-               for (; cit != cen; ++cit)
-                       xs << *cit;
-
-               vector<xml::FontTag>::const_iterator sit = tagsToOpen.begin();
-               vector<xml::FontTag>::const_iterator sen = tagsToOpen.end();
-               for (; sit != sen; ++sit)
-                       xs << *sit;
-
+               for (auto const & t : tagsToClose)
+                       xs << t;
+               for (auto const & t : tagsToOpen)
+                       xs << t;
                tagsToClose.clear();
                tagsToOpen.clear();
 
@@ -3961,7 +4053,9 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf,
                        char_type c = getUChar(buf.masterBuffer()->params(),
                                               runparams, i);
                        if (c == ' ' && (style.free_spacing || runparams.free_spacing))
-                               xs << XMLStream::ESCAPE_NONE << "&nbsp;";
+                               xs << XMLStream::ESCAPE_NONE << "&#160;";
+                       else if (c == '\'')
+                               xs << XMLStream::ESCAPE_NONE << "&#8217;";
                        else
                                xs << c;
                }
@@ -4080,27 +4174,12 @@ bool Paragraph::needsCProtection(bool const fragile) const
        }
 
        // now check whether we have insets that need cprotection
-       pos_type size = pos_type(d->text_.size());
-       for (pos_type i = 0; i < size; ++i) {
-               if (!isInset(i))
+       for (auto const & icit : d->insetlist_) {
+               Inset const * ins = icit.inset;
+               if (!ins)
                        continue;
-               Inset const * ins = getInset(i);
                if (ins->needsCProtection(maintext, fragile))
                        return true;
-               // Now check math environments
-               InsetMath const * im = getInset(i)->asInsetMath();
-               if (!im || im->cell(0).empty())
-                       continue;
-               switch(im->cell(0)[0]->lyxCode()) {
-               case MATH_AMSARRAY_CODE:
-               case MATH_SUBSTACK_CODE:
-               case MATH_ENV_CODE:
-               case MATH_XYMATRIX_CODE:
-                       // these need cprotection
-                       return true;
-               default:
-                       break;
-               }
        }
 
        return false;
@@ -4211,7 +4290,10 @@ docstring Paragraph::asString(pos_type beg, pos_type end, int options, const Out
                else if (c == META_INSET && (options & AS_STR_INSETS)) {
                        if (c == META_INSET && (options & AS_STR_PLAINTEXT)) {
                                LASSERT(runparams != nullptr, return docstring());
-                               getInset(i)->plaintext(os, *runparams);
+                               if (runparams->find_effective())
+                                       getInset(i)->toString(os);
+                               else
+                                       getInset(i)->plaintext(os, *runparams);
                        } else if (c == META_INSET && (options & AS_STR_MATHED)
                                   && getInset(i)->lyxCode() == REF_CODE) {
                                Buffer const & buf = getInset(i)->buffer();
@@ -4540,7 +4622,6 @@ void Paragraph::changeCase(BufferParams const & bparams, pos_type pos,
        }
 }
 
-
 int Paragraph::find(docstring const & str, bool cs, bool mw,
                pos_type start_pos, bool del) const
 {
@@ -4565,7 +4646,14 @@ int Paragraph::find(docstring const & str, bool cs, bool mw,
                        if (!inset->isLetter() && !inset->isChar())
                                break;
                        odocstringstream os;
-                       inset->toString(os);
+                       if (inset->lyxCode() == lyx::QUOTE_CODE) {
+                               OutputParams op(0);
+                               op.find_set_feature(OutputParams::SearchQuick);
+                               inset->plaintext(os, op);
+                       }
+                       else {
+                               inset->toString(os);
+                       }
                        docstring const insetstring = os.str();
                        if (!insetstring.empty()) {
                                int const insetstringsize = insetstring.length();
@@ -4581,9 +4669,10 @@ int Paragraph::find(docstring const & str, bool cs, bool mw,
                }
                if (nonmatch || i == strsize)
                        break;
-               if (cs && str[i] != d->text_[pos])
+               char_type dp = d->text_[pos];
+               if (cs && str[i] != dp)
                        break;
-               if (!cs && uppercase(str[i]) != uppercase(d->text_[pos]))
+               if (!cs && uppercase(str[i]) != uppercase(dp))
                        break;
        }
 
@@ -4830,6 +4919,19 @@ Language * Paragraph::Private::getSpellLanguage(pos_type const from) const
 void Paragraph::requestSpellCheck(pos_type pos)
 {
        d->requestSpellCheck(pos);
+       if (pos == -1) {
+               // Also request spellcheck within (text) insets
+               for (auto const & insets : insetList()) {
+                       if (!insets.inset->asInsetText())
+                               continue;
+                       ParagraphList & inset_pars =
+                               insets.inset->asInsetText()->paragraphs();
+                       ParagraphList::iterator pit = inset_pars.begin();
+                       ParagraphList::iterator pend = inset_pars.end();
+                       for (; pit != pend; ++pit)
+                               pit->requestSpellCheck();
+               }
+       }
 }