Math commands used in text mode now always use the current selection as contents

(#9762)

* fixes a bug where this was already the expected behaviour of
  math-subscript and math-superscript but failed.

* corrects the behaviour where if there is \newcommand in the
  selection, then a corresponding macro template is introduced
  instead of a math inset.

  * fixes a bug where math-display, math-subscript and math-supscript
    would also introduce such a macro template in a way unrelated to
    their function. Now it only happens with math-mode without
    arguments.

  * fixes a bug where a text that does not denote a macro definition,
    e.g. "aaa\newcommandaaa", would produce \invalidmacro.
This commit is contained in:
Guillaume Munch 2015-08-01 08:05:33 +01:00
parent 699a6db9fa
commit 61145265fc
4 changed files with 68 additions and 74 deletions

View File

@ -132,7 +132,7 @@ static void finishChange(Cursor & cur, bool selecting)
} }
static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display) static void mathDispatch(Cursor & cur, FuncRequest const & cmd)
{ {
cur.recordUndo(); cur.recordUndo();
docstring sel = cur.selectionAsString(false); docstring sel = cur.selectionAsString(false);
@ -152,45 +152,39 @@ static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display)
LATTEST(old_pos == cur.pos()); LATTEST(old_pos == cur.pos());
#endif #endif
cur.nextInset()->edit(cur, true); cur.nextInset()->edit(cur, true);
// don't do that also for LFUN_MATH_MODE if (cmd.action() != LFUN_MATH_MODE)
// unless you want end up with always changing // LFUN_MATH_MODE has a different meaning in math mode
// to mathrm when opening an inlined inset -- cur.dispatch(cmd);
// I really hate "LyXfunc overloading"...
if (display)
cur.dispatch(FuncRequest(LFUN_MATH_DISPLAY));
// Avoid an unnecessary undo step if cmd.argument
// is empty
if (!cmd.argument().empty())
cur.dispatch(FuncRequest(LFUN_MATH_INSERT,
cmd.argument()));
} else { } else {
// create a macro if we see "\\newcommand" InsetMathHull * formula = new InsetMathHull(cur.buffer());
// somewhere, and an ordinary formula string const selstr = to_utf8(sel);
// otherwise istringstream is(selstr);
if (sel.find(from_ascii("\\newcommand")) == string::npos Lexer lex;
&& sel.find(from_ascii("\\newlyxcommand")) == string::npos lex.setStream(is);
&& sel.find(from_ascii("\\def")) == string::npos) if (!formula->readQuiet(lex)) {
{ // No valid formula, let's try with delims
InsetMathHull * formula = new InsetMathHull(cur.buffer()); is.str("$" + selstr + "$");
string const selstr = to_utf8(sel);
istringstream is(selstr);
Lexer lex;
lex.setStream(is); lex.setStream(is);
if (!formula->readQuiet(lex)) { if (!formula->readQuiet(lex)) {
// No valid formula, let's try with delims // Still not valid, leave it as is
is.str("$" + selstr + "$"); valid = false;
lex.setStream(is); delete formula;
if (!formula->readQuiet(lex)) { cur.insert(sel);
// Still not valid, leave it as is }
valid = false; }
delete formula; if (valid) {
cur.insert(sel); cur.insert(formula);
} else cur.nextInset()->edit(cur, true);
cur.insert(formula); LASSERT(cur.inMathed(), return);
} else cur.pos() = 0;
cur.insert(formula); cur.resetAnchor();
} else { cur.setSelection(true);
cur.insert(new MathMacroTemplate(cur.buffer(), sel)); cur.pos() = cur.lastpos();
if (cmd.action() != LFUN_MATH_MODE)
// LFUN_MATH_MODE has a different meaning in math mode
cur.dispatch(cmd);
cur.clearSelection();
cur.pos() = cur.lastpos();
} }
} }
if (valid) if (valid)
@ -2015,22 +2009,38 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
changeDepth(cur, INC_DEPTH); changeDepth(cur, INC_DEPTH);
break; break;
case LFUN_MATH_DISPLAY:
mathDispatch(cur, cmd, true);
break;
case LFUN_REGEXP_MODE: case LFUN_REGEXP_MODE:
regexpDispatch(cur, cmd); regexpDispatch(cur, cmd);
break; break;
case LFUN_MATH_MODE: case LFUN_MATH_MODE: {
if (cmd.argument() == "on") if (cmd.argument() == "on" || cmd.argument() == "") {
// don't pass "on" as argument // don't pass "on" as argument
// (it would appear literally in the first cell) // (it would appear literally in the first cell)
mathDispatch(cur, FuncRequest(LFUN_MATH_MODE), false); docstring sel = cur.selectionAsString(false);
else MathMacroTemplate * macro = new MathMacroTemplate(cur.buffer());
mathDispatch(cur, cmd, false); // create a macro template if we see "\\newcommand" somewhere, and
// an ordinary formula otherwise
if (!sel.empty()
&& (sel.find(from_ascii("\\newcommand")) != string::npos
|| sel.find(from_ascii("\\newlyxcommand")) != string::npos
|| sel.find(from_ascii("\\def")) != string::npos)
&& macro->fromString(sel)) {
cur.recordUndo();
replaceSelection(cur);
cur.insert(macro);
} else {
// no meaningful macro template was found
delete macro;
mathDispatch(cur,FuncRequest(LFUN_MATH_MODE));
}
} else
// The argument is meaningful
// We replace cmd with LFUN_MATH_INSERT because LFUN_MATH_MODE
// has a different meaning in math mode
mathDispatch(cur, FuncRequest(LFUN_MATH_INSERT,cmd.argument()));
break; break;
}
case LFUN_MATH_MACRO: case LFUN_MATH_MACRO:
if (cmd.argument().empty()) if (cmd.argument().empty())
@ -2058,27 +2068,16 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
} }
break; break;
// passthrough hat and underscore outside mathed: case LFUN_MATH_DISPLAY:
case LFUN_MATH_SUBSCRIPT: case LFUN_MATH_SUBSCRIPT:
mathDispatch(cur, FuncRequest(LFUN_SELF_INSERT, "_"), false);
break;
case LFUN_MATH_SUPERSCRIPT: case LFUN_MATH_SUPERSCRIPT:
mathDispatch(cur, FuncRequest(LFUN_SELF_INSERT, "^"), false);
break;
case LFUN_MATH_INSERT: case LFUN_MATH_INSERT:
case LFUN_MATH_AMS_MATRIX: case LFUN_MATH_AMS_MATRIX:
case LFUN_MATH_MATRIX: case LFUN_MATH_MATRIX:
case LFUN_MATH_DELIM: case LFUN_MATH_DELIM:
case LFUN_MATH_BIGDELIM: { case LFUN_MATH_BIGDELIM:
cur.recordUndo(); mathDispatch(cur, cmd);
cap::replaceSelection(cur);
cur.insert(new InsetMathHull(cur.buffer(), hullSimple));
checkAndActivateInset(cur, true);
LASSERT(cur.inMathed(), break);
cur.dispatch(cmd);
break; break;
}
case LFUN_FONT_EMPH: { case LFUN_FONT_EMPH: {
Font font(ignore_font, ignore_language); Font font(ignore_font, ignore_language);

View File

@ -243,7 +243,8 @@ MacroTable::iterator
MacroTable::insert(Buffer * buf, docstring const & def) 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);
mac.fromString(def);
MacroData data(buf, mac); MacroData data(buf, mac);
return insert(mac.name(), data); return insert(mac.name(), data);
} }

View File

@ -425,26 +425,20 @@ MathMacroTemplate::MathMacroTemplate(Buffer * buf, docstring const & name, int n
} }
MathMacroTemplate::MathMacroTemplate(Buffer * buf, docstring const & str) bool MathMacroTemplate::fromString(docstring const & str)
: InsetMathNest(buf, 3), numargs_(0), optionals_(0),
type_(MacroTypeNewcommand), lookOutdated_(true)
{ {
buffer_ = buf; MathData ar(buffer_);
initMath();
MathData ar(buf);
mathed_parse_cell(ar, str, Parse::NORMAL); mathed_parse_cell(ar, str, Parse::NORMAL);
if (ar.size() != 1 || !ar[0]->asMacroTemplate()) { if (ar.size() != 1 || !ar[0]->asMacroTemplate()) {
lyxerr << "Cannot read macro from '" << ar << "'" << endl; lyxerr << "Cannot read macro from '" << ar << "'" << endl;
asArray(from_ascii("invalidmacro"), cell(0)); asArray(from_ascii("invalidmacro"), cell(0));
// FIXME: The macro template does not make sense after this. // The macro template does not make sense after this.
// The whole parsing should not be in a constructor which return false;
// has no chance to report failure.
return;
} }
operator=( *(ar[0]->asMacroTemplate()) ); operator=( *(ar[0]->asMacroTemplate()) );
updateLook(); updateLook();
return true;
} }

View File

@ -34,8 +34,8 @@ public:
std::vector<MathData> const & optionalValues = std::vector<MathData>(), std::vector<MathData> const & optionalValues = std::vector<MathData>(),
MathData const & def = MathData(), MathData const & def = MathData(),
MathData const & display = MathData()); MathData const & display = MathData());
/// /// parses from string, returns false if failed
MathMacroTemplate(Buffer * buf, const docstring & str); bool fromString (const docstring & str);
/// ///
bool editable() const { return true; } bool editable() const { return true; }
/// ///