X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FText3.cpp;h=7ec8947d64e077fabeb36c2841002f83264564c0;hb=c7d29be153debac82e3d2e8865fcc849f0a5f40d;hp=71293f80301152055633644007ce08bab5740db3;hpb=1ac48c7cba8ee5c516ee1e676894f06107149945;p=lyx.git diff --git a/src/Text3.cpp b/src/Text3.cpp index 71293f8030..7ec8947d64 100644 --- a/src/Text3.cpp +++ b/src/Text3.cpp @@ -53,7 +53,7 @@ #include "frontends/Selection.h" #include "insets/InsetArgument.h" -#include "insets/InsetCollapsable.h" +#include "insets/InsetCollapsible.h" #include "insets/InsetCommand.h" #include "insets/InsetExternal.h" #include "insets/InsetFloat.h" @@ -78,7 +78,7 @@ #include "support/regex.h" #include "mathed/InsetMathHull.h" -#include "mathed/MathMacroTemplate.h" +#include "mathed/InsetMathMacroTemplate.h" #include #include @@ -89,6 +89,7 @@ using namespace lyx::support; namespace lyx { using cap::copySelection; +using cap::copySelectionToTemp; using cap::cutSelection; using cap::cutSelectionToTemp; using cap::pasteFromStack; @@ -245,24 +246,11 @@ static bool doInsertInset(Cursor & cur, Text * text, if (!inset) return false; - if (InsetCollapsable * ci = inset->asInsetCollapsable()) + if (InsetCollapsible * ci = inset->asInsetCollapsible()) ci->setButtonLabel(); cur.recordUndo(); - if (cmd.action() == LFUN_INDEX_INSERT) { - docstring ds = subst(text->getStringToIndex(cur), '\n', ' '); - text->insertInset(cur, inset); - if (edit) - inset->edit(cur, true); - // Now put this into inset - Font const f(inherit_font, cur.current_font.language()); - if (!ds.empty()) { - cur.text()->insertStringAsLines(cur, ds, f); - cur.leaveInset(*inset); - } - return true; - } - else if (cmd.action() == LFUN_ARGUMENT_INSERT) { + if (cmd.action() == LFUN_ARGUMENT_INSERT) { bool cotextinsert = false; InsetArgument const * const ia = static_cast(inset); Layout const & lay = cur.paragraph().layout(); @@ -301,9 +289,16 @@ static bool doInsertInset(Cursor & cur, Text * text, bool gotsel = false; if (cur.selection()) { - cutSelectionToTemp(cur, false, pastesel); + if (cmd.action() == LFUN_INDEX_INSERT) + copySelectionToTemp(cur); + else + cutSelectionToTemp(cur, pastesel); + cur.clearSelection(); + gotsel = true; + } else if (cmd.action() == LFUN_INDEX_INSERT) { + gotsel = text->selectWordWhenUnderCursor(cur, WHOLE_WORD); + copySelectionToTemp(cur); cur.clearSelection(); - gotsel = true; } text->insertInset(cur, inset); @@ -366,7 +361,23 @@ enum OutlineOp { }; -static void outline(OutlineOp mode, Cursor & cur) +static void insertSeparator(Cursor & cur, depth_type const depth) +{ + Buffer & buf = *cur.buffer(); + lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_BREAK)); + DocumentClass const & tc = buf.params().documentClass(); + lyx::dispatch(FuncRequest(LFUN_LAYOUT, from_ascii("\"") + tc.plainLayout().name() + + from_ascii("\" ignoreautonests"))); + // FIXME: Bibitem mess! + if (cur.prevInset() && cur.prevInset()->lyxCode() == BIBITEM_CODE) + lyx::dispatch(FuncRequest(LFUN_CHAR_DELETE_BACKWARD)); + lyx::dispatch(FuncRequest(LFUN_SEPARATOR_INSERT, "plain")); + while (cur.paragraph().params().depth() > depth) + lyx::dispatch(FuncRequest(LFUN_DEPTH_DECREMENT)); +} + + +static void outline(OutlineOp mode, Cursor & cur, Text * text) { Buffer & buf = *cur.buffer(); pit_type & pit = cur.pit(); @@ -377,6 +388,7 @@ static void outline(OutlineOp mode, Cursor & cur) // The final paragraph of area to be copied: ParagraphList::iterator finish = start; ParagraphList::iterator const end = pars.end(); + depth_type const current_depth = cur.paragraph().params().depth(); int const thistoclevel = buf.text().getTocLevel(distance(bgn, start)); int toclevel; @@ -411,10 +423,47 @@ static void outline(OutlineOp mode, Cursor & cur) // Not found; do nothing if (toclevel == Layout::NOT_IN_TOC || toclevel > thistoclevel) return; - pit_type const newpit = distance(bgn, dest); + pit_type newpit = distance(bgn, dest); pit_type const len = distance(start, finish); pit_type const deletepit = pit + len; buf.undo().recordUndo(cur, newpit, deletepit - 1); + // If we move an environment upwards, make sure it is + // separated from its new neighbour below: + // If an environment of the same layout follows, and the moved + // paragraph sequence does not end with a separator, insert one. + ParagraphList::iterator lastmoved = finish; + --lastmoved; + if (start->layout().isEnvironment() + && dest->layout() == start->layout() + && !lastmoved->isEnvSeparator(lastmoved->beginOfBody())) { + cur.pit() = distance(bgn, lastmoved); + cur.pos() = cur.lastpos(); + insertSeparator(cur, current_depth); + cur.pit() = pit; + } + // Likewise, if we moved an environment upwards, make sure it + // is separated from its new neighbour above. + // The paragraph before the target of movement + if (dest != bgn) { + ParagraphList::iterator before = dest; + --before; + // Get the parent paragraph (outer in nested context) + pit_type const parent = + before->params().depth() > current_depth + ? text->depthHook(distance(bgn, before), current_depth) + : distance(bgn, before); + // If a environment with same layout preceeds the moved one in the new + // position, and there is no separator yet, insert one. + if (start->layout().isEnvironment() + && pars[parent].layout() == start->layout() + && !before->isEnvSeparator(before->beginOfBody())) { + cur.pit() = distance(bgn, before); + cur.pos() = cur.lastpos(); + insertSeparator(cur, current_depth); + cur.pit() = pit; + } + } + newpit = distance(bgn, dest); pars.splice(dest, start, finish); cur.pit() = newpit; break; @@ -432,9 +481,45 @@ static void outline(OutlineOp mode, Cursor & cur) && toclevel <= thistoclevel) break; } - // One such was found: + // One such was found, so go on... + // If we move an environment downwards, make sure it is + // separated from its new neighbour above. pit_type newpit = distance(bgn, dest); buf.undo().recordUndo(cur, pit, newpit - 1); + // The paragraph before the target of movement + ParagraphList::iterator before = dest; + --before; + // Get the parent paragraph (outer in nested context) + pit_type const parent = + before->params().depth() > current_depth + ? text->depthHook(distance(bgn, before), current_depth) + : distance(bgn, before); + // If a environment with same layout preceeds the moved one in the new + // position, and there is no separator yet, insert one. + if (start->layout().isEnvironment() + && pars[parent].layout() == start->layout() + && !before->isEnvSeparator(before->beginOfBody())) { + cur.pit() = distance(bgn, before); + cur.pos() = cur.lastpos(); + insertSeparator(cur, current_depth); + cur.pit() = pit; + } + // Likewise, make sure moved environments are separated + // from their new neighbour below: + // If an environment of the same layout follows, and the moved + // paragraph sequence does not end with a separator, insert one. + ParagraphList::iterator lastmoved = finish; + --lastmoved; + if (dest != end + && start->layout().isEnvironment() + && dest->layout() == start->layout() + && !lastmoved->isEnvSeparator(lastmoved->beginOfBody())) { + cur.pit() = distance(bgn, lastmoved); + cur.pos() = cur.lastpos(); + insertSeparator(cur, current_depth); + cur.pit() = pit; + } + newpit = distance(bgn, dest); pit_type const len = distance(start, finish); pars.splice(dest, start, finish); cur.pit() = newpit - len; @@ -452,7 +537,7 @@ static void outline(OutlineOp mode, Cursor & cur) DocumentClass const & tc = buf.params().documentClass(); DocumentClass::const_iterator lit = tc.begin(); DocumentClass::const_iterator len = tc.end(); - int const newtoclevel = + int const newtoclevel = (mode == OutlineIn ? toclevel + 1 : toclevel - 1); LabelType const oldlabeltype = start->layout().labeltype; @@ -484,14 +569,14 @@ bool Text::isRTL(Paragraph const & par) const return par.isRTL(buffer.params()); } - + namespace { - + Language const * getLanguage(Cursor const & cur, string const & lang) { return lang.empty() ? cur.getFont().language() : languages.getLanguage(lang); } -} +} // namespace void Text::dispatch(Cursor & cur, FuncRequest & cmd) @@ -518,7 +603,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) cur.noScreenUpdate(); LBUFERR(this == cur.text()); - + // NOTE: This should NOT be a reference. See commit 94a5481a. CursorSlice const oldTopSlice = cur.top(); bool const oldBoundary = cur.boundary(); @@ -584,7 +669,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) case LFUN_WORD_DELETE_FORWARD: if (cur.selection()) - cutSelection(cur, true, false); + cutSelection(cur, false); else deleteWordForward(cur, cmd.getArg(0) == "force"); finishChange(cur, false); @@ -592,7 +677,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) case LFUN_WORD_DELETE_BACKWARD: if (cur.selection()) - cutSelection(cur, true, false); + cutSelection(cur, false); else deleteWordBackward(cur, cmd.getArg(0) == "force"); finishChange(cur, false); @@ -600,7 +685,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) case LFUN_LINE_DELETE_FORWARD: if (cur.selection()) - cutSelection(cur, true, false); + cutSelection(cur, false); else tm->deleteLineForward(cur); finishChange(cur, false); @@ -770,6 +855,18 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) cur.upDownInText(up, needsUpdate); needsUpdate |= cur.beforeDispatchCursor().inMathed(); } else { + pos_type newpos = up ? 0 : cur.lastpos(); + if (lyxrc.mac_like_cursor_movement && cur.pos() != newpos) { + needsUpdate |= cur.selHandle(select); + // we do not reset the targetx of the cursor + cur.pos() = newpos; + needsUpdate |= bv->checkDepm(cur, bv->cursor()); + cur.updateTextTargetOffset(); + if (needsUpdate) + cur.forceBufferUpdate(); + break; + } + // if the cursor cannot be moved up or down do not remove // the selection right now, but wait for the next dispatch. if (select) @@ -835,6 +932,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) break; } cur.pos() = cur.lastpos(); + cur.boundary(false); + cur.setCurrentFont(); needsUpdate |= cur != old_cur; break; @@ -1064,7 +1163,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) needsUpdate |= erase(cur); cur.resetAnchor(); } else { - cutSelection(cur, true, false); + cutSelection(cur, false); singleParUpdate = false; } moveCursor(cur, false); @@ -1094,7 +1193,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) } } } else { - cutSelection(cur, true, false); + DocIterator const dit = cur.selectionBegin(); + cutSelection(cur, false); + if (cur.buffer()->params().track_changes) + // since we're doing backwards deletion, + // and the selection is not really cut, + // move cursor before selection (#11630) + cur.setCursor(dit); singleParUpdate = false; } break; @@ -1108,6 +1213,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) pit_type prev = pit > 0 ? depthHook(pit, par.getDepth()) : pit; if (prev < pit && cur.pos() == par.beginOfBody() && !par.size() && !par.isEnvSeparator(cur.pos()) + && !par.layout().keepempty && !par.layout().isCommand() && pars_[prev].layout() != par.layout() && pars_[prev].layout().isEnvironment() @@ -1127,9 +1233,9 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) Font const f(inherit_font, cur.current_font.language()); pars_[cur.pit() - 1].resetFonts(f); } else { - if (par.isEnvSeparator(cur.pos())) + if (par.isEnvSeparator(cur.pos()) && cmd.getArg(1) != "ignoresep") cur.posForward(); - breakParagraph(cur, cmd.argument() == "inverse"); + breakParagraph(cur, cmd.getArg(0) == "inverse"); } cur.resetAnchor(); // If we have a list and autoinsert item insets, @@ -1181,8 +1287,9 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) } */ if (cur.selection()) - cutSelection(cur, true, false); + cutSelection(cur, false); cur.insert(inset); + cur.forceBufferUpdate(); if (inset->editable() && inset->asInsetText()) inset->edit(cur, true); else @@ -1227,6 +1334,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) } ins->setParams(inspar); + break; } case LFUN_SPACE_INSERT: @@ -1371,15 +1479,10 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) } case LFUN_CUT: - cutSelection(cur, true, true); + cutSelection(cur, true); cur.message(_("Cut")); break; - case LFUN_COPY: - copySelection(cur); - cur.message(_("Copy")); - break; - case LFUN_SERVER_GET_XY: cur.message(from_utf8( convert(tm->cursorX(cur.top(), cur.boundary())) @@ -1404,7 +1507,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) break; case LFUN_LAYOUT: { - docstring layout = cmd.argument(); + bool const ignoreautonests = cmd.getArg(1) == "ignoreautonests"; + docstring layout = ignoreautonests ? from_utf8(cmd.getArg(0)) : cmd.argument(); LYXERR(Debug::INFO, "LFUN_LAYOUT: (arg) " << to_utf8(layout)); Paragraph const & para = cur.paragraph(); @@ -1458,8 +1562,18 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) } } - if (change_layout) + if (change_layout) { setLayout(cur, layout); + if (cur.pit() > 0 && !ignoreautonests) { + set const & autonests = + pars_[cur.pit() - 1].layout().autonests(); + set const & autonested = + pars_[cur.pit()].layout().isAutonestedBy(); + if (autonests.find(layout) != autonests.end() + || autonested.find(old_layout) != autonested.end()) + lyx::dispatch(FuncRequest(LFUN_DEPTH_INCREMENT)); + } + } Layout::LaTeXArgMap args = tclass[layout].args(); Layout::LaTeXArgMap::const_iterator lait = args.begin(); @@ -1477,36 +1591,80 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) case LFUN_ENVIRONMENT_SPLIT: { bool const outer = cmd.argument() == "outer"; + bool const previous = cmd.argument() == "previous"; + bool const before = cmd.argument() == "before"; + bool const normal = cmd.argument().empty(); Paragraph const & para = cur.paragraph(); - docstring layout = para.layout().name(); + docstring layout; + if (para.layout().isEnvironment()) + layout = para.layout().name(); depth_type split_depth = cur.paragraph().params().depth(); - if (outer) { - // check if we have an environment in our nesting hierarchy + depth_type nextpar_depth = 0; + if (outer || previous) { + // check if we have an environment in our scope pit_type pit = cur.pit(); Paragraph cpar = pars_[pit]; while (true) { - if (pit == 0 || cpar.params().depth() == 0) + if (pit == 0) break; --pit; cpar = pars_[pit]; + if (layout.empty() && previous + && cpar.layout().isEnvironment() + && cpar.params().depth() <= split_depth) + layout = cpar.layout().name(); if (cpar.params().depth() < split_depth && cpar.layout().isEnvironment()) { - layout = cpar.layout().name(); + if (!previous) + layout = cpar.layout().name(); split_depth = cpar.params().depth(); } + if (cpar.params().depth() == 0) + break; } } - if (cur.pos() > 0) + if ((outer || normal) && cur.pit() < cur.lastpit()) { + // save nesting of following paragraph + Paragraph cpar = pars_[cur.pit() + 1]; + nextpar_depth = cpar.params().depth(); + } + if (before) + cur.top().setPitPos(cur.pit(), 0); + if (before || cur.pos() > 0) lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_BREAK)); + else if (previous && cur.nextInset() && cur.nextInset()->lyxCode() == SEPARATOR_CODE) + lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_BREAK, "inverse ignoresep")); if (outer) { while (cur.paragraph().params().depth() > split_depth) lyx::dispatch(FuncRequest(LFUN_DEPTH_DECREMENT)); } DocumentClass const & tc = bv->buffer().params().documentClass(); - lyx::dispatch(FuncRequest(LFUN_LAYOUT, tc.plainLayout().name())); + lyx::dispatch(FuncRequest(LFUN_LAYOUT, from_ascii("\"") + tc.plainLayout().name() + + from_ascii("\" ignoreautonests"))); lyx::dispatch(FuncRequest(LFUN_SEPARATOR_INSERT, "plain")); - lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_BREAK, "inverse")); + if (before) { + cur.backwardPos(); + lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_BREAK, "inverse ignoresep")); + while (cur.paragraph().params().depth() < split_depth) + lyx::dispatch(FuncRequest(LFUN_DEPTH_INCREMENT)); + } + else + lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_BREAK, "inverse")); lyx::dispatch(FuncRequest(LFUN_LAYOUT, layout)); + if ((outer || normal) && nextpar_depth > 0) { + // restore nesting of following paragraph + DocIterator scur = cur; + depth_type const max_depth = cur.paragraph().params().depth() + 1; + cur.forwardPar(); + while (cur.paragraph().params().depth() < min(nextpar_depth, max_depth)) { + depth_type const olddepth = cur.paragraph().params().depth(); + lyx::dispatch(FuncRequest(LFUN_DEPTH_INCREMENT)); + if (olddepth == cur.paragraph().params().depth()) + // leave loop if no incrementation happens + break; + } + cur.setCursor(scur); + } break; } @@ -1539,21 +1697,6 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) bv->buffer().errors("Paste"); 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) { - lyxerr << "Inserting c: " << c << endl; - docstring s = docstring(1, c); - lyx::dispatch(FuncRequest(LFUN_SELF_INSERT, s)); - } - } - break; - } - case LFUN_QUOTE_INSERT: { cap::replaceSelection(cur); cur.recordUndo(); @@ -1712,6 +1855,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) // reset the anchor. bvcur.setCursor(cur); bvcur.selection(true); + bvcur.setCurrentFont(); if (cur.top() == old) { // We didn't move one iota, so no need to update the screen. cur.screenUpdateFlags(Update::SinglePar | Update::FitCursor); @@ -1774,14 +1918,11 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) // true (on). if (lyxrc.auto_region_delete && cur.selection()) - cutSelection(cur, false, false); - + cutSelection(cur, false); cur.clearSelection(); - docstring::const_iterator cit = cmd.argument().begin(); - docstring::const_iterator const end = cmd.argument().end(); - for (; cit != end; ++cit) - bv->translateAndInsert(*cit, this, cur); + for (char_type c : cmd.argument()) + bv->translateAndInsert(c, this, cur); cur.resetAnchor(); moveCursor(cur, false); @@ -1858,7 +1999,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) if (cmd.argument().empty() && cur.selection()) { // if command argument is empty use current selection as parameter. docstring ds = cur.selectionAsString(false); - cutSelection(cur, true, false); + cutSelection(cur, false); FuncRequest cmd0(cmd, ds); inset = createInset(cur.buffer(), cmd0); } else { @@ -1868,6 +2009,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) break; cur.recordUndo(); insertInset(cur, inset); + cur.forceBufferUpdate(); cur.posForward(); break; } @@ -2044,7 +2186,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) // don't pass "on" as argument // (it would appear literally in the first cell) docstring sel = cur.selectionAsString(false); - MathMacroTemplate * macro = new MathMacroTemplate(cur.buffer()); + InsetMathMacroTemplate * macro = new InsetMathMacroTemplate(cur.buffer()); // create a macro template if we see "\\newcommand" somewhere, and // an ordinary formula otherwise if (!sel.empty() @@ -2080,7 +2222,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) MacroType type = MacroTypeNewcommand; if (s2 == "def") type = MacroTypeDef; - MathMacroTemplate * inset = new MathMacroTemplate(cur.buffer(), + InsetMathMacroTemplate * inset = new InsetMathMacroTemplate(cur.buffer(), from_utf8(token(s, ' ', 0)), nargs, false, type); inset->setBuffer(bv->buffer()); insertInset(cur, inset); @@ -2228,7 +2370,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) // Set the freefont using the contents of \param data dispatched from // the frontends and apply it at the current cursor location. case LFUN_TEXTSTYLE_UPDATE: { - Font font; + Font font(ignore_font, ignore_language); bool toggle; if (font.fromString(to_utf8(cmd.argument()), toggle)) { freefont = font; @@ -2324,7 +2466,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) if (tclass.floats().typeExist(to_utf8(cmd.argument()))) { cur.recordUndo(); if (cur.selection()) - cutSelection(cur, true, false); + cutSelection(cur, false); breakParagraph(cur); if (cur.lastpos() != 0) { @@ -2368,8 +2510,15 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) docstring arg = cmd.argument(); if (arg.empty()) { arg = cur.selectionAsString(false); - // FIXME + // Too large. We unselect if needed and try to get + // the first word in selection or under cursor if (arg.size() > 100 || arg.empty()) { + if (cur.selection()) { + DocIterator selbeg = cur.selectionBegin(); + cur.clearSelection(); + setCursorIntern(cur, selbeg.pit(), selbeg.pos()); + cur.screenUpdateFlags(Update::Force); + } // Get word or selection selectWordWhenUnderCursor(cur, WHOLE_WORD); arg = cur.selectionAsString(false); @@ -2482,27 +2631,27 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) break; case LFUN_OUTLINE_UP: - outline(OutlineUp, cur); + outline(OutlineUp, cur, this); setCursor(cur, cur.pit(), 0); cur.forceBufferUpdate(); needsUpdate = true; break; case LFUN_OUTLINE_DOWN: - outline(OutlineDown, cur); + outline(OutlineDown, cur, this); setCursor(cur, cur.pit(), 0); cur.forceBufferUpdate(); needsUpdate = true; break; case LFUN_OUTLINE_IN: - outline(OutlineIn, cur); + outline(OutlineIn, cur, this); cur.forceBufferUpdate(); needsUpdate = true; break; case LFUN_OUTLINE_OUT: - outline(OutlineOut, cur); + outline(OutlineOut, cur, this); cur.forceBufferUpdate(); needsUpdate = true; break; @@ -2971,7 +3120,6 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, break; case LFUN_CUT: - case LFUN_COPY: enable = cur.selection(); break; @@ -3055,17 +3203,37 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, case LFUN_CHANGE_ACCEPT: case LFUN_CHANGE_REJECT: - // In principle, these LFUNs should only be enabled if there - // is a change at the current position/in the current selection. - // However, without proper optimizations, this will inevitably - // result in unacceptable performance - just imagine a user who - // wants to select the complete content of a long document. if (!cur.selection()) enable = cur.paragraph().isChanged(cur.pos()); - else - // TODO: context-sensitive enabling of LFUN_CHANGE_ACCEPT/REJECT - // for selections. - enable = true; + else { + // will enable if there is a change in the selection + enable = false; + + // cheap improvement for efficiency: using cached + // buffer variable, if there is no change in the + // document, no need to check further. + if (!cur.buffer()->areChangesPresent()) + break; + + for (DocIterator it = cur.selectionBegin(); ; it.forwardPar()) { + pos_type const beg = it.pos(); + pos_type end; + bool const in_last_par = (it.pit() == cur.selectionEnd().pit() && + it.idx() == cur.selectionEnd().idx()); + if (in_last_par) + end = cur.selectionEnd().pos(); + else + // the +1 is needed for cases, e.g., where there is a + // paragraph break. See #11629. + end = it.lastpos() + 1; + if (beg != end && it.paragraph().isChanged(beg, end)) { + enable = true; + break; + } + if (in_last_par) + break; + } + } break; case LFUN_OUTLINE_UP: @@ -3137,7 +3305,8 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, case LFUN_LAYOUT: { DocumentClass const & tclass = cur.buffer()->params().documentClass(); - docstring layout = cmd.argument(); + bool const ignoreautonests = cmd.getArg(1) == "ignoreautonests"; + docstring layout = ignoreautonests ? from_utf8(cmd.getArg(0)) : cmd.argument(); if (layout.empty()) layout = tclass.defaultLayoutName(); enable = !owner_->forcePlainLayout() && tclass.hasLayout(layout); @@ -3164,8 +3333,22 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, enable = res; break; } + else if (cmd.argument() == "previous") { + // look if we have an environment in the previous par + pit_type pit = cur.pit(); + Paragraph cpar = pars_[pit]; + if (pit > 0) { + --pit; + cpar = pars_[pit]; + enable = cpar.layout().isEnvironment(); + break; + } + enable = false; + break; + } else if (cur.paragraph().layout().isEnvironment()) { - enable = true; + enable = cmd.argument() == "before" + || cur.pos() > 0 || !isFirstInSequence(cur.pit()); break; } enable = false;