#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"
#include "support/regex.h"
#include "mathed/InsetMathHull.h"
-#include "mathed/MathMacroTemplate.h"
+#include "mathed/InsetMathMacroTemplate.h"
#include <clocale>
#include <sstream>
namespace lyx {
using cap::copySelection;
+using cap::copySelectionToTemp;
using cap::cutSelection;
using cap::cutSelectionToTemp;
using cap::pasteFromStack;
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<InsetArgument const *>(inset);
Layout const & lay = cur.paragraph().layout();
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);
};
-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();
// 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;
// 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;
&& 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;
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;
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)
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();
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);
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);
case LFUN_LINE_DELETE_FORWARD:
if (cur.selection())
- cutSelection(cur, true, false);
+ cutSelection(cur, false);
else
tm->deleteLineForward(cur);
finishChange(cur, false);
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)
break;
}
cur.pos() = cur.lastpos();
+ cur.boundary(false);
+ cur.setCurrentFont();
needsUpdate |= cur != old_cur;
break;
needsUpdate |= erase(cur);
cur.resetAnchor();
} else {
- cutSelection(cur, true, false);
+ cutSelection(cur, false);
singleParUpdate = false;
}
moveCursor(cur, false);
}
}
} 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;
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()
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,
}
*/
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
}
ins->setParams(inspar);
+ break;
}
case LFUN_SPACE_INSERT:
}
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<string>(tm->cursorX(cur.top(), cur.boundary()))
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();
}
}
- if (change_layout)
+ if (change_layout) {
setLayout(cur, layout);
+ if (cur.pit() > 0 && !ignoreautonests) {
+ set<docstring> const & autonests =
+ pars_[cur.pit() - 1].layout().autonests();
+ set<docstring> 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();
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;
}
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();
// 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);
// 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);
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 {
break;
cur.recordUndo();
insertInset(cur, inset);
+ cur.forceBufferUpdate();
cur.posForward();
break;
}
// 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()
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);
// 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;
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) {
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);
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;
break;
case LFUN_CUT:
- case LFUN_COPY:
enable = cur.selection();
break;
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:
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);
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;