From 90837aaf6eee523fd594c0ea7f44c053bb49a3cf Mon Sep 17 00:00:00 2001 From: Enrico Forestieri Date: Mon, 16 Jun 2008 01:21:17 +0000 Subject: [PATCH] Fix bug 1527 http://bugzilla.lyx.org/show_bug.cgi?id=1527 * src/mathed/*.cpp: - Track mode (math or text) when outputting latex code and properly wrap commands that are in the wrong mode with either \ensuremath or \lyxmathsym. * src/mathed/MathParser.cpp: - Parse \ensuremath and \lyxmathsym, such that exported latex produces the same result when imported back. - Replace latex commands with corresponding unicode symbols. * src/Encoding.cpp: - Implement Encodings::fromLaTeXCommand() for converting either a single or a sequence of latex commands to unicode symbols. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@25270 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/Encoding.cpp | 93 +++++++++++++++++++++++ src/Encoding.h | 13 ++++ src/mathed/CommandInset.cpp | 12 ++- src/mathed/CommandInset.h | 4 +- src/mathed/InsetMath.cpp | 7 ++ src/mathed/InsetMathAMSArray.cpp | 8 ++ src/mathed/InsetMathArray.cpp | 10 +++ src/mathed/InsetMathBig.cpp | 8 ++ src/mathed/InsetMathBoldSymbol.cpp | 8 ++ src/mathed/InsetMathBox.cpp | 18 ++--- src/mathed/InsetMathCases.cpp | 7 ++ src/mathed/InsetMathDecoration.cpp | 8 ++ src/mathed/InsetMathDelim.cpp | 10 +++ src/mathed/InsetMathEnv.cpp | 8 ++ src/mathed/InsetMathFrac.cpp | 25 +++++- src/mathed/InsetMathGrid.cpp | 16 +++- src/mathed/InsetMathNest.cpp | 6 +- src/mathed/InsetMathOverset.cpp | 7 ++ src/mathed/InsetMathPhantom.cpp | 8 ++ src/mathed/InsetMathRef.cpp | 4 +- src/mathed/InsetMathRoot.cpp | 8 ++ src/mathed/InsetMathScript.cpp | 10 +++ src/mathed/InsetMathSize.cpp | 8 ++ src/mathed/InsetMathSpace.cpp | 8 ++ src/mathed/InsetMathSplit.cpp | 8 ++ src/mathed/InsetMathSqrt.cpp | 8 ++ src/mathed/InsetMathStackrel.cpp | 8 ++ src/mathed/InsetMathString.cpp | 38 +++++++--- src/mathed/InsetMathSubstack.cpp | 8 ++ src/mathed/InsetMathSymbol.cpp | 8 ++ src/mathed/InsetMathTabular.cpp | 11 +++ src/mathed/InsetMathUnderset.cpp | 8 ++ src/mathed/InsetMathXArrow.cpp | 10 +++ src/mathed/InsetMathXYArrow.cpp | 8 ++ src/mathed/InsetMathXYMatrix.cpp | 8 ++ src/mathed/MathMacro.cpp | 21 +++++- src/mathed/MathParser.cpp | 117 ++++++++++++++++++++++++----- src/mathed/MathStream.cpp | 47 ++++++++++-- src/mathed/MathStream.h | 6 ++ 39 files changed, 570 insertions(+), 58 deletions(-) diff --git a/src/Encoding.cpp b/src/Encoding.cpp index e08095cf2d..e75fe3ede7 100644 --- a/src/Encoding.cpp +++ b/src/Encoding.cpp @@ -386,6 +386,99 @@ bool Encodings::latexMathChar(char_type c, docstring & command) } +char_type Encodings::fromLaTeXCommand(docstring const & cmd, bool & combining) +{ + CharInfoMap::const_iterator const end = unicodesymbols.end(); + CharInfoMap::const_iterator it = unicodesymbols.begin(); + for (; it != end; ++it) { + docstring const math = it->second.mathcommand; + docstring const text = it->second.textcommand; + if (math == cmd || text == cmd) { + combining = it->second.combining; + return it->first; + } + } + return 0; +} + + +docstring Encodings::fromLaTeXCommand(docstring const & cmd, docstring & rem) +{ + docstring symbols; + size_t i = 0; + size_t const cmdend = cmd.size(); + CharInfoMap::const_iterator const uniend = unicodesymbols.end(); + for (size_t j = 0; j < cmdend; ++j) { + // Also get the char after a backslash + if (j + 1 < cmdend && cmd[j] == '\\') + ++j; + // If a macro argument follows, get it, too + if (j + 1 < cmdend && cmd[j + 1] == '{') { + size_t k = j + 1; + int count = 1; + while (k < cmdend && count && k != docstring::npos) { + k = cmd.find_first_of(from_ascii("{}"), k + 1); + if (cmd[k] == '{') + ++count; + else + --count; + } + if (k != docstring::npos) + j = k; + } + // Start with this substring and try augmenting it when it is + // the prefix of some command in the unicodesymbols file + docstring const subcmd = cmd.substr(i, j - i + 1); + + CharInfoMap::const_iterator it = unicodesymbols.begin(); + size_t unicmd_size = 0; + char_type c; + for (; it != uniend; ++it) { + docstring const math = it->second.mathcommand; + docstring const text = it->second.textcommand; + size_t cur_size = max(math.size(), text.size()); + // The current math or text unicode command cannot + // match, or we already matched a longer one + if (cur_size < subcmd.size() || cur_size <= unicmd_size) + continue; + + docstring tmp = subcmd; + size_t k = j; + while (prefixIs(math, tmp) || prefixIs(text, tmp)) { + ++k; + if (k >= cmdend || cur_size <= tmp.size()) + break; + tmp += cmd[k]; + } + // No match + if (k == j) + continue; + + // The last added char caused a mismatch, because + // we didn't exhaust the chars in cmd and didn't + // exceed the maximum size of the current unicmd + if (k < cmdend && cur_size > tmp.size()) + tmp.resize(tmp.size() - 1); + + // If this is an exact match, we found a (longer) + // matching command in the unicodesymbols file + if (math == tmp || text == tmp) { + c = it->first; + j = k - 1; + i = j + 1; + unicmd_size = cur_size; + } + } + if (unicmd_size) + symbols += c; + else if (j + 1 == cmdend) + // No luck. Return what remains + rem = cmd.substr(i); + } + return symbols; +} + + void Encodings::validate(char_type c, LaTeXFeatures & features, bool for_mathed) { CharInfoMap::const_iterator const it = unicodesymbols.find(c); diff --git a/src/Encoding.h b/src/Encoding.h index f5b02826bf..4de3512836 100644 --- a/src/Encoding.h +++ b/src/Encoding.h @@ -171,6 +171,19 @@ public: * \return whether \p command is a math mode command */ static bool latexMathChar(char_type c, docstring & command); + + /** + * Convert the LaTeX command in \p cmd to the corresponding unicode + * point and set \p combining to true if it is a combining symbol + */ + static char_type fromLaTeXCommand(docstring const & cmd, bool & combining); + /** + * Convert the LaTeX commands in \p cmd and \return a docstring + * of corresponding unicode points. The conversion stops at the + * first command which could not be converted, and the remaining + * unconverted commands are returned in \p rem + */ + static docstring fromLaTeXCommand(docstring const & cmd, docstring & rem); /** * Add the preamble snippet needed for the output of \p c to * \p features. diff --git a/src/mathed/CommandInset.cpp b/src/mathed/CommandInset.cpp index 7c24458cf5..9edf51b07a 100644 --- a/src/mathed/CommandInset.cpp +++ b/src/mathed/CommandInset.cpp @@ -23,8 +23,9 @@ using namespace std; namespace lyx { -CommandInset::CommandInset(docstring const & name) - : InsetMathNest(2), name_(name), set_label_(false) +CommandInset::CommandInset(docstring const & name, bool needs_math_mode) + : InsetMathNest(2), name_(name), needs_math_mode_(needs_math_mode), + set_label_(false) { lock_ = true; } @@ -64,10 +65,17 @@ void CommandInset::draw(PainterInfo & pi, int x, int y) const void CommandInset::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode() && needs_math_mode_) { + os << "\\ensuremath{"; + os.textMode(false); + } os << '\\' << name_.c_str(); if (cell(1).size()) os << '[' << cell(1) << ']'; os << '{' << cell(0) << '}'; + os.pendingBrace(brace); } diff --git a/src/mathed/CommandInset.h b/src/mathed/CommandInset.h index c1b8ffe714..98f96664dc 100644 --- a/src/mathed/CommandInset.h +++ b/src/mathed/CommandInset.h @@ -25,7 +25,7 @@ namespace lyx { class CommandInset : public InsetMathNest { public: /// - explicit CommandInset(docstring const & name); + explicit CommandInset(docstring const & name, bool needs_math_mode = true); /// void metrics(MetricsInfo & mi, Dimension & dim) const; /// @@ -49,6 +49,8 @@ private: /// docstring name_; /// + bool needs_math_mode_; + /// mutable bool set_label_; /// mutable RenderButton button_; diff --git a/src/mathed/InsetMath.cpp b/src/mathed/InsetMath.cpp index 49e0ad65ce..dce8d59892 100644 --- a/src/mathed/InsetMath.cpp +++ b/src/mathed/InsetMath.cpp @@ -68,12 +68,19 @@ void InsetMath::drawT(TextPainter &, int, int) const void InsetMath::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + } docstring const s = name(); os << "\\" << s; // We need an extra ' ' unless this is a single-char-non-ASCII name // or anything non-ASCII follows if (s.size() != 1 || isAlphaASCII(s[0])) os.pendingSpace(true); + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathAMSArray.cpp b/src/mathed/InsetMathAMSArray.cpp index 3a615d987a..fc839088c3 100644 --- a/src/mathed/InsetMathAMSArray.cpp +++ b/src/mathed/InsetMathAMSArray.cpp @@ -122,9 +122,17 @@ bool InsetMathAMSArray::getStatus(Cursor & cur, FuncRequest const & cmd, void InsetMathAMSArray::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << "\\begin{" << name_ << '}'; InsetMathGrid::write(os); os << "\\end{" << name_ << '}'; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathArray.cpp b/src/mathed/InsetMathArray.cpp index 78e190e053..0d9c7d5c87 100644 --- a/src/mathed/InsetMathArray.cpp +++ b/src/mathed/InsetMathArray.cpp @@ -95,6 +95,14 @@ void InsetMathArray::draw(PainterInfo & pi, int x, int y) const void InsetMathArray::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } + if (os.fragile()) os << "\\protect"; os << "\\begin{" << name_ << '}'; @@ -111,6 +119,8 @@ void InsetMathArray::write(WriteStream & os) const os << "\\end{" << name_ << '}'; // adding a \n here is bad if the array is the last item // in an \eqnarray... + + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathBig.cpp b/src/mathed/InsetMathBig.cpp index c547a7bb97..6e54064aca 100644 --- a/src/mathed/InsetMathBig.cpp +++ b/src/mathed/InsetMathBig.cpp @@ -89,9 +89,17 @@ void InsetMathBig::draw(PainterInfo & pi, int x, int y) const void InsetMathBig::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << '\\' << name_ << delim_; if (delim_[0] == '\\') os.pendingSpace(true); + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathBoldSymbol.cpp b/src/mathed/InsetMathBoldSymbol.cpp index f5bb350a01..3cca1180fb 100644 --- a/src/mathed/InsetMathBoldSymbol.cpp +++ b/src/mathed/InsetMathBoldSymbol.cpp @@ -76,6 +76,13 @@ void InsetMathBoldSymbol::validate(LaTeXFeatures & features) const void InsetMathBoldSymbol::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } switch (kind_) { case AMS_BOLD: os << "\\boldsymbol{" << cell(0) << "}"; @@ -87,6 +94,7 @@ void InsetMathBoldSymbol::write(WriteStream & os) const os << "\\hm{" << cell(0) << "}"; break; } + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathBox.cpp b/src/mathed/InsetMathBox.cpp index bb4ffc6944..46544d296d 100644 --- a/src/mathed/InsetMathBox.cpp +++ b/src/mathed/InsetMathBox.cpp @@ -39,10 +39,10 @@ InsetMathBox::InsetMathBox(docstring const & name) void InsetMathBox::write(WriteStream & os) const { - bool oldmode = os.textMode(); + bool textmode = os.textMode(); os.textMode(true); os << '\\' << name_ << '{' << cell(0) << '}'; - os.textMode(oldmode); + os.textMode(textmode); } @@ -118,10 +118,10 @@ void InsetMathFBox::draw(PainterInfo & pi, int x, int y) const void InsetMathFBox::write(WriteStream & os) const { - bool oldmode = os.textMode(); + bool textmode = os.textMode(); os.textMode(true); os << "\\fbox{" << cell(0) << '}'; - os.textMode(oldmode); + os.textMode(textmode); } @@ -217,7 +217,7 @@ void InsetMathMakebox::draw(PainterInfo & pi, int x, int y) const void InsetMathMakebox::write(WriteStream & os) const { - bool oldmode = os.textMode(); + bool textmode = os.textMode(); os.textMode(true); os << (framebox_ ? "\\framebox" : "\\makebox"); if (cell(0).size() || !os.latex()) { @@ -226,7 +226,7 @@ void InsetMathMakebox::write(WriteStream & os) const os << '[' << cell(1) << ']'; } os << '{' << cell(2) << '}'; - os.textMode(oldmode); + os.textMode(textmode); } @@ -275,10 +275,10 @@ void InsetMathBoxed::draw(PainterInfo & pi, int x, int y) const void InsetMathBoxed::write(WriteStream & os) const { - bool oldmode = os.textMode(); - os.textMode(true); + bool textmode = os.textMode(); + os.textMode(false); os << "\\boxed{" << cell(0) << '}'; - os.textMode(oldmode); + os.textMode(textmode); } diff --git a/src/mathed/InsetMathCases.cpp b/src/mathed/InsetMathCases.cpp index 63a78848c2..eb53248402 100644 --- a/src/mathed/InsetMathCases.cpp +++ b/src/mathed/InsetMathCases.cpp @@ -107,6 +107,12 @@ bool InsetMathCases::getStatus(Cursor & cur, FuncRequest const & cmd, void InsetMathCases::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } if (os.fragile()) os << "\\protect"; os << "\\begin{cases}\n"; @@ -114,6 +120,7 @@ void InsetMathCases::write(WriteStream & os) const if (os.fragile()) os << "\\protect"; os << "\\end{cases}"; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathDecoration.cpp b/src/mathed/InsetMathDecoration.cpp index 777fa75aca..d53efb0354 100644 --- a/src/mathed/InsetMathDecoration.cpp +++ b/src/mathed/InsetMathDecoration.cpp @@ -139,9 +139,17 @@ void InsetMathDecoration::draw(PainterInfo & pi, int x, int y) const void InsetMathDecoration::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } if (os.fragile() && protect()) os << "\\protect"; os << '\\' << key_->name << '{' << cell(0) << '}'; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathDelim.cpp b/src/mathed/InsetMathDelim.cpp index 403c1cf65d..9cf6414e29 100644 --- a/src/mathed/InsetMathDelim.cpp +++ b/src/mathed/InsetMathDelim.cpp @@ -59,8 +59,18 @@ Inset * InsetMathDelim::clone() const void InsetMathDelim::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } + os << "\\left" << convertDelimToLatexName(left_) << cell(0) << "\\right" << convertDelimToLatexName(right_); + + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathEnv.cpp b/src/mathed/InsetMathEnv.cpp index 82460b986c..f04d87119f 100644 --- a/src/mathed/InsetMathEnv.cpp +++ b/src/mathed/InsetMathEnv.cpp @@ -48,7 +48,15 @@ void InsetMathEnv::draw(PainterInfo & pi, int x, int y) const void InsetMathEnv::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << "\\begin{" << name_ << '}' << cell(0) << "\\end{" << name_ << '}'; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathFrac.cpp b/src/mathed/InsetMathFrac.cpp index ac2d894e09..58e0c1b180 100644 --- a/src/mathed/InsetMathFrac.cpp +++ b/src/mathed/InsetMathFrac.cpp @@ -265,6 +265,14 @@ void InsetMathFrac::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const void InsetMathFrac::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } + switch (kind_) { case ATOP: os << '{' << cell(0) << "\\atop " << cell(1) << '}'; @@ -288,6 +296,8 @@ void InsetMathFrac::write(WriteStream & os) const os << "\\unit{" << cell(0) << '}'; break; } + + os.pendingBrace(brace); } @@ -535,6 +545,14 @@ bool InsetMathBinom::extraBraces() const void InsetMathBinom::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } + switch (kind_) { case BINOM: os << "\\binom{" << cell(0) << "}{" << cell(1) << '}'; @@ -549,6 +567,8 @@ void InsetMathBinom::write(WriteStream & os) const os << '{' << cell(0) << " \\brack " << cell(1) << '}'; break; } + + os.pendingBrace(brace); } @@ -560,10 +580,9 @@ void InsetMathBinom::normalize(NormalStream & os) const void InsetMathBinom::validate(LaTeXFeatures & features) const { - if (kind_ == BINOM) { + if (kind_ == BINOM) features.require("binom"); - InsetMathNest::validate(features); - } + InsetMathNest::validate(features); } diff --git a/src/mathed/InsetMathGrid.cpp b/src/mathed/InsetMathGrid.cpp index 0d2460f617..1e4f2e8dff 100644 --- a/src/mathed/InsetMathGrid.cpp +++ b/src/mathed/InsetMathGrid.cpp @@ -967,6 +967,9 @@ void InsetMathGrid::mathmlize(MathStream & os) const void InsetMathGrid::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + docstring eol; for (row_type row = 0; row < nrows(); ++row) { os << verboseHLine(rowinfo_[row].lines_); @@ -978,8 +981,15 @@ void InsetMathGrid::write(WriteStream & os) const lastcol = col + 1; emptyline = false; } - for (col_type col = 0; col < lastcol; ++col) - os << cell(index(row, col)) << eocString(col, lastcol); + for (col_type col = 0; col < lastcol; ++col) { + os << cell(index(row, col)); + if (os.pendingBrace()) { + os.pendingBrace(false); + os.textMode(true); + os << '}'; + } + os << eocString(col, lastcol); + } eol = eolString(row, emptyline, os.fragile()); os << eol; // append newline only if line wasn't completely empty @@ -996,6 +1006,8 @@ void InsetMathGrid::write(WriteStream & os) const } os << s; } + + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathNest.cpp b/src/mathed/InsetMathNest.cpp index 8c470759d5..747f0ca157 100644 --- a/src/mathed/InsetMathNest.cpp +++ b/src/mathed/InsetMathNest.cpp @@ -75,7 +75,7 @@ using cap::selClearOrDel; char const * text_commands[] = { "text", "textrm", "textsf", "texttt", "textmd", "textbf", "textup", "textit", - "textsl", "textsc" }; + "textsl", "textsc", "textnormal" }; int const num_text_commands = sizeof(text_commands) / sizeof(*text_commands); @@ -341,7 +341,7 @@ MathData InsetMathNest::glue() const void InsetMathNest::write(WriteStream & os) const { - bool oldmode = os.textMode(); + bool textmode = os.textMode(); docstring const latex_name = name().c_str(); for (int i = 0; i < num_text_commands; ++i) { if (latex_name == from_ascii(text_commands[i])) { @@ -358,7 +358,7 @@ void InsetMathNest::write(WriteStream & os) const os << "\\lyxlock"; os.pendingSpace(true); } - os.textMode(oldmode); + os.textMode(textmode); } diff --git a/src/mathed/InsetMathOverset.cpp b/src/mathed/InsetMathOverset.cpp index 62a82427cd..5d8edefef8 100644 --- a/src/mathed/InsetMathOverset.cpp +++ b/src/mathed/InsetMathOverset.cpp @@ -73,7 +73,14 @@ bool InsetMathOverset::idxLast(Cursor & cur) const void InsetMathOverset::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + } os << "\\overset{" << cell(0) << "}{" << cell(1) << '}'; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathPhantom.cpp b/src/mathed/InsetMathPhantom.cpp index ef2ccbbb50..ba9b89a96a 100644 --- a/src/mathed/InsetMathPhantom.cpp +++ b/src/mathed/InsetMathPhantom.cpp @@ -119,6 +119,13 @@ void InsetMathPhantom::draw(PainterInfo & pi, int x, int y) const void InsetMathPhantom::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } switch (kind_) { case phantom: os << "\\phantom{"; @@ -131,6 +138,7 @@ void InsetMathPhantom::write(WriteStream & os) const break; } os << cell(0) << '}'; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathRef.cpp b/src/mathed/InsetMathRef.cpp index 20740f83c9..8ba745fdc4 100644 --- a/src/mathed/InsetMathRef.cpp +++ b/src/mathed/InsetMathRef.cpp @@ -36,12 +36,12 @@ using namespace std; namespace lyx { InsetMathRef::InsetMathRef() - : CommandInset(from_ascii("ref")) + : CommandInset(from_ascii("ref"), false) {} InsetMathRef::InsetMathRef(docstring const & data) - : CommandInset(data) + : CommandInset(data, false) {} diff --git a/src/mathed/InsetMathRoot.cpp b/src/mathed/InsetMathRoot.cpp index f9424ed4ed..006c0716ae 100644 --- a/src/mathed/InsetMathRoot.cpp +++ b/src/mathed/InsetMathRoot.cpp @@ -72,7 +72,15 @@ void InsetMathRoot::draw(PainterInfo & pi, int x, int y) const void InsetMathRoot::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << "\\sqrt[" << cell(0) << "]{" << cell(1) << '}'; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathScript.cpp b/src/mathed/InsetMathScript.cpp index 482315f28c..6bf53dd799 100644 --- a/src/mathed/InsetMathScript.cpp +++ b/src/mathed/InsetMathScript.cpp @@ -525,6 +525,14 @@ bool InsetMathScript::idxUpDown(Cursor & cur, bool up) const void InsetMathScript::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } + if (nuc().size()) { os << nuc(); //if (nuc().back()->takesLimits()) { @@ -548,6 +556,8 @@ void InsetMathScript::write(WriteStream & os) const if (lock_ && !os.latex()) os << "\\lyxlock "; + + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathSize.cpp b/src/mathed/InsetMathSize.cpp index c014d90adf..898a395139 100644 --- a/src/mathed/InsetMathSize.cpp +++ b/src/mathed/InsetMathSize.cpp @@ -52,7 +52,15 @@ void InsetMathSize::draw(PainterInfo & pi, int x, int y) const void InsetMathSize::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << "{\\" << key_->name << ' ' << cell(0) << '}'; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathSpace.cpp b/src/mathed/InsetMathSpace.cpp index 7d44accf7b..60950c30ad 100644 --- a/src/mathed/InsetMathSpace.cpp +++ b/src/mathed/InsetMathSpace.cpp @@ -147,8 +147,16 @@ void InsetMathSpace::normalize(NormalStream & os) const void InsetMathSpace::write(WriteStream & os) const { if (space_ >= 0 && space_ < nSpace) { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << '\\' << latex_mathspace[space_]; os.pendingSpace(true); + os.pendingBrace(brace); } } diff --git a/src/mathed/InsetMathSplit.cpp b/src/mathed/InsetMathSplit.cpp index d05b5f25e3..95fbc80f5f 100644 --- a/src/mathed/InsetMathSplit.cpp +++ b/src/mathed/InsetMathSplit.cpp @@ -87,6 +87,13 @@ bool InsetMathSplit::getStatus(Cursor & cur, FuncRequest const & cmd, void InsetMathSplit::write(WriteStream & ws) const { + bool brace = ws.pendingBrace(); + ws.pendingBrace(false); + if (ws.latex() && ws.textMode()) { + ws << "\\ensuremath{"; + ws.textMode(false); + brace = true; + } if (ws.fragile()) ws << "\\protect"; ws << "\\begin{" << name_ << '}'; @@ -98,6 +105,7 @@ void InsetMathSplit::write(WriteStream & ws) const if (ws.fragile()) ws << "\\protect"; ws << "\\end{" << name_ << "}\n"; + ws.pendingBrace(brace); } diff --git a/src/mathed/InsetMathSqrt.cpp b/src/mathed/InsetMathSqrt.cpp index 941ad92b92..11304a9bd1 100644 --- a/src/mathed/InsetMathSqrt.cpp +++ b/src/mathed/InsetMathSqrt.cpp @@ -80,7 +80,15 @@ void InsetMathSqrt::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const void InsetMathSqrt::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << "\\sqrt{" << cell(0) << '}'; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathStackrel.cpp b/src/mathed/InsetMathStackrel.cpp index 2879659e1e..410e21f1d8 100644 --- a/src/mathed/InsetMathStackrel.cpp +++ b/src/mathed/InsetMathStackrel.cpp @@ -58,7 +58,15 @@ void InsetMathStackrel::draw(PainterInfo & pi, int x, int y) const void InsetMathStackrel::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << "\\stackrel{" << cell(0) << "}{" << cell(1) << '}'; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathString.cpp b/src/mathed/InsetMathString.cpp index bfa17019b0..d3fb984241 100644 --- a/src/mathed/InsetMathString.cpp +++ b/src/mathed/InsetMathString.cpp @@ -111,35 +111,45 @@ void InsetMathString::write(WriteStream & os) const docstring::const_iterator cit = str_.begin(); docstring::const_iterator end = str_.end(); - bool in_forced_mode = false; + // We may already be inside an \ensuremath command. + bool in_forced_mode = os.pendingBrace(); + + // We will take care of matching braces. + os.pendingBrace(false); + while (cit != end) { char_type const c = *cit; try { docstring command(1, c); if (c < 0x80 || Encodings::latexMathChar(c, command)) { if (os.textMode()) { - if (c < 0x80 && in_forced_mode) { + if (in_forced_mode) { + // we were inside \lyxmathsym os << '}'; + os.textMode(false); in_forced_mode = false; } - if (c >= 0x80 && !in_forced_mode) { + if (c >= 0x80) { os << "\\ensuremath{"; + os.textMode(false); in_forced_mode = true; } - } else if (in_forced_mode) { + } else if (c < 0x80 && in_forced_mode) { + // we were inside \ensuremath os << '}'; + os.textMode(true); in_forced_mode = false; } - } else { - if (os.textMode()) { + } else if (!os.textMode()) { if (in_forced_mode) { + // we were inside \ensuremath os << '}'; in_forced_mode = false; + } else { + os << "\\lyxmathsym{"; + in_forced_mode = true; } - } else if (!in_forced_mode) { - os << "\\lyxmathsym{"; - in_forced_mode = true; - } + os.textMode(true); } os << command; // We may need a space if the command contains a macro @@ -162,8 +172,14 @@ void InsetMathString::write(WriteStream & os) const } ++cit; } - if (in_forced_mode) + + if (in_forced_mode && os.textMode()) { + // We have to care for closing \lyxmathsym os << '}'; + os.textMode(false); + } else { + os.pendingBrace(in_forced_mode); + } } diff --git a/src/mathed/InsetMathSubstack.cpp b/src/mathed/InsetMathSubstack.cpp index fd0d57acec..e5abe9818a 100644 --- a/src/mathed/InsetMathSubstack.cpp +++ b/src/mathed/InsetMathSubstack.cpp @@ -89,9 +89,17 @@ void InsetMathSubstack::infoize(odocstream & os) const void InsetMathSubstack::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << "\\substack{"; InsetMathGrid::write(os); os << "}\n"; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathSymbol.cpp b/src/mathed/InsetMathSymbol.cpp index 52d6eee858..28119d2a9b 100644 --- a/src/mathed/InsetMathSymbol.cpp +++ b/src/mathed/InsetMathSymbol.cpp @@ -206,7 +206,15 @@ void InsetMathSymbol::octave(OctaveStream & os) const void InsetMathSymbol::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << '\\' << name(); + os.pendingBrace(brace); // $,#, etc. In theory the restriction based on catcodes, but then // we do not handle catcodes very well, let alone cat code changes, diff --git a/src/mathed/InsetMathTabular.cpp b/src/mathed/InsetMathTabular.cpp index b951900efd..8d59cbd1df 100644 --- a/src/mathed/InsetMathTabular.cpp +++ b/src/mathed/InsetMathTabular.cpp @@ -65,6 +65,15 @@ void InsetMathTabular::draw(PainterInfo & pi, int x, int y) const void InsetMathTabular::write(WriteStream & os) const { + // This is a text mode tabular, so close any previous \ensuremath + // command and set the proper mode. + if (os.latex() && os.pendingBrace()) { + os.pendingBrace(false); + os << '}'; + } + bool textmode = os.textMode(); + os.textMode(true); + if (os.fragile()) os << "\\protect"; os << "\\begin{" << name_ << '}'; @@ -81,6 +90,8 @@ void InsetMathTabular::write(WriteStream & os) const os << "\\end{" << name_ << '}'; // adding a \n here is bad if the tabular is the last item // in an \eqnarray... + + os.textMode(textmode); } diff --git a/src/mathed/InsetMathUnderset.cpp b/src/mathed/InsetMathUnderset.cpp index a66a225af2..ae5ab36228 100644 --- a/src/mathed/InsetMathUnderset.cpp +++ b/src/mathed/InsetMathUnderset.cpp @@ -84,7 +84,15 @@ bool InsetMathUnderset::idxUpDown(Cursor & cur, bool up) const void InsetMathUnderset::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << "\\underset{" << cell(0) << "}{" << cell(1) << '}'; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathXArrow.cpp b/src/mathed/InsetMathXArrow.cpp index 3faee295f3..78d5390a3f 100644 --- a/src/mathed/InsetMathXArrow.cpp +++ b/src/mathed/InsetMathXArrow.cpp @@ -62,10 +62,20 @@ void InsetMathXArrow::draw(PainterInfo & pi, int x, int y) const void InsetMathXArrow::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } + os << '\\' << name_; if (cell(1).size()) os << '[' << cell(1) << ']'; os << '{' << cell(0) << '}'; + + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathXYArrow.cpp b/src/mathed/InsetMathXYArrow.cpp index 22f20a2b61..866c3bb1d6 100644 --- a/src/mathed/InsetMathXYArrow.cpp +++ b/src/mathed/InsetMathXYArrow.cpp @@ -140,12 +140,20 @@ void InsetMathXYArrow::draw(PainterInfo & pi, int x, int y) const void InsetMathXYArrow::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << "\\ar"; if (cell(0).size()) os << '[' << cell(0) << ']'; if (cell(1).size()) os << (up_ ? '^' : '_') << '{' << cell(1) << '}'; os << " "; + os.pendingBrace(brace); } diff --git a/src/mathed/InsetMathXYMatrix.cpp b/src/mathed/InsetMathXYMatrix.cpp index 2b58c332c1..9be4e2efa6 100644 --- a/src/mathed/InsetMathXYMatrix.cpp +++ b/src/mathed/InsetMathXYMatrix.cpp @@ -53,6 +53,13 @@ void InsetMathXYMatrix::metrics(MetricsInfo & mi, Dimension & dim) const void InsetMathXYMatrix::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex() && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } os << "\\xymatrix"; switch (spacing_code_) { case 'R': @@ -71,6 +78,7 @@ void InsetMathXYMatrix::write(WriteStream & os) const os << '{'; InsetMathGrid::write(os); os << "}\n"; + os.pendingBrace(brace); } diff --git a/src/mathed/MathMacro.cpp b/src/mathed/MathMacro.cpp index bf6132630a..339719483b 100644 --- a/src/mathed/MathMacro.cpp +++ b/src/mathed/MathMacro.cpp @@ -655,10 +655,27 @@ bool MathMacro::folded() const void MathMacro::write(WriteStream & os) const { + bool brace = os.pendingBrace(); + os.pendingBrace(false); + if (os.latex()) { + if (os.textMode() && macro_) { + // This is for sure a math macro + os << "\\ensuremath{"; + os.textMode(false); + brace = true; + } else if (brace && !macro_) { + // Cannot tell, so don't mess with the mode + os << '}'; + os.textMode(true); + brace = false; + } + } + // non-normal mode if (displayMode_ != DISPLAY_NORMAL) { - os << "\\" << name() << " "; + os << "\\" << name(); os.pendingSpace(true); + os.pendingBrace(brace); return; } @@ -705,6 +722,8 @@ void MathMacro::write(WriteStream & os) const // add space if there was no argument if (first) os.pendingSpace(true); + + os.pendingBrace(brace); } diff --git a/src/mathed/MathParser.cpp b/src/mathed/MathParser.cpp index 806f423781..1831114035 100644 --- a/src/mathed/MathParser.cpp +++ b/src/mathed/MathParser.cpp @@ -62,6 +62,7 @@ following hack as starting point to write some macros: #include "MathMacroArgument.h" #include "MathSupport.h" +#include "Encoding.h" #include "Lexer.h" #include "support/debug.h" @@ -1525,6 +1526,46 @@ void Parser::parse1(InsetMathGrid & grid, unsigned flags, } #endif + else if (t.cs() == "lyxmathsym" || t.cs() == "ensuremath") { + skipSpaces(); + if (getToken().cat() != catBegin) { + error("'{' expected in \\" + t.cs()); + return; + } + int count = 0; + docstring cmd; + CatCode cat = nextToken().cat(); + while (good() && (count || cat != catEnd)) { + if (cat == catBegin) + ++count; + else if (cat == catEnd) + --count; + cmd += getToken().asInput(); + cat = nextToken().cat(); + } + if (getToken().cat() != catEnd) { + error("'}' expected in \\" + t.cs()); + return; + } + if (t.cs() == "ensuremath") { + MathData ar; + mathed_parse_cell(ar, cmd); + cell->append(ar); + } else { + docstring rem; + cmd = Encodings::fromLaTeXCommand(cmd, rem); + for (size_t i = 0; i < cmd.size(); ++i) + cell->push_back(MathAtom(new InsetMathChar(cmd[i]))); + if (rem.size()) { + MathAtom at = createInsetMath(t.cs()); + cell->push_back(at); + MathData ar; + mathed_parse_cell(ar, '{' + rem + '}'); + cell->append(ar); + } + } + } + else if (t.cs().size()) { latexkeys const * l = in_word_set(t.cs()); if (l) { @@ -1576,26 +1617,66 @@ void Parser::parse1(InsetMathGrid & grid, unsigned flags, } else { - MathAtom at = createInsetMath(t.cs()); - InsetMath::mode_type m = mode; - //if (m == InsetMath::UNDECIDED_MODE) - //lyxerr << "default creation: m1: " << m << endl; - if (at->currentMode() != InsetMath::UNDECIDED_MODE) - m = at->currentMode(); - //lyxerr << "default creation: m2: " << m << endl; - InsetMath::idx_type start = 0; - // this fails on \bigg[...\bigg] - //MathData opt; - //parse(opt, FLAG_OPTION, InsetMath::VERBATIM_MODE); - //if (opt.size()) { - // start = 1; - // at.nucleus()->cell(0) = opt; - //} - for (InsetMath::idx_type i = start; i < at->nargs(); ++i) { - parse(at.nucleus()->cell(i), FLAG_ITEM, m); + bool is_unicode_symbol = false; + if (mode == InsetMath::TEXT_MODE) { + int num_tokens = 0; + docstring cmd = prevToken().asInput(); skipSpaces(); + CatCode cat = nextToken().cat(); + if (cat == catBegin) { + int count = 0; + while (good() && (count || cat != catEnd)) { + cat = nextToken().cat(); + cmd += getToken().asInput(); + ++num_tokens; + if (cat == catBegin) + ++count; + else if (cat == catEnd) + --count; + } + } + bool is_combining; + char_type c = + Encodings::fromLaTeXCommand(cmd, is_combining); + if (is_combining) { + if (cat == catLetter) + cmd += '{'; + cmd += getToken().asInput(); + ++num_tokens; + if (cat == catLetter) + cmd += '}'; + c = Encodings::fromLaTeXCommand(cmd, is_combining); + } + if (c) { + is_unicode_symbol = true; + cell->push_back(MathAtom(new InsetMathChar(c))); + } else { + while (num_tokens--) + putback(); + } + } + if (!is_unicode_symbol) { + MathAtom at = createInsetMath(t.cs()); + InsetMath::mode_type m = mode; + //if (m == InsetMath::UNDECIDED_MODE) + //lyxerr << "default creation: m1: " << m << endl; + if (at->currentMode() != InsetMath::UNDECIDED_MODE) + m = at->currentMode(); + //lyxerr << "default creation: m2: " << m << endl; + InsetMath::idx_type start = 0; + // this fails on \bigg[...\bigg] + //MathData opt; + //parse(opt, FLAG_OPTION, InsetMath::VERBATIM_MODE); + //if (opt.size()) { + // start = 1; + // at.nucleus()->cell(0) = opt; + //} + for (InsetMath::idx_type i = start; i < at->nargs(); ++i) { + parse(at.nucleus()->cell(i), FLAG_ITEM, m); + skipSpaces(); + } + cell->push_back(at); } - cell->push_back(at); } } diff --git a/src/mathed/MathStream.cpp b/src/mathed/MathStream.cpp index 8677358b55..f9779d0d6f 100644 --- a/src/mathed/MathStream.cpp +++ b/src/mathed/MathStream.cpp @@ -86,7 +86,12 @@ NormalStream & operator<<(NormalStream & ns, int i) WriteStream & operator<<(WriteStream & ws, docstring const & s) { - if (ws.pendingSpace() && s.length() > 0) { + if (ws.pendingBrace()) { + ws.os() << '}'; + ws.pendingBrace(false); + ws.pendingSpace(false); + ws.textMode(true); + } else if (ws.pendingSpace() && s.length() > 0) { if (isAlphaASCII(s[0])) ws.os() << ' '; ws.pendingSpace(false); @@ -105,19 +110,23 @@ WriteStream & operator<<(WriteStream & ws, docstring const & s) WriteStream::WriteStream(odocstream & os, bool fragile, bool latex, bool dryrun) : os_(os), fragile_(fragile), firstitem_(false), latex_(latex), - dryrun_(dryrun), pendingspace_(false), textmode_(false), line_(0) + dryrun_(dryrun), pendingspace_(false), pendingbrace_(false), + textmode_(false), line_(0) {} WriteStream::WriteStream(odocstream & os) : os_(os), fragile_(false), firstitem_(false), latex_(false), - dryrun_(false), pendingspace_(false), textmode_(false), line_(0) + dryrun_(false), pendingspace_(false), pendingbrace_(false), + textmode_(false), line_(0) {} WriteStream::~WriteStream() { - if (pendingspace_) + if (pendingbrace_) + os_ << '}'; + else if (pendingspace_) os_ << ' '; } @@ -134,6 +143,12 @@ void WriteStream::pendingSpace(bool how) } +void WriteStream::pendingBrace(bool brace) +{ + pendingbrace_ = brace; +} + + void WriteStream::textMode(bool textmode) { textmode_ = textmode; @@ -156,7 +171,12 @@ WriteStream & operator<<(WriteStream & ws, MathData const & ar) WriteStream & operator<<(WriteStream & ws, char const * s) { - if (ws.pendingSpace() && strlen(s) > 0) { + if (ws.pendingBrace()) { + ws.os() << '}'; + ws.pendingBrace(false); + ws.pendingSpace(false); + ws.textMode(true); + } else if (ws.pendingSpace() && strlen(s) > 0) { if (isAlphaASCII(s[0])) ws.os() << ' '; ws.pendingSpace(false); @@ -169,7 +189,12 @@ WriteStream & operator<<(WriteStream & ws, char const * s) WriteStream & operator<<(WriteStream & ws, char c) { - if (ws.pendingSpace()) { + if (ws.pendingBrace()) { + ws.os() << '}'; + ws.pendingBrace(false); + ws.pendingSpace(false); + ws.textMode(true); + } else if (ws.pendingSpace()) { if (isAlphaASCII(c)) ws.os() << ' '; ws.pendingSpace(false); @@ -183,6 +208,11 @@ WriteStream & operator<<(WriteStream & ws, char c) WriteStream & operator<<(WriteStream & ws, int i) { + if (ws.pendingBrace()) { + ws.os() << '}'; + ws.pendingBrace(false); + ws.textMode(true); + } ws.os() << i; return ws; } @@ -190,6 +220,11 @@ WriteStream & operator<<(WriteStream & ws, int i) WriteStream & operator<<(WriteStream & ws, unsigned int i) { + if (ws.pendingBrace()) { + ws.os() << '}'; + ws.pendingBrace(false); + ws.textMode(true); + } ws.os() << i; return ws; } diff --git a/src/mathed/MathStream.h b/src/mathed/MathStream.h index 92b63c2a6b..3c12b0f55f 100644 --- a/src/mathed/MathStream.h +++ b/src/mathed/MathStream.h @@ -54,6 +54,10 @@ public: void pendingSpace(bool how); /// writes space if next thing is isalpha() bool pendingSpace() const { return pendingspace_; } + /// tell whether to write the closing brace of \ensuremath + void pendingBrace(bool brace); + /// tell whether to write the closing brace of \ensuremath + bool pendingBrace() const { return pendingbrace_; } /// tell whether we are in text mode or not when producing latex code void textMode(bool textmode); /// tell whether we are in text mode or not when producing latex code @@ -71,6 +75,8 @@ private: bool dryrun_; /// do we have a space pending? bool pendingspace_; + /// do we have a brace pending? + bool pendingbrace_; /// are we in text mode when producing latex code? bool textmode_; /// -- 2.39.5