Sanitize InsetMathHull and add a check for mutability in LFUN_MATH_MUTATE

Remove in particular all comparisons < and >= involving HullType.

Add a guard to make sure that mutate() only operates on types it has been
designed for. Then I figured I could use this new knowledge to give feedback
when math-mutate is not implemented via getStatus(). (To test this, insert a
regexp in Advanced Search & Replace and try to change it into a standard
equation via the contextual menu.)
This commit is contained in:
Guillaume Munch 2015-12-14 01:54:27 +00:00
parent e3ab552ccb
commit 9bf7d99def
4 changed files with 258 additions and 118 deletions

View File

@ -34,7 +34,8 @@ enum HullType {
hullFlAlign, hullFlAlign,
hullMultline, hullMultline,
hullGather, hullGather,
hullRegexp hullRegexp,
hullUnknown
}; };
HullType hullType(docstring const & name); HullType hullType(docstring const & name);

View File

@ -1850,17 +1850,32 @@ char InsetMathGrid::colAlign(HullType type, col_type col)
case hullFlAlign: case hullFlAlign:
return "rl"[col & 1]; return "rl"[col & 1];
default: case hullUnknown:
case hullNone:
case hullSimple:
case hullEquation:
case hullRegexp:
return 'c'; return 'c';
} }
// avoid warning
return 'c';
} }
//static //static
int InsetMathGrid::colSpace(HullType type, col_type col) int InsetMathGrid::colSpace(HullType type, col_type col)
{ {
int alignInterSpace; int alignInterSpace = 0;
switch (type) { switch (type) {
case hullUnknown:
case hullNone:
case hullSimple:
case hullEquation:
case hullMultline:
case hullGather:
case hullRegexp:
return 0;
case hullEqnArray: case hullEqnArray:
return 5; return 5;
@ -1877,8 +1892,6 @@ int InsetMathGrid::colSpace(HullType type, col_type col)
case hullFlAlign: case hullFlAlign:
alignInterSpace = 60; alignInterSpace = 60;
break; break;
default:
return 0;
} }
return (col % 2) ? alignInterSpace : 0; return (col % 2) ? alignInterSpace : 0;
} }

View File

@ -79,17 +79,25 @@ namespace {
int getCols(HullType type) int getCols(HullType type)
{ {
switch (type) { switch (type) {
case hullEqnArray: case hullEqnArray:
return 3; return 3;
case hullAlign: case hullAlign:
case hullFlAlign: case hullFlAlign:
case hullAlignAt: case hullAlignAt:
case hullXAlignAt: case hullXAlignAt:
case hullXXAlignAt: case hullXXAlignAt:
return 2; return 2;
default: case hullUnknown:
return 1; case hullNone:
case hullSimple:
case hullEquation:
case hullMultline:
case hullGather:
case hullRegexp:
return 1;
} }
// avoid warning
return 0;
} }
@ -128,29 +136,30 @@ HullType hullType(docstring const & s)
if (s == "flalign") return hullFlAlign; if (s == "flalign") return hullFlAlign;
if (s == "regexp") return hullRegexp; if (s == "regexp") return hullRegexp;
lyxerr << "unknown hull type '" << to_utf8(s) << "'" << endl; lyxerr << "unknown hull type '" << to_utf8(s) << "'" << endl;
return HullType(-1); return hullUnknown;
} }
docstring hullName(HullType type) docstring hullName(HullType type)
{ {
switch (type) { switch (type) {
case hullNone: return from_ascii("none"); case hullNone: return from_ascii("none");
case hullSimple: return from_ascii("simple"); case hullSimple: return from_ascii("simple");
case hullEquation: return from_ascii("equation"); case hullEquation: return from_ascii("equation");
case hullEqnArray: return from_ascii("eqnarray"); case hullEqnArray: return from_ascii("eqnarray");
case hullAlign: return from_ascii("align"); case hullAlign: return from_ascii("align");
case hullAlignAt: return from_ascii("alignat"); case hullAlignAt: return from_ascii("alignat");
case hullXAlignAt: return from_ascii("xalignat"); case hullXAlignAt: return from_ascii("xalignat");
case hullXXAlignAt: return from_ascii("xxalignat"); case hullXXAlignAt: return from_ascii("xxalignat");
case hullMultline: return from_ascii("multline"); case hullMultline: return from_ascii("multline");
case hullGather: return from_ascii("gather"); case hullGather: return from_ascii("gather");
case hullFlAlign: return from_ascii("flalign"); case hullFlAlign: return from_ascii("flalign");
case hullRegexp: return from_ascii("regexp"); case hullRegexp: return from_ascii("regexp");
default: case hullUnknown:
lyxerr << "unknown hull type '" << type << "'" << endl; lyxerr << "unknown hull type" << endl;
return from_ascii("none"); break;
} }
return from_ascii("none");
} }
static InsetLabel * dummy_pointer = 0; static InsetLabel * dummy_pointer = 0;
@ -326,9 +335,26 @@ Inset * InsetMathHull::editXY(Cursor & cur, int x, int y)
InsetMath::mode_type InsetMathHull::currentMode() const InsetMath::mode_type InsetMathHull::currentMode() const
{ {
if (type_ == hullNone) switch (type_) {
case hullNone:
return UNDECIDED_MODE; return UNDECIDED_MODE;
// definitely math mode ... // definitely math mode ...
case hullUnknown:
case hullSimple:
case hullEquation:
case hullMultline:
case hullGather:
case hullEqnArray:
case hullAlign:
case hullFlAlign:
case hullAlignAt:
case hullXAlignAt:
case hullXXAlignAt:
case hullRegexp:
return MATH_MODE;
}
// avoid warning
return MATH_MODE; return MATH_MODE;
} }
@ -401,33 +427,27 @@ int InsetMathHull::defaultColSpace(col_type col)
docstring InsetMathHull::standardFont() const docstring InsetMathHull::standardFont() const
{ {
docstring font_name;
switch (type_) { switch (type_) {
case hullRegexp: case hullRegexp:
font_name = from_ascii("texttt"); return from_ascii("texttt");
break;
case hullNone: case hullNone:
font_name = from_ascii("lyxnochange"); return from_ascii("lyxnochange");
break;
default: default:
font_name = from_ascii("mathnormal"); return from_ascii("mathnormal");
} }
return font_name;
} }
ColorCode InsetMathHull::standardColor() const ColorCode InsetMathHull::standardColor() const
{ {
ColorCode color;
switch (type_) { switch (type_) {
case hullRegexp: case hullRegexp:
case hullNone: case hullNone:
color = Color_foreground; return Color_foreground;
break;
default: default:
color = Color_math; return Color_math;
} }
return color;
} }
@ -850,20 +870,22 @@ bool InsetMathHull::numbered(row_type row) const
bool InsetMathHull::ams() const bool InsetMathHull::ams() const
{ {
switch (type_) { switch (type_) {
case hullAlign: case hullAlign:
case hullFlAlign: case hullFlAlign:
case hullMultline: case hullMultline:
case hullGather: case hullGather:
case hullAlignAt: case hullAlignAt:
case hullXAlignAt: case hullXAlignAt:
case hullXXAlignAt: case hullXXAlignAt:
return true; return true;
case hullNone: case hullUnknown:
case hullSimple: case hullRegexp:
case hullEquation: return false;
case hullEqnArray: case hullNone:
case hullRegexp: case hullSimple:
break; case hullEquation:
case hullEqnArray:
break;
} }
for (size_t row = 0; row < numbered_.size(); ++row) for (size_t row = 0; row < numbered_.size(); ++row)
if (numbered_[row] == NOTAG) if (numbered_[row] == NOTAG)
@ -874,21 +896,46 @@ bool InsetMathHull::ams() const
Inset::DisplayType InsetMathHull::display() const Inset::DisplayType InsetMathHull::display() const
{ {
if (type_ == hullSimple || type_ == hullNone || type_ == hullRegexp) switch (type_) {
case hullUnknown:
case hullSimple:
case hullNone:
case hullRegexp:
return Inline; return Inline;
case hullEqnArray:
case hullAlign:
case hullFlAlign:
case hullAlignAt:
case hullXAlignAt:
case hullXXAlignAt:
case hullEquation:
case hullMultline:
case hullGather:
return AlignCenter;
}
// avoid warning
return AlignCenter; return AlignCenter;
} }
bool InsetMathHull::numberedType() const bool InsetMathHull::numberedType() const
{ {
if (type_ == hullNone) switch (type_) {
return false; case hullUnknown:
if (type_ == hullSimple) case hullNone:
return false; case hullSimple:
if (type_ == hullXXAlignAt) case hullXXAlignAt:
return false; case hullRegexp:
if (type_ == hullRegexp)
return false; return false;
case hullEqnArray:
case hullAlign:
case hullFlAlign:
case hullAlignAt:
case hullXAlignAt:
case hullEquation:
case hullMultline:
case hullGather:
break;
}
for (row_type row = 0; row < nrows(); ++row) for (row_type row = 0; row < nrows(); ++row)
if (numbered(row)) if (numbered(row))
return true; return true;
@ -987,7 +1034,7 @@ void InsetMathHull::header_write(WriteStream & os) const
os << "\\regexp{"; os << "\\regexp{";
break; break;
default: case hullUnknown:
os << "\n"; os << "\n";
os.startOuterRow(); os.startOuterRow();
os << "\\begin{unknown" << star(n) << "}\n"; os << "\\begin{unknown" << star(n) << "}\n";
@ -1041,7 +1088,7 @@ void InsetMathHull::footer_write(WriteStream & os) const
os << "\\endregexp{}}"; os << "\\endregexp{}}";
break; break;
default: case hullUnknown:
os << "\n"; os << "\n";
os.startOuterRow(); os.startOuterRow();
os << "\\end{unknown" << star(n) << "}\n"; os << "\\end{unknown" << star(n) << "}\n";
@ -1066,6 +1113,7 @@ bool InsetMathHull::isTable() const
case hullSimple: case hullSimple:
case hullEquation: case hullEquation:
case hullRegexp: case hullRegexp:
case hullUnknown:
break; break;
} }
return false; return false;
@ -1273,10 +1321,46 @@ void InsetMathHull::setType(HullType type)
} }
bool InsetMathHull::isMutable(HullType type)
{
switch (type) {
case hullNone:
case hullSimple:
case hullEquation:
case hullEqnArray:
case hullAlign:
case hullFlAlign:
case hullAlignAt:
case hullXAlignAt:
case hullXXAlignAt:
case hullMultline:
case hullGather:
return true;
case hullUnknown:
case hullRegexp:
return false;
}
// avoid warning
return false;
}
void InsetMathHull::mutate(HullType newtype) void InsetMathHull::mutate(HullType newtype)
{ {
//lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl; //lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl;
if (newtype == type_)
return;
// This guards the algorithm below it, which is designed with certain types
// in mind.
if (!isMutable(newtype) || !isMutable(type_)) {
lyxerr << "mutation from '" << to_utf8(hullName(type_))
<< "' to '" << to_utf8(hullName(newtype))
<< "' not implemented" << endl;
return;
}
// we try to move along the chain // we try to move along the chain
// none <-> simple <-> equation <-> eqnarray -> *align* -> multline, gather -+ // none <-> simple <-> equation <-> eqnarray -> *align* -> multline, gather -+
// ^ | // ^ |
@ -1285,22 +1369,14 @@ void InsetMathHull::mutate(HullType newtype)
// directly supported because it handles labels and numbering for // directly supported because it handles labels and numbering for
// "down mutation". // "down mutation".
if (newtype == type_) { switch (type_) {
// done case hullNone:
}
else if (newtype < hullNone) {
// unknown type
dump();
}
else if (type_ == hullNone) {
setType(hullSimple); setType(hullSimple);
numbered(0, false); numbered(0, false);
mutate(newtype); mutate(newtype);
} break;
else if (type_ == hullSimple) { case hullSimple:
if (newtype == hullNone) { if (newtype == hullNone) {
setType(hullNone); setType(hullNone);
numbered(0, false); numbered(0, false);
@ -1309,95 +1385,138 @@ void InsetMathHull::mutate(HullType newtype)
numbered(0, label_[0] ? true : false); numbered(0, label_[0] ? true : false);
mutate(newtype); mutate(newtype);
} }
} break;
else if (type_ == hullEquation) { case hullEquation:
if (newtype < type_) { switch (newtype) {
case hullNone:
case hullSimple:
setType(hullSimple); setType(hullSimple);
numbered(0, false); numbered(0, false);
mutate(newtype); mutate(newtype);
} else if (newtype == hullEqnArray) { break;
case hullEqnArray:
// split it "nicely" on the first relop // split it "nicely" on the first relop
splitTo3Cols(); splitTo3Cols();
setType(hullEqnArray); setType(hullEqnArray);
} else if (newtype == hullMultline || newtype == hullGather) { break;
case hullMultline:
case hullGather:
setType(newtype); setType(newtype);
} else { break;
default:
// *align*
// split it "nicely" // split it "nicely"
splitTo2Cols(); splitTo2Cols();
setType(hullAlign); setType(hullAlign);
mutate(newtype); mutate(newtype);
break;
} }
} break;
else if (type_ == hullEqnArray) { case hullEqnArray:
if (newtype < type_) { switch (newtype) {
case hullNone:
case hullSimple:
case hullEquation:
glueall(newtype); glueall(newtype);
mutate(newtype); mutate(newtype);
} else { // align & Co. break;
default:
// align & Co.
changeCols(2); changeCols(2);
setType(hullAlign); setType(hullAlign);
mutate(newtype); mutate(newtype);
break;
} }
} break;
else if (type_ == hullAlign || type_ == hullAlignAt || case hullAlign:
type_ == hullXAlignAt || type_ == hullFlAlign) { case hullAlignAt:
if (newtype < hullAlign) { case hullXAlignAt:
case hullFlAlign:
switch (newtype) {
case hullNone:
case hullSimple:
case hullEquation:
case hullEqnArray:
changeCols(3); changeCols(3);
setType(hullEqnArray); setType(hullEqnArray);
mutate(newtype); mutate(newtype);
} else if (newtype == hullGather || newtype == hullMultline) { break;
case hullGather:
case hullMultline:
changeCols(1); changeCols(1);
setType(newtype); setType(newtype);
} else if (newtype == hullXXAlignAt) { break;
case hullXXAlignAt:
for (row_type row = 0; row < nrows(); ++row) for (row_type row = 0; row < nrows(); ++row)
numbered(row, false); numbered(row, false);
setType(newtype); setType(newtype);
} else { break;
default:
setType(newtype); setType(newtype);
break;
} }
} break;
else if (type_ == hullXXAlignAt) { case hullXXAlignAt:
for (row_type row = 0; row < nrows(); ++row) for (row_type row = 0; row < nrows(); ++row)
numbered(row, false); numbered(row, false);
if (newtype < hullAlign) { switch (newtype) {
case hullNone:
case hullSimple:
case hullEquation:
case hullEqnArray:
changeCols(3); changeCols(3);
setType(hullEqnArray); setType(hullEqnArray);
mutate(newtype); mutate(newtype);
} else if (newtype == hullGather || newtype == hullMultline) { break;
case hullGather:
case hullMultline:
changeCols(1); changeCols(1);
setType(newtype); setType(newtype);
} else { break;
default:
setType(newtype); setType(newtype);
break;
} }
} break;
else if (type_ == hullMultline || type_ == hullGather) { case hullMultline:
if (newtype == hullGather || newtype == hullMultline) case hullGather:
switch (newtype) {
case hullGather:
case hullMultline:
setType(newtype); setType(newtype);
else if (newtype == hullAlign || newtype == hullFlAlign || break;
newtype == hullAlignAt || newtype == hullXAlignAt) { case hullAlign:
case hullFlAlign:
case hullAlignAt:
case hullXAlignAt:
splitTo2Cols(); splitTo2Cols();
setType(newtype); setType(newtype);
} else if (newtype == hullXXAlignAt) { break;
case hullXXAlignAt:
splitTo2Cols(); splitTo2Cols();
for (row_type row = 0; row < nrows(); ++row) for (row_type row = 0; row < nrows(); ++row)
numbered(row, false); numbered(row, false);
setType(newtype); setType(newtype);
} else { break;
default:
// first we mutate to EqnArray
splitTo3Cols(); splitTo3Cols();
setType(hullEqnArray); setType(hullEqnArray);
mutate(newtype); mutate(newtype);
break;
} }
} break;
else { default:
lyxerr << "mutation from '" << to_utf8(hullName(type_)) // we passed the guard so we should not be here
<< "' to '" << to_utf8(hullName(newtype)) LASSERT("Mutation not implemented, but should have been.", return);
<< "' not implemented" << endl; break;
} }// switch
} }
@ -1475,7 +1594,12 @@ void InsetMathHull::doExtern(Cursor & cur, FuncRequest & func)
} }
// only inline, display or eqnarray math is allowed // only inline, display or eqnarray math is allowed
if (getType() > hullEqnArray) { switch (getType()) {
case hullSimple:
case hullEquation:
case hullEqnArray:
break;
default:
frontend::Alert::warning(_("Bad math environment"), frontend::Alert::warning(_("Bad math environment"),
_("Computation cannot be performed for AMS " _("Computation cannot be performed for AMS "
"math environments.\nChange the math " "math environments.\nChange the math "
@ -1772,9 +1896,9 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd,
case LFUN_MATH_MUTATE: { case LFUN_MATH_MUTATE: {
HullType const ht = hullType(cmd.argument()); HullType const ht = hullType(cmd.argument());
status.setOnOff(type_ == ht); status.setOnOff(type_ == ht);
status.setEnabled(true); status.setEnabled(isMutable(ht) && isMutable(type_));
if (ht != hullSimple) { if (ht != hullSimple && status.enabled()) {
Cursor tmpcur = cur; Cursor tmpcur = cur;
while (!tmpcur.empty()) { while (!tmpcur.empty()) {
InsetCode code = tmpcur.inset().lyxCode(); InsetCode code = tmpcur.inset().lyxCode();

View File

@ -105,6 +105,8 @@ public:
/// get type /// get type
HullType getType() const; HullType getType() const;
/// is mutation implemented for this type?
static bool isMutable(HullType type);
/// change type /// change type
void mutate(HullType newtype); void mutate(HullType newtype);