X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FCursor.cpp;h=7afefcf372e3b7cd26558c69af60f8dd28ecf55d;hb=7cc431bd55c0df8acff679a2da72d85e74f3a8d7;hp=173729ba338673bba4533672f47a5b92749e91bb;hpb=9296344b9a26191a2092d175a51e357ecc35145d;p=lyx.git diff --git a/src/Cursor.cpp b/src/Cursor.cpp index 173729ba33..7afefcf372 100644 --- a/src/Cursor.cpp +++ b/src/Cursor.cpp @@ -14,19 +14,19 @@ #include +#include "Cursor.h" + #include "Buffer.h" #include "BufferView.h" #include "CoordCache.h" -#include "Cursor.h" #include "CutAndPaste.h" -#include "DispatchResult.h" #include "FuncCode.h" #include "FuncRequest.h" +#include "Language.h" #include "Layout.h" #include "LyXAction.h" #include "LyXRC.h" #include "Paragraph.h" -#include "ParIterator.h" #include "Row.h" #include "texstream.h" #include "Text.h" @@ -35,12 +35,11 @@ #include "support/debug.h" #include "support/docstream.h" -#include "support/ExceptionMessage.h" #include "support/gettext.h" #include "support/lassert.h" +#include "insets/InsetLayout.h" #include "insets/InsetTabular.h" -#include "insets/InsetText.h" #include "mathed/InsetMath.h" #include "mathed/InsetMathBrace.h" @@ -51,6 +50,8 @@ #include "mathed/MathFactory.h" #include "mathed/InsetMathMacro.h" +#include "frontends/Application.h" + #include #include #include @@ -121,19 +122,19 @@ DocIterator bruteFind(Cursor const & c, int x, int y) CursorData::CursorData() : DocIterator(), anchor_(), selection_(false), mark_(false), - word_selection_(false), autocorrect_(false), current_font(inherit_font) + word_selection_(false), current_font(inherit_font) {} CursorData::CursorData(Buffer * buffer) : DocIterator(buffer), anchor_(), selection_(false), mark_(false), - word_selection_(false), autocorrect_(false), current_font(inherit_font) + word_selection_(false), current_font(inherit_font) {} CursorData::CursorData(DocIterator const & dit) : DocIterator(dit), anchor_(), selection_(false), mark_(false), - word_selection_(false), autocorrect_(false), current_font(inherit_font) + word_selection_(false), current_font(inherit_font) {} @@ -321,6 +322,7 @@ DocIterator CursorData::selectionEnd() const if (di.depth() > depth()) { di.resize(depth()); ++di.pos(); + di.boundary(true); } return di; } @@ -330,6 +332,8 @@ namespace { docstring parbreak(CursorData const * cur) { + if (cur->inset().getLayout().parbreakIgnored()) + return docstring(); odocstringstream os; os << '\n'; // only add blank line if we're not in a ParbreakIsNewline situation @@ -342,7 +346,7 @@ docstring parbreak(CursorData const * cur) } -docstring CursorData::selectionAsString(bool with_label) const +docstring CursorData::selectionAsString(bool const with_label, bool const skipdelete) const { if (!selection()) return docstring(); @@ -350,8 +354,12 @@ docstring CursorData::selectionAsString(bool with_label) const if (inMathed()) return cap::grabSelection(*this); - int const label = with_label + int label = with_label ? AS_STR_LABEL | AS_STR_INSETS : AS_STR_INSETS; + if (skipdelete) + label = with_label + ? AS_STR_LABEL | AS_STR_INSETS | AS_STR_SKIPDELETE + : AS_STR_INSETS | AS_STR_SKIPDELETE; idx_type const startidx = selBegin().idx(); idx_type const endidx = selEnd().idx(); @@ -496,6 +504,56 @@ void CursorData::clearSelection() } +int CursorData::countInsetsInSelection(InsetCode const & inset_code) const +{ + if (!selection_) + return 0; + + DocIterator from, to; + from = selectionBegin(); + to = selectionEnd(); + + int count = 0; + + if (!from.nextInset()) //move to closest inset + from.forwardInset(); + + while (!from.empty() && from < to) { + Inset * inset = from.nextInset(); + if (!inset) + break; + if (inset->lyxCode() == inset_code) + count ++; + from.forwardInset(); + } + return count; +} + + +bool CursorData::insetInSelection(InsetCode const & inset_code) const +{ + if (!selection_) + return false; + + DocIterator from, to; + from = selectionBegin(); + to = selectionEnd(); + + if (!from.nextInset()) //move to closest inset + from.forwardInset(); + + while (!from.empty() && from < to) { + Inset * inset = from.nextInset(); + if (!inset) + break; + if (inset->lyxCode() == inset_code) + return true; + from.forwardInset(); + } + return false; +} + + bool CursorData::fixIfBroken() { bool const broken_cursor = DocIterator::fixIfBroken(); @@ -521,38 +579,18 @@ void CursorData::sanitize() } -bool CursorData::isInside(Inset const * p) const +bool CursorData::undoAction() { - for (size_t i = 0; i != depth(); ++i) - if (&operator[](i).inset() == p) - return true; - return false; -} - - -void CursorData::leaveInset(Inset const & inset) -{ - for (size_t i = 0; i != depth(); ++i) { - if (&operator[](i).inset() == &inset) { - resize(i); - return; - } - } -} - - -bool CursorData::textUndo() -{ - if (!buffer()->undo().textUndo(*this)) + if (!buffer()->undo().undoAction(*this)) return false; sanitize(); return true; } -bool CursorData::textRedo() +bool CursorData::redoAction() { - if (!buffer()->undo().textRedo(*this)) + if (!buffer()->undo().redoAction(*this)) return false; sanitize(); return true; @@ -577,6 +615,12 @@ void CursorData::endUndoGroup() const } +void CursorData::splitUndoGroup() const +{ + buffer()->undo().splitUndoGroup(*this); +} + + void CursorData::recordUndo(pit_type from, pit_type to) const { buffer()->undo().recordUndo(*this, from, to); @@ -595,9 +639,9 @@ void CursorData::recordUndo(UndoKind kind) const } -void CursorData::recordUndoInset(Inset const * in) const +void CursorData::recordUndoInset(Inset const * inset) const { - buffer()->undo().recordUndoInset(*this, in); + buffer()->undo().recordUndoInset(*this, inset); } @@ -627,7 +671,7 @@ void CursorData::recordUndoSelection() const } -int CursorData::currentMode() +int CursorData::currentMode() const { LASSERT(!empty(), return Inset::UNDECIDED_MODE); for (int i = depth() - 1; i >= 0; --i) { @@ -855,19 +899,44 @@ void Cursor::pop() } -void Cursor::push(Inset & p) +void Cursor::push(Inset & inset) { - push_back(CursorSlice(p)); - p.setBuffer(*buffer()); + push_back(CursorSlice(inset)); + inset.setBuffer(*buffer()); } -void Cursor::pushBackward(Inset & p) +void Cursor::pushBackward(Inset & inset) { LASSERT(!empty(), return); //lyxerr << "Entering inset " << t << " front" << endl; + push(inset); + inset.idxFirst(*this); +} + + +void Cursor::editInsertedInset() +{ + LASSERT(!empty(), return); + if (pos() == 0) + return; + + InsetMath &p = prevMath(); + if (!p.isActive()) + return; + + posBackward(); push(p); p.idxFirst(*this); + // this could be a while() loop, but only one cell is not empty in + // cases we are interested in. The cell is not empty because we + // have inserted the selection in there. + if (!cell().empty()) { + // if it is not empty, move to the next one. + if (!inset().idxNext(*this)) + // If there is no next one, exit the inset. + popForward(); + } } @@ -1312,19 +1381,19 @@ void Cursor::updateTextTargetOffset() } -bool Cursor::selHandle(bool sel) +bool Cursor::selHandle(bool selecting) { //lyxerr << "Cursor::selHandle" << endl; if (mark()) - sel = true; - if (sel == selection()) + selecting = true; + if (selecting == selection()) return false; - if (!sel) + if (!selecting) cap::saveSelection(*this); resetAnchor(); - selection(sel); + selection(selecting); return true; } @@ -1365,10 +1434,7 @@ bool Cursor::atFirstOrLastRow(bool up) /////////////////////////////////////////////////////////////////// #include "mathed/InsetMathChar.h" -#include "mathed/InsetMathGrid.h" -#include "mathed/InsetMathScript.h" #include "mathed/InsetMathUnknown.h" -#include "mathed/MathFactory.h" #include "mathed/MathStream.h" #include "mathed/MathSupport.h" @@ -1491,14 +1557,11 @@ void Cursor::niceInsert(MathAtom const & t) plainInsert(t); // If possible, enter the new inset and move the contents of the selection if (t->isActive()) { - posBackward(); - // be careful here: don't use 'pushBackward(t)' as this we need to - // push the clone, not the original - pushBackward(*nextInset()); - // We may not use niceInsert here (recursion) + idx_type const idx = prevMath().asNestInset()->firstIdx(); MathData ar(buffer()); asArray(safe, ar); - insert(ar); + prevMath().cell(idx).insert(0, ar); + editInsertedInset(); } else if (t->asMacro() && !safe.empty()) { MathData ar(buffer()); asArray(safe, ar); @@ -1532,9 +1595,20 @@ bool Cursor::backspace(bool const force) // [|], can not delete from inside return false; } else { - if (inMathed()) - pullArg(); - else + if (inMathed()) { + switch (inset().asInsetMath()->getType()) { + case hullEqnArray: + case hullAlign: + case hullFlAlign: { + FuncRequest cmd(LFUN_CHAR_BACKWARD); + this->dispatch(cmd); + break; + } + default: + pullArg(); + break; + } + } else popBackward(); return true; } @@ -1635,14 +1709,17 @@ bool Cursor::down() } -void Cursor::handleNest(MathAtom const & a, int c) +void Cursor::handleNest(MathAtom const & a) { - //lyxerr << "Cursor::handleNest: " << c << endl; + idx_type const idx = a.nucleus()->asNestInset()->firstIdx(); + //lyxerr << "Cursor::handleNest: " << idx << endl; + InsetMath const * im = selectionBegin().inset().asInsetMath(); + Parse::flags const f = im && im->currentMode() != InsetMath::MATH_MODE + ? Parse::TEXTMODE : Parse::NORMAL; MathAtom t = a; - asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c)); + asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(idx), f); insert(t); - posBackward(); - pushBackward(*nextInset()); + editInsertedInset(); } @@ -1684,14 +1761,15 @@ bool Cursor::macroModeClose(bool cancel) --pos(); cell().erase(pos()); - // do nothing if the macro name is empty - if (s == "\\" || cancel) - return false; - // trigger updates of macros, at least, if no full // updates take place anyway screenUpdateFlags(Update::Force); + // do nothing if the macro name is empty + if (s == "\\" || cancel) { + return false; + } + docstring const name = s.substr(1); InsetMathNest * const in = inset().asInsetMath()->asNestInset(); if (in && in->interpretString(*this, s)) @@ -1703,12 +1781,13 @@ bool Cursor::macroModeClose(bool cancel) // try to put argument into macro, if we just inserted a macro bool macroArg = false; InsetMathMacro * atomAsMacro = atom.nucleus()->asMacro(); + InsetMathNest * atomAsNest = atom.nucleus()->asNestInset(); if (atomAsMacro) { // macros here are still unfolded (in init mode in fact). So // we have to resolve the macro here manually and check its arity // to put the selection behind it if arity > 0. MacroData const * data = buffer()->getMacro(atomAsMacro->name()); - if (!selection.empty() && data && data->numargs() - data->optionals() > 0) { + if (!selection.empty() && data && data->numargs()) { macroArg = true; atomAsMacro->setDisplayMode(InsetMathMacro::DISPLAY_INTERACTIVE_INIT, 1); } else @@ -1717,8 +1796,8 @@ bool Cursor::macroModeClose(bool cancel) } // insert remembered selection into first argument of a non-macro - else if (atom.nucleus()->nargs() > 0) - atom.nucleus()->cell(0).append(selection); + else if (atomAsNest && atomAsNest->nargs() > 0) + atomAsNest->cell(atomAsNest->firstIdx()).append(selection); MathWordList const & words = mathedWordList(); MathWordList::const_iterator it = words.find(name); @@ -1770,13 +1849,13 @@ bool Cursor::inMacroMode() const InsetMathUnknown * Cursor::activeMacro() { - return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0; + return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : nullptr; } InsetMathUnknown const * Cursor::activeMacro() const { - return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0; + return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : nullptr; } @@ -1815,7 +1894,7 @@ void Cursor::normalize() << " in atom: '"; odocstringstream os; otexrowstream ots(os); - WriteStream wi(ots, false, true, WriteStream::wsDefault); + TeXMathStream wi(ots, false, true, TeXMathStream::wsDefault); inset().asInsetMath()->write(wi); lyxerr << to_utf8(os.str()) << endl; pos() = lastpos(); @@ -1962,20 +2041,39 @@ bool Cursor::mathForward(bool word) posForward(); while (pos() < lastpos() && mc == nextMath().mathClass()); } else if (openable(nextAtom())) { + InsetMathScript const * n = nextMath().asScriptInset(); + bool to_brace_deco = n && !n->nuc().empty() + && n->nuc().back()->lyxCode() == MATH_DECORATION_CODE + && n->nuc().back()->mathClass() == MC_OP; // single step: try to enter the next inset pushBackward(nextMath()); inset().idxFirst(*this); + // Make sure the cursor moves directly to an + // \overbrace or \underbrace inset (bug 2264) + if (to_brace_deco) { + pushBackward(nextMath()); + inset().idxFirst(*this); + } } else posForward(); return true; } if (inset().idxForward(*this)) return true; + InsetMath const * m = inset().asInsetMath(); + bool from_brace_deco = m + && m->lyxCode() == MATH_DECORATION_CODE + && m->mathClass() == MC_OP; // try to pop forwards --- but don't pop out of math! leave that to // the FINISH lfuns int s = depth() - 2; - if (s >= 0 && operator[](s).inset().asInsetMath()) - return popForward(); + if (s >= 0 && operator[](s).inset().asInsetMath() && popForward()) { + // Make sure the cursor moves directly to an + // \overbrace or \underbrace inset (bug 2264) + bool to_script = inset().asInsetMath() + && inset().asInsetMath()->asScriptInset(); + return from_brace_deco && to_script ? mathForward(word) : true; + } return false; } @@ -1997,21 +2095,41 @@ bool Cursor::mathBackward(bool word) while (pos() > 0 && mc == prevMath().mathClass()); } } else if (openable(prevAtom())) { + InsetMathScript const * p = prevMath().asScriptInset(); + bool to_brace_deco = p && !p->nuc().empty() + && p->nuc().back()->lyxCode() == MATH_DECORATION_CODE + && p->nuc().back()->mathClass() == MC_OP; // single step: try to enter the preceding inset posBackward(); push(nextMath()); inset().idxLast(*this); + // Make sure the cursor moves directly to an + // \overbrace or \underbrace inset (bug 2264) + if (to_brace_deco) { + posBackward(); + push(nextMath()); + inset().idxLast(*this); + } } else posBackward(); return true; } if (inset().idxBackward(*this)) return true; + InsetMath const * m = inset().asInsetMath(); + bool from_brace_deco = m + && m->lyxCode() == MATH_DECORATION_CODE + && m->mathClass() == MC_OP; // try to pop backwards --- but don't pop out of math! leave that to // the FINISH lfuns int s = depth() - 2; - if (s >= 0 && operator[](s).inset().asInsetMath()) - return popBackward(); + if (s >= 0 && operator[](s).inset().asInsetMath() && popBackward()) { + // Make sure the cursor moves directly to an + // \overbrace or \underbrace inset (bug 2264) + bool to_script = inset().asInsetMath() + && inset().asInsetMath()->asScriptInset(); + return from_brace_deco && to_script ? mathBackward(word) : true; + } return false; } @@ -2104,15 +2222,15 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded) // with and without selection are handled differently if (!selection()) { - int yo = bv().getPos(*this).y_; + int yo1 = bv().getPos(*this).y_; Cursor old = *this; // To next/previous row // FIXME: the y position is often guessed wrongly across styles and // insets, which leads to weird behaviour. if (up) - tm.editXY(*this, xo, yo - textRow().ascent() - 1); + tm.editXY(*this, xo, yo1 - textRow().ascent() - 1); else - tm.editXY(*this, xo, yo + textRow().descent() + 1); + tm.editXY(*this, xo, yo1 + textRow().descent() + 1); x_target_ = old.x_target_; clearSelection(); @@ -2140,10 +2258,10 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded) --next_row; } else if (pit() > 0) { --pit(); - TextMetrics & tm = bv_->textMetrics(text()); - if (!tm.contains(pit())) - tm.newParMetricsUp(); - ParagraphMetrics const & pmcur = tm.parMetrics(pit()); + TextMetrics & tm2 = bv_->textMetrics(text()); + if (!tm2.contains(pit())) + tm2.newParMetricsUp(); + ParagraphMetrics const & pmcur = tm2.parMetrics(pit()); next_row = pmcur.rows().size() - 1; } } else { @@ -2151,9 +2269,9 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded) ++next_row; } else if (pit() + 1 < int(text()->paragraphs().size())) { ++pit(); - TextMetrics & tm = bv_->textMetrics(text()); - if (!tm.contains(pit())) - tm.newParMetricsDown(); + TextMetrics & tm2 = bv_->textMetrics(text()); + if (!tm2.contains(pit())) + tm2.newParMetricsDown(); next_row = 0; } } @@ -2231,6 +2349,12 @@ void Cursor::screenUpdateFlags(Update::flags f) const } +void Cursor::noScreenUpdate() const +{ + disp_.screenUpdate(Update::None); +} + + void Cursor::forceBufferUpdate() const { disp_.forceBufferUpdate(); @@ -2249,12 +2373,6 @@ bool Cursor::needBufferUpdate() const } -void Cursor::noScreenUpdate() const -{ - disp_.screenUpdate(Update::None); -} - - Font Cursor::getFont() const { // The logic here should more or less match to the @@ -2334,6 +2452,22 @@ bool notifyCursorLeavesOrEnters(Cursor const & old, Cursor & cur) } +void Cursor::setLanguageFromInput() +{ + if (!lyxrc.respect_os_kbd_language + || !inTexted() + || paragraph().isPassThru()) + return; + string const & code = theApp()->inputLanguageCode(); + Language const * lang = languages.getFromCode(code, buffer()->getLanguages()); + if (lang) { + current_font.setLanguage(lang); + real_current_font.setLanguage(lang); + } else + LYXERR0("setLanguageFromCode: unknown language code " << code); +} + + void Cursor::setCurrentFont() { CursorSlice const & cs = innerTextSlice(); @@ -2367,6 +2501,9 @@ void Cursor::setCurrentFont() current_font = par.getFontSettings(bufparams, cpos); real_current_font = tm.displayFont(cpit, cpos); + // set language to input language + setLanguageFromInput(); + // special case for paragraph end if (cs.pos() == lastpos() && tm.isRTLBoundary(cpit, cs.pos()) @@ -2377,23 +2514,26 @@ void Cursor::setCurrentFont() real_current_font.setLanguage(lang); real_current_font.fontInfo().setNumber(FONT_OFF); } + + // No language in pass thru situations + if (cs.paragraph().isPassThru()) { + current_font.setLanguage(latex_language); + real_current_font.setLanguage(latex_language); + } } void Cursor::checkBufferStructure() { + if (buffer()->isInternal()) + return; + Buffer const * master = buffer()->masterBuffer(); master->tocBackend().updateItem(*this); if (master != buffer() && !master->hasGuiDelegate()) // In case the master has no gui associated with it, // the TocItem is not updated (part of bug 5699). buffer()->tocBackend().updateItem(*this); - - // If the last tracked change of the paragraph has just been - // deleted, then we need to recompute the buffer flag - // tracked_changes_present_. - if (inTexted() && paragraph().isChangeUpdateRequired()) - disp_.forceChangesUpdate(); }