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.
This commit is contained in:
Jean-Marc Lasgouttes 2016-05-30 10:33:35 +02:00
parent 0872bb78b4
commit 361bd53bc3
19 changed files with 245 additions and 71 deletions

View 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 \

View 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;

View 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; }

View 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;
}

View 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; }

View 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);
}

View 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 [...]?

View 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;

View 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;
///

View 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();
}

View 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;

View 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;

View 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;

View 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; }

View 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,30 +92,21 @@ 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
{
return sym_->extra == "mathpunct";
}
bool InsetMathSymbol::isOrdAlpha() const
{
return sym_->extra == "mathord" || sym_->extra == "mathalpha";
}
MathClass InsetMathSymbol::mathClass() const
{
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;
}
bool InsetMathSymbol::isScriptable() const
{
return scriptable_;

View 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?

82
src/mathed/MathClass.cpp Normal file
View File

@ -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

64
src/mathed/MathClass.h Normal file
View File

@ -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

View 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);