#include "DispatchResult.h"
#include "Encoding.h"
#include "Font.h"
+#include "FuncCode.h"
#include "FuncRequest.h"
#include "Language.h"
-#include "lfuns.h"
#include "LyXFunc.h" // only for setMessage()
#include "LyXRC.h"
#include "paragraph_funcs.h"
#include "TextMetrics.h"
#include "TocBackend.h"
+#include "support/assert.h"
#include "support/debug.h"
#include "support/docstream.h"
#include "insets/InsetText.h"
#include "mathed/InsetMath.h"
+#include "mathed/InsetMathBrace.h"
#include "mathed/InsetMathScript.h"
#include "mathed/MacroTable.h"
#include "mathed/MathData.h"
#include "mathed/MathMacro.h"
-#include <boost/assert.hpp>
#include <boost/bind.hpp>
#include <sstream>
bool bruteFind(Cursor & cursor,
int x, int y, int xlow, int xhigh, int ylow, int yhigh)
{
- BOOST_ASSERT(!cursor.empty());
+ LASSERT(!cursor.empty(), return false);
Inset & inset = cursor[0].inset();
BufferView & bv = cursor.bv();
// store some values to be used inside of the handlers
beforeDispatchCursor_ = *this;
- for (; depth(); pop()) {
+ for (; depth(); pop(), boundary(false)) {
LYXERR(Debug::DEBUG, "Cursor::dispatch: cmd: "
<< cmd0 << endl << *this);
- BOOST_ASSERT(pos() <= lastpos());
- BOOST_ASSERT(idx() <= lastidx());
- BOOST_ASSERT(pit() <= lastpit());
+ LASSERT(pos() <= lastpos(), /**/);
+ LASSERT(idx() <= lastidx(), /**/);
+ LASSERT(pit() <= lastpit(), /**/);
// The common case is 'LFUN handled, need update', so make the
// LFUN handler's life easier by assuming this as default value.
BufferView & Cursor::bv() const
{
- BOOST_ASSERT(bv_);
+ LASSERT(bv_, /**/);
return *bv_;
}
Buffer & Cursor::buffer() const
{
- BOOST_ASSERT(bv_);
+ LASSERT(bv_, /**/);
return bv_->buffer();
}
void Cursor::pop()
{
- BOOST_ASSERT(depth() >= 1);
+ LASSERT(depth() >= 1, /**/);
pop_back();
}
void Cursor::push(Inset & p)
{
push_back(CursorSlice(p));
+ p.setBuffer(bv_->buffer());
}
void Cursor::pushBackward(Inset & p)
{
- BOOST_ASSERT(!empty());
+ LASSERT(!empty(), /**/);
//lyxerr << "Entering inset " << t << " front" << endl;
push(p);
p.idxFirst(*this);
bool Cursor::popBackward()
{
- BOOST_ASSERT(!empty());
+ LASSERT(!empty(), /**/);
if (depth() == 1)
return false;
pop();
bool Cursor::popForward()
{
- BOOST_ASSERT(!empty());
+ LASSERT(!empty(), /**/);
//lyxerr << "Leaving inset from in back" << endl;
const pos_type lp = (depth() > 1) ? (*this)[depth() - 2].lastpos() : 0;
if (depth() == 1)
int Cursor::currentMode()
{
- BOOST_ASSERT(!empty());
+ LASSERT(!empty(), /**/);
for (int i = depth() - 1; i >= 0; --i) {
int res = operator[](i).inset().currentMode();
if (res != Inset::UNDECIDED_MODE)
{
CursorSlice const & cs = innerTextSlice();
ParagraphMetrics const & pm = bv().parMetrics(cs.text(), cs.pit());
- BOOST_ASSERT(!pm.rows().empty());
+ LASSERT(!pm.rows().empty(), /**/);
return pm.getRow(pos(), boundary());
}
Buffer const & buf = buffer();
Row const & row = textRow();
bool par_is_LTR = !par.isRTL(buf.params());
+
+ // Inside a table, determining whether to move to the next or previous row
+ // should be done based on the table's direction.
+ int s = depth() - 1;
+ if (s >= 1 && (*this)[s].inset().asInsetTabular()) {
+ par_is_LTR = !(*this)[s].inset().asInsetTabular()->isRightToLeft(*this);
+ LYXERR(Debug::RTL, "Inside table! par_is_LTR=" << (par_is_LTR ? 1 : 0));
+ }
// if moving left in an LTR paragraph or moving right in an RTL one,
// move to previous row
CursorSlice Cursor::anchor() const
{
- BOOST_ASSERT(anchor_.depth() >= depth());
+ LASSERT(anchor_.depth() >= depth(), /**/);
CursorSlice normal = anchor_[depth() - 1];
if (depth() < anchor_.depth() && top() <= normal) {
// anchor is behind cursor -> move anchor behind the inset
{
cell().insert(pos(), t);
++pos();
+ inset().setBuffer(bv_->buffer());
+ inset().initView();
}
void Cursor::insert(char_type c)
{
//lyxerr << "Cursor::insert char '" << c << "'" << endl;
- BOOST_ASSERT(!empty());
+ LASSERT(!empty(), /**/);
if (inMathed()) {
cap::selClearOrDel(*this);
insert(new InsetMathChar(c));
}
-void Cursor::insert(Inset * inset)
+void Cursor::insert(Inset * inset0)
{
+ LASSERT(inset0, /**/);
if (inMathed())
- insert(MathAtom(inset));
- else
- text()->insertInset(*this, inset);
+ insert(MathAtom(inset0));
+ else {
+ text()->insertInset(*this, inset0);
+ inset0->setBuffer(bv_->buffer());
+ inset0->initView();
+ }
}
return false;
InsetMathUnknown * p = activeMacro();
p->finalize();
+ MathData selection;
+ asArray(p->selection(), selection);
docstring const s = p->name();
--pos();
cell().erase(pos());
if (in && in->interpretString(*this, s))
return true;
MathAtom atom = createInsetMath(name);
+
+ // try to put argument into macro, if we just inserted a macro
+ bool macroArg = false;
MathMacro * atomAsMacro = atom.nucleus()->asMacro();
if (atomAsMacro) {
- // make non-greedy, i.e. don't eat parameters from the right
- atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT);
+ // 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.size() > 0 && data && data->numargs() - data->optionals() > 0) {
+ macroArg = true;
+ atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT, 1);
+ } else
+ // non-greedy case. Do not touch the arguments behind
+ atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT, 0);
}
+
+ // insert remembered selection into first argument of a non-macro
+ else if (atom.nucleus()->nargs() > 0)
+ atom.nucleus()->cell(0).append(selection);
+
plainInsert(atom);
+
+ // finally put the macro argument behind, if needed
+ if (macroArg) {
+ if (selection.size() > 1)
+ plainInsert(MathAtom(new InsetMathBrace(selection)));
+ else
+ insert(selection);
+ }
+
return true;
}
bool Cursor::upDownInText(bool up, bool & updateNeeded)
{
- BOOST_ASSERT(text());
+ LASSERT(text(), /**/);
// where are we?
int xo = 0;
if (pit() + 1 >= int(text()->paragraphs().size()) &&
row + 1 >= int(pm.rows().size()))
return false;
- }
+ }
// with and without selection are handled differently
if (!selection()) {
top().pos() = min(tm.x2pos(pit(), row - 1, xo), top().lastpos());
} else if (pit() > 0) {
--pit();
- ParagraphMetrics const & pmcur = bv_->parMetrics(text(), pit());
+ TextMetrics & tm = bv_->textMetrics(text());
+ if (!tm.contains(pit()))
+ tm.newParMetricsUp();
+ ParagraphMetrics const & pmcur = tm.parMetrics(pit());
top().pos() = min(tm.x2pos(pit(), pmcur.rows().size() - 1, xo), top().lastpos());
}
} else {
top().pos() = min(tm.x2pos(pit(), row + 1, xo), top().lastpos());
} else if (pit() + 1 < int(text()->paragraphs().size())) {
++pit();
+ TextMetrics & tm = bv_->textMetrics(text());
+ if (!tm.contains(pit()))
+ tm.newParMetricsDown();
top().pos() = min(tm.x2pos(pit(), 0, xo), top().lastpos());
}
}
return docstring();
if (inTexted()) {
- Buffer const & buffer = bv().buffer();
ParagraphList const & pars = text()->paragraphs();
// should be const ...
size_t const endpos = selEnd().pos();
if (startpit == endpit)
- return pars[startpit].asString(buffer, startpos, endpos, label);
+ return pars[startpit].asString(startpos, endpos, label);
// First paragraph in selection
docstring result = pars[startpit].
- asString(buffer, startpos, pars[startpit].size(), label)
+ asString(startpos, pars[startpit].size(), label)
+ parbreak(pars[startpit]);
// The paragraphs in between (if any)
for (pit_type pit = startpit + 1; pit != endpit; ++pit) {
Paragraph const & par = pars[pit];
- result += par.asString(buffer, 0, par.size(), label)
+ result += par.asString(0, par.size(), label)
+ parbreak(pars[pit]);
}
// Last paragraph in selection
- result += pars[endpit].asString(buffer, 0, endpos, label);
+ result += pars[endpit].asString(0, endpos, label);
return result;
}
if (&old[i].inset() != &cur[i].inset())
break;
}
+
+ // update words if we just moved to another paragraph
+ if (i == old.depth() && i == cur.depth()
+ && !cur.buffer().isClean()
+ && cur.inTexted() && old.inTexted()
+ && cur.pit() != old.pit()) {
+ old.paragraph().updateWords(old.top());
+ return false;
+ }
// notify everything on top of the common part in old cursor,
// but stop if the inset claims the cursor to be invalid now
// get font
BufferParams const & bufparams = buffer().params();
current_font = par.getFontSettings(bufparams, cpos);
- real_current_font = tm.getDisplayFont(cpit, cpos);
+ real_current_font = tm.displayFont(cpit, cpos);
// special case for paragraph end
if (cs.pos() == lastpos()
void Cursor::recordUndoSelection()
{
- bv_->buffer().undo().recordUndo(*this, ATOMIC_UNDO,
- selBegin().pit(), selEnd().pit());
+ if (inMathed()) {
+ if (cap::multipleCellsSelected(*this))
+ recordUndoInset();
+ else
+ recordUndo();
+ } else
+ bv_->buffer().undo().recordUndo(*this, ATOMIC_UNDO,
+ selBegin().pit(), selEnd().pit());
}
void Cursor::checkBufferStructure()
{
- if (paragraph().layout()->toclevel == Layout::NOT_IN_TOC)
+ if (paragraph().layout().toclevel == Layout::NOT_IN_TOC)
return;
Buffer const * master = buffer().masterBuffer();
master->tocBackend().updateItem(ParConstIterator(*this));