Fix html export of \ne (second part of bug #9372)

The fix consists of two parts: The needed infrastructure to assign HTML
entities to global math macros, and the actual fix for \ne and \neq.
This commit is contained in:
Georg Baum 2014-12-29 21:13:42 +01:00
parent a88e6e1ea5
commit cc87f81002
9 changed files with 195 additions and 126 deletions

View File

@ -1124,8 +1124,8 @@ pod lyxblacktext 0 0 func x amsmath
# pre-defined macros # pre-defined macros
# #
\def\neq{\not=} \def\neq{\not=} mathrel ≠
\def\ne{\not=} \def\ne{\not=} mathrel ≠
\def\notin{\not\in} \def\notin{\not\in}
\def\slash{/} \def\slash{/}

View File

@ -1030,7 +1030,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_REGEXP_MODE: { case LFUN_REGEXP_MODE: {
InsetMath * im = cur.inset().asInsetMath(); InsetMath * im = cur.inset().asInsetMath();
if (im) { if (im) {
InsetMathHull * i = im->asHullInset(); InsetMathHull * i = im->asHullInset();
if (i && i->getType() == hullRegexp) { if (i && i->getType() == hullRegexp) {
cur.message(_("Already in regular expression mode")); cur.message(_("Already in regular expression mode"));
break; break;
@ -1093,7 +1093,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
&& name != "Bmatrix" && name != "vmatrix" && name != "Bmatrix" && name != "vmatrix"
&& name != "Vmatrix" && name != "matrix") && name != "Vmatrix" && name != "matrix")
name = from_ascii("matrix"); name = from_ascii("matrix");
cur.niceInsert( cur.niceInsert(
MathAtom(new InsetMathAMSArray(buffer_, name, m, n))); MathAtom(new InsetMathAMSArray(buffer_, name, m, n)));
break; break;
@ -1280,7 +1280,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
if (createInsetMath_fromDialogStr(cmd.argument(), ar)) { if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
cur.recordUndoSelection(); cur.recordUndoSelection();
cur.insert(ar); cur.insert(ar);
cur.forceBufferUpdate(); cur.forceBufferUpdate();
} else } else
cur.undispatched(); cur.undispatched();
break; break;
@ -1456,7 +1456,7 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd,
case LFUN_CAPTION_INSERT: case LFUN_CAPTION_INSERT:
flag.setEnabled(false); flag.setEnabled(false);
break; break;
case LFUN_SPACE_INSERT: { case LFUN_SPACE_INSERT: {
docstring const & name = cmd.argument(); docstring const & name = cmd.argument();
if (name == "visible") if (name == "visible")
@ -1636,9 +1636,8 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
} }
// do not finish macro for known * commands // do not finish macro for known * commands
MathWordList const & mwl = mathedWordList();
bool star_macro = c == '*' 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)); || cur.buffer()->getMacro(name.substr(1) + "*", cur, true));
if (isAlphaASCII(c) || star_macro) { if (isAlphaASCII(c) || star_macro) {
cur.activeMacro()->setName(name + docstring(1, c)); cur.activeMacro()->setName(name + docstring(1, c));
@ -1731,7 +1730,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
cur.autocorrect() = false; cur.autocorrect() = false;
cur.message(_("Autocorrect Off ('!' to enter)")); cur.message(_("Autocorrect Off ('!' to enter)"));
return true; return true;
} }
if (lyxrc.autocorrection_math && c == '!' && !cur.autocorrect()) { if (lyxrc.autocorrection_math && c == '!' && !cur.autocorrect()) {
cur.autocorrect() = true; cur.autocorrect() = true;
cur.message(_("Autocorrect On (<space> to exit)")); cur.message(_("Autocorrect On (<space> to exit)"));
@ -2197,8 +2196,11 @@ MathCompletionList::MathCompletionList(Cursor const & cur)
MathWordList::const_iterator it2; MathWordList::const_iterator it2;
//lyxerr << "Globals completion commands: "; //lyxerr << "Globals completion commands: ";
for (it2 = words.begin(); it2 != words.end(); ++it2) { for (it2 = words.begin(); it2 != words.end(); ++it2) {
globals.push_back("\\" + (*it2).first); if (it2->second.inset != "macro") {
//lyxerr << "\\" + (*it2).first << " "; // macros are already read from MacroTable::globalMacros()
globals.push_back('\\' + it2->first);
//lyxerr << '\\' + it2->first << ' ';
}
} }
//lyxerr << std::endl; //lyxerr << std::endl;
sort(globals.begin(), globals.end()); sort(globals.begin(), globals.end());

View File

@ -186,22 +186,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 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. // with MathMLtype.
char const * type = MathMLtype(sym_->extra); char const * type = sym_->MathMLtype();
os << '<' << type << "> "; os << '<' << type << "> ";
if (sym_->xmlname == "x") if (sym_->xmlname == "x")
// unknown so far // unknown so far
os << name(); os << name();
else else
@ -212,15 +203,15 @@ void InsetMathSymbol::mathmlize(MathStream & os) const
void InsetMathSymbol::htmlize(HtmlStream & os, bool spacing) 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. // with MathMLtype.
char const * type = MathMLtype(sym_->extra); char const * type = sym_->MathMLtype();
bool op = (std::string(type) == "mo"); bool op = (std::string(type) == "mo");
if (sym_->xmlname == "x") if (sym_->xmlname == "x")
// unknown so far // unknown so far
os << ' ' << name() << ' '; os << ' ' << name() << ' ';
else if (op && spacing) else if (op && spacing)
os << ' ' << sym_->xmlname << ' '; os << ' ' << sym_->xmlname << ' ';
else else
os << sym_->xmlname; os << sym_->xmlname;

View File

@ -14,6 +14,7 @@
#include "MacroTable.h" #include "MacroTable.h"
#include "MathMacroTemplate.h" #include "MathMacroTemplate.h"
#include "MathMacroArgument.h" #include "MathMacroArgument.h"
#include "MathParser.h"
#include "MathStream.h" #include "MathStream.h"
#include "MathSupport.h" #include "MathSupport.h"
#include "InsetMathNest.h" #include "InsetMathNest.h"
@ -41,13 +42,13 @@ namespace lyx {
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
MacroData::MacroData(Buffer * buf) MacroData::MacroData(Buffer * buf)
: buffer_(buf), queried_(true), numargs_(0), optionals_(0), lockCount_(0), : buffer_(buf), queried_(true), numargs_(0), sym_(0), optionals_(0),
redefinition_(false), type_(MacroTypeNewcommand) lockCount_(0), redefinition_(false), type_(MacroTypeNewcommand)
{} {}
MacroData::MacroData(Buffer * buf, DocIterator const & pos) 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), optionals_(0), lockCount_(0), redefinition_(false),
type_(MacroTypeNewcommand) type_(MacroTypeNewcommand)
{ {
@ -55,8 +56,8 @@ MacroData::MacroData(Buffer * buf, DocIterator const & pos)
MacroData::MacroData(Buffer * buf, MathMacroTemplate const & macro) MacroData::MacroData(Buffer * buf, MathMacroTemplate const & macro)
: buffer_(buf), queried_(false), numargs_(0), optionals_(0), lockCount_(0), : buffer_(buf), queried_(false), numargs_(0), sym_(0), optionals_(0),
redefinition_(false), type_(MacroTypeNewcommand) lockCount_(0), redefinition_(false), type_(MacroTypeNewcommand)
{ {
queryData(macro); queryData(macro);
} }
@ -110,6 +111,14 @@ vector<docstring> const & MacroData::defaults() const
} }
string const MacroData::requires() const
{
if (sym_)
return to_utf8(sym_->requires);
return string();
}
void MacroData::unlock() const void MacroData::unlock() const
{ {
--lockCount_; --lockCount_;
@ -210,12 +219,11 @@ MacroTable::insert(docstring const & name, MacroData const & data)
MacroTable::iterator 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; //lyxerr << "MacroTable::insert, def: " << to_utf8(def) << endl;
MathMacroTemplate mac(buf, def); MathMacroTemplate mac(buf, def);
MacroData data(buf, mac); MacroData data(buf, mac);
data.requires() = requires;
return insert(mac.name(), data); return insert(mac.name(), data);
} }

View File

@ -27,6 +27,7 @@ class Buffer;
class MathData; class MathData;
class MathMacroTemplate; class MathMacroTemplate;
class Paragraph; class Paragraph;
class latexkeys;
enum MacroType { enum MacroType {
MacroTypeNewcommand, MacroTypeNewcommand,
@ -59,9 +60,9 @@ public:
/// ///
std::vector<docstring> const & defaults() const; std::vector<docstring> const & defaults() const;
/// ///
std::string const & requires() const { return requires_; } std::string const requires() const;
/// ///
std::string & requires() { return requires_; } void setSymbol(latexkeys const * sym) { sym_ = sym; }
/// lock while being drawn to avoid recursions /// lock while being drawn to avoid recursions
int lock() const { return ++lockCount_; } int lock() const { return ++lockCount_; }
@ -86,7 +87,7 @@ public:
return definition_ == x.definition_ return definition_ == x.definition_
&& numargs_ == x.numargs_ && numargs_ == x.numargs_
&& display_ == x.display_ && display_ == x.display_
&& requires_ == x.requires_ && sym_ == x.sym_
&& optionals_ == x.optionals_ && optionals_ == x.optionals_
&& defaults_ == x.defaults_; && defaults_ == x.defaults_;
} }
@ -118,7 +119,7 @@ private:
/// ///
mutable docstring display_; mutable docstring display_;
/// ///
std::string requires_; latexkeys const * sym_;
/// ///
mutable size_t optionals_; mutable size_t optionals_;
/// ///
@ -149,7 +150,7 @@ class MacroTable : public std::map<docstring, MacroData>
{ {
public: public:
/// Parse full "\\def..." or "\\newcommand..." or ... /// 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 /// Insert pre-digested macro definition
iterator insert(docstring const & name, MacroData const & data); iterator insert(docstring const & name, MacroData const & data);
/// ///

View File

@ -175,18 +175,50 @@ void initSymbols()
// special case of pre-defined macros // special case of pre-defined macros
if (line.size() > 8 && line.substr(0, 5) == "\\def\\") { if (line.size() > 8 && line.substr(0, 5) == "\\def\\") {
//lyxerr << "macro definition: '" << line << '\'' << endl; //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); istringstream is(line);
string macro; string macro;
string requires; string requires;
string extra;
string xmlname;
is >> macro >> requires; is >> macro >> requires;
if ((is >> xmlname)) {
extra = requires;
if (!(is >> requires))
requires = "";
} else
xmlname = "";
MacroTable::iterator it = MacroTable::globalMacros().insert( 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 // If you change the following output, please adjust
// development/tools/generate_symbols_images.py. // development/tools/generate_symbols_images.py.
LYXERR(Debug::MATHED, "read symbol '" << to_utf8(it->first) LYXERR(Debug::MATHED, "read symbol '" << to_utf8(it->first)
<< " inset: macro" << " inset: macro"
<< " draw: 0" << " draw: 0"
<< " extra: " << " extra: " << extra
<< " xml: " << xmlname
<< " requires: " << requires << '\''); << " requires: " << requires << '\'');
continue; continue;
} }
@ -270,6 +302,7 @@ void initSymbols()
<< " inset: " << to_utf8(tmp.inset) << " inset: " << to_utf8(tmp.inset)
<< " draw: " << int(tmp.draw.empty() ? 0 : tmp.draw[0]) << " draw: " << int(tmp.draw.empty() ? 0 : tmp.draw[0])
<< " extra: " << to_utf8(tmp.extra) << " extra: " << to_utf8(tmp.extra)
<< " xml: " << to_utf8(tmp.xmlname)
<< " requires: " << to_utf8(tmp.requires) << '\''); << " requires: " << to_utf8(tmp.requires) << '\'');
} }
docstring tmp = from_ascii("cmm"); 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) latexkeys const * in_word_set(docstring const & str)
{ {
MathWordList::iterator it = theMathWordList.find(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);
} }

View File

@ -52,11 +52,11 @@ namespace lyx {
class ArgumentProxy : public InsetMath { class ArgumentProxy : public InsetMath {
public: public:
/// ///
ArgumentProxy(MathMacro & mathMacro, size_t idx) ArgumentProxy(MathMacro & mathMacro, size_t idx)
: mathMacro_(mathMacro), idx_(idx) {} : mathMacro_(mathMacro), idx_(idx) {}
/// ///
ArgumentProxy(MathMacro & mathMacro, size_t idx, docstring const & def) ArgumentProxy(MathMacro & mathMacro, size_t idx, docstring const & def)
: mathMacro_(mathMacro), idx_(idx) : mathMacro_(mathMacro), idx_(idx)
{ {
asArray(def, def_); asArray(def, def_);
} }
@ -81,13 +81,13 @@ public:
/// ///
void draw(PainterInfo & pi, int x, int y) const { void draw(PainterInfo & pi, int x, int y) const {
if (mathMacro_.editMetrics(pi.base.bv)) { if (mathMacro_.editMetrics(pi.base.bv)) {
// The only way a ArgumentProxy can appear is in a cell of the // The only way a ArgumentProxy can appear is in a cell of the
// MathMacro. Moreover the cells are only drawn in the DISPLAY_FOLDED // MathMacro. Moreover the cells are only drawn in the DISPLAY_FOLDED
// mode and then, if the macro is edited the monochrome // mode and then, if the macro is edited the monochrome
// mode is entered by the MathMacro before calling the cells' draw // mode is entered by the MathMacro before calling the cells' draw
// method. Then eventually this code is reached and the proxy leaves // method. Then eventually this code is reached and the proxy leaves
// monochrome mode temporarely. Hence, if it is not in monochrome // monochrome mode temporarely. Hence, if it is not in monochrome
// here (and the assert triggers in pain.leaveMonochromeMode()) // here (and the assert triggers in pain.leaveMonochromeMode())
// it's a bug. // it's a bug.
pi.pain.leaveMonochromeMode(); pi.pain.leaveMonochromeMode();
mathMacro_.cell(idx_).draw(pi, x, y); mathMacro_.cell(idx_).draw(pi, x, y);
@ -102,17 +102,17 @@ public:
size_t idx() const { return idx_; } size_t idx() const { return idx_; }
/// ///
int kerning(BufferView const * bv) const int kerning(BufferView const * bv) const
{ {
if (mathMacro_.editMetrics(bv) if (mathMacro_.editMetrics(bv)
|| !mathMacro_.cell(idx_).empty()) || !mathMacro_.cell(idx_).empty())
return mathMacro_.cell(idx_).kerning(bv); return mathMacro_.cell(idx_).kerning(bv);
else else
return def_.kerning(bv); return def_.kerning(bv);
} }
private: private:
/// ///
Inset * clone() const Inset * clone() const
{ {
return new ArgumentProxy(*this); return new ArgumentProxy(*this);
} }
@ -215,7 +215,7 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
dim.asc = max(bsdim.ascent(), dim.ascent()); dim.asc = max(bsdim.ascent(), dim.ascent());
dim.des = max(bsdim.descent(), dim.descent()); dim.des = max(bsdim.descent(), dim.descent());
metricsMarkers(dim); 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]) { && editing_[mi.base.bv]) {
// Macro will be edited in a old-style list mode here: // 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; Dimension fontDim;
FontInfo labelFont = sane_font; FontInfo labelFont = sane_font;
math_font_max_dim(labelFont, fontDim.asc, fontDim.des); math_font_max_dim(labelFont, fontDim.asc, fontDim.des);
// get dimension of components of list view // get dimension of components of list view
Dimension nameDim; Dimension nameDim;
nameDim.wid = mathed_string_width(mi.base.font, from_ascii("Macro \\") + name() + ": "); 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.wid = mathed_string_width(labelFont, from_ascii("#9: "));
argDim.asc = fontDim.asc; argDim.asc = fontDim.asc;
argDim.des = fontDim.des; argDim.des = fontDim.des;
Dimension defDim; Dimension defDim;
definition_.metrics(mi, defDim); definition_.metrics(mi, defDim);
// add them up // add them up
dim.wid = nameDim.wid + defDim.wid; dim.wid = nameDim.wid + defDim.wid;
dim.asc = max(nameDim.asc, defDim.asc); dim.asc = max(nameDim.asc, defDim.asc);
dim.des = max(nameDim.des, defDim.des); dim.des = max(nameDim.des, defDim.des);
for (idx_type i = 0; i < nargs(); ++i) { for (idx_type i = 0; i < nargs(); ++i) {
Dimension cdim; Dimension cdim;
cell(i).metrics(mi, cdim); cell(i).metrics(mi, cdim);
dim.des += max(argDim.height(), cdim.height()) + 1; dim.des += max(argDim.height(), cdim.height()) + 1;
dim.wid = max(dim.wid, argDim.wid + cdim.wid); dim.wid = max(dim.wid, argDim.wid + cdim.wid);
} }
// make space for box and markers, 2 pixels // make space for box and markers, 2 pixels
dim.asc += 1; dim.asc += 1;
dim.des += 1; dim.des += 1;
@ -273,7 +273,7 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
macro_->unlock(); macro_->unlock();
// calculate dimension with label while editing // 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]) { && editing_[mi.base.bv]) {
FontInfo font = mi.base.font; FontInfo font = mi.base.font;
augmentFont(font, from_ascii("lyxtex")); augmentFont(font, from_ascii("lyxtex"));
@ -288,7 +288,6 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
dim.asc += 1 + namedim.height() + 1; dim.asc += 1 + namedim.height() + 1;
dim.des += 2; 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()) { if (validName()) {
macro_ = mc.get(name()); macro_ = mc.get(name());
if (macro_ && macroBackup_ != *macro_) { if (macro_ && macroBackup_ != *macro_) {
macroBackup_ = *macro_; macroBackup_ = *macro_;
needsUpdate_ = true; needsUpdate_ = true;
@ -350,22 +349,22 @@ void MathMacro::updateRepresentation(Cursor * cur, MacroContext const & mc,
// update requires // update requires
requires_ = macro_->requires(); requires_ = macro_->requires();
if (!needsUpdate_ if (!needsUpdate_
// non-normal mode? We are done! // non-normal mode? We are done!
|| (displayMode_ != DISPLAY_NORMAL)) || (displayMode_ != DISPLAY_NORMAL))
return; return;
needsUpdate_ = false; needsUpdate_ = false;
// get default values of macro // get default values of macro
vector<docstring> const & defaults = macro_->defaults(); vector<docstring> const & defaults = macro_->defaults();
// create MathMacroArgumentValue objects pointing to the cells of the macro // create MathMacroArgumentValue objects pointing to the cells of the macro
vector<MathData> values(nargs()); vector<MathData> values(nargs());
for (size_t i = 0; i < nargs(); ++i) { for (size_t i = 0; i < nargs(); ++i) {
ArgumentProxy * proxy; ArgumentProxy * proxy;
if (i < defaults.size()) if (i < defaults.size())
proxy = new ArgumentProxy(*this, i, defaults[i]); proxy = new ArgumentProxy(*this, i, defaults[i]);
else else
proxy = new ArgumentProxy(*this, i); proxy = new ArgumentProxy(*this, i);
@ -395,7 +394,7 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const
int expx = x; int expx = x;
int expy = y; int expy = y;
if (displayMode_ == DISPLAY_INIT || displayMode_ == DISPLAY_INTERACTIVE_INIT) { if (displayMode_ == DISPLAY_INIT || displayMode_ == DISPLAY_INTERACTIVE_INIT) {
FontSetChanger dummy(pi.base, "lyxtex"); FontSetChanger dummy(pi.base, "lyxtex");
pi.pain.text(x, y, from_ascii("\\") + name(), pi.base.font); pi.pain.text(x, y, from_ascii("\\") + name(), pi.base.font);
} else if (displayMode_ == DISPLAY_UNFOLDED) { } else if (displayMode_ == DISPLAY_UNFOLDED) {
@ -407,17 +406,17 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const
} else if (lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_LIST } else if (lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_LIST
&& editing_[pi.base.bv]) { && editing_[pi.base.bv]) {
// Macro will be edited in a old-style list mode here: // Macro will be edited in a old-style list mode here:
CoordCache const & coords = pi.base.bv->coordCache(); CoordCache const & coords = pi.base.bv->coordCache();
FontInfo const & labelFont = sane_font; FontInfo const & labelFont = sane_font;
// markers and box needs two pixels // markers and box needs two pixels
x += 2; x += 2;
// get maximal font height // get maximal font height
Dimension fontDim; Dimension fontDim;
math_font_max_dim(pi.base.font, fontDim.asc, fontDim.des); math_font_max_dim(pi.base.font, fontDim.asc, fontDim.des);
// draw label // draw label
docstring label = from_ascii("Macro \\") + name() + from_ascii(": "); docstring label = from_ascii("Macro \\") + name() + from_ascii(": ");
pi.pain.text(x, y, label, labelFont); pi.pain.text(x, y, label, labelFont);
@ -427,38 +426,38 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const
definition_.draw(pi, x, y); definition_.draw(pi, x, y);
Dimension const & defDim = coords.getArrays().dim(&definition_); Dimension const & defDim = coords.getArrays().dim(&definition_);
y += max(fontDim.des, defDim.des); y += max(fontDim.des, defDim.des);
// draw parameters // draw parameters
docstring str = from_ascii("#9"); docstring str = from_ascii("#9");
int strw1 = mathed_string_width(labelFont, from_ascii("#9")); int strw1 = mathed_string_width(labelFont, from_ascii("#9"));
int strw2 = mathed_string_width(labelFont, from_ascii(": ")); int strw2 = mathed_string_width(labelFont, from_ascii(": "));
for (idx_type i = 0; i < nargs(); ++i) { for (idx_type i = 0; i < nargs(); ++i) {
// position of label // position of label
Dimension const & cdim = coords.getArrays().dim(&cell(i)); Dimension const & cdim = coords.getArrays().dim(&cell(i));
x = expx + 2; x = expx + 2;
y += max(fontDim.asc, cdim.asc) + 1; y += max(fontDim.asc, cdim.asc) + 1;
// draw label // draw label
str[1] = '1' + i; str[1] = '1' + i;
pi.pain.text(x, y, str, labelFont); pi.pain.text(x, y, str, labelFont);
x += strw1; x += strw1;
pi.pain.text(x, y, from_ascii(":"), labelFont); pi.pain.text(x, y, from_ascii(":"), labelFont);
x += strw2; x += strw2;
// draw paramter // draw paramter
cell(i).draw(pi, x, y); cell(i).draw(pi, x, y);
// next line // next line
y += max(fontDim.des, cdim.des); 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); dim.height() - 2, Color_mathmacroframe);
drawMarkers2(pi, expx, expy); drawMarkers2(pi, expx, expy);
} else { } else {
bool drawBox = lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_INLINE_BOX; bool drawBox = lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_INLINE_BOX;
// warm up cells // warm up cells
for (size_t i = 0; i < nargs(); ++i) for (size_t i = 0; i < nargs(); ++i)
cell(i).setXY(*pi.base.bv, x, y); cell(i).setXY(*pi.base.bv, x, y);
@ -483,7 +482,7 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const
pi.pain.leaveMonochromeMode(); pi.pain.leaveMonochromeMode();
if (drawBox) if (drawBox)
pi.pain.rectangle(x, y - dim.asc, dim.wid, pi.pain.rectangle(x, y - dim.asc, dim.wid,
dim.height(), Color_mathmacroframe); dim.height(), Color_mathmacroframe);
} else } else
expanded_.cell(0).draw(pi, expx, expy); expanded_.cell(0).draw(pi, expx, expy);
@ -508,7 +507,7 @@ void MathMacro::drawSelection(PainterInfo & pi, int x, int y) const
void MathMacro::setDisplayMode(MathMacro::DisplayMode mode, int appetite) void MathMacro::setDisplayMode(MathMacro::DisplayMode mode, int appetite)
{ {
if (displayMode_ != mode) { if (displayMode_ != mode) {
// transfer name if changing from or to DISPLAY_UNFOLDED // transfer name if changing from or to DISPLAY_UNFOLDED
if (mode == DISPLAY_UNFOLDED) { if (mode == DISPLAY_UNFOLDED) {
cells_.resize(1); cells_.resize(1);
@ -521,7 +520,7 @@ void MathMacro::setDisplayMode(MathMacro::DisplayMode mode, int appetite)
displayMode_ = mode; displayMode_ = mode;
needsUpdate_ = true; needsUpdate_ = true;
} }
// the interactive init mode is non-greedy by default // the interactive init mode is non-greedy by default
if (appetite == -1) if (appetite == -1)
appetite_ = (mode == DISPLAY_INTERACTIVE_INIT) ? 0 : 9; appetite_ = (mode == DISPLAY_INTERACTIVE_INIT) ? 0 : 9;
@ -556,7 +555,7 @@ bool MathMacro::validName() const
for (size_t i = 0; i<n.size(); ++i) { for (size_t i = 0; i<n.size(); ++i) {
if (!(n[i] >= 'a' && n[i] <= 'z') if (!(n[i] >= 'a' && n[i] <= 'z')
&& !(n[i] >= 'A' && n[i] <= 'Z') && !(n[i] >= 'A' && n[i] <= 'Z')
&& n[i] != '*') && n[i] != '*')
return false; return false;
} }
@ -571,7 +570,7 @@ void MathMacro::validate(LaTeXFeatures & features) const
if (name() == "binom") if (name() == "binom")
features.require("binom"); features.require("binom");
// validate the cells and the definition // validate the cells and the definition
if (displayMode() == DISPLAY_NORMAL) { if (displayMode() == DISPLAY_NORMAL) {
definition_.validate(features); definition_.validate(features);
@ -592,7 +591,7 @@ Inset * MathMacro::editXY(Cursor & cur, int x, int y)
// We may have 0 arguments, but InsetMathNest requires at least one. // We may have 0 arguments, but InsetMathNest requires at least one.
if (nargs() > 0) { if (nargs() > 0) {
cur.screenUpdateFlags(Update::SinglePar); cur.screenUpdateFlags(Update::SinglePar);
return InsetMathNest::editXY(cur, x, y); return InsetMathNest::editXY(cur, x, y);
} else } else
return this; return this;
} }
@ -661,14 +660,14 @@ void MathMacro::attachArguments(vector<MathData> const & args, size_t arity, int
} }
bool MathMacro::idxFirst(Cursor & cur) const bool MathMacro::idxFirst(Cursor & cur) const
{ {
cur.screenUpdateFlags(Update::SinglePar); cur.screenUpdateFlags(Update::SinglePar);
return InsetMathNest::idxFirst(cur); return InsetMathNest::idxFirst(cur);
} }
bool MathMacro::idxLast(Cursor & cur) const bool MathMacro::idxLast(Cursor & cur) const
{ {
cur.screenUpdateFlags(Update::SinglePar); cur.screenUpdateFlags(Update::SinglePar);
return InsetMathNest::idxLast(cur); return InsetMathNest::idxLast(cur);
@ -745,10 +744,10 @@ void MathMacro::write(WriteStream & os) const
// Always protect macros in a fragile environment // Always protect macros in a fragile environment
if (os.fragile()) if (os.fragile())
os << "\\protect"; os << "\\protect";
os << "\\" << name(); os << "\\" << name();
bool first = true; bool first = true;
// Optional arguments: // Optional arguments:
// First find last non-empty optional argument // First find last non-empty optional argument
idx_type emptyOptFrom = 0; idx_type emptyOptFrom = 0;
@ -757,19 +756,19 @@ void MathMacro::write(WriteStream & os) const
if (!cell(i).empty()) if (!cell(i).empty())
emptyOptFrom = i + 1; emptyOptFrom = i + 1;
} }
// print out optionals // print out optionals
for (i=0; i < cells_.size() && i < emptyOptFrom; ++i) { for (i=0; i < cells_.size() && i < emptyOptFrom; ++i) {
first = false; first = false;
os << "[" << cell(i) << "]"; os << "[" << cell(i) << "]";
} }
// skip the tailing empty optionals // skip the tailing empty optionals
i = optionals_; i = optionals_;
// Print remaining arguments // Print remaining arguments
for (; i < cells_.size(); ++i) { for (; i < cells_.size(); ++i) {
if (cell(i).size() == 1 if (cell(i).size() == 1
&& cell(i)[0].nucleus()->asCharInset() && cell(i)[0].nucleus()->asCharInset()
&& isASCII(cell(i)[0].nucleus()->asCharInset()->getChar())) { && isASCII(cell(i)[0].nucleus()->asCharInset()->getChar())) {
if (first) if (first)
@ -794,6 +793,17 @@ void MathMacro::maple(MapleStream & os) const
void MathMacro::mathmlize(MathStream & os) const void MathMacro::mathmlize(MathStream & os) const
{ {
MathWordList const & words = mathedWordList();
MathWordList::const_iterator it = words.find(name());
if (it != words.end()) {
docstring const xmlname = it->second.xmlname;
if (!xmlname.empty()) {
char const * type = it->second.MathMLtype();
os << '<' << type << "> " << xmlname << " /<"
<< type << '>';
return;
}
}
MathData const & data = expanded_.cell(0); MathData const & data = expanded_.cell(0);
if (data.empty()) { if (data.empty()) {
// this means that we do not recognize the macro // this means that we do not recognize the macro
@ -805,6 +815,15 @@ void MathMacro::mathmlize(MathStream & os) const
void MathMacro::htmlize(HtmlStream & os) const void MathMacro::htmlize(HtmlStream & os) const
{ {
MathWordList const & words = mathedWordList();
MathWordList::const_iterator it = words.find(name());
if (it != words.end()) {
docstring const xmlname = it->second.xmlname;
if (!xmlname.empty()) {
os << ' ' << xmlname << ' ';
return;
}
}
MathData const & data = expanded_.cell(0); MathData const & data = expanded_.cell(0);
if (data.empty()) { if (data.empty()) {
// this means that we do not recognize the macro // this means that we do not recognize the macro
@ -872,7 +891,7 @@ bool MathMacro::automaticPopupCompletion() const
} }
CompletionList const * CompletionList const *
MathMacro::createCompletionList(Cursor const & cur) const MathMacro::createCompletionList(Cursor const & cur) const
{ {
if (displayMode() != DISPLAY_UNFOLDED) if (displayMode() != DISPLAY_UNFOLDED)
@ -889,7 +908,7 @@ docstring MathMacro::completionPrefix(Cursor const & cur) const
if (!completionSupported(cur)) if (!completionSupported(cur))
return docstring(); return docstring();
return "\\" + name(); return "\\" + name();
} }
@ -908,14 +927,14 @@ bool MathMacro::insertCompletion(Cursor & cur, docstring const & s,
asArray(newName, cell(0)); asArray(newName, cell(0));
cur.bv().cursor().pos() = name().size(); cur.bv().cursor().pos() = name().size();
cur.screenUpdateFlags(Update::SinglePar); cur.screenUpdateFlags(Update::SinglePar);
// finish macro // finish macro
if (finished) { if (finished) {
cur.bv().cursor().pop(); cur.bv().cursor().pop();
++cur.bv().cursor().pos(); ++cur.bv().cursor().pos();
cur.screenUpdateFlags(Update::SinglePar); cur.screenUpdateFlags(Update::SinglePar);
} }
return true; return true;
} }
@ -925,14 +944,14 @@ void MathMacro::completionPosAndDim(Cursor const & cur, int & x, int & y,
{ {
if (displayMode() != DISPLAY_UNFOLDED) if (displayMode() != DISPLAY_UNFOLDED)
InsetMathNest::completionPosAndDim(cur, x, y, dim); InsetMathNest::completionPosAndDim(cur, x, y, dim);
// get inset dimensions // get inset dimensions
dim = cur.bv().coordCache().insets().dim(this); dim = cur.bv().coordCache().insets().dim(this);
// FIXME: these 3 are no accurate, but should depend on the font. // 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. // Now the popup jumps down if you enter a char with descent > 0.
dim.des += 3; dim.des += 3;
dim.asc += 3; dim.asc += 3;
// and position // and position
Point xy Point xy
= cur.bv().coordCache().insets().xy(this); = cur.bv().coordCache().insets().xy(this);

View File

@ -1066,10 +1066,10 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
t.cs() == "def") { t.cs() == "def") {
if (t.cs() == "global") if (t.cs() == "global")
getToken(); getToken();
// get name // get name
docstring name = getToken().cs(); docstring name = getToken().cs();
// read parameters // read parameters
int nargs = 0; int nargs = 0;
docstring pars; docstring pars;
@ -1078,17 +1078,17 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
++nargs; ++nargs;
} }
nargs /= 2; nargs /= 2;
// read definition // read definition
MathData def; MathData def;
parse(def, FLAG_ITEM, InsetMath::UNDECIDED_MODE); parse(def, FLAG_ITEM, InsetMath::UNDECIDED_MODE);
// is a version for display attached? // is a version for display attached?
skipSpaces(); skipSpaces();
MathData display; MathData display;
if (nextToken().cat() == catBegin) if (nextToken().cat() == catBegin)
parse(display, FLAG_ITEM, InsetMath::MATH_MODE); parse(display, FLAG_ITEM, InsetMath::MATH_MODE);
cell->push_back(MathAtom(new MathMacroTemplate(buf, cell->push_back(MathAtom(new MathMacroTemplate(buf,
name, nargs, 0, MacroTypeDef, name, nargs, 0, MacroTypeDef,
vector<MathData>(), def, display))); vector<MathData>(), def, display)));
@ -1096,7 +1096,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
if (buf && (mode_ & Parse::TRACKMACRO)) if (buf && (mode_ & Parse::TRACKMACRO))
buf->usermacros.insert(name); buf->usermacros.insert(name);
} }
else if (t.cs() == "newcommand" || else if (t.cs() == "newcommand" ||
t.cs() == "renewcommand" || t.cs() == "renewcommand" ||
t.cs() == "newlyxcommand") { t.cs() == "newlyxcommand") {
@ -1110,13 +1110,13 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
error("'}' in \\newcommand expected"); error("'}' in \\newcommand expected");
return success_; return success_;
} }
// get arity // get arity
docstring const arg = getArg('[', ']'); docstring const arg = getArg('[', ']');
int nargs = 0; int nargs = 0;
if (!arg.empty()) if (!arg.empty())
nargs = convert<int>(arg); nargs = convert<int>(arg);
// optional argument given? // optional argument given?
skipSpaces(); skipSpaces();
int optionals = 0; int optionals = 0;
@ -1127,16 +1127,16 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
parse(optionalValues[optionals], FLAG_BRACK_LAST, mode); parse(optionalValues[optionals], FLAG_BRACK_LAST, mode);
++optionals; ++optionals;
} }
MathData def; MathData def;
parse(def, FLAG_ITEM, InsetMath::UNDECIDED_MODE); parse(def, FLAG_ITEM, InsetMath::UNDECIDED_MODE);
// is a version for display attached? // is a version for display attached?
skipSpaces(); skipSpaces();
MathData display; MathData display;
if (nextToken().cat() == catBegin) if (nextToken().cat() == catBegin)
parse(display, FLAG_ITEM, InsetMath::MATH_MODE); parse(display, FLAG_ITEM, InsetMath::MATH_MODE);
cell->push_back(MathAtom(new MathMacroTemplate(buf, cell->push_back(MathAtom(new MathMacroTemplate(buf,
name, nargs, optionals, MacroTypeNewcommand, name, nargs, optionals, MacroTypeNewcommand,
optionalValues, def, display))); optionalValues, def, display)));
@ -1144,7 +1144,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
if (buf && (mode_ & Parse::TRACKMACRO)) if (buf && (mode_ & Parse::TRACKMACRO))
buf->usermacros.insert(name); buf->usermacros.insert(name);
} }
else if (t.cs() == "newcommandx" || else if (t.cs() == "newcommandx" ||
t.cs() == "renewcommandx") { t.cs() == "renewcommandx") {
// \newcommandx{\foo}[2][usedefault, addprefix=\global,1=default]{#1,#2} // \newcommandx{\foo}[2][usedefault, addprefix=\global,1=default]{#1,#2}
@ -1159,7 +1159,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
} }
} else } else
name = getToken().cs(); name = getToken().cs();
// get arity // get arity
docstring const arg = getArg('[', ']'); docstring const arg = getArg('[', ']');
if (arg.empty()) { if (arg.empty()) {
@ -1167,14 +1167,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
return success_; return success_;
} }
int nargs = convert<int>(arg); int nargs = convert<int>(arg);
// get options // get options
int optionals = 0; int optionals = 0;
vector<MathData> optionalValues; vector<MathData> optionalValues;
if (nextToken().character() == '[') { if (nextToken().character() == '[') {
// skip '[' // skip '['
getToken(); getToken();
// handle 'opt=value' options, separated by ','. // handle 'opt=value' options, separated by ','.
skipSpaces(); skipSpaces();
while (nextToken().character() != ']' && good()) { while (nextToken().character() != ']' && good()) {
@ -1187,14 +1187,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
"for given optional parameter."); "for given optional parameter.");
return success_; return success_;
} }
// skip '=' // skip '='
if (getToken().character() != '=') { if (getToken().character() != '=') {
error("'=' and optional parameter value " error("'=' and optional parameter value "
"expected for \\newcommandx"); "expected for \\newcommandx");
return success_; return success_;
} }
// get value // get value
int optNum = max(size_t(n), optionalValues.size()); int optNum = max(size_t(n), optionalValues.size());
optionalValues.resize(optNum); optionalValues.resize(optNum);
@ -1209,12 +1209,12 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
} else if (nextToken().cat() == catLetter) { } else if (nextToken().cat() == catLetter) {
// we in fact ignore every non-optional // we in fact ignore every non-optional
// parameter // parameter
// get option name // get option name
docstring opt; docstring opt;
while (nextToken().cat() == catLetter) while (nextToken().cat() == catLetter)
opt += getChar(); opt += getChar();
// value? // value?
skipSpaces(); skipSpaces();
MathData value; MathData value;
@ -1222,14 +1222,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
getToken(); getToken();
while (nextToken().character() != ']' while (nextToken().character() != ']'
&& nextToken().character() != ',') && nextToken().character() != ',')
parse(value, FLAG_ITEM, parse(value, FLAG_ITEM,
InsetMath::UNDECIDED_MODE); InsetMath::UNDECIDED_MODE);
} }
} else { } else {
error("option for \\newcommandx expected"); error("option for \\newcommandx expected");
return success_; return success_;
} }
// skip komma // skip komma
skipSpaces(); skipSpaces();
if (nextToken().character() == ',') { if (nextToken().character() == ',') {
@ -1241,7 +1241,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
return success_; return success_;
} }
} }
// skip ']' // skip ']'
if (!good()) if (!good())
return success_; return success_;
@ -1481,7 +1481,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
else if (t.cs() == "cfrac") { else if (t.cs() == "cfrac") {
// allowed formats are \cfrac[pos]{num}{denom} // allowed formats are \cfrac[pos]{num}{denom}
docstring const arg = getArg('[', ']'); docstring const arg = getArg('[', ']');
//lyxerr << "got so far: '" << arg << "'" << endl; //lyxerr << "got so far: '" << arg << "'" << endl;
if (arg == "l") if (arg == "l")
cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRACLEFT))); cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRACLEFT)));
else if (arg == "r") else if (arg == "r")
@ -1593,13 +1593,13 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
else if (t.cs() == "begin") { else if (t.cs() == "begin") {
docstring const name = getArg('{', '}'); docstring const name = getArg('{', '}');
if (name.empty()) { if (name.empty()) {
success_ = false; success_ = false;
error("found invalid environment"); error("found invalid environment");
return success_; return success_;
} }
environments_.push_back(name); environments_.push_back(name);
if (name == "array" || name == "subarray") { if (name == "array" || name == "subarray") {
@ -2155,6 +2155,15 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
} // anonymous namespace } // 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) bool mathed_parse_cell(MathData & ar, docstring const & str, Parse::flags f)
{ {
return Parser(str, f, ar.buffer()).parse(ar, 0, f & Parse::TEXTMODE ? return Parser(str, f, ar.buffer()).parse(ar, 0, f & Parse::TEXTMODE ?

View File

@ -30,6 +30,8 @@ class Lexer;
/// ///
class latexkeys { class latexkeys {
public: public:
///
char const * MathMLtype() const;
/// name of the macro or primitive /// name of the macro or primitive
docstring name; docstring name;
/// name of a inset that handles that macro /// name of a inset that handles that macro