#include <config.h>
+#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"
#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"
#include "mathed/MathFactory.h"
#include "mathed/InsetMathMacro.h"
+#include "frontends/Application.h"
+
#include <sstream>
#include <limits>
#include <map>
CursorData::CursorData()
: DocIterator(), anchor_(), selection_(false), mark_(false),
- word_selection_(false), current_font(inherit_font), autocorrect_(false)
+ word_selection_(false), current_font(inherit_font)
{}
CursorData::CursorData(Buffer * buffer)
: DocIterator(buffer), anchor_(), selection_(false), mark_(false),
- word_selection_(false), current_font(inherit_font), autocorrect_(false)
+ word_selection_(false), current_font(inherit_font)
{}
CursorData::CursorData(DocIterator const & dit)
: DocIterator(dit), anchor_(), selection_(false), mark_(false),
- word_selection_(false), current_font(inherit_font), autocorrect_(false)
+ word_selection_(false), current_font(inherit_font)
{}
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
}
-docstring CursorData::selectionAsString(bool with_label) const
+docstring CursorData::selectionAsString(bool const with_label, bool const skipdelete) const
{
if (!selection())
return docstring();
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();
{
if (!lyxrc.spellcheck_continuously || new_word_.empty())
return ;
- if (!inTexted())
- clearNewWordPosition();
- else {
- // forget the position of the current new word if
- // 1) the paragraph changes or
- // 2) the count of nested insets changes or
- // 3) the cursor pos is out of paragraph bound
- if (pit() != new_word_.pit() ||
- depth() != new_word_.depth() ||
- new_word_.pos() > new_word_.lastpos()) {
+ // forget the position of the current new word if
+ // 1) or the remembered position was "broken"
+ // 2) or the count of nested insets changed
+ // 3) the top-level inset is not the same anymore
+ // 4) the cell index changed
+ // 5) or the paragraph changed
+ // 6) or the cursor pos is out of paragraph bound
+ if (new_word_.fixIfBroken()
+ || depth() != new_word_.depth()
+ || &inset() != &new_word_.inset()
+ || pit() != new_word_.pit()
+ || idx() != new_word_.idx()
+ || new_word_.pos() > new_word_.lastpos())
clearNewWordPosition();
- } else if (new_word_.fixIfBroken())
- // 4) or the remembered position was "broken"
- clearNewWordPosition();
- else {
- FontSpan nw = locateWord(WHOLE_WORD);
- if (!nw.empty()) {
- FontSpan ow = new_word_.locateWord(WHOLE_WORD);
- if (nw.intersect(ow).empty())
- clearNewWordPosition();
- else
- LYXERR(Debug::DEBUG, "new word: "
- << " par: " << pit()
- << " pos: " << nw.first << ".." << nw.last);
- } else {
+ else {
+ FontSpan nw = locateWord(WHOLE_WORD);
+ if (!nw.empty()) {
+ FontSpan ow = new_word_.locateWord(WHOLE_WORD);
+ if (nw.intersect(ow).empty())
clearNewWordPosition();
- }
- }
+ else
+ LYXERR(Debug::DEBUG, "new word: "
+ << " par: " << pit()
+ << " pos: " << nw.first << ".." << nw.last);
+ } else
+ clearNewWordPosition();
}
}
}
+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();
void CursorData::sanitize()
{
DocIterator::sanitize();
+ new_word_.sanitize();
if (selection())
anchor_.sanitize();
else
}
-bool CursorData::isInside(Inset const * p) const
-{
- 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()
+bool CursorData::undoAction()
{
- 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;
}
+void CursorData::splitUndoGroup() const
+{
+ buffer()->undo().splitUndoGroup(*this);
+}
+
+
void CursorData::recordUndo(pit_type from, pit_type to) const
{
buffer()->undo().recordUndo(*this, from, to);
}
-void CursorData::recordUndoInset(Inset const * in) const
+void CursorData::recordUndoInset(Inset const * inset) const
{
- buffer()->undo().recordUndoInset(*this, in);
+ buffer()->undo().recordUndoInset(*this, inset);
}
}
-int CursorData::currentMode()
+int CursorData::currentMode() const
{
LASSERT(!empty(), return Inset::UNDECIDED_MODE);
for (int i = depth() - 1; i >= 0; --i) {
}
-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();
+ }
}
}
-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;
}
///////////////////////////////////////////////////////////////////
#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"
return true;
// we can't move into anything new during selection
- if (depth() >= anchor_.depth())
+ if (depth() >= realAnchor().depth())
return false;
- if (t.nucleus() != &anchor_[depth()].inset())
+ if (t.nucleus() != &realAnchor()[depth()].inset())
return false;
return true;
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);
}
-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;
MathAtom t = a;
- asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c));
+ asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(idx));
insert(t);
- posBackward();
- pushBackward(*nextInset());
+ editInsertedInset();
}
}
-bool Cursor::macroModeClose()
+bool Cursor::macroModeClose(bool cancel)
{
if (!inMacroMode())
return false;
--pos();
cell().erase(pos());
- // do nothing if the macro name is empty
- if (s == "\\")
- 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))
// 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
}
// 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);
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;
}
<< " 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();
// 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();
--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 {
++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;
}
}
}
+void Cursor::noScreenUpdate() const
+{
+ disp_.screenUpdate(Update::None);
+}
+
+
void Cursor::forceBufferUpdate() const
{
disp_.forceBufferUpdate();
}
-void Cursor::noScreenUpdate() const
-{
- disp_.screenUpdate(Update::None);
-}
-
-
Font Cursor::getFont() const
{
// The logic here should more or less match to the
void Cursor::sanitize()
{
- setBuffer(buffer());
+ setBuffer(&bv_->buffer());
CursorData::sanitize();
- new_word_.sanitize();
}
}
+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();
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())
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);
+ }
}
// 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();
}