From: Jean-Marc Lasgouttes Date: Mon, 30 May 2016 08:33:35 +0000 (+0200) Subject: Introduce the notion of math class X-Git-Tag: 2.3.0alpha1~741^2~6 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=361bd53bc36da61c6abfc2e0b7b7c7294800bbd9;p=features.git Introduce the notion of math class This done according to the TeXbook. This class replaces the individual isMathXXX() methods. The mathClass() method (currently unused) is provided for the following insets: * InsetMathChar (with a revised list of affected characters) * InsetMathSymbol: the class is given by the `extra' field Operators defined in lib/symbols (e.g. \log) are MC_OP * InsetMathFrac is MC_INNER (except nicefrac and units) * InsetDelimiters is MC_INNER * InsetStackrel is MC_REL * The class of InsetScript is the class of the last element of its nucleus (yes, it is a hack, but doing it right is more work). Remove the explicit spacing that was done in the different insets. The spacing will be reintroduced properly in a forthcoming commit. --- diff --git a/src/Makefile.am b/src/Makefile.am index f3dd870077..fc135af00e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -447,14 +447,15 @@ SOURCEFILESMATHED = \ mathed/InsetMathXArrow.cpp \ mathed/InsetMathXYMatrix.cpp \ mathed/InsetMathDiagram.cpp \ + mathed/MacroTable.cpp \ mathed/MathAtom.cpp \ mathed/MathAutoCorrect.cpp \ + mathed/MathClass.cpp \ mathed/MathData.cpp \ mathed/MathExtern.cpp \ mathed/MathFactory.cpp \ mathed/MathMacro.cpp \ mathed/MathMacroArgument.cpp \ - mathed/MacroTable.cpp \ mathed/MathMacroTemplate.cpp \ mathed/MathParser.cpp \ mathed/MathStream.cpp \ @@ -518,6 +519,7 @@ HEADERFILESMATHED = \ mathed/InsetMathDiagram.h \ mathed/MathAtom.h \ mathed/MathAutoCorrect.h \ + mathed/MathClass.h \ mathed/MathData.h \ mathed/MathCompletionList.h \ mathed/MathExtern.h \ diff --git a/src/mathed/InsetMath.cpp b/src/mathed/InsetMath.cpp index 2fb1ff5a55..aec53d0518 100644 --- a/src/mathed/InsetMath.cpp +++ b/src/mathed/InsetMath.cpp @@ -49,6 +49,12 @@ MathData const & InsetMath::cell(idx_type) const } +MathClass InsetMath::mathClass() const +{ + return MC_ORD; +} + + void InsetMath::dump() const { lyxerr << "---------------------------------------------" << endl; diff --git a/src/mathed/InsetMath.h b/src/mathed/InsetMath.h index da84af1010..e791099b72 100644 --- a/src/mathed/InsetMath.h +++ b/src/mathed/InsetMath.h @@ -13,6 +13,8 @@ #ifndef MATH_INSET_H #define MATH_INSET_H +#include "MathClass.h" + #include "insets/Inset.h" @@ -160,14 +162,11 @@ public: virtual InsetMathRef * asRefInset() { return 0; } virtual InsetMathSpecialChar const * asSpecialCharInset() const { return 0; } + /// The class of the math object (used primarily for spacing) + virtual MathClass mathClass() const; + /// identifies things that can get scripts virtual bool isScriptable() const { return false; } - /// identifies a binary operators (used for spacing) - virtual bool isMathBin() const { return false; } - /// identifies relational operators (used for spacing and splitting equations) - virtual bool isMathRel() const { return false; } - /// identifies punctuation (used for spacing) - virtual bool isMathPunct() const { return false; } /// will this get written as a single block in {..} virtual bool extraBraces() const { return false; } diff --git a/src/mathed/InsetMathChar.cpp b/src/mathed/InsetMathChar.cpp index ae843bf00d..1669515b66 100644 --- a/src/mathed/InsetMathChar.cpp +++ b/src/mathed/InsetMathChar.cpp @@ -121,8 +121,6 @@ void InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const dim = fm.dimension(char_); kerning_ = fm.rbearing(char_) - dim.wid; } - if (mathfont && isMathPunct()) - dim.wid += mathed_thinmuskip(mi.base.font); } @@ -266,22 +264,19 @@ void InsetMathChar::htmlize(HtmlStream & ms) const } -bool InsetMathChar::isMathBin() const +MathClass InsetMathChar::mathClass() const { - return subst_ && subst_->extra == "mathbin"; -} - - -bool InsetMathChar::isMathRel() const -{ - return subst_ && subst_->extra == "mathrel"; -} - - -bool InsetMathChar::isMathPunct() const -{ - return support::contains(",;", static_cast(char_)) - || (subst_ && subst_->extra == "mathpunct"); + // this information comes from fontmath.ltx in LaTeX source. + char const ch = static_cast(char_); + if (subst_) + return string_to_class(subst_->extra); + else if (support::contains(",;", ch)) + return MC_PUNCT; + else if (support::contains("([", ch)) + return MC_OPEN; + else if (support::contains(")]!?", ch)) + return MC_CLOSE; + else return MC_ORD; } diff --git a/src/mathed/InsetMathChar.h b/src/mathed/InsetMathChar.h index ea190211b7..6e7ff72c9c 100644 --- a/src/mathed/InsetMathChar.h +++ b/src/mathed/InsetMathChar.h @@ -51,11 +51,7 @@ public: /// char_type getChar() const { return char_; } /// - bool isMathBin() const; - /// - bool isMathRel() const; - /// - bool isMathPunct() const; + MathClass mathClass() const; /// InsetCode lyxCode() const { return MATH_CHAR_CODE; } diff --git a/src/mathed/InsetMathDelim.cpp b/src/mathed/InsetMathDelim.cpp index 68e4430514..4ab179e7b2 100644 --- a/src/mathed/InsetMathDelim.cpp +++ b/src/mathed/InsetMathDelim.cpp @@ -115,7 +115,7 @@ void InsetMathDelim::metrics(MetricsInfo & mi, Dimension & dim) const dw_ = 8; if (dw_ < 4) dw_ = 4; - dim.wid = dim0.width() + 2 * dw_ + 2 * mathed_thinmuskip(mi.base.font); + dim.wid = dim0.width() + 2 * dw_; dim.asc = max(a0, d0) + h0; dim.des = max(a0, d0) - h0; } @@ -125,10 +125,9 @@ void InsetMathDelim::draw(PainterInfo & pi, int x, int y) const { Dimension const dim = dimension(*pi.base.bv); int const b = y - dim.asc; - int const skip = mathed_thinmuskip(pi.base.font); - cell(0).draw(pi, x + dw_ + skip, y); - mathed_draw_deco(pi, x + skip, b, dw_, dim.height(), left_); - mathed_draw_deco(pi, x + dim.width() - dw_ - skip, + cell(0).draw(pi, x + dw_, y); + mathed_draw_deco(pi, x, b, dw_, dim.height(), left_); + mathed_draw_deco(pi, x + dim.width() - dw_, b, dw_, dim.height(), right_); setPosCache(pi, x, y); } diff --git a/src/mathed/InsetMathDelim.h b/src/mathed/InsetMathDelim.h index 3a09ede2f3..5a7e816404 100644 --- a/src/mathed/InsetMathDelim.h +++ b/src/mathed/InsetMathDelim.h @@ -30,6 +30,8 @@ public: InsetMathDelim * asDelimInset() { return this; } /// InsetMathDelim const * asDelimInset() const { return this; } + /// + MathClass mathClass() const { return MC_INNER; } /// is it (...)? bool isParenthesis() const; /// is it [...]? diff --git a/src/mathed/InsetMathFrac.cpp b/src/mathed/InsetMathFrac.cpp index ab876e060d..263587ed6e 100644 --- a/src/mathed/InsetMathFrac.cpp +++ b/src/mathed/InsetMathFrac.cpp @@ -123,6 +123,31 @@ bool InsetMathFrac::idxBackward(Cursor & cur) const } +MathClass InsetMathFrac::mathClass() const +{ + // Generalized fractions are of inner class (see The TeXbook, p. 292) + // But stuff from the unit/nicefrac packages are not real fractions. + MathClass mc = MC_ORD; + switch (kind_) { + case ATOP: + case OVER: + case FRAC: + case DFRAC: + case TFRAC: + case CFRAC: + case CFRACLEFT: + case CFRACRIGHT: + mc = MC_INNER; + break; + case NICEFRAC: + case UNITFRAC: + case UNIT: + break; + } + return mc; +} + + void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const { Dimension dim0, dim1, dim2; diff --git a/src/mathed/InsetMathFrac.h b/src/mathed/InsetMathFrac.h index c030c8a51a..96b62930ba 100644 --- a/src/mathed/InsetMathFrac.h +++ b/src/mathed/InsetMathFrac.h @@ -62,6 +62,8 @@ public: /// bool idxBackward(Cursor &) const; /// + MathClass mathClass() const; + /// void metrics(MetricsInfo & mi, Dimension & dim) const; /// void draw(PainterInfo &, int x, int y) const; @@ -117,6 +119,8 @@ public: void write(WriteStream & os) const; /// void normalize(NormalStream &) const; + /// Generalized fractions are of inner class (see The TeXbook, p.292) + MathClass mathClass() const { return MC_INNER; } /// void metrics(MetricsInfo & mi, Dimension & dim) const; /// diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp index e2ceb5c903..dc943bb520 100644 --- a/src/mathed/InsetMathHull.cpp +++ b/src/mathed/InsetMathHull.cpp @@ -108,7 +108,7 @@ namespace { size_t firstRelOp(MathData const & ar) { for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it) - if ((*it)->isMathRel()) + if ((*it)->mathClass() == MC_REL) return it - ar.begin(); return ar.size(); } diff --git a/src/mathed/InsetMathScript.cpp b/src/mathed/InsetMathScript.cpp index b4cd5909be..8098a1a2d8 100644 --- a/src/mathed/InsetMathScript.cpp +++ b/src/mathed/InsetMathScript.cpp @@ -273,6 +273,19 @@ int InsetMathScript::nker(BufferView const * bv) const } +MathClass InsetMathScript::mathClass() const +{ + // FIXME: this is a hack, since the class will not be correct if + // the nucleus has several elements. + // The correct implementation would require to linearize the nucleus. + if (nuc().empty()) + return MC_ORD; + else + // return the class of last element since this is the one that counts. + return nuc().back()->mathClass(); +} + + void InsetMathScript::metrics(MetricsInfo & mi, Dimension & dim) const { Dimension dim0; diff --git a/src/mathed/InsetMathScript.h b/src/mathed/InsetMathScript.h index e84886b7d3..d0707439b9 100644 --- a/src/mathed/InsetMathScript.h +++ b/src/mathed/InsetMathScript.h @@ -33,6 +33,8 @@ public: /// mode_type currentMode() const { return MATH_MODE; } /// + MathClass mathClass() const; + /// void metrics(MetricsInfo & mi, Dimension & dim) const; /// void draw(PainterInfo & pi, int x, int y) const; diff --git a/src/mathed/InsetMathStackrel.cpp b/src/mathed/InsetMathStackrel.cpp index 9412d99182..3dda0dae24 100644 --- a/src/mathed/InsetMathStackrel.cpp +++ b/src/mathed/InsetMathStackrel.cpp @@ -52,6 +52,13 @@ bool InsetMathStackrel::idxUpDown(Cursor & cur, bool up) const } +MathClass InsetMathStackrel::mathClass() const +{ + // FIXME: update this when/if \stackbin is supported + return MC_REL; +} + + void InsetMathStackrel::metrics(MetricsInfo & mi, Dimension & dim) const { Dimension dim1; diff --git a/src/mathed/InsetMathStackrel.h b/src/mathed/InsetMathStackrel.h index 91862a7792..d6ac815182 100644 --- a/src/mathed/InsetMathStackrel.h +++ b/src/mathed/InsetMathStackrel.h @@ -24,6 +24,8 @@ public: /// bool idxUpDown(Cursor &, bool up) const; /// + MathClass mathClass() const; + /// void metrics(MetricsInfo & mi, Dimension & dim) const; /// void draw(PainterInfo & pi, int x, int y) const; @@ -35,7 +37,7 @@ public: void mathmlize(MathStream &) const; /// void htmlize(HtmlStream &) const; - /// + /// void validate(LaTeXFeatures &) const; /// InsetCode lyxCode() const { return MATH_STACKREL_CODE; } diff --git a/src/mathed/InsetMathSymbol.cpp b/src/mathed/InsetMathSymbol.cpp index 620ca226a2..01bafe614d 100644 --- a/src/mathed/InsetMathSymbol.cpp +++ b/src/mathed/InsetMathSymbol.cpp @@ -70,7 +70,7 @@ void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc += h_; dim.des -= h_; } - // set striptable_ + // set scriptable_ scriptable_ = false; if (mi.base.style == LM_ST_DISPLAY) if (sym_->inset == "cmex" || sym_->inset == "esint" || @@ -92,27 +92,18 @@ InsetMath::mode_type InsetMathSymbol::currentMode() const } -bool InsetMathSymbol::isMathBin() const -{ - return sym_->extra == "mathbin"; -} - - -bool InsetMathSymbol::isMathRel() const -{ - return sym_->extra == "mathrel"; -} - - -bool InsetMathSymbol::isMathPunct() const +bool InsetMathSymbol::isOrdAlpha() const { - return sym_->extra == "mathpunct"; + return sym_->extra == "mathord" || sym_->extra == "mathalpha"; } -bool InsetMathSymbol::isOrdAlpha() const +MathClass InsetMathSymbol::mathClass() const { - return sym_->extra == "mathord" || sym_->extra == "mathalpha"; + if (sym_->extra == "func" || sym_->extra == "funclim") + return MC_OP; + MathClass const mc = string_to_class(sym_->extra); + return (mc == MC_UNKNOWN) ? MC_ORD : mc; } diff --git a/src/mathed/InsetMathSymbol.h b/src/mathed/InsetMathSymbol.h index 6ca3ded7d1..67b33fd85a 100644 --- a/src/mathed/InsetMathSymbol.h +++ b/src/mathed/InsetMathSymbol.h @@ -40,11 +40,7 @@ public: /// mode_type currentMode() const; /// - bool isMathRel() const; - /// - bool isMathBin() const; - /// - bool isMathPunct() const; + MathClass mathClass() const; /// bool isOrdAlpha() const; /// do we take scripts? diff --git a/src/mathed/MathClass.cpp b/src/mathed/MathClass.cpp new file mode 100644 index 0000000000..fae7654334 --- /dev/null +++ b/src/mathed/MathClass.cpp @@ -0,0 +1,82 @@ +/** + * \file MathClass.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Jean-Marc Lasgouttes + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "MathClass.h" + +#include "support/docstring.h" +#include "support/lassert.h" + +using namespace std; + +namespace lyx { + + +docstring const class_to_string(MathClass const mc) +{ + string s; + switch (mc) { + case MC_ORD: + s = "mathord"; + break; + case MC_OP: + s = "mathop"; + break; + case MC_BIN: + s = "mathbin"; + break; + case MC_REL: + s = "mathrel"; + break; + case MC_OPEN: + s = "mathopen"; + break; + case MC_CLOSE: + s = "mathclose"; + break; + case MC_PUNCT: + s = "mathpunct"; + break; + case MC_INNER: + s = "mathinner"; + break; + case MC_UNKNOWN: + LATTEST(false); + s = "mathord"; + } + return from_ascii(s); +} + + +MathClass string_to_class(docstring const &s) +{ + if (s == "mathop") + return MC_OP; + else if (s == "mathbin") + return MC_BIN; + else if (s == "mathrel") + return MC_REL; + else if (s == "mathopen") + return MC_OPEN; + else if (s == "mathclose") + return MC_CLOSE; + else if (s == "mathpunct") + return MC_PUNCT; + else if (s == "mathinner") + return MC_INNER; + else if (s == "mathord") + return MC_ORD; + else + return MC_UNKNOWN; +} + + +} // namespace lyx diff --git a/src/mathed/MathClass.h b/src/mathed/MathClass.h new file mode 100644 index 0000000000..ceedd8db07 --- /dev/null +++ b/src/mathed/MathClass.h @@ -0,0 +1,64 @@ +// -*- C++ -*- +/** + * \file MathClass.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Jean-Marc Lasgouttes + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef MATH_CLASS_H +#define MATH_CLASS_H + +#include "support/strfwd.h" + +namespace lyx { + + +/* The TeXbook, p. 158: + * + * There are thirteen kinds of atoms, each of which might act + * differently in a formula; for example, ‘(’ is an Open atom because + * it comes from an opening. Here is a complete list of the different + * kinds: + + * + Ord: an ordinary atom like ‘x’ + * + Op: a large operator atom like ‘\sum’ + * + Bin: a binary operation atom like ‘+’ + * + Rel: a relation atom like ‘=’ + * + Open: an opening atom like ‘(’ + * + Close: a closing atom like ‘)’ + * + Punct: a punctuation atom like ‘,’ + * + Inner: an inner atom like ‘\frac{1}{2}’ + * + Over: an overline atom like ‘\overline{x}’ + * + Under: an underline atom like ‘\underline{x}’ + * + Acc: an accented atom like ‘\hat{x}’ + * + Rad: a radical atom like ‘\sqrt{2}’ + * + Vcent: a vbox to be centered, produced by \vcenter. + * + * Over, Under, Acc, Rad and Vcent are not considered in the enum + * below. The relvant elements will be considered as Ord. + */ +enum MathClass { + MC_ORD, + MC_OP, + MC_BIN, + MC_REL, + MC_OPEN, + MC_CLOSE, + MC_PUNCT, + MC_INNER, + MC_UNKNOWN +}; + + +MathClass string_to_class(docstring const &); + +docstring const class_to_string(MathClass); + + +} // namespace lyx + +#endif diff --git a/src/mathed/MathSupport.cpp b/src/mathed/MathSupport.cpp index 0c610b1e69..9d79a8abfa 100644 --- a/src/mathed/MathSupport.cpp +++ b/src/mathed/MathSupport.cpp @@ -671,13 +671,6 @@ void mathedSymbolDim(MetricsInfo & mi, Dimension & dim, latexkeys const * sym) std::string const font = italic_upcase_greek ? "cmm" : sym->inset; Changer dummy = mi.base.changeFontSet(font); mathed_string_dim(mi.base.font, sym->draw, dim); - // seperate things a bit - if (sym->extra == "mathbin") - dim.wid += 2 * mathed_medmuskip(mi.base.font); - else if (sym->extra == "mathrel") - dim.wid += 2 * mathed_thickmuskip(mi.base.font); - else if (sym->extra == "mathpunct") - dim.wid += mathed_thinmuskip(mi.base.font); } @@ -693,10 +686,6 @@ void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym) sym->extra == "mathalpha" && pi.base.fontname == "mathit"; std::string const font = italic_upcase_greek ? "cmm" : sym->inset; - if (sym->extra == "mathbin") - x += mathed_medmuskip(pi.base.font); - else if (sym->extra == "mathrel") - x += mathed_thickmuskip(pi.base.font); Changer dummy = pi.base.changeFontSet(font); pi.draw(x, y, sym->draw);