X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FText3.cpp;h=adeb80b88f15ec737c699a0d305d6cd71683f8b2;hb=ce2e1554908785d7accba292985017fb961b1450;hp=617037f87168498c265897453cb9dbf117e14ad0;hpb=e575e7eebd32d687f3e23be0eeca185adb3b341b;p=lyx.git diff --git a/src/Text3.cpp b/src/Text3.cpp index 617037f871..adeb80b88f 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 @@ -245,7 +245,7 @@ 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(); @@ -366,7 +366,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 +393,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 +428,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 +486,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 +542,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 +574,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 +608,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(); @@ -770,6 +860,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 +937,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) break; } cur.pos() = cur.lastpos(); + cur.boundary(false); + cur.setCurrentFont(); needsUpdate |= cur != old_cur; break; @@ -1127,9 +1231,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, @@ -1183,6 +1287,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) if (cur.selection()) cutSelection(cur, true, false); cur.insert(inset); + cur.forceBufferUpdate(); if (inset->editable() && inset->asInsetText()) inset->edit(cur, true); else @@ -1227,6 +1332,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) } ins->setParams(inspar); + break; } case LFUN_SPACE_INSERT: @@ -1243,6 +1349,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) string const name = to_utf8(cmd.argument()); if (name == "hyphenation") specialChar(cur, InsetSpecialChar::HYPHENATION); + else if (name == "allowbreak") + specialChar(cur, InsetSpecialChar::ALLOWBREAK); else if (name == "ligature-break") specialChar(cur, InsetSpecialChar::LIGATURE_BREAK); else if (name == "slash") @@ -1402,7 +1510,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(); @@ -1456,8 +1565,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(); @@ -1475,36 +1594,75 @@ 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)) + lyx::dispatch(FuncRequest(LFUN_DEPTH_INCREMENT)); + cur.setCursor(scur); + } break; } @@ -1690,7 +1848,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) int const wh = bv->workHeight(); int const y = max(0, min(wh - 1, cmd.y())); - tm->setCursorFromCoordinates(cur, cmd.x(), y, true); + tm->setCursorFromCoordinates(cur, cmd.x(), y); cur.setTargetX(cmd.x()); // Don't allow selecting a separator inset if (cur.pos() && cur.paragraph().isEnvSeparator(cur.pos() - 1)) @@ -1710,6 +1868,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); @@ -1866,6 +2025,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) break; cur.recordUndo(); insertInset(cur, inset); + cur.forceBufferUpdate(); cur.posForward(); break; } @@ -2042,7 +2202,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() @@ -2078,7 +2238,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); @@ -2480,27 +2640,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; @@ -2839,19 +2999,13 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, for (; pit <= lastpit; ++pit) { if (pars_[pit].layout() != lay) break; - InsetList::const_iterator it = pars_[pit].insetList().begin(); - InsetList::const_iterator end = pars_[pit].insetList().end(); - for (; it != end; ++it) { - if (it->inset->lyxCode() == ARG_CODE) { - InsetArgument const * ins = - static_cast(it->inset); + for (auto const & table : pars_[pit].insetList()) + if (InsetArgument const * ins = table.inset->asInsetArgument()) if (ins->name() == arg) { // we have this already enable = false; break; } - } - } } } else enable = false; @@ -3141,7 +3295,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); @@ -3168,8 +3323,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;