diff --git a/lib/symbols b/lib/symbols index e32f50dfc9..5604a79340 100644 --- a/lib/symbols +++ b/lib/symbols @@ -90,6 +90,9 @@ texttt font textmode textup font textmode emph font textmode noun font textmode +# ce and cf are provided by the mhchem package +ce font forcetext +cf font forcetext # old-style font commands bf oldfont none diff --git a/src/Cursor.cpp b/src/Cursor.cpp index dc20944178..911331861d 100644 --- a/src/Cursor.cpp +++ b/src/Cursor.cpp @@ -404,7 +404,10 @@ int Cursor::currentMode() LASSERT(!empty(), /**/); for (int i = depth() - 1; i >= 0; --i) { int res = operator[](i).inset().currentMode(); - if (res != Inset::UNDECIDED_MODE) + bool locked_mode = operator[](i).inset().lockedMode(); + // Also return UNDECIDED_MODE when the mode is locked, + // as in this case it is treated the same as TEXT_MODE + if (res != Inset::UNDECIDED_MODE || locked_mode) return res; } return Inset::TEXT_MODE; diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp index 8f8e8b141d..aaf5460b0d 100644 --- a/src/LaTeXFeatures.cpp +++ b/src/LaTeXFeatures.cpp @@ -690,6 +690,10 @@ string const LaTeXFeatures::getPackages() const packages << "\\PassOptionsToPackage{normalem}{ulem}\n" "\\usepackage{ulem}\n"; + if (mustProvide("mhchem")) + packages << "\\PassOptionsToPackage{version=3}{mhchem}\n" + "\\usepackage{mhchem}\n"; + if (mustProvide("nomencl")) { // Make it work with the new and old version of the package, // but don't use the compatibility option since it is diff --git a/src/insets/Inset.h b/src/insets/Inset.h index ea8fbfc54a..e82657ef3b 100644 --- a/src/insets/Inset.h +++ b/src/insets/Inset.h @@ -470,6 +470,8 @@ public: enum mode_type {UNDECIDED_MODE, TEXT_MODE, MATH_MODE}; /// return text or mathmode if that is possible to determine virtual mode_type currentMode() const { return UNDECIDED_MODE; } + /// returns whether changing mode during latex export is forbidden + virtual bool lockedMode() const { return false; } /// returns whether this inset is allowed in other insets of given mode virtual bool allowedIn(mode_type) const { return true; } /** diff --git a/src/mathed/InsetMath.h b/src/mathed/InsetMath.h index 589f7b27e3..4e79e7b6e4 100644 --- a/src/mathed/InsetMath.h +++ b/src/mathed/InsetMath.h @@ -97,6 +97,9 @@ public: /// this is overridden in math text insets (i.e. mbox) bool inMathed() const { return true; } + /// this is overridden by specific insets + virtual mode_type currentMode() const { return MATH_MODE; } + /// the ascent of the inset above the baseline /// compute the size of the object for text based drawing virtual void metricsT(TextMetricsInfo const & mi, Dimension & dim) const; diff --git a/src/mathed/InsetMathFont.cpp b/src/mathed/InsetMathFont.cpp index 86582600b8..dcf4747c60 100644 --- a/src/mathed/InsetMathFont.cpp +++ b/src/mathed/InsetMathFont.cpp @@ -44,6 +44,14 @@ InsetMath::mode_type InsetMathFont::currentMode() const } +bool InsetMathFont::lockedMode() const +{ + if (key_->extra == "forcetext") + return true; + return false; +} + + void InsetMathFont::metrics(MetricsInfo & mi, Dimension & dim) const { FontSetChanger dummy(mi.base, key_->name); @@ -93,6 +101,8 @@ void InsetMathFont::validate(LaTeXFeatures & features) const features.require("amstext"); if (key_->name == "textipa") features.require("tipa"); + if (key_->name == "ce" || key_->name == "cf") + features.require("mhchem"); } diff --git a/src/mathed/InsetMathFont.h b/src/mathed/InsetMathFont.h index a55c1f77b1..d93286dfae 100644 --- a/src/mathed/InsetMathFont.h +++ b/src/mathed/InsetMathFont.h @@ -31,6 +31,8 @@ public: InsetMathFont const * asFontInset() const { return this; } /// are we in math mode, text mode, or unsure? mode_type currentMode() const; + /// do we allow changing mode during latex export? + bool lockedMode() const; /// docstring name() const; /// diff --git a/src/mathed/InsetMathGrid.cpp b/src/mathed/InsetMathGrid.cpp index a6f19b5bea..fb90a3e3c8 100644 --- a/src/mathed/InsetMathGrid.cpp +++ b/src/mathed/InsetMathGrid.cpp @@ -1251,7 +1251,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) parseflg |= Parse::VERBATIM; // fall through case LFUN_PASTE: { - if (cur.currentMode() == TEXT_MODE) + if (cur.currentMode() <= TEXT_MODE) parseflg |= Parse::TEXTMODE; cur.message(_("Paste")); cap::replaceSelection(cur); diff --git a/src/mathed/InsetMathNest.cpp b/src/mathed/InsetMathNest.cpp index 1671452209..74d227394e 100644 --- a/src/mathed/InsetMathNest.cpp +++ b/src/mathed/InsetMathNest.cpp @@ -339,7 +339,7 @@ MathData InsetMathNest::glue() const void InsetMathNest::write(WriteStream & os) const { - ModeSpecifier specifier(os, currentMode()); + ModeSpecifier specifier(os, currentMode(), lockedMode()); docstring const latex_name = name(); os << '\\' << latex_name; for (size_t i = 0; i < nargs(); ++i) @@ -524,7 +524,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) parseflg |= Parse::VERBATIM; // fall through case LFUN_PASTE: { - if (cur.currentMode() == TEXT_MODE) + if (cur.currentMode() <= TEXT_MODE) parseflg |= Parse::TEXTMODE; cur.recordUndoSelection(); cur.message(_("Paste")); @@ -890,37 +890,37 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) break; case LFUN_FONT_BOLD: - if (currentMode() == TEXT_MODE) + if (currentMode() <= TEXT_MODE) handleFont(cur, cmd.argument(), "textbf"); else handleFont(cur, cmd.argument(), "mathbf"); break; case LFUN_FONT_BOLDSYMBOL: - if (currentMode() == TEXT_MODE) + if (currentMode() <= TEXT_MODE) handleFont(cur, cmd.argument(), "textbf"); else handleFont(cur, cmd.argument(), "boldsymbol"); break; case LFUN_FONT_SANS: - if (currentMode() == TEXT_MODE) + if (currentMode() <= TEXT_MODE) handleFont(cur, cmd.argument(), "textsf"); else handleFont(cur, cmd.argument(), "mathsf"); break; case LFUN_FONT_EMPH: - if (currentMode() == TEXT_MODE) + if (currentMode() <= TEXT_MODE) handleFont(cur, cmd.argument(), "emph"); else handleFont(cur, cmd.argument(), "mathcal"); break; case LFUN_FONT_ROMAN: - if (currentMode() == TEXT_MODE) + if (currentMode() <= TEXT_MODE) handleFont(cur, cmd.argument(), "textrm"); else handleFont(cur, cmd.argument(), "mathrm"); break; case LFUN_FONT_TYPEWRITER: - if (currentMode() == TEXT_MODE) + if (currentMode() <= TEXT_MODE) handleFont(cur, cmd.argument(), "texttt"); else handleFont(cur, cmd.argument(), "mathtt"); @@ -929,13 +929,13 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) handleFont(cur, cmd.argument(), "mathfrak"); break; case LFUN_FONT_ITAL: - if (currentMode() == TEXT_MODE) + if (currentMode() <= TEXT_MODE) handleFont(cur, cmd.argument(), "textit"); else handleFont(cur, cmd.argument(), "mathit"); break; case LFUN_FONT_NOUN: - if (currentMode() == TEXT_MODE) + if (currentMode() <= TEXT_MODE) // FIXME: should be "noun" handleFont(cur, cmd.argument(), "textsc"); else @@ -955,7 +955,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) docstring const save_selection = grabAndEraseSelection(cur); selClearOrDel(cur); //cur.plainInsert(MathAtom(new InsetMathMBox(cur.bv()))); - if (currentMode() == Inset::TEXT_MODE) + if (currentMode() <= Inset::TEXT_MODE) cur.plainInsert(MathAtom(new InsetMathEnsureMath)); else cur.plainInsert(MathAtom(new InsetMathBox(from_ascii("mbox")))); @@ -1459,7 +1459,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type c) // remove the '\\' if (c == '\\') { cur.backspace(); - if (currentMode() == InsetMath::TEXT_MODE) + if (currentMode() <= InsetMath::TEXT_MODE) cur.niceInsert(createInsetMath("textbackslash")); else cur.niceInsert(createInsetMath("backslash")); @@ -1551,14 +1551,14 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type c) selClearOrDel(cur); if (c == '\n') { - if (currentMode() == InsetMath::TEXT_MODE) + if (currentMode() <= InsetMath::TEXT_MODE) cur.insert(c); return true; } if (c == ' ') { - if (currentMode() == InsetMath::TEXT_MODE) { - // insert spaces in text mode, + if (currentMode() <= InsetMath::TEXT_MODE) { + // insert spaces in text or undecided mode, // but suppress direct insertion of two spaces in a row // the still allows typing 'a' and deleting the 'a', but // it is better than nothing... @@ -1609,7 +1609,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type c) cur.niceInsert(createInsetMath("sim")); return true; } - if (!isAsciiOrMathAlpha(c)) { + if (currentMode() == InsetMath::MATH_MODE && !isAsciiOrMathAlpha(c)) { MathAtom at = createInsetMath("text"); at.nucleus()->cell(0).push_back(MathAtom(new InsetMathChar(c))); cur.niceInsert(at); diff --git a/src/mathed/InsetMathString.cpp b/src/mathed/InsetMathString.cpp index 0dd17fe6d1..6e4c99ee70 100644 --- a/src/mathed/InsetMathString.cpp +++ b/src/mathed/InsetMathString.cpp @@ -103,7 +103,7 @@ void InsetMathString::mathmlize(MathStream & os) const void InsetMathString::write(WriteStream & os) const { - if (!os.latex()) { + if (!os.latex() || os.lockedMode()) { os << str_; return; } diff --git a/src/mathed/MathFactory.cpp b/src/mathed/MathFactory.cpp index 006453410a..b27739270f 100644 --- a/src/mathed/MathFactory.cpp +++ b/src/mathed/MathFactory.cpp @@ -275,7 +275,7 @@ bool ensureMath(WriteStream & os, bool needs_math_mode, bool macro) } -bool ensureMode(WriteStream & os, InsetMath::mode_type mode) +int ensureMode(WriteStream & os, InsetMath::mode_type mode, bool locked) { bool textmode = mode == InsetMath::TEXT_MODE; if (os.latex() && textmode && os.pendingBrace()) { @@ -284,9 +284,11 @@ bool ensureMode(WriteStream & os, InsetMath::mode_type mode) os.pendingSpace(false); os.textMode(true); } - bool oldmode = os.textMode(); + int oldmodes = os.textMode() ? 1 : 0; os.textMode(textmode); - return oldmode; + oldmodes |= os.lockedMode() ? 2 : 0; + os.lockedMode(locked); + return oldmodes; } diff --git a/src/mathed/MathStream.cpp b/src/mathed/MathStream.cpp index 67622ebd54..d2a86af506 100644 --- a/src/mathed/MathStream.cpp +++ b/src/mathed/MathStream.cpp @@ -155,6 +155,12 @@ void WriteStream::textMode(bool textmode) } +void WriteStream::lockedMode(bool locked) +{ + locked_ = locked; +} + + WriteStream & operator<<(WriteStream & ws, MathAtom const & at) { at->write(ws); diff --git a/src/mathed/MathStream.h b/src/mathed/MathStream.h index e88f7cd85e..2ab8f7f713 100644 --- a/src/mathed/MathStream.h +++ b/src/mathed/MathStream.h @@ -65,6 +65,10 @@ public: void textMode(bool textmode); /// tell whether we are in text mode or not when producing latex code bool textMode() const { return textmode_; } + /// tell whether we are allowed to switch mode when producing latex code + void lockedMode(bool locked); + /// tell whether we are allowed to switch mode when producing latex code + bool lockedMode() const { return locked_; } /// LaTeX encoding Encoding const * encoding() const { return encoding_; } private: @@ -84,6 +88,8 @@ private: bool pendingbrace_; /// are we in text mode when producing latex code? bool textmode_; + /// are we allowed to switch mode when producing latex code? + bool locked_; /// int line_; /// @@ -109,7 +115,7 @@ WriteStream & operator<<(WriteStream &, unsigned int); bool ensureMath(WriteStream & os, bool needs_math_mode = true, bool macro = false); /// ensure the requested mode, possibly by closing \ensuremath -bool ensureMode(WriteStream & os, InsetMath::mode_type mode); +int ensureMode(WriteStream & os, InsetMath::mode_type mode, bool locked); /** @@ -169,12 +175,22 @@ private: * environment works in a given mode. For example, \mbox works in text * mode, but \boxed works in math mode. Note that no mode changing commands * are needed, but we have to track the current mode, hence this class. + * This is only used when exporting to latex and helps determining whether + * the mode needs being temporarily switched when a command would not work + * in the current mode. As there are cases where this switching is to be + * avoided, the optional third parameter can be used to lock the mode. * - * Example: + * Example 1: * * ModeSpecifier specifier(os, TEXT_MODE); * - * Sets the current mode to text mode. + * Sets the current mode to text mode and allows mode switching. + * + * Example 2: + * + * ModeSpecifier specifier(os, TEXT_MODE, true); + * + * Sets the current mode to text mode and disallows mode switching. * * At the end of specifier's scope the mode is reset to its previous value. */ @@ -182,15 +198,20 @@ class ModeSpecifier { public: /// - explicit ModeSpecifier(WriteStream & os, InsetMath::mode_type mode) - : os_(os), textmode_(ensureMode(os, mode)) {} + explicit ModeSpecifier(WriteStream & os, InsetMath::mode_type mode, + bool locked = false) + : os_(os), oldmodes_(ensureMode(os, mode, locked)) {} /// - ~ModeSpecifier() { os_.textMode(textmode_); } + ~ModeSpecifier() + { + os_.textMode(oldmodes_ & 1); + os_.lockedMode(oldmodes_ & 2); + } private: /// WriteStream & os_; /// - bool textmode_; + int oldmodes_; }; diff --git a/src/mathed/MathSupport.cpp b/src/mathed/MathSupport.cpp index 267e7ea1af..528a25e1de 100644 --- a/src/mathed/MathSupport.cpp +++ b/src/mathed/MathSupport.cpp @@ -580,6 +580,12 @@ fontinfo fontinfos[] = { {"textipa", inh_family, inh_series, inh_shape, Color_foreground}, + // mhchem support + {"ce", inh_family, inh_series, + inh_shape, Color_foreground}, + {"cf", inh_family, inh_series, + inh_shape, Color_foreground}, + // LyX internal usage {"lyxtex", inh_family, inh_series, UP_SHAPE, Color_latex}, diff --git a/status.16x b/status.16x index 1209629faf..8d9a66e8b8 100644 --- a/status.16x +++ b/status.16x @@ -179,6 +179,9 @@ What's new - Fix wrong labeling as "child only" branch if branches were unknown. +- Fix typesetting of chemical equations by adding support for the mhchem + package (bugs 6047, 4043, and 5394). + * DOCUMENTATION AND LOCALIZATION