From dbbc4239a6cfae12bc4f4adb22b814445bdd1aae Mon Sep 17 00:00:00 2001 From: Georg Baum Date: Tue, 30 Dec 2014 13:39:52 +0100 Subject: [PATCH] Fix HTML output of \gg, \ll and \ne (bug #9372) The fix consists of three parts: The fix for \ll and \gg, the needed infrastructure to assign HTML entities to global math macros, and the actual fix for \ne and \neq. --- lib/symbols | 10 +-- src/mathed/InsetMathNest.cpp | 20 ++--- src/mathed/InsetMathSymbol.cpp | 25 ++----- src/mathed/MacroTable.cpp | 36 +++++++-- src/mathed/MacroTable.h | 15 ++-- src/mathed/MathFactory.cpp | 43 ++++++++++- src/mathed/MathMacro.cpp | 133 +++++++++++++++++++-------------- src/mathed/MathParser.cpp | 59 ++++++++------- src/mathed/MathParser.h | 2 + status.21x | 2 + 10 files changed, 216 insertions(+), 129 deletions(-) diff --git a/lib/symbols b/lib/symbols index 2b5aea2feb..b9b21b945c 100644 --- a/lib/symbols +++ b/lib/symbols @@ -289,7 +289,7 @@ diamondsuit cmsy 125 168 mathord ♢ heartsuit cmsy 126 169 mathord ♡ spadesuit cmsy 127 170 mathord ♠ # We define lyxnot as mathrel in order to have proper alignment -lyxnot cmsy 54 47 mathrel ∖ +lyxnot cmsy 54 47 mathrel / iffont cmsy # 9mu = 0.5em which is the extra space added to relation operators \def\not{\lyxnot\kern-9mu} @@ -373,8 +373,8 @@ subseteq cmsy 181 205 mathrel ⊆ in cmsy 50 206 mathrel ∈ ni cmsy 51 39 mathrel ∋ owns cmsy 51 39 mathrel ∋ -gg cmsy 192 0 mathrel > -ll cmsy 191 0 mathrel < +gg cmsy 192 0 mathrel ≫ +ll cmsy 191 0 mathrel ≪ leftrightarrow cmsy 36 171 mathrel ↔ leftarrow cmsy 195 172 mathrel ← gets cmsy 195 172 mathrel ← @@ -1120,8 +1120,8 @@ pod lyxblacktext 0 0 func x amsmath # pre-defined macros # -\def\neq{\not=} -\def\ne{\not=} +\def\neq{\not=} mathrel ≠ +\def\ne{\not=} mathrel ≠ \def\notin{\not\in} \def\slash{/} diff --git a/src/mathed/InsetMathNest.cpp b/src/mathed/InsetMathNest.cpp index 83e49c43b8..2e32bbb0ac 100644 --- a/src/mathed/InsetMathNest.cpp +++ b/src/mathed/InsetMathNest.cpp @@ -1029,7 +1029,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_REGEXP_MODE: { InsetMath * im = cur.inset().asInsetMath(); if (im) { - InsetMathHull * i = im->asHullInset(); + InsetMathHull * i = im->asHullInset(); if (i && i->getType() == hullRegexp) { cur.message(_("Already in regular expression mode")); break; @@ -1092,7 +1092,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) && name != "Bmatrix" && name != "vmatrix" && name != "Vmatrix" && name != "matrix") name = from_ascii("matrix"); - + cur.niceInsert( MathAtom(new InsetMathAMSArray(buffer_, name, m, n))); break; @@ -1279,7 +1279,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) if (createInsetMath_fromDialogStr(cmd.argument(), ar)) { cur.recordUndoSelection(); cur.insert(ar); - cur.forceBufferUpdate(); + cur.forceBufferUpdate(); } else cur.undispatched(); break; @@ -1455,7 +1455,7 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd, case LFUN_CAPTION_INSERT: flag.setEnabled(false); break; - + case LFUN_SPACE_INSERT: { docstring const & name = cmd.argument(); if (name == "visible") @@ -1635,9 +1635,8 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c) } // do not finish macro for known * commands - MathWordList const & mwl = mathedWordList(); bool star_macro = c == '*' - && (mwl.find(name.substr(1) + "*") != mwl.end() + && (in_word_set(name.substr(1) + '*') || cur.buffer()->getMacro(name.substr(1) + "*", cur, true)); if (isAlphaASCII(c) || star_macro) { cur.activeMacro()->setName(name + docstring(1, c)); @@ -1730,7 +1729,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c) cur.autocorrect() = false; cur.message(_("Autocorrect Off ('!' to enter)")); return true; - } + } if (lyxrc.autocorrection_math && c == '!' && !cur.autocorrect()) { cur.autocorrect() = true; cur.message(_("Autocorrect On ( to exit)")); @@ -2183,8 +2182,11 @@ MathCompletionList::MathCompletionList(Cursor const & cur) MathWordList::const_iterator it2; //lyxerr << "Globals completion commands: "; for (it2 = words.begin(); it2 != words.end(); ++it2) { - globals.push_back("\\" + (*it2).first); - //lyxerr << "\\" + (*it2).first << " "; + if (it2->second.inset != "macro") { + // macros are already read from MacroTable::globalMacros() + globals.push_back('\\' + it2->first); + //lyxerr << '\\' + it2->first << ' '; + } } //lyxerr << std::endl; sort(globals.begin(), globals.end()); diff --git a/src/mathed/InsetMathSymbol.cpp b/src/mathed/InsetMathSymbol.cpp index 1999846729..97c7aea1b6 100644 --- a/src/mathed/InsetMathSymbol.cpp +++ b/src/mathed/InsetMathSymbol.cpp @@ -185,22 +185,13 @@ void InsetMathSymbol::mathematica(MathematicaStream & os) const } -// FIXME This will likely need some work. -char const * MathMLtype(docstring const & s) -{ - if (s == "mathord") - return "mi"; - return "mo"; -} - - void InsetMathSymbol::mathmlize(MathStream & os) const { - // FIXME We may need to do more interesting things + // FIXME We may need to do more interesting things // with MathMLtype. - char const * type = MathMLtype(sym_->extra); + char const * type = sym_->MathMLtype(); os << '<' << type << "> "; - if (sym_->xmlname == "x") + if (sym_->xmlname == "x") // unknown so far os << name(); else @@ -211,15 +202,15 @@ void InsetMathSymbol::mathmlize(MathStream & os) const void InsetMathSymbol::htmlize(HtmlStream & os, bool spacing) const { - // FIXME We may need to do more interesting things + // FIXME We may need to do more interesting things // with MathMLtype. - char const * type = MathMLtype(sym_->extra); + char const * type = sym_->MathMLtype(); bool op = (std::string(type) == "mo"); - - if (sym_->xmlname == "x") + + if (sym_->xmlname == "x") // unknown so far os << ' ' << name() << ' '; - else if (op && spacing) + else if (op && spacing) os << ' ' << sym_->xmlname << ' '; else os << sym_->xmlname; diff --git a/src/mathed/MacroTable.cpp b/src/mathed/MacroTable.cpp index 4af30d4c54..3ac42929b6 100644 --- a/src/mathed/MacroTable.cpp +++ b/src/mathed/MacroTable.cpp @@ -14,6 +14,7 @@ #include "MacroTable.h" #include "MathMacroTemplate.h" #include "MathMacroArgument.h" +#include "MathParser.h" #include "MathStream.h" #include "MathSupport.h" #include "InsetMathNest.h" @@ -41,13 +42,13 @@ namespace lyx { ///////////////////////////////////////////////////////////////////// MacroData::MacroData(Buffer * buf) - : buffer_(buf), queried_(true), numargs_(0), optionals_(0), lockCount_(0), - redefinition_(false), type_(MacroTypeNewcommand) + : buffer_(buf), queried_(true), numargs_(0), sym_(0), optionals_(0), + lockCount_(0), redefinition_(false), type_(MacroTypeNewcommand) {} MacroData::MacroData(Buffer * buf, DocIterator const & pos) - : buffer_(buf), pos_(pos), queried_(false), numargs_(0), + : buffer_(buf), pos_(pos), queried_(false), numargs_(0), sym_(0), optionals_(0), lockCount_(0), redefinition_(false), type_(MacroTypeNewcommand) { @@ -55,8 +56,8 @@ MacroData::MacroData(Buffer * buf, DocIterator const & pos) MacroData::MacroData(Buffer * buf, MathMacroTemplate const & macro) - : buffer_(buf), queried_(false), numargs_(0), optionals_(0), lockCount_(0), - redefinition_(false), type_(MacroTypeNewcommand) + : buffer_(buf), queried_(false), numargs_(0), sym_(0), optionals_(0), + lockCount_(0), redefinition_(false), type_(MacroTypeNewcommand) { queryData(macro); } @@ -110,6 +111,28 @@ vector const & MacroData::defaults() const } +string const MacroData::requires() const +{ + if (sym_) + return to_utf8(sym_->requires); + return string(); +} + + +docstring const MacroData::xmlname() const +{ + if (sym_) + return sym_->xmlname; + return docstring(); +} + + +char const * MacroData::MathMLtype() const +{ + return sym_ ? sym_->MathMLtype() : 0; +} + + void MacroData::unlock() const { --lockCount_; @@ -210,12 +233,11 @@ MacroTable::insert(docstring const & name, MacroData const & data) MacroTable::iterator -MacroTable::insert(Buffer * buf, docstring const & def, string const & requires) +MacroTable::insert(Buffer * buf, docstring const & def) { //lyxerr << "MacroTable::insert, def: " << to_utf8(def) << endl; MathMacroTemplate mac(buf, def); MacroData data(buf, mac); - data.requires() = requires; return insert(mac.name(), data); } diff --git a/src/mathed/MacroTable.h b/src/mathed/MacroTable.h index 0f9f60dc41..97029a3df0 100644 --- a/src/mathed/MacroTable.h +++ b/src/mathed/MacroTable.h @@ -27,6 +27,7 @@ class Buffer; class MathData; class MathMacroTemplate; class Paragraph; +class latexkeys; enum MacroType { MacroTypeNewcommand, @@ -59,9 +60,13 @@ public: /// std::vector const & defaults() const; /// - std::string const & requires() const { return requires_; } + std::string const requires() const; /// - std::string & requires() { return requires_; } + docstring const xmlname() const; + /// + char const * MathMLtype() const; + /// + void setSymbol(latexkeys const * sym) { sym_ = sym; } /// lock while being drawn to avoid recursions int lock() const { return ++lockCount_; } @@ -86,7 +91,7 @@ public: return definition_ == x.definition_ && numargs_ == x.numargs_ && display_ == x.display_ - && requires_ == x.requires_ + && sym_ == x.sym_ && optionals_ == x.optionals_ && defaults_ == x.defaults_; } @@ -118,7 +123,7 @@ private: /// mutable docstring display_; /// - std::string requires_; + latexkeys const * sym_; /// mutable size_t optionals_; /// @@ -149,7 +154,7 @@ class MacroTable : public std::map { public: /// Parse full "\\def..." or "\\newcommand..." or ... - iterator insert(Buffer * buf, docstring const & definition, std::string const &); + iterator insert(Buffer * buf, docstring const & definition); /// Insert pre-digested macro definition iterator insert(docstring const & name, MacroData const & data); /// diff --git a/src/mathed/MathFactory.cpp b/src/mathed/MathFactory.cpp index 961e70e9f4..f4c5773c7a 100644 --- a/src/mathed/MathFactory.cpp +++ b/src/mathed/MathFactory.cpp @@ -175,18 +175,50 @@ void initSymbols() // special case of pre-defined macros if (line.size() > 8 && line.substr(0, 5) == "\\def\\") { //lyxerr << "macro definition: '" << line << '\'' << endl; + // syntax: Either + // \def\macroname{definition} + // or + // \def\macroname{definition} requires + // or + // \def\macroname{definition} extra xmlname requires istringstream is(line); string macro; string requires; + string extra; + string xmlname; is >> macro >> requires; + if ((is >> xmlname)) { + extra = requires; + if (!(is >> requires)) + requires = ""; + } else + xmlname = ""; MacroTable::iterator it = MacroTable::globalMacros().insert( - 0, from_utf8(macro), requires); + 0, from_utf8(macro)); + if (!extra.empty() || !xmlname.empty() || !requires.empty()) { + MathWordList::iterator wit = theMathWordList.find(it->first); + if (wit != theMathWordList.end()) + LYXERR(Debug::MATHED, "readSymbols: inset " + << to_utf8(it->first) << " already exists."); + else { + latexkeys tmp; + tmp.inset = from_ascii("macro"); + tmp.name = it->first; + tmp.extra = from_utf8(extra); + tmp.xmlname = from_utf8(xmlname); + tmp.requires = from_utf8(requires); + theMathWordList[it->first] = tmp; + wit = theMathWordList.find(it->first); + it->second.setSymbol(&(wit->second)); + } + } // If you change the following output, please adjust // development/tools/generate_symbols_images.py. LYXERR(Debug::MATHED, "read symbol '" << to_utf8(it->first) << " inset: macro" << " draw: 0" - << " extra: " + << " extra: " << extra + << " xml: " << xmlname << " requires: " << requires << '\''); continue; } @@ -270,6 +302,7 @@ void initSymbols() << " inset: " << to_utf8(tmp.inset) << " draw: " << int(tmp.draw.empty() ? 0 : tmp.draw[0]) << " extra: " << to_utf8(tmp.extra) + << " xml: " << to_utf8(tmp.xmlname) << " requires: " << to_utf8(tmp.requires) << '\''); } docstring tmp = from_ascii("cmm"); @@ -354,7 +387,11 @@ int ensureMode(WriteStream & os, InsetMath::mode_type mode, latexkeys const * in_word_set(docstring const & str) { MathWordList::iterator it = theMathWordList.find(str); - return it != theMathWordList.end() ? &(it->second) : 0; + if (it == theMathWordList.end()) + return 0; + if (it->second.inset == "macro") + return 0; + return &(it->second); } diff --git a/src/mathed/MathMacro.cpp b/src/mathed/MathMacro.cpp index 941e29aee2..745b12bcf5 100644 --- a/src/mathed/MathMacro.cpp +++ b/src/mathed/MathMacro.cpp @@ -52,11 +52,11 @@ namespace lyx { class ArgumentProxy : public InsetMath { public: /// - ArgumentProxy(MathMacro & mathMacro, size_t idx) + ArgumentProxy(MathMacro & mathMacro, size_t idx) : mathMacro_(mathMacro), idx_(idx) {} /// - ArgumentProxy(MathMacro & mathMacro, size_t idx, docstring const & def) - : mathMacro_(mathMacro), idx_(idx) + ArgumentProxy(MathMacro & mathMacro, size_t idx, docstring const & def) + : mathMacro_(mathMacro), idx_(idx) { asArray(def, def_); } @@ -81,13 +81,13 @@ public: /// void draw(PainterInfo & pi, int x, int y) const { if (mathMacro_.editMetrics(pi.base.bv)) { - // The only way a ArgumentProxy can appear is in a cell of the - // MathMacro. Moreover the cells are only drawn in the DISPLAY_FOLDED - // mode and then, if the macro is edited the monochrome + // The only way a ArgumentProxy can appear is in a cell of the + // MathMacro. Moreover the cells are only drawn in the DISPLAY_FOLDED + // mode and then, if the macro is edited the monochrome // mode is entered by the MathMacro before calling the cells' draw // method. Then eventually this code is reached and the proxy leaves - // monochrome mode temporarely. Hence, if it is not in monochrome - // here (and the assert triggers in pain.leaveMonochromeMode()) + // monochrome mode temporarely. Hence, if it is not in monochrome + // here (and the assert triggers in pain.leaveMonochromeMode()) // it's a bug. pi.pain.leaveMonochromeMode(); mathMacro_.cell(idx_).draw(pi, x, y); @@ -102,17 +102,17 @@ public: size_t idx() const { return idx_; } /// int kerning(BufferView const * bv) const - { + { if (mathMacro_.editMetrics(bv) || !mathMacro_.cell(idx_).empty()) - return mathMacro_.cell(idx_).kerning(bv); + return mathMacro_.cell(idx_).kerning(bv); else return def_.kerning(bv); } private: /// - Inset * clone() const + Inset * clone() const { return new ArgumentProxy(*this); } @@ -215,7 +215,7 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc = max(bsdim.ascent(), dim.ascent()); dim.des = max(bsdim.descent(), dim.descent()); metricsMarkers(dim); - } else if (lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_LIST + } else if (lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_LIST && editing_[mi.base.bv]) { // Macro will be edited in a old-style list mode here: @@ -223,7 +223,7 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const Dimension fontDim; FontInfo labelFont = sane_font; math_font_max_dim(labelFont, fontDim.asc, fontDim.des); - + // get dimension of components of list view Dimension nameDim; nameDim.wid = mathed_string_width(mi.base.font, from_ascii("Macro \\") + name() + ": "); @@ -234,22 +234,22 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const argDim.wid = mathed_string_width(labelFont, from_ascii("#9: ")); argDim.asc = fontDim.asc; argDim.des = fontDim.des; - + Dimension defDim; definition_.metrics(mi, defDim); - + // add them up dim.wid = nameDim.wid + defDim.wid; dim.asc = max(nameDim.asc, defDim.asc); dim.des = max(nameDim.des, defDim.des); - + for (idx_type i = 0; i < nargs(); ++i) { Dimension cdim; cell(i).metrics(mi, cdim); dim.des += max(argDim.height(), cdim.height()) + 1; dim.wid = max(dim.wid, argDim.wid + cdim.wid); } - + // make space for box and markers, 2 pixels dim.asc += 1; dim.des += 1; @@ -273,7 +273,7 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const macro_->unlock(); // calculate dimension with label while editing - if (lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_INLINE_BOX + if (lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_INLINE_BOX && editing_[mi.base.bv]) { FontInfo font = mi.base.font; augmentFont(font, from_ascii("lyxtex")); @@ -288,7 +288,6 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc += 1 + namedim.height() + 1; dim.des += 2; } - } } @@ -301,10 +300,10 @@ int MathMacro::kerning(BufferView const * bv) const { } -void MathMacro::updateMacro(MacroContext const & mc) +void MathMacro::updateMacro(MacroContext const & mc) { if (validName()) { - macro_ = mc.get(name()); + macro_ = mc.get(name()); if (macro_ && macroBackup_ != *macro_) { macroBackup_ = *macro_; needsUpdate_ = true; @@ -343,22 +342,22 @@ void MathMacro::updateRepresentation(Cursor * cur, MacroContext const & mc, // update requires requires_ = macro_->requires(); - + if (!needsUpdate_ // non-normal mode? We are done! || (displayMode_ != DISPLAY_NORMAL)) return; needsUpdate_ = false; - + // get default values of macro vector const & defaults = macro_->defaults(); - + // create MathMacroArgumentValue objects pointing to the cells of the macro vector values(nargs()); for (size_t i = 0; i < nargs(); ++i) { ArgumentProxy * proxy; - if (i < defaults.size()) + if (i < defaults.size()) proxy = new ArgumentProxy(*this, i, defaults[i]); else proxy = new ArgumentProxy(*this, i); @@ -388,7 +387,7 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const int expx = x; int expy = y; - if (displayMode_ == DISPLAY_INIT || displayMode_ == DISPLAY_INTERACTIVE_INIT) { + if (displayMode_ == DISPLAY_INIT || displayMode_ == DISPLAY_INTERACTIVE_INIT) { FontSetChanger dummy(pi.base, "lyxtex"); pi.pain.text(x, y, from_ascii("\\") + name(), pi.base.font); } else if (displayMode_ == DISPLAY_UNFOLDED) { @@ -400,17 +399,17 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const } else if (lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_LIST && editing_[pi.base.bv]) { // Macro will be edited in a old-style list mode here: - + CoordCache const & coords = pi.base.bv->coordCache(); FontInfo const & labelFont = sane_font; - + // markers and box needs two pixels x += 2; - + // get maximal font height Dimension fontDim; math_font_max_dim(pi.base.font, fontDim.asc, fontDim.des); - + // draw label docstring label = from_ascii("Macro \\") + name() + from_ascii(": "); pi.pain.text(x, y, label, labelFont); @@ -420,38 +419,38 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const definition_.draw(pi, x, y); Dimension const & defDim = coords.getArrays().dim(&definition_); y += max(fontDim.des, defDim.des); - + // draw parameters docstring str = from_ascii("#9"); int strw1 = mathed_string_width(labelFont, from_ascii("#9")); int strw2 = mathed_string_width(labelFont, from_ascii(": ")); - + for (idx_type i = 0; i < nargs(); ++i) { // position of label Dimension const & cdim = coords.getArrays().dim(&cell(i)); x = expx + 2; y += max(fontDim.asc, cdim.asc) + 1; - + // draw label str[1] = '1' + i; pi.pain.text(x, y, str, labelFont); x += strw1; pi.pain.text(x, y, from_ascii(":"), labelFont); x += strw2; - + // draw paramter cell(i).draw(pi, x, y); - + // next line y += max(fontDim.des, cdim.des); } - - pi.pain.rectangle(expx + 1, expy - dim.asc + 1, dim.wid - 3, + + pi.pain.rectangle(expx + 1, expy - dim.asc + 1, dim.wid - 3, dim.height() - 2, Color_mathmacroframe); drawMarkers2(pi, expx, expy); } else { bool drawBox = lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_INLINE_BOX; - + // warm up cells for (size_t i = 0; i < nargs(); ++i) cell(i).setXY(*pi.base.bv, x, y); @@ -476,7 +475,7 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const pi.pain.leaveMonochromeMode(); if (drawBox) - pi.pain.rectangle(x, y - dim.asc, dim.wid, + pi.pain.rectangle(x, y - dim.asc, dim.wid, dim.height(), Color_mathmacroframe); } else expanded_.cell(0).draw(pi, expx, expy); @@ -501,7 +500,7 @@ void MathMacro::drawSelection(PainterInfo & pi, int x, int y) const void MathMacro::setDisplayMode(MathMacro::DisplayMode mode, int appetite) { - if (displayMode_ != mode) { + if (displayMode_ != mode) { // transfer name if changing from or to DISPLAY_UNFOLDED if (mode == DISPLAY_UNFOLDED) { cells_.resize(1); @@ -514,7 +513,7 @@ void MathMacro::setDisplayMode(MathMacro::DisplayMode mode, int appetite) displayMode_ = mode; needsUpdate_ = true; } - + // the interactive init mode is non-greedy by default if (appetite == -1) appetite_ = (mode == DISPLAY_INTERACTIVE_INIT) ? 0 : 9; @@ -549,7 +548,7 @@ bool MathMacro::validName() const for (size_t i = 0; i= 'a' && n[i] <= 'z') && !(n[i] >= 'A' && n[i] <= 'Z') - && n[i] != '*') + && n[i] != '*') return false; } @@ -564,7 +563,7 @@ void MathMacro::validate(LaTeXFeatures & features) const if (name() == "binom") features.require("binom"); - + // validate the cells and the definition if (displayMode() == DISPLAY_NORMAL) { definition_.validate(features); @@ -585,7 +584,7 @@ Inset * MathMacro::editXY(Cursor & cur, int x, int y) // We may have 0 arguments, but InsetMathNest requires at least one. if (nargs() > 0) { cur.screenUpdateFlags(Update::SinglePar); - return InsetMathNest::editXY(cur, x, y); + return InsetMathNest::editXY(cur, x, y); } else return this; } @@ -654,14 +653,14 @@ void MathMacro::attachArguments(vector const & args, size_t arity, int } -bool MathMacro::idxFirst(Cursor & cur) const +bool MathMacro::idxFirst(Cursor & cur) const { cur.screenUpdateFlags(Update::SinglePar); return InsetMathNest::idxFirst(cur); } -bool MathMacro::idxLast(Cursor & cur) const +bool MathMacro::idxLast(Cursor & cur) const { cur.screenUpdateFlags(Update::SinglePar); return InsetMathNest::idxLast(cur); @@ -738,10 +737,10 @@ void MathMacro::write(WriteStream & os) const // Always protect macros in a fragile environment if (os.fragile()) os << "\\protect"; - + os << "\\" << name(); bool first = true; - + // Optional arguments: // First find last non-empty optional argument idx_type emptyOptFrom = 0; @@ -750,19 +749,19 @@ void MathMacro::write(WriteStream & os) const if (!cell(i).empty()) emptyOptFrom = i + 1; } - + // print out optionals for (i=0; i < cells_.size() && i < emptyOptFrom; ++i) { first = false; os << "[" << cell(i) << "]"; } - + // skip the tailing empty optionals i = optionals_; - + // Print remaining arguments for (; i < cells_.size(); ++i) { - if (cell(i).size() == 1 + if (cell(i).size() == 1 && cell(i)[0].nucleus()->asCharInset() && isASCII(cell(i)[0].nucleus()->asCharInset()->getChar())) { if (first) @@ -787,6 +786,16 @@ void MathMacro::maple(MapleStream & os) const void MathMacro::mathmlize(MathStream & os) const { + LATTEST(macro_); + if (macro_) { + docstring const xmlname = macro_->xmlname(); + if (!xmlname.empty()) { + char const * type = macro_->MathMLtype(); + os << '<' << type << "> " << xmlname << " /<" + << type << '>'; + return; + } + } MathData const & data = expanded_.cell(0); if (data.empty()) { // this means that we do not recognize the macro @@ -798,6 +807,14 @@ void MathMacro::mathmlize(MathStream & os) const void MathMacro::htmlize(HtmlStream & os) const { + LATTEST(macro_); + if (macro_) { + docstring const xmlname = macro_->xmlname(); + if (!xmlname.empty()) { + os << ' ' << xmlname << ' '; + return; + } + } MathData const & data = expanded_.cell(0); if (data.empty()) { // this means that we do not recognize the macro @@ -865,7 +882,7 @@ bool MathMacro::automaticPopupCompletion() const } -CompletionList const * +CompletionList const * MathMacro::createCompletionList(Cursor const & cur) const { if (displayMode() != DISPLAY_UNFOLDED) @@ -882,7 +899,7 @@ docstring MathMacro::completionPrefix(Cursor const & cur) const if (!completionSupported(cur)) return docstring(); - + return "\\" + name(); } @@ -901,14 +918,14 @@ bool MathMacro::insertCompletion(Cursor & cur, docstring const & s, asArray(newName, cell(0)); cur.bv().cursor().pos() = name().size(); cur.screenUpdateFlags(Update::SinglePar); - + // finish macro if (finished) { cur.bv().cursor().pop(); ++cur.bv().cursor().pos(); cur.screenUpdateFlags(Update::SinglePar); } - + return true; } @@ -918,14 +935,14 @@ void MathMacro::completionPosAndDim(Cursor const & cur, int & x, int & y, { if (displayMode() != DISPLAY_UNFOLDED) InsetMathNest::completionPosAndDim(cur, x, y, dim); - + // get inset dimensions dim = cur.bv().coordCache().insets().dim(this); // FIXME: these 3 are no accurate, but should depend on the font. // Now the popup jumps down if you enter a char with descent > 0. dim.des += 3; dim.asc += 3; - + // and position Point xy = cur.bv().coordCache().insets().xy(this); diff --git a/src/mathed/MathParser.cpp b/src/mathed/MathParser.cpp index 1c7f2ff0ad..e740d23db8 100644 --- a/src/mathed/MathParser.cpp +++ b/src/mathed/MathParser.cpp @@ -1039,10 +1039,10 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, t.cs() == "def") { if (t.cs() == "global") getToken(); - + // get name docstring name = getToken().cs(); - + // read parameters int nargs = 0; docstring pars; @@ -1051,17 +1051,17 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, ++nargs; } nargs /= 2; - + // read definition MathData def; parse(def, FLAG_ITEM, InsetMath::UNDECIDED_MODE); - + // is a version for display attached? skipSpaces(); MathData display; if (nextToken().cat() == catBegin) parse(display, FLAG_ITEM, InsetMath::MATH_MODE); - + cell->push_back(MathAtom(new MathMacroTemplate(buf, name, nargs, 0, MacroTypeDef, vector(), def, display))); @@ -1069,7 +1069,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, if (buf && (mode_ & Parse::TRACKMACRO)) buf->usermacros.insert(name); } - + else if (t.cs() == "newcommand" || t.cs() == "renewcommand" || t.cs() == "newlyxcommand") { @@ -1083,13 +1083,13 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, error("'}' in \\newcommand expected"); return success_; } - + // get arity docstring const arg = getArg('[', ']'); int nargs = 0; if (!arg.empty()) nargs = convert(arg); - + // optional argument given? skipSpaces(); int optionals = 0; @@ -1100,16 +1100,16 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, parse(optionalValues[optionals], FLAG_BRACK_LAST, mode); ++optionals; } - + MathData def; parse(def, FLAG_ITEM, InsetMath::UNDECIDED_MODE); - + // is a version for display attached? skipSpaces(); MathData display; if (nextToken().cat() == catBegin) parse(display, FLAG_ITEM, InsetMath::MATH_MODE); - + cell->push_back(MathAtom(new MathMacroTemplate(buf, name, nargs, optionals, MacroTypeNewcommand, optionalValues, def, display))); @@ -1117,7 +1117,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, if (buf && (mode_ & Parse::TRACKMACRO)) buf->usermacros.insert(name); } - + else if (t.cs() == "newcommandx" || t.cs() == "renewcommandx") { // \newcommandx{\foo}[2][usedefault, addprefix=\global,1=default]{#1,#2} @@ -1132,7 +1132,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } } else name = getToken().cs(); - + // get arity docstring const arg = getArg('[', ']'); if (arg.empty()) { @@ -1140,14 +1140,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, return success_; } int nargs = convert(arg); - + // get options int optionals = 0; vector optionalValues; if (nextToken().character() == '[') { // skip '[' getToken(); - + // handle 'opt=value' options, separated by ','. skipSpaces(); while (nextToken().character() != ']' && good()) { @@ -1160,14 +1160,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, "for given optional parameter."); return success_; } - + // skip '=' if (getToken().character() != '=') { error("'=' and optional parameter value " "expected for \\newcommandx"); return success_; } - + // get value int optNum = max(size_t(n), optionalValues.size()); optionalValues.resize(optNum); @@ -1182,12 +1182,12 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } else if (nextToken().cat() == catLetter) { // we in fact ignore every non-optional // parameter - + // get option name docstring opt; while (nextToken().cat() == catLetter) opt += getChar(); - + // value? skipSpaces(); MathData value; @@ -1195,14 +1195,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, getToken(); while (nextToken().character() != ']' && nextToken().character() != ',') - parse(value, FLAG_ITEM, + parse(value, FLAG_ITEM, InsetMath::UNDECIDED_MODE); } } else { error("option for \\newcommandx expected"); return success_; } - + // skip komma skipSpaces(); if (nextToken().character() == ',') { @@ -1214,7 +1214,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, return success_; } } - + // skip ']' if (!good()) return success_; @@ -1434,7 +1434,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, else if (t.cs() == "cfrac") { // allowed formats are \cfrac[pos]{num}{denom} docstring const arg = getArg('[', ']'); - //lyxerr << "got so far: '" << arg << "'" << endl; + //lyxerr << "got so far: '" << arg << "'" << endl; if (arg == "l") cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRACLEFT))); else if (arg == "r") @@ -1534,13 +1534,13 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, else if (t.cs() == "begin") { docstring const name = getArg('{', '}'); - + if (name.empty()) { success_ = false; error("found invalid environment"); return success_; } - + environments_.push_back(name); if (name == "array" || name == "subarray") { @@ -2089,6 +2089,15 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } // anonymous namespace +// FIXME This will likely need some work. +char const * latexkeys::MathMLtype() const +{ + if (extra == "mathord") + return "mi"; + return "mo"; +} + + bool mathed_parse_cell(MathData & ar, docstring const & str, Parse::flags f) { return Parser(str, f, ar.buffer()).parse(ar, 0, f & Parse::TEXTMODE ? diff --git a/src/mathed/MathParser.h b/src/mathed/MathParser.h index 745b038d2a..63e1be2598 100644 --- a/src/mathed/MathParser.h +++ b/src/mathed/MathParser.h @@ -30,6 +30,8 @@ class Lexer; /// class latexkeys { public: + /// + char const * MathMLtype() const; /// name of the macro or primitive docstring name; /// name of a inset that handles that macro diff --git a/status.21x b/status.21x index cfe41f8ff8..d83eb4b660 100644 --- a/status.21x +++ b/status.21x @@ -176,6 +176,8 @@ What's new * LYXHTML +- Fix export of \ll, \gg, \ne and \neq in math formulas (bug 9372). + * TEX2LYX -- 2.39.5