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
This commit is contained in:
Enrico Forestieri 2008-06-16 01:21:17 +00:00
parent 4044737b8d
commit 90837aaf6e
39 changed files with 570 additions and 58 deletions

View File

@ -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) void Encodings::validate(char_type c, LaTeXFeatures & features, bool for_mathed)
{ {
CharInfoMap::const_iterator const it = unicodesymbols.find(c); CharInfoMap::const_iterator const it = unicodesymbols.find(c);

View File

@ -171,6 +171,19 @@ public:
* \return whether \p command is a math mode command * \return whether \p command is a math mode command
*/ */
static bool latexMathChar(char_type c, docstring & 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 * Add the preamble snippet needed for the output of \p c to
* \p features. * \p features.

View File

@ -23,8 +23,9 @@ using namespace std;
namespace lyx { namespace lyx {
CommandInset::CommandInset(docstring const & name) CommandInset::CommandInset(docstring const & name, bool needs_math_mode)
: InsetMathNest(2), name_(name), set_label_(false) : InsetMathNest(2), name_(name), needs_math_mode_(needs_math_mode),
set_label_(false)
{ {
lock_ = true; lock_ = true;
} }
@ -64,10 +65,17 @@ void CommandInset::draw(PainterInfo & pi, int x, int y) const
void CommandInset::write(WriteStream & os) 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(); os << '\\' << name_.c_str();
if (cell(1).size()) if (cell(1).size())
os << '[' << cell(1) << ']'; os << '[' << cell(1) << ']';
os << '{' << cell(0) << '}'; os << '{' << cell(0) << '}';
os.pendingBrace(brace);
} }

View File

@ -25,7 +25,7 @@ namespace lyx {
class CommandInset : public InsetMathNest { class CommandInset : public InsetMathNest {
public: public:
/// ///
explicit CommandInset(docstring const & name); explicit CommandInset(docstring const & name, bool needs_math_mode = true);
/// ///
void metrics(MetricsInfo & mi, Dimension & dim) const; void metrics(MetricsInfo & mi, Dimension & dim) const;
/// ///
@ -49,6 +49,8 @@ private:
/// ///
docstring name_; docstring name_;
/// ///
bool needs_math_mode_;
///
mutable bool set_label_; mutable bool set_label_;
/// ///
mutable RenderButton button_; mutable RenderButton button_;

View File

@ -68,12 +68,19 @@ void InsetMath::drawT(TextPainter &, int, int) const
void InsetMath::write(WriteStream & os) 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(); docstring const s = name();
os << "\\" << s; os << "\\" << s;
// We need an extra ' ' unless this is a single-char-non-ASCII name // We need an extra ' ' unless this is a single-char-non-ASCII name
// or anything non-ASCII follows // or anything non-ASCII follows
if (s.size() != 1 || isAlphaASCII(s[0])) if (s.size() != 1 || isAlphaASCII(s[0]))
os.pendingSpace(true); os.pendingSpace(true);
os.pendingBrace(brace);
} }

View File

@ -122,9 +122,17 @@ bool InsetMathAMSArray::getStatus(Cursor & cur, FuncRequest const & cmd,
void InsetMathAMSArray::write(WriteStream & os) const 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_ << '}'; os << "\\begin{" << name_ << '}';
InsetMathGrid::write(os); InsetMathGrid::write(os);
os << "\\end{" << name_ << '}'; os << "\\end{" << name_ << '}';
os.pendingBrace(brace);
} }

View File

@ -95,6 +95,14 @@ void InsetMathArray::draw(PainterInfo & pi, int x, int y) const
void InsetMathArray::write(WriteStream & os) 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()) if (os.fragile())
os << "\\protect"; os << "\\protect";
os << "\\begin{" << name_ << '}'; os << "\\begin{" << name_ << '}';
@ -111,6 +119,8 @@ void InsetMathArray::write(WriteStream & os) const
os << "\\end{" << name_ << '}'; os << "\\end{" << name_ << '}';
// adding a \n here is bad if the array is the last item // adding a \n here is bad if the array is the last item
// in an \eqnarray... // in an \eqnarray...
os.pendingBrace(brace);
} }

View File

@ -89,9 +89,17 @@ void InsetMathBig::draw(PainterInfo & pi, int x, int y) const
void InsetMathBig::write(WriteStream & os) 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_; os << '\\' << name_ << delim_;
if (delim_[0] == '\\') if (delim_[0] == '\\')
os.pendingSpace(true); os.pendingSpace(true);
os.pendingBrace(brace);
} }

View File

@ -76,6 +76,13 @@ void InsetMathBoldSymbol::validate(LaTeXFeatures & features) const
void InsetMathBoldSymbol::write(WriteStream & os) 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_) { switch (kind_) {
case AMS_BOLD: case AMS_BOLD:
os << "\\boldsymbol{" << cell(0) << "}"; os << "\\boldsymbol{" << cell(0) << "}";
@ -87,6 +94,7 @@ void InsetMathBoldSymbol::write(WriteStream & os) const
os << "\\hm{" << cell(0) << "}"; os << "\\hm{" << cell(0) << "}";
break; break;
} }
os.pendingBrace(brace);
} }

View File

@ -39,10 +39,10 @@ InsetMathBox::InsetMathBox(docstring const & name)
void InsetMathBox::write(WriteStream & os) const void InsetMathBox::write(WriteStream & os) const
{ {
bool oldmode = os.textMode(); bool textmode = os.textMode();
os.textMode(true); os.textMode(true);
os << '\\' << name_ << '{' << cell(0) << '}'; 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 void InsetMathFBox::write(WriteStream & os) const
{ {
bool oldmode = os.textMode(); bool textmode = os.textMode();
os.textMode(true); os.textMode(true);
os << "\\fbox{" << cell(0) << '}'; 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 void InsetMathMakebox::write(WriteStream & os) const
{ {
bool oldmode = os.textMode(); bool textmode = os.textMode();
os.textMode(true); os.textMode(true);
os << (framebox_ ? "\\framebox" : "\\makebox"); os << (framebox_ ? "\\framebox" : "\\makebox");
if (cell(0).size() || !os.latex()) { if (cell(0).size() || !os.latex()) {
@ -226,7 +226,7 @@ void InsetMathMakebox::write(WriteStream & os) const
os << '[' << cell(1) << ']'; os << '[' << cell(1) << ']';
} }
os << '{' << cell(2) << '}'; 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 void InsetMathBoxed::write(WriteStream & os) const
{ {
bool oldmode = os.textMode(); bool textmode = os.textMode();
os.textMode(true); os.textMode(false);
os << "\\boxed{" << cell(0) << '}'; os << "\\boxed{" << cell(0) << '}';
os.textMode(oldmode); os.textMode(textmode);
} }

View File

@ -107,6 +107,12 @@ bool InsetMathCases::getStatus(Cursor & cur, FuncRequest const & cmd,
void InsetMathCases::write(WriteStream & os) const 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()) if (os.fragile())
os << "\\protect"; os << "\\protect";
os << "\\begin{cases}\n"; os << "\\begin{cases}\n";
@ -114,6 +120,7 @@ void InsetMathCases::write(WriteStream & os) const
if (os.fragile()) if (os.fragile())
os << "\\protect"; os << "\\protect";
os << "\\end{cases}"; os << "\\end{cases}";
os.pendingBrace(brace);
} }

View File

@ -139,9 +139,17 @@ void InsetMathDecoration::draw(PainterInfo & pi, int x, int y) const
void InsetMathDecoration::write(WriteStream & os) 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()) if (os.fragile() && protect())
os << "\\protect"; os << "\\protect";
os << '\\' << key_->name << '{' << cell(0) << '}'; os << '\\' << key_->name << '{' << cell(0) << '}';
os.pendingBrace(brace);
} }

View File

@ -59,8 +59,18 @@ Inset * InsetMathDelim::clone() const
void InsetMathDelim::write(WriteStream & os) 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) os << "\\left" << convertDelimToLatexName(left_) << cell(0)
<< "\\right" << convertDelimToLatexName(right_); << "\\right" << convertDelimToLatexName(right_);
os.pendingBrace(brace);
} }

View File

@ -48,7 +48,15 @@ void InsetMathEnv::draw(PainterInfo & pi, int x, int y) const
void InsetMathEnv::write(WriteStream & os) 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 << "\\begin{" << name_ << '}' << cell(0) << "\\end{" << name_ << '}';
os.pendingBrace(brace);
} }

View File

@ -265,6 +265,14 @@ void InsetMathFrac::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const
void InsetMathFrac::write(WriteStream & os) 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_) { switch (kind_) {
case ATOP: case ATOP:
os << '{' << cell(0) << "\\atop " << cell(1) << '}'; os << '{' << cell(0) << "\\atop " << cell(1) << '}';
@ -288,6 +296,8 @@ void InsetMathFrac::write(WriteStream & os) const
os << "\\unit{" << cell(0) << '}'; os << "\\unit{" << cell(0) << '}';
break; break;
} }
os.pendingBrace(brace);
} }
@ -535,6 +545,14 @@ bool InsetMathBinom::extraBraces() const
void InsetMathBinom::write(WriteStream & os) 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_) { switch (kind_) {
case BINOM: case BINOM:
os << "\\binom{" << cell(0) << "}{" << cell(1) << '}'; os << "\\binom{" << cell(0) << "}{" << cell(1) << '}';
@ -549,6 +567,8 @@ void InsetMathBinom::write(WriteStream & os) const
os << '{' << cell(0) << " \\brack " << cell(1) << '}'; os << '{' << cell(0) << " \\brack " << cell(1) << '}';
break; break;
} }
os.pendingBrace(brace);
} }
@ -560,10 +580,9 @@ void InsetMathBinom::normalize(NormalStream & os) const
void InsetMathBinom::validate(LaTeXFeatures & features) const void InsetMathBinom::validate(LaTeXFeatures & features) const
{ {
if (kind_ == BINOM) { if (kind_ == BINOM)
features.require("binom"); features.require("binom");
InsetMathNest::validate(features); InsetMathNest::validate(features);
}
} }

View File

@ -967,6 +967,9 @@ void InsetMathGrid::mathmlize(MathStream & os) const
void InsetMathGrid::write(WriteStream & os) const void InsetMathGrid::write(WriteStream & os) const
{ {
bool brace = os.pendingBrace();
os.pendingBrace(false);
docstring eol; docstring eol;
for (row_type row = 0; row < nrows(); ++row) { for (row_type row = 0; row < nrows(); ++row) {
os << verboseHLine(rowinfo_[row].lines_); os << verboseHLine(rowinfo_[row].lines_);
@ -978,8 +981,15 @@ void InsetMathGrid::write(WriteStream & os) const
lastcol = col + 1; lastcol = col + 1;
emptyline = false; emptyline = false;
} }
for (col_type col = 0; col < lastcol; ++col) for (col_type col = 0; col < lastcol; ++col) {
os << cell(index(row, col)) << eocString(col, lastcol); 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()); eol = eolString(row, emptyline, os.fragile());
os << eol; os << eol;
// append newline only if line wasn't completely empty // append newline only if line wasn't completely empty
@ -996,6 +1006,8 @@ void InsetMathGrid::write(WriteStream & os) const
} }
os << s; os << s;
} }
os.pendingBrace(brace);
} }

View File

@ -75,7 +75,7 @@ using cap::selClearOrDel;
char const * text_commands[] = char const * text_commands[] =
{ "text", "textrm", "textsf", "texttt", "textmd", "textbf", "textup", "textit", { "text", "textrm", "textsf", "texttt", "textmd", "textbf", "textup", "textit",
"textsl", "textsc" }; "textsl", "textsc", "textnormal" };
int const num_text_commands = sizeof(text_commands) / sizeof(*text_commands); 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 void InsetMathNest::write(WriteStream & os) const
{ {
bool oldmode = os.textMode(); bool textmode = os.textMode();
docstring const latex_name = name().c_str(); docstring const latex_name = name().c_str();
for (int i = 0; i < num_text_commands; ++i) { for (int i = 0; i < num_text_commands; ++i) {
if (latex_name == from_ascii(text_commands[i])) { if (latex_name == from_ascii(text_commands[i])) {
@ -358,7 +358,7 @@ void InsetMathNest::write(WriteStream & os) const
os << "\\lyxlock"; os << "\\lyxlock";
os.pendingSpace(true); os.pendingSpace(true);
} }
os.textMode(oldmode); os.textMode(textmode);
} }

View File

@ -73,7 +73,14 @@ bool InsetMathOverset::idxLast(Cursor & cur) const
void InsetMathOverset::write(WriteStream & os) 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 << "\\overset{" << cell(0) << "}{" << cell(1) << '}';
os.pendingBrace(brace);
} }

View File

@ -119,6 +119,13 @@ void InsetMathPhantom::draw(PainterInfo & pi, int x, int y) const
void InsetMathPhantom::write(WriteStream & os) 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_) { switch (kind_) {
case phantom: case phantom:
os << "\\phantom{"; os << "\\phantom{";
@ -131,6 +138,7 @@ void InsetMathPhantom::write(WriteStream & os) const
break; break;
} }
os << cell(0) << '}'; os << cell(0) << '}';
os.pendingBrace(brace);
} }

View File

@ -36,12 +36,12 @@ using namespace std;
namespace lyx { namespace lyx {
InsetMathRef::InsetMathRef() InsetMathRef::InsetMathRef()
: CommandInset(from_ascii("ref")) : CommandInset(from_ascii("ref"), false)
{} {}
InsetMathRef::InsetMathRef(docstring const & data) InsetMathRef::InsetMathRef(docstring const & data)
: CommandInset(data) : CommandInset(data, false)
{} {}

View File

@ -72,7 +72,15 @@ void InsetMathRoot::draw(PainterInfo & pi, int x, int y) const
void InsetMathRoot::write(WriteStream & os) 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 << "\\sqrt[" << cell(0) << "]{" << cell(1) << '}';
os.pendingBrace(brace);
} }

View File

@ -525,6 +525,14 @@ bool InsetMathScript::idxUpDown(Cursor & cur, bool up) const
void InsetMathScript::write(WriteStream & os) 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()) { if (nuc().size()) {
os << nuc(); os << nuc();
//if (nuc().back()->takesLimits()) { //if (nuc().back()->takesLimits()) {
@ -548,6 +556,8 @@ void InsetMathScript::write(WriteStream & os) const
if (lock_ && !os.latex()) if (lock_ && !os.latex())
os << "\\lyxlock "; os << "\\lyxlock ";
os.pendingBrace(brace);
} }

View File

@ -52,7 +52,15 @@ void InsetMathSize::draw(PainterInfo & pi, int x, int y) const
void InsetMathSize::write(WriteStream & os) 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 << "{\\" << key_->name << ' ' << cell(0) << '}';
os.pendingBrace(brace);
} }

View File

@ -147,8 +147,16 @@ void InsetMathSpace::normalize(NormalStream & os) const
void InsetMathSpace::write(WriteStream & os) const void InsetMathSpace::write(WriteStream & os) const
{ {
if (space_ >= 0 && space_ < nSpace) { 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 << '\\' << latex_mathspace[space_];
os.pendingSpace(true); os.pendingSpace(true);
os.pendingBrace(brace);
} }
} }

View File

@ -87,6 +87,13 @@ bool InsetMathSplit::getStatus(Cursor & cur, FuncRequest const & cmd,
void InsetMathSplit::write(WriteStream & ws) const 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()) if (ws.fragile())
ws << "\\protect"; ws << "\\protect";
ws << "\\begin{" << name_ << '}'; ws << "\\begin{" << name_ << '}';
@ -98,6 +105,7 @@ void InsetMathSplit::write(WriteStream & ws) const
if (ws.fragile()) if (ws.fragile())
ws << "\\protect"; ws << "\\protect";
ws << "\\end{" << name_ << "}\n"; ws << "\\end{" << name_ << "}\n";
ws.pendingBrace(brace);
} }

View File

@ -80,7 +80,15 @@ void InsetMathSqrt::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const
void InsetMathSqrt::write(WriteStream & os) 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 << "\\sqrt{" << cell(0) << '}';
os.pendingBrace(brace);
} }

View File

@ -58,7 +58,15 @@ void InsetMathStackrel::draw(PainterInfo & pi, int x, int y) const
void InsetMathStackrel::write(WriteStream & os) 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 << "\\stackrel{" << cell(0) << "}{" << cell(1) << '}';
os.pendingBrace(brace);
} }

View File

@ -111,35 +111,45 @@ void InsetMathString::write(WriteStream & os) const
docstring::const_iterator cit = str_.begin(); docstring::const_iterator cit = str_.begin();
docstring::const_iterator end = str_.end(); 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) { while (cit != end) {
char_type const c = *cit; char_type const c = *cit;
try { try {
docstring command(1, c); docstring command(1, c);
if (c < 0x80 || Encodings::latexMathChar(c, command)) { if (c < 0x80 || Encodings::latexMathChar(c, command)) {
if (os.textMode()) { if (os.textMode()) {
if (c < 0x80 && in_forced_mode) { if (in_forced_mode) {
// we were inside \lyxmathsym
os << '}'; os << '}';
os.textMode(false);
in_forced_mode = false; in_forced_mode = false;
} }
if (c >= 0x80 && !in_forced_mode) { if (c >= 0x80) {
os << "\\ensuremath{"; os << "\\ensuremath{";
os.textMode(false);
in_forced_mode = true; in_forced_mode = true;
} }
} else if (in_forced_mode) { } else if (c < 0x80 && in_forced_mode) {
// we were inside \ensuremath
os << '}'; os << '}';
os.textMode(true);
in_forced_mode = false; in_forced_mode = false;
} }
} else { } else if (!os.textMode()) {
if (os.textMode()) {
if (in_forced_mode) { if (in_forced_mode) {
// we were inside \ensuremath
os << '}'; os << '}';
in_forced_mode = false; in_forced_mode = false;
} } else {
} else if (!in_forced_mode) {
os << "\\lyxmathsym{"; os << "\\lyxmathsym{";
in_forced_mode = true; in_forced_mode = true;
} }
os.textMode(true);
} }
os << command; os << command;
// We may need a space if the command contains a macro // We may need a space if the command contains a macro
@ -162,8 +172,14 @@ void InsetMathString::write(WriteStream & os) const
} }
++cit; ++cit;
} }
if (in_forced_mode)
if (in_forced_mode && os.textMode()) {
// We have to care for closing \lyxmathsym
os << '}'; os << '}';
os.textMode(false);
} else {
os.pendingBrace(in_forced_mode);
}
} }

View File

@ -89,9 +89,17 @@ void InsetMathSubstack::infoize(odocstream & os) const
void InsetMathSubstack::write(WriteStream & 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{"; os << "\\substack{";
InsetMathGrid::write(os); InsetMathGrid::write(os);
os << "}\n"; os << "}\n";
os.pendingBrace(brace);
} }

View File

@ -206,7 +206,15 @@ void InsetMathSymbol::octave(OctaveStream & os) const
void InsetMathSymbol::write(WriteStream & 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 << '\\' << name();
os.pendingBrace(brace);
// $,#, etc. In theory the restriction based on catcodes, but then // $,#, etc. In theory the restriction based on catcodes, but then
// we do not handle catcodes very well, let alone cat code changes, // we do not handle catcodes very well, let alone cat code changes,

View File

@ -65,6 +65,15 @@ void InsetMathTabular::draw(PainterInfo & pi, int x, int y) const
void InsetMathTabular::write(WriteStream & os) 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()) if (os.fragile())
os << "\\protect"; os << "\\protect";
os << "\\begin{" << name_ << '}'; os << "\\begin{" << name_ << '}';
@ -81,6 +90,8 @@ void InsetMathTabular::write(WriteStream & os) const
os << "\\end{" << name_ << '}'; os << "\\end{" << name_ << '}';
// adding a \n here is bad if the tabular is the last item // adding a \n here is bad if the tabular is the last item
// in an \eqnarray... // in an \eqnarray...
os.textMode(textmode);
} }

View File

@ -84,7 +84,15 @@ bool InsetMathUnderset::idxUpDown(Cursor & cur, bool up) const
void InsetMathUnderset::write(WriteStream & os) 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 << "\\underset{" << cell(0) << "}{" << cell(1) << '}';
os.pendingBrace(brace);
} }

View File

@ -62,10 +62,20 @@ void InsetMathXArrow::draw(PainterInfo & pi, int x, int y) const
void InsetMathXArrow::write(WriteStream & os) 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_; os << '\\' << name_;
if (cell(1).size()) if (cell(1).size())
os << '[' << cell(1) << ']'; os << '[' << cell(1) << ']';
os << '{' << cell(0) << '}'; os << '{' << cell(0) << '}';
os.pendingBrace(brace);
} }

View File

@ -140,12 +140,20 @@ void InsetMathXYArrow::draw(PainterInfo & pi, int x, int y) const
void InsetMathXYArrow::write(WriteStream & os) 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"; os << "\\ar";
if (cell(0).size()) if (cell(0).size())
os << '[' << cell(0) << ']'; os << '[' << cell(0) << ']';
if (cell(1).size()) if (cell(1).size())
os << (up_ ? '^' : '_') << '{' << cell(1) << '}'; os << (up_ ? '^' : '_') << '{' << cell(1) << '}';
os << " "; os << " ";
os.pendingBrace(brace);
} }

View File

@ -53,6 +53,13 @@ void InsetMathXYMatrix::metrics(MetricsInfo & mi, Dimension & dim) const
void InsetMathXYMatrix::write(WriteStream & os) 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"; os << "\\xymatrix";
switch (spacing_code_) { switch (spacing_code_) {
case 'R': case 'R':
@ -71,6 +78,7 @@ void InsetMathXYMatrix::write(WriteStream & os) const
os << '{'; os << '{';
InsetMathGrid::write(os); InsetMathGrid::write(os);
os << "}\n"; os << "}\n";
os.pendingBrace(brace);
} }

View File

@ -655,10 +655,27 @@ bool MathMacro::folded() const
void MathMacro::write(WriteStream & os) 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 // non-normal mode
if (displayMode_ != DISPLAY_NORMAL) { if (displayMode_ != DISPLAY_NORMAL) {
os << "\\" << name() << " "; os << "\\" << name();
os.pendingSpace(true); os.pendingSpace(true);
os.pendingBrace(brace);
return; return;
} }
@ -705,6 +722,8 @@ void MathMacro::write(WriteStream & os) const
// add space if there was no argument // add space if there was no argument
if (first) if (first)
os.pendingSpace(true); os.pendingSpace(true);
os.pendingBrace(brace);
} }

View File

@ -62,6 +62,7 @@ following hack as starting point to write some macros:
#include "MathMacroArgument.h" #include "MathMacroArgument.h"
#include "MathSupport.h" #include "MathSupport.h"
#include "Encoding.h"
#include "Lexer.h" #include "Lexer.h"
#include "support/debug.h" #include "support/debug.h"
@ -1525,6 +1526,46 @@ void Parser::parse1(InsetMathGrid & grid, unsigned flags,
} }
#endif #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()) { else if (t.cs().size()) {
latexkeys const * l = in_word_set(t.cs()); latexkeys const * l = in_word_set(t.cs());
if (l) { if (l) {
@ -1576,6 +1617,45 @@ void Parser::parse1(InsetMathGrid & grid, unsigned flags,
} }
else { else {
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()); MathAtom at = createInsetMath(t.cs());
InsetMath::mode_type m = mode; InsetMath::mode_type m = mode;
//if (m == InsetMath::UNDECIDED_MODE) //if (m == InsetMath::UNDECIDED_MODE)
@ -1598,6 +1678,7 @@ void Parser::parse1(InsetMathGrid & grid, unsigned flags,
cell->push_back(at); cell->push_back(at);
} }
} }
}
if (flags & FLAG_LEAVE) { if (flags & FLAG_LEAVE) {

View File

@ -86,7 +86,12 @@ NormalStream & operator<<(NormalStream & ns, int i)
WriteStream & operator<<(WriteStream & ws, docstring const & s) 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])) if (isAlphaASCII(s[0]))
ws.os() << ' '; ws.os() << ' ';
ws.pendingSpace(false); ws.pendingSpace(false);
@ -105,19 +110,23 @@ WriteStream & operator<<(WriteStream & ws, docstring const & s)
WriteStream::WriteStream(odocstream & os, bool fragile, bool latex, bool dryrun) WriteStream::WriteStream(odocstream & os, bool fragile, bool latex, bool dryrun)
: os_(os), fragile_(fragile), firstitem_(false), latex_(latex), : 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) WriteStream::WriteStream(odocstream & os)
: os_(os), fragile_(false), firstitem_(false), latex_(false), : 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() WriteStream::~WriteStream()
{ {
if (pendingspace_) if (pendingbrace_)
os_ << '}';
else if (pendingspace_)
os_ << ' '; os_ << ' ';
} }
@ -134,6 +143,12 @@ void WriteStream::pendingSpace(bool how)
} }
void WriteStream::pendingBrace(bool brace)
{
pendingbrace_ = brace;
}
void WriteStream::textMode(bool textmode) void WriteStream::textMode(bool textmode)
{ {
textmode_ = textmode; textmode_ = textmode;
@ -156,7 +171,12 @@ WriteStream & operator<<(WriteStream & ws, MathData const & ar)
WriteStream & operator<<(WriteStream & ws, char const * s) 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])) if (isAlphaASCII(s[0]))
ws.os() << ' '; ws.os() << ' ';
ws.pendingSpace(false); ws.pendingSpace(false);
@ -169,7 +189,12 @@ WriteStream & operator<<(WriteStream & ws, char const * s)
WriteStream & operator<<(WriteStream & ws, char c) 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)) if (isAlphaASCII(c))
ws.os() << ' '; ws.os() << ' ';
ws.pendingSpace(false); ws.pendingSpace(false);
@ -183,6 +208,11 @@ WriteStream & operator<<(WriteStream & ws, char c)
WriteStream & operator<<(WriteStream & ws, int i) WriteStream & operator<<(WriteStream & ws, int i)
{ {
if (ws.pendingBrace()) {
ws.os() << '}';
ws.pendingBrace(false);
ws.textMode(true);
}
ws.os() << i; ws.os() << i;
return ws; return ws;
} }
@ -190,6 +220,11 @@ WriteStream & operator<<(WriteStream & ws, int i)
WriteStream & operator<<(WriteStream & ws, unsigned int i) WriteStream & operator<<(WriteStream & ws, unsigned int i)
{ {
if (ws.pendingBrace()) {
ws.os() << '}';
ws.pendingBrace(false);
ws.textMode(true);
}
ws.os() << i; ws.os() << i;
return ws; return ws;
} }

View File

@ -54,6 +54,10 @@ public:
void pendingSpace(bool how); void pendingSpace(bool how);
/// writes space if next thing is isalpha() /// writes space if next thing is isalpha()
bool pendingSpace() const { return pendingspace_; } 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 /// tell whether we are in text mode or not when producing latex code
void textMode(bool textmode); void textMode(bool textmode);
/// tell whether we are in text mode or not when producing latex code /// tell whether we are in text mode or not when producing latex code
@ -71,6 +75,8 @@ private:
bool dryrun_; bool dryrun_;
/// do we have a space pending? /// do we have a space pending?
bool pendingspace_; bool pendingspace_;
/// do we have a brace pending?
bool pendingbrace_;
/// are we in text mode when producing latex code? /// are we in text mode when producing latex code?
bool textmode_; bool textmode_;
/// ///