]> git.lyx.org Git - features.git/commitdiff
Introduce the notion of math class
authorJean-Marc Lasgouttes <lasgouttes@lyx.org>
Mon, 30 May 2016 08:33:35 +0000 (10:33 +0200)
committerJean-Marc Lasgouttes <lasgouttes@lyx.org>
Wed, 16 Nov 2016 14:21:52 +0000 (15:21 +0100)
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.

19 files changed:
src/Makefile.am
src/mathed/InsetMath.cpp
src/mathed/InsetMath.h
src/mathed/InsetMathChar.cpp
src/mathed/InsetMathChar.h
src/mathed/InsetMathDelim.cpp
src/mathed/InsetMathDelim.h
src/mathed/InsetMathFrac.cpp
src/mathed/InsetMathFrac.h
src/mathed/InsetMathHull.cpp
src/mathed/InsetMathScript.cpp
src/mathed/InsetMathScript.h
src/mathed/InsetMathStackrel.cpp
src/mathed/InsetMathStackrel.h
src/mathed/InsetMathSymbol.cpp
src/mathed/InsetMathSymbol.h
src/mathed/MathClass.cpp [new file with mode: 0644]
src/mathed/MathClass.h [new file with mode: 0644]
src/mathed/MathSupport.cpp

index f3dd8700776cf263d1792788e3177c9eacd8cf63..fc135af00e514d28da3532bf13afae728fdb5258 100644 (file)
@@ -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 \
index 2fb1ff5a55b5c7de5055afa686b874383995d67e..aec53d0518a961da755350b0d127a270b79e9ba2 100644 (file)
@@ -49,6 +49,12 @@ MathData const & InsetMath::cell(idx_type) const
 }
 
 
+MathClass InsetMath::mathClass() const
+{
+       return MC_ORD;
+}
+
+
 void InsetMath::dump() const
 {
        lyxerr << "---------------------------------------------" << endl;
index da84af1010c101ef16d084680ae9f97bd5bd625c..e791099b728e7b3118397b66a3bc033eb42546c9 100644 (file)
@@ -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; }
 
index ae843bf00dd6c9e5f66215b44e0d67a2096b533c..1669515b66dcfbe9126634bfde75c7f57b6ed08e 100644 (file)
@@ -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>(char_))
-               || (subst_ && subst_->extra == "mathpunct");
+       // this information comes from fontmath.ltx in LaTeX source.
+       char const ch = static_cast<char>(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;
 }
 
 
index ea190211b777f7efd7feceba0e36538f7cc2c934..6e7ff72c9caf5d98f91b47ebf9eee2bc6654c1aa 100644 (file)
@@ -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; }
 
index 68e4430514775eb8e8f832e4d3a04d92e635e8ad..4ab179e7b29ec97eb6bb751b5baa31a8af8288db 100644 (file)
@@ -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);
 }
index 3a09ede2f32bd509356bb2a518a02a07177d6a26..5a7e8164049cfb7948559b8dd12587adc149d57a 100644 (file)
@@ -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 [...]?
index ab876e060d86dea0e333a33cef7ca30dad91f390..263587ed6e472396053f14627cc9e5241359885c 100644 (file)
@@ -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;
index c030c8a51a0203f15b2429b64988f345a744e2e7..96b62930ba1ef1b3d845d24dab80f16a8d80f3cd 100644 (file)
@@ -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;
        ///
index e2ceb5c903e2fdcab5c38f2917206ecd29a552ab..dc943bb52043ccc8922f4737fca06d169335840c 100644 (file)
@@ -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();
        }
index b4cd5909be06cca3c8dfff89a12ad90c948cffb7..8098a1a2d8d67cf7a4078648fce6505b6b7fa42b 100644 (file)
@@ -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;
index e84886b7d3bf922a8d42cae1e0beff345cc5de53..d0707439b9a75bc2c79204e160ee815fded49104 100644 (file)
@@ -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;
index 9412d9918245b493b6866c55aa9939d911e287a9..3dda0dae242226b8f823c9a119e858e2b22028d2 100644 (file)
@@ -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;
index 91862a7792b8ecf8e62629757cdc745b420a3c27..d6ac81518231201cc2608ea2c681b63d82e1f0d0 100644 (file)
@@ -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; }
index 620ca226a2881b6c182c4885cb86a39c49716c59..01bafe614d9b0748f94cc0d41160d20744f30460 100644 (file)
@@ -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;
 }
 
 
index 6ca3ded7d1bbd0df864326e00305184a0c823caf..67b33fd85a96dc19b03994afc47fc7963bcd520a 100644 (file)
@@ -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 (file)
index 0000000..fae7654
--- /dev/null
@@ -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 <config.h>
+
+#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 (file)
index 0000000..ceedd8d
--- /dev/null
@@ -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
index 0c610b1e69412c202c66505d576d4401870452fc..9d79a8abfa0110fa6d0a2bf90d5912080065b921 100644 (file)
@@ -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);