X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FInsetMathNest.cpp;h=abaeec903c6c882661ee21f1f9b6a0a2d65c62a5;hb=d9082639080b9de993742bd352f92e5183058cf5;hp=229b923d0fbed1ff1d288c3921ac3450421d6b75;hpb=608124728db223f3ee13d16b89165a46daf9e24e;p=lyx.git diff --git a/src/mathed/InsetMathNest.cpp b/src/mathed/InsetMathNest.cpp index 229b923d0f..abaeec903c 100644 --- a/src/mathed/InsetMathNest.cpp +++ b/src/mathed/InsetMathNest.cpp @@ -30,7 +30,6 @@ #include "InsetMathUnknown.h" #include "MathAutoCorrect.h" #include "MathCompletionList.h" -#include "MathData.h" #include "MathFactory.h" #include "InsetMathMacro.h" #include "InsetMathMacroArgument.h" @@ -52,7 +51,6 @@ #include "LyX.h" #include "LyXRC.h" #include "MetricsInfo.h" -#include "OutputParams.h" #include "TexRow.h" #include "Text.h" @@ -86,7 +84,11 @@ using cap::selClearOrDel; InsetMathNest::InsetMathNest(Buffer * buf, idx_type nargs) : InsetMath(buf), cells_(nargs), lock_(false) { - setBuffer(*buf); + // FIXME This should not really be necessary, but when we are + // initializing the table of global macros, we create macros + // with no associated Buffer. + if (buf) + setBuffer(*buf); } @@ -118,15 +120,12 @@ InsetMathNest & InsetMathNest::operator=(InsetMathNest const & inset) void InsetMathNest::setBuffer(Buffer & buffer) { InsetMath::setBuffer(buffer); - for (idx_type i = 0, n = nargs(); i != n; ++i) { - MathData & data = cell(i); - for (size_t j = 0; j != data.size(); ++j) - data[j].nucleus()->setBuffer(buffer); - } + for (MathData & data : cells_) + data.setBuffer(buffer); } -InsetMath::idx_type InsetMathNest::nargs() const +idx_type InsetMathNest::nargs() const { return cells_.size(); } @@ -188,10 +187,10 @@ void InsetMathNest::cellsMetrics(MetricsInfo const & mi) const } -void InsetMathNest::updateBuffer(ParIterator const & it, UpdateType utype) +void InsetMathNest::updateBuffer(ParIterator const & it, UpdateType utype, bool const deleted) { for (idx_type i = 0, n = nargs(); i != n; ++i) - cell(i).updateBuffer(it, utype); + cell(i).updateBuffer(it, utype, deleted); } @@ -219,7 +218,7 @@ bool InsetMathNest::idxPrev(Cursor & cur) const if (cur.idx() == 0) return false; --cur.idx(); - cur.pos() = cur.lastpos(); + cur.pos() = lyxrc.mac_like_cursor_movement ? cur.lastpos() : 0; return true; } @@ -235,7 +234,7 @@ bool InsetMathNest::idxFirst(Cursor & cur) const LASSERT(&cur.inset() == this, return false); if (nargs() == 0) return false; - cur.idx() = 0; + cur.idx() = firstIdx(); cur.pos() = 0; return true; } @@ -246,7 +245,7 @@ bool InsetMathNest::idxLast(Cursor & cur) const LASSERT(&cur.inset() == this, return false); if (nargs() == 0) return false; - cur.idx() = cur.lastidx(); + cur.idx() = lastIdx(); cur.pos() = cur.lastpos(); return true; } @@ -256,7 +255,7 @@ void InsetMathNest::dump() const { odocstringstream oss; otexrowstream ots(oss); - WriteStream os(ots); + TeXMathStream os(ots); os << "---------------------------------------------\n"; write(os); os << "\n"; @@ -327,12 +326,13 @@ MathData InsetMathNest::glue() const } -void InsetMathNest::write(WriteStream & os) const +void InsetMathNest::write(TeXMathStream & os) const { MathEnsurer ensurer(os, currentMode() == MATH_MODE); ModeSpecifier specifier(os, currentMode(), lockedMode()); docstring const latex_name = name(); os << '\\' << latex_name; + os.inMathClass(asClassInset()); for (size_t i = 0; i < nargs(); ++i) { Changer dummy = os.changeRowEntry(TexRow::mathEntry(id(),i)); os << '{' << cell(i) << '}'; @@ -343,6 +343,7 @@ void InsetMathNest::write(WriteStream & os) const os << "\\lyxlock"; os.pendingSpace(true); } + os.inMathClass(false); } @@ -357,28 +358,26 @@ void InsetMathNest::normalize(NormalStream & os) const void InsetMathNest::latex(otexstream & os, OutputParams const & runparams) const { - WriteStream wi(os, runparams.moving_arg, true, - runparams.dryrun ? WriteStream::wsDryrun : WriteStream::wsDefault, - runparams.encoding); - wi.strikeoutMath(runparams.inDeletedInset - && (!LaTeXFeatures::isAvailable("dvipost") - || (runparams.flavor != OutputParams::LATEX - && runparams.flavor != OutputParams::DVILUATEX))); + TeXMathStream wi(os, runparams.moving_arg, true, + runparams.dryrun ? TeXMathStream::wsDryrun : TeXMathStream::wsDefault, + runparams.encoding); + wi.strikeoutMath(runparams.inDeletedInset); if (runparams.inulemcmd) { - wi.ulemCmd(WriteStream::UNDERLINE); + wi.ulemCmd(TeXMathStream::UNDERLINE); if (runparams.local_font) { FontInfo f = runparams.local_font->fontInfo(); if (f.strikeout() == FONT_ON) - wi.ulemCmd(WriteStream::STRIKEOUT); + wi.ulemCmd(TeXMathStream::STRIKEOUT); } } wi.canBreakLine(os.canBreakLine()); Changer dummy = wi.changeRowEntry(TexRow::textEntry(runparams.lastid, runparams.lastpos)); write(wi); - // Reset parbreak status after a math inset. + // Reset parbreak and command termination status after a math inset. os.lastChar(0); os.canBreakLine(wi.canBreakLine()); + os.terminateCommand(false); } @@ -451,8 +450,8 @@ void InsetMathNest::handleNest(Cursor & cur, MathAtom const & nest) void InsetMathNest::handleNest(Cursor & cur, MathAtom const & nest, docstring const & arg) { - CursorSlice i1 = cur.selBegin(); - CursorSlice i2 = cur.selEnd(); + DocIterator const i1 = cur.selectionBegin(); + DocIterator const i2 = cur.selectionEnd(); if (!i1.inset().asInsetMath()) return; if (i1.idx() == i2.idx()) { @@ -463,8 +462,9 @@ void InsetMathNest::handleNest(Cursor & cur, MathAtom const & nest, } // multiple selected cells in a simple non-grid inset - if (i1.asInsetMath()->nrows() == 0 || i1.asInsetMath()->ncols() == 0) { + if (i1.inset().nrows() == 0 || i1.inset().ncols() == 0) { for (idx_type i = i1.idx(); i <= i2.idx(); ++i) { + cur.setCursor(i1); // select cell cur.idx() = i; cur.pos() = 0; @@ -472,14 +472,9 @@ void InsetMathNest::handleNest(Cursor & cur, MathAtom const & nest, cur.pos() = cur.lastpos(); cur.setSelection(); - // change font of cell + // do the real job cur.handleNest(nest); cur.insert(arg); - - // cur is in the font inset now. If the loop continues, - // we need to get outside again for the next cell - if (i + 1 <= i2.idx()) - cur.pop_back(); } return; } @@ -487,24 +482,20 @@ void InsetMathNest::handleNest(Cursor & cur, MathAtom const & nest, // the complicated case with multiple selected cells in a grid row_type r1, r2; col_type c1, c2; - cap::region(i1, i2, r1, r2, c1, c2); + cap::region(i1.top(), i2.top(), r1, r2, c1, c2); for (row_type row = r1; row <= r2; ++row) { for (col_type col = c1; col <= c2; ++col) { + cur.setCursor(i1); // select cell - cur.idx() = i1.asInsetMath()->index(row, col); + cur.idx() = i1.inset().index(row, col); cur.pos() = 0; cur.resetAnchor(); cur.pos() = cur.lastpos(); cur.setSelection(); - // + // do the real job cur.handleNest(nest); cur.insert(arg); - - // cur is in the font inset now. If the loop continues, - // we need to get outside again for the next cell - if (col + 1 <= c2 || row + 1 <= r2) - cur.pop_back(); } } } @@ -523,7 +514,6 @@ void InsetMathNest::handleFont2(Cursor & cur, docstring const & arg) // FIXME: support other font changes here as well? } - void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) { //LYXERR0("InsetMathNest: request: " << cmd); @@ -560,7 +550,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CUT: cur.recordUndo(); - cutSelection(cur, true, true); + cutSelection(cur, true); cur.message(_("Cut")); // Prevent stale position >= size crash // Probably not necessary anymore, see eraseSelection (gb 2005-10-09) @@ -568,11 +558,6 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) cur.forceBufferUpdate(); break; - case LFUN_COPY: - copySelection(cur); - cur.message(_("Copy")); - break; - case LFUN_MOUSE_PRESS: lfunMousePress(cur, cmd); break; @@ -709,12 +694,6 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) || act == LFUN_PARAGRAPH_UP_SELECT; cur.selHandle(select); - // handle autocorrect: - if (lyxrc.autocorrection_math && cur.autocorrect()) { - cur.autocorrect() = false; - cur.message(_("Autocorrect Off ('!' to enter)")); - } - // go up/down bool up = act == LFUN_UP || act == LFUN_UP_SELECT || act == LFUN_PARAGRAPH_UP || act == LFUN_PARAGRAPH_UP_SELECT; @@ -796,12 +775,24 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CELL_FORWARD: cur.screenUpdateFlags(Update::Decoration | Update::FitCursor); - cur.inset().idxNext(cur); + cur.selHandle(false); + cur.clearTargetX(); + cur.macroModeClose(); + if (!cur.inset().idxNext(cur)) { + cur.idx() = firstIdx(); + cur.pos() = 0; + } break; case LFUN_CELL_BACKWARD: cur.screenUpdateFlags(Update::Decoration | Update::FitCursor); - cur.inset().idxPrev(cur); + cur.selHandle(false); + cur.clearTargetX(); + cur.macroModeClose(); + if (!cur.inset().idxPrev(cur)) { + cur.idx() = lastIdx(); + cur.pos() = lyxrc.mac_like_cursor_movement ? cur.lastpos() : 0; + } break; case LFUN_WORD_DELETE_BACKWARD: @@ -836,8 +827,12 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) if (cur.selection()) cur.clearSelection(); else { - cmd = FuncRequest(LFUN_FINISHED_FORWARD); - cur.undispatched(); + if (cur.inMacroMode()) + cur.macroModeClose(true); + else { + cmd = FuncRequest(LFUN_FINISHED_FORWARD); + cur.undispatched(); + } } break; @@ -850,40 +845,37 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) break; case LFUN_SELF_INSERT: - if (cmd.argument().size() != 1) { - cur.recordUndoSelection(); - docstring const arg = cmd.argument(); - if (!interpretString(cur, arg)) - cur.insert(arg); + // special case first for big delimiters + if (cmd.argument().size() != 1 && interpretString(cur, cmd.argument())) break; - } - // Don't record undo steps if we are in macro mode and thus - // cmd.argument is the next character of the macro name. - // Otherwise we'll get an invalid cursor if we undo after - // the macro was finished and the macro is a known command, - // e.g. sqrt. Cursor::macroModeClose replaces in this case - // the InsetMathUnknown with name "frac" by an empty - // InsetMathFrac -> a pos value > 0 is invalid. - // A side effect is that an undo before the macro is finished - // undoes the complete macro, not only the last character. - // At the time we hit '\' we are not in macro mode, still. - if (!cur.inMacroMode()) - cur.recordUndoSelection(); - // spacial handling of space. If we insert an inset - // via macro mode, we want to put the cursor inside it - // if relevant. Think typing "\frac". - if (cmd.argument()[0] == ' ' - && cur.inMacroMode() && cur.macroName() != "\\" - && cur.macroModeClose() && cur.pos() > 0) { - MathAtom const atom = cur.prevAtom(); - if (atom->asNestInset() && atom->isActive()) { - cur.posBackward(); - cur.pushBackward(*cur.nextInset()); + for (char_type c : cmd.argument()) { + // Don't record undo steps if we are in macro mode and thus + // cmd.argument is the next character of the macro name. + // Otherwise we'll get an invalid cursor if we undo after + // the macro was finished and the macro is a known command, + // e.g. sqrt. Cursor::macroModeClose replaces in this case + // the InsetMathUnknown with name "frac" by an empty + // InsetMathFrac -> a pos value > 0 is invalid. + // A side effect is that an undo before the macro is finished + // undoes the complete macro, not only the last character. + // At the time we hit '\' we are not in macro mode, still. + if (!cur.inMacroMode()) + cur.recordUndoSelection(); + + // special handling of space. If we insert an inset + // via macro mode, we want to put the cursor inside it + // if relevant. Think typing "\frac". + if (c == ' ' + && cur.inMacroMode() && cur.macroName() != "\\" + && cur.macroModeClose() && cur.pos() > 0) + cur.editInsertedInset(); + else if (!interpretChar(cur, c)) { + cmd = FuncRequest(LFUN_FINISHED_FORWARD); + cur.undispatched(); + // FIXME: can we avoid skipping the end of the string? + break; } - } else if (!interpretChar(cur, cmd.argument()[0])) { - cmd = FuncRequest(LFUN_FINISHED_FORWARD); - cur.undispatched(); } break; @@ -1087,7 +1079,8 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) // check if we have a valid decoration if (name != "pmatrix" && name != "bmatrix" && name != "Bmatrix" && name != "vmatrix" - && name != "Vmatrix" && name != "matrix") + && name != "Vmatrix" && name != "matrix" + && name != "smallmatrix") name = from_ascii("matrix"); cur.niceInsert( @@ -1229,10 +1222,12 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) cur.recordUndoSelection(); if (cmd.argument() == "^" || cmd.argument() == "_") interpretChar(cur, cmd.argument()[0]); + else if (!cur.selection()) + cur.niceInsert(cmd.argument()); else { - MathData ar; + MathData ar(cur.buffer()); asArray(cmd.argument(), ar); - if (cur.selection() && ar.size() == 1 + if (ar.size() == 1 && ar[0]->asNestInset() && ar[0]->asNestInset()->nargs() > 1) handleNest(cur, ar[0]); @@ -1242,22 +1237,6 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) break; } - case LFUN_UNICODE_INSERT: { - if (cmd.argument().empty()) - break; - docstring hexstring = cmd.argument(); - if (isHex(hexstring)) { - char_type c = hexToInt(hexstring); - if (c >= 32 && c < 0x10ffff) { - docstring s = docstring(1, c); - FuncCode code = currentMode() == MATH_MODE ? - LFUN_MATH_INSERT : LFUN_SELF_INSERT; - lyx::dispatch(FuncRequest(code, s)); - } - } - break; - } - case LFUN_DIALOG_SHOW_NEW_INSET: { docstring const & name = cmd.argument(); string data; @@ -1288,6 +1267,34 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) } break; + case LFUN_MATH_LIMITS: { + InsetMath * in = 0; + if (cur.pos() < cur.lastpos() && cur.nextMath().allowsLimitsChange()) + in = &cur.nextMath(); + else if (cur.pos() > 0 && cur.prevMath().allowsLimitsChange()) + in = &cur.prevMath(); + else if (cur.lastpos() > 0 && cur.cell().back()->allowsLimitsChange()) + in = cur.cell().back().nucleus(); + // only when nucleus allows this + if (!in) + return; + cur.recordUndoInset(); + if (!cmd.argument().empty()) { + if (cmd.argument() == "limits") + in->limits(LIMITS); + else if (cmd.argument() == "nolimits") + in->limits(NO_LIMITS); + else + in->limits(AUTO_LIMITS); + } else if (in->limits() != AUTO_LIMITS) + in->limits(AUTO_LIMITS); + else if (in->defaultLimits(cur.cell().displayStyle()) == LIMITS) + in->limits(NO_LIMITS); + else + in->limits(LIMITS); + return; + } + default: InsetMath::doDispatch(cur, cmd); break; @@ -1337,9 +1344,6 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd, bool ret = true; string const arg = to_utf8(cmd.argument()); switch (cmd.action()) { - case LFUN_INSET_MODIFY: - flag.setEnabled(false); - break; #if 0 case LFUN_INSET_MODIFY: // FIXME: check temporarily disabled @@ -1415,7 +1419,7 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd, case LFUN_INSET_INSERT: { // Don't test createMathInset_fromDialogStr(), since // getStatus is not called with a valid reference and the - // dialog would not be applyable. + // dialog would not be applicable. string const name = cmd.getArg(0); flag.setEnabled(name == "ref" || name == "mathspace"); break; @@ -1471,6 +1475,29 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd, break; } + case LFUN_MATH_LIMITS: { + InsetMath * in = 0; + if (cur.pos() < cur.lastpos() && cur.nextMath().allowsLimitsChange()) + in = &cur.nextMath(); + else if (cur.pos() > 0 && cur.prevMath().allowsLimitsChange()) + in = &cur.prevMath(); + else if (cur.lastpos() > 0 && cur.cell().back()->allowsLimitsChange()) + in = cur.cell().back().nucleus(); + if (in) { + if (!cmd.argument().empty()) { + if (cmd.argument() == "limits") + flag.setOnOff(in->limits() == LIMITS); + else if (cmd.argument() == "nolimits") + flag.setOnOff(in->limits() == NO_LIMITS); + else + flag.setOnOff(in->limits() == AUTO_LIMITS); + } + flag.setEnabled(true); + } else + flag.setEnabled(false); + return true; + } + default: ret = false; break; @@ -1482,10 +1509,9 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd, void InsetMathNest::edit(Cursor & cur, bool front, EntryDirection entry_from) { cur.push(*this); - bool enter_front = (entry_from == Inset::ENTRY_DIRECTION_RIGHT || + bool enter_front = (entry_from == Inset::ENTRY_DIRECTION_LEFT || (entry_from == Inset::ENTRY_DIRECTION_IGNORE && front)); - cur.idx() = enter_front ? 0 : cur.lastidx(); - cur.pos() = enter_front ? 0 : cur.lastpos(); + enter_front ? idxFirst(cur) : idxLast(cur); cur.resetAnchor(); //lyxerr << "InsetMathNest::edit, cur:\n" << cur << endl; } @@ -1620,6 +1646,11 @@ void InsetMathNest::lfunMouseRelease(Cursor & cur, FuncRequest & cmd) bool InsetMathNest::interpretChar(Cursor & cur, char_type const c) { + // try auto-correction + if (lyxrc.autocorrection_math && cur.pos() != 0 + && math_autocorrect(cur, c)) + return true; + //lyxerr << "interpret 2: '" << c << "'" << endl; docstring save_selection; if (c == '^' || c == '_') @@ -1725,7 +1756,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c) MathAtom const atom = cur.prevAtom(); if (atom->asNestInset() && atom->isActive()) { cur.posBackward(); - cur.pushBackward(*cur.nextInset()); + cur.nextInset()->edit(cur, true); } } if (c == '{') @@ -1736,18 +1767,6 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c) } - // leave autocorrect mode if necessary - if (lyxrc.autocorrection_math && c == ' ' && cur.autocorrect()) { - cur.autocorrect() = false; - cur.message(_("Autocorrect Off ('!' to enter)")); - return true; - } - if (lyxrc.autocorrection_math && c == '!' && !cur.autocorrect()) { - cur.autocorrect() = true; - cur.message(_("Autocorrect On ( to exit)")); - return true; - } - // just clear selection on pressing the space bar if (cur.selection() && c == ' ') { cur.selection(false); @@ -1851,7 +1870,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c) if (currentMode() == InsetMath::MATH_MODE && Encodings::isUnicodeTextOnly(c)) { MathAtom at = createInsetMath("text", buf); at.nucleus()->cell(0).push_back(MathAtom(new InsetMathChar(c))); - cur.niceInsert(at); + cur.insert(at); cur.posForward(); return true; } @@ -1872,26 +1891,23 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c) return true; } - - // try auto-correction - if (lyxrc.autocorrection_math && cur.autocorrect() && cur.pos() != 0 - && math_autocorrect(cur.prevAtom(), c)) - return true; - // no special circumstances, so insert the character without any fuss cur.insert(c); - if (lyxrc.autocorrection_math) { - if (!cur.autocorrect()) - cur.message(_("Autocorrect Off ('!' to enter)")); - else - cur.message(_("Autocorrect On ( to exit)")); - } return true; } bool InsetMathNest::interpretString(Cursor & cur, docstring const & str) { + if (str == "\\limits" || str == "\\nolimits") { + if (cur.pos() > 0 && cur.prevMath().allowsLimitsChange()) { + cur.prevMath().limits(str == "\\limits" ? LIMITS : NO_LIMITS); + return true; + } else { + cur.message(bformat(_("Cannot apply %1$s here."), str)); + return false; + } + } // Create a InsetMathBig from cur.cell()[cur.pos() - 1] and t if // possible if (!cur.empty() && cur.pos() > 0 && @@ -1902,6 +1918,7 @@ bool InsetMathNest::interpretString(Cursor & cur, docstring const & str) prev = prev.substr(1); latexkeys const * l = in_word_set(prev); if (l && l->inset == "big") { + cur.recordUndoSelection(); cur.cell()[cur.pos() - 1] = MathAtom(new InsetMathBig(prev, str)); return true; @@ -2001,7 +2018,7 @@ CompletionList const * InsetMathNest::createCompletionList(Cursor const & cur) const { if (!cur.inMacroMode()) - return 0; + return nullptr; return new MathCompletionList(cur); } @@ -2210,11 +2227,11 @@ std::string MathCompletionList::icon(size_t idx) const else cmd = locals[idx]; - // get the icon resource name by stripping the backslash + // get the icon name by stripping the backslash docstring icon_name = frontend::Application::mathIcon(cmd.substr(1)); if (icon_name.empty()) return std::string(); - return "images/math/" + to_utf8(icon_name); + return "math/" + to_utf8(icon_name); } std::vector MathCompletionList::globals;