#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>
using cap::copySelection;
using cap::cutSelection;
+using cap::cutSelectionToTemp;
using cap::pasteFromStack;
+using cap::pasteFromTemp;
using cap::pasteClipboardText;
using cap::pasteClipboardGraphics;
using cap::replaceSelection;
if (!inset)
return false;
- if (InsetCollapsable * ci = inset->asInsetCollapsable())
+ if (InsetCollapsible * ci = inset->asInsetCollapsible())
ci->setButtonLabel();
cur.recordUndo();
bool gotsel = false;
if (cur.selection()) {
- cutSelection(cur, false, pastesel);
+ cutSelectionToTemp(cur, false, pastesel);
cur.clearSelection();
gotsel = true;
}
if (!gotsel || !pastesel)
return true;
- pasteFromStack(cur, cur.buffer()->errorList("Paste"), 0);
+ pasteFromTemp(cur, cur.buffer()->errorList("Paste"));
cur.buffer()->errors("Paste");
cur.clearSelection(); // bug 393
cur.finishUndo();
};
-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();
if (cur.selection())
cutSelection(cur, true, false);
else
- deleteWordForward(cur);
+ deleteWordForward(cur, cmd.getArg(0) == "force");
finishChange(cur, false);
break;
if (cur.selection())
cutSelection(cur, true, false);
else
- deleteWordBackward(cur);
+ deleteWordBackward(cur, cmd.getArg(0) == "force");
finishChange(cur, false);
break;
break;
}
cur.pos() = cur.lastpos();
+ cur.boundary(false);
+ cur.setCurrentFont();
needsUpdate |= cur != old_cur;
break;
if (cur.pos() == cur.paragraph().size())
// Par boundary, force full-screen update
singleParUpdate = false;
+ else if (cmd.getArg(0) != "force" && cur.confirmDeletion()) {
+ cur.resetAnchor();
+ cur.selection(true);
+ cur.posForward();
+ cur.setSelection();
+ break;
+ }
needsUpdate |= erase(cur);
cur.resetAnchor();
} else {
// Par boundary, full-screen update
if (par_boundary)
singleParUpdate = false;
+ else if (cmd.getArg(0) != "force" && cur.confirmDeletion(true)) {
+ cur.resetAnchor();
+ cur.selection(true);
+ cur.posBackward();
+ cur.setSelection();
+ break;
+ }
needsUpdate |= backspace(cur);
cur.resetAnchor();
if (par_boundary && !first_par && cur.pos() > 0
Paragraph const & par = pars_[pit];
bool lastpar = (pit == pit_type(pars_.size() - 1));
Paragraph const & nextpar = lastpar ? par : pars_[pit + 1];
- pit_type prev = pit;
- if (pit > 0) {
- if (!pars_[pit - 1].layout().isEnvironment())
- prev = depthHook(pit, par.getDepth());
- else if (pars_[pit - 1].getDepth() >= par.getDepth())
- prev = pit - 1;
- }
+ 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().isCommand()
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);
cur.insert(inset);
+ cur.forceBufferUpdate();
if (inset->editable() && inset->asInsetText())
inset->edit(cur, true);
else
}
ins->setParams(inspar);
+ break;
}
case LFUN_SPACE_INSERT:
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")
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))
+ lyx::dispatch(FuncRequest(LFUN_DEPTH_INCREMENT));
+ cur.setCursor(scur);
+ }
break;
}
while (pos > 0 && par.isDeleted(pos - 1))
--pos;
- BufferParams const & bufparams = bv->buffer().params();
- bool const hebrew =
- par.getFontSettings(bufparams, pos).language()->lang() == "hebrew";
- bool const allow_inset_quote = !(par.isPassThru() || hebrew);
-
- string const arg = to_utf8(cmd.argument());
- if (allow_inset_quote) {
- char_type c = ' ';
- if (pos > 0 && (!cur.prevInset() || !cur.prevInset()->isSpace()))
+ bool const inner = (cmd.getArg(0) == "single" || cmd.getArg(0) == "inner");
+
+ // Guess quote side.
+ // A space triggers an opening quote. This is passed if the preceding
+ // char/inset is a space or at paragraph start.
+ char_type c = ' ';
+ if (pos > 0 && !par.isSpace(pos - 1)) {
+ if (cur.prevInset() && cur.prevInset()->lyxCode() == QUOTE_CODE) {
+ // If an opening double quotation mark precedes, and this
+ // is a single quote, make it opening as well
+ InsetQuotes & ins =
+ static_cast<InsetQuotes &>(*cur.prevInset());
+ string const type = ins.getType();
+ if (!suffixIs(type, "ld") || !inner)
+ c = par.getChar(pos - 1);
+ }
+ else if (!cur.prevInset()
+ || (cur.prevInset() && cur.prevInset()->isChar()))
+ // If a char precedes, pass that and let InsetQuote decide
c = par.getChar(pos - 1);
- InsetQuotes::QuoteTimes const quote_type = (arg == "single")
- ? InsetQuotes::SingleQuotes : InsetQuotes::DoubleQuotes;
- cur.insert(new InsetQuotes(cur.buffer(), c, quote_type));
- cur.posForward();
- } else {
- // The cursor might have been invalidated by the replaceSelection.
- cur.buffer()->changed(true);
- string const quote_string = (arg == "single") ? "'" : "\"";
- lyx::dispatch(FuncRequest(LFUN_SELF_INSERT, quote_string));
+ else {
+ while (pos > 0) {
+ if (par.getInset(pos - 1)
+ && !par.getInset(pos - 1)->isPartOfTextSequence()) {
+ // skip "invisible" insets
+ --pos;
+ continue;
+ }
+ c = par.getChar(pos - 1);
+ break;
+ }
+ }
}
+ InsetQuotesParams::QuoteLevel const quote_level = inner
+ ? InsetQuotesParams::SecondaryQuotes : InsetQuotesParams::PrimaryQuotes;
+ cur.insert(new InsetQuotes(cur.buffer(), c, quote_level, cmd.getArg(1), cmd.getArg(2)));
+ cur.buffer()->updateBuffer();
+ cur.posForward();
break;
}
// 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);
}
case LFUN_HREF_INSERT: {
- // FIXME If we're actually given an argument, shouldn't
- // we use it, whether or not we have a selection?
docstring content = cmd.argument();
- if (cur.selection()) {
+ if (content.empty() && cur.selection())
content = cur.selectionAsString(false);
- cutSelection(cur, true, false);
- }
InsetCommandParams p(HYPERLINK_CODE);
if (!content.empty()){
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);
break;
}
+ case LFUN_FONT_CROSSOUT: {
+ Font font(ignore_font, ignore_language);
+ font.fontInfo().setXout(FONT_TOGGLE);
+ toggleAndShow(cur, this, font);
+ break;
+ }
+
case LFUN_FONT_UNDERUNDERLINE: {
Font font(ignore_font, ignore_language);
font.fontInfo().setUuline(FONT_TOGGLE);
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;
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<InsetArgument const *>(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;
case LFUN_QUOTE_INSERT:
// always allow this, since we will inset a raw quote
// if an inset is not allowed.
+ allow_in_passthru = true;
break;
case LFUN_SPECIALCHAR_INSERT:
code = SPECIALCHAR_CODE;
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;
case LFUN_FONT_STATE:
case LFUN_FONT_UNDERLINE:
case LFUN_FONT_STRIKEOUT:
+ case LFUN_FONT_CROSSOUT:
case LFUN_FONT_UNDERUNDERLINE:
case LFUN_FONT_UNDERWAVE:
case LFUN_TEXTSTYLE_APPLY: