New word-movement behaviour in Math

Following discussion on the list:
https://www.mail-archive.com/lyx-users@lists.lyx.org/msg103012.html

This defines a new behaviour for Ctrl[+Shift]+Arrow in math:

* Left/Right does not enter insets

* Left/Right jump groups of insets that have the same math class ("words")

* Enable Up/Down for consistency.
This commit is contained in:
Guillaume Munch 2016-05-27 21:00:54 +01:00
parent f77e5733cf
commit 981f065bde
5 changed files with 125 additions and 72 deletions

View File

@ -1742,6 +1742,77 @@ bool Cursor::upDownInMath(bool up)
}
InsetMath & Cursor::nextMath()
{
return *nextAtom().nucleus();
}
InsetMath & Cursor::prevMath()
{
return *prevAtom().nucleus();
}
bool Cursor::mathForward(bool word)
{
LASSERT(inMathed(), return false);
if (pos() < lastpos()) {
if (word) {
// word: skip a group of insets with same math class
MathClass mc = nextMath().mathClass();
do
posForward();
while (pos() < lastpos() && mc == nextMath().mathClass());
} else if (openable(nextAtom())) {
// single step: try to enter the next inset
pushBackward(nextMath());
inset().idxFirst(*this);
} else
posForward();
return true;
}
if (inset().idxForward(*this))
return true;
// 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();
return false;
}
bool Cursor::mathBackward(bool word)
{
LASSERT(inMathed(), return false);
if (pos() > 0) {
if (word) {
// word: skip a group of insets with same math class
MathClass mc = prevMath().mathClass();
do
posBackward();
while (pos() > 0 && mc == prevMath().mathClass());
} else if (openable(prevAtom())) {
// single step: try to enter the preceding inset
posBackward();
push(nextMath());
inset().idxLast(*this);
} else
posBackward();
return true;
}
if (inset().idxBackward(*this))
return true;
// 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();
return false;
}
bool Cursor::atFirstOrLastRow(bool up)
{
TextMetrics const & tm = bv_->textMetrics(text());

View File

@ -473,6 +473,15 @@ public:
/// return true if successful
bool upDownInMath(bool up);
///
InsetMath & nextMath();
///
InsetMath & prevMath();
/// move forward in math. word: whether to skip a whole "word" (insets with
/// the same mathclass)
bool mathForward(bool word);
///
bool mathBackward(bool word);
///
void plainErase();
///
void plainInsert(MathAtom const & at);

View File

@ -1669,13 +1669,9 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
}
case LFUN_LINE_BEGIN:
case LFUN_WORD_BACKWARD:
case LFUN_WORD_LEFT:
cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
// fall through
case LFUN_LINE_BEGIN_SELECT:
case LFUN_WORD_BACKWARD_SELECT:
case LFUN_WORD_LEFT_SELECT:
cur.selHandle(act == LFUN_WORD_BACKWARD_SELECT ||
act == LFUN_WORD_LEFT_SELECT ||
act == LFUN_LINE_BEGIN_SELECT);
@ -1694,13 +1690,9 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
}
break;
case LFUN_WORD_FORWARD:
case LFUN_WORD_RIGHT:
case LFUN_LINE_END:
cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
// fall through
case LFUN_WORD_FORWARD_SELECT:
case LFUN_WORD_RIGHT_SELECT:
case LFUN_LINE_END_SELECT:
cur.selHandle(act == LFUN_WORD_FORWARD_SELECT ||
act == LFUN_WORD_RIGHT_SELECT ||

View File

@ -642,21 +642,42 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
cur.bv().cursor() = cur;
break;
case LFUN_WORD_RIGHT:
case LFUN_WORD_LEFT:
case LFUN_WORD_BACKWARD:
case LFUN_WORD_FORWARD:
case LFUN_CHAR_RIGHT:
case LFUN_CHAR_LEFT:
case LFUN_CHAR_BACKWARD:
case LFUN_CHAR_FORWARD:
cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
// fall through
case LFUN_WORD_RIGHT_SELECT:
case LFUN_WORD_LEFT_SELECT:
case LFUN_WORD_BACKWARD_SELECT:
case LFUN_WORD_FORWARD_SELECT:
case LFUN_CHAR_RIGHT_SELECT:
case LFUN_CHAR_LEFT_SELECT:
case LFUN_CHAR_BACKWARD_SELECT:
case LFUN_CHAR_FORWARD_SELECT: {
// are we in a selection?
bool select = (act == LFUN_CHAR_RIGHT_SELECT
bool select = (act == LFUN_WORD_RIGHT_SELECT
|| act == LFUN_WORD_LEFT_SELECT
|| act == LFUN_WORD_BACKWARD_SELECT
|| act == LFUN_WORD_FORWARD_SELECT
|| act == LFUN_CHAR_RIGHT_SELECT
|| act == LFUN_CHAR_LEFT_SELECT
|| act == LFUN_CHAR_BACKWARD_SELECT
|| act == LFUN_CHAR_FORWARD_SELECT);
// select words
bool word = (act == LFUN_WORD_RIGHT_SELECT
|| act == LFUN_WORD_LEFT_SELECT
|| act == LFUN_WORD_BACKWARD_SELECT
|| act == LFUN_WORD_FORWARD_SELECT
|| act == LFUN_WORD_RIGHT
|| act == LFUN_WORD_LEFT
|| act == LFUN_WORD_BACKWARD
|| act == LFUN_WORD_FORWARD);
// are we moving forward or backwards?
// If the command was RIGHT or LEFT, then whether we're moving forward
// or backwards depends on the cursor movement mode (logical or visual):
@ -669,18 +690,24 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
FuncCode finish_lfun;
if (act == LFUN_CHAR_FORWARD
|| act == LFUN_CHAR_FORWARD_SELECT) {
|| act == LFUN_CHAR_FORWARD_SELECT
|| act == LFUN_WORD_FORWARD
|| act == LFUN_WORD_FORWARD_SELECT) {
forward = true;
finish_lfun = LFUN_FINISHED_FORWARD;
}
else if (act == LFUN_CHAR_BACKWARD
|| act == LFUN_CHAR_BACKWARD_SELECT) {
|| act == LFUN_CHAR_BACKWARD_SELECT
|| act == LFUN_WORD_BACKWARD
|| act == LFUN_WORD_BACKWARD_SELECT) {
forward = false;
finish_lfun = LFUN_FINISHED_BACKWARD;
}
else {
bool right = (act == LFUN_CHAR_RIGHT_SELECT
|| act == LFUN_CHAR_RIGHT);
|| act == LFUN_CHAR_RIGHT
|| act == LFUN_WORD_RIGHT_SELECT
|| act == LFUN_WORD_RIGHT);
if (lyxrc.visual_cursor || !cur.reverseDirectionNeeded())
forward = right;
else
@ -696,7 +723,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
cur.clearTargetX();
cur.macroModeClose();
// try moving forward or backwards as necessary...
if (!(forward ? cursorMathForward(cur) : cursorMathBackward(cur))) {
if (!(forward ? cur.mathForward(word) : cur.mathBackward(word))) {
// ... and if movement failed, then finish forward or backwards
// as necessary
cmd = FuncRequest(finish_lfun);
@ -707,10 +734,14 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_DOWN:
case LFUN_UP:
case LFUN_PARAGRAPH_UP:
case LFUN_PARAGRAPH_DOWN:
cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
// fall through
case LFUN_DOWN_SELECT:
case LFUN_UP_SELECT: {
case LFUN_UP_SELECT:
case LFUN_PARAGRAPH_UP_SELECT:
case LFUN_PARAGRAPH_DOWN_SELECT: {
// close active macro
if (cur.inMacroMode()) {
cur.macroModeClose();
@ -718,8 +749,10 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
}
// stop/start the selection
bool select = act == LFUN_DOWN_SELECT ||
act == LFUN_UP_SELECT;
bool select = act == LFUN_DOWN_SELECT
|| act == LFUN_UP_SELECT
|| act == LFUN_PARAGRAPH_DOWN_SELECT
|| act == LFUN_PARAGRAPH_UP_SELECT;
cur.selHandle(select);
// handle autocorrect:
@ -729,7 +762,8 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
}
// go up/down
bool up = act == LFUN_UP || act == LFUN_UP_SELECT;
bool up = act == LFUN_UP || act == LFUN_UP_SELECT
|| act == LFUN_PARAGRAPH_UP || act == LFUN_PARAGRAPH_UP_SELECT;
bool successful = cur.upDownInMath(up);
if (successful)
break;
@ -763,22 +797,10 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
cur.bv().cursor() = cur;
break;
case LFUN_PARAGRAPH_UP:
case LFUN_PARAGRAPH_DOWN:
cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
// fall through
case LFUN_PARAGRAPH_UP_SELECT:
case LFUN_PARAGRAPH_DOWN_SELECT:
break;
case LFUN_LINE_BEGIN:
case LFUN_WORD_BACKWARD:
case LFUN_WORD_LEFT:
cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
// fall through
case LFUN_LINE_BEGIN_SELECT:
case LFUN_WORD_BACKWARD_SELECT:
case LFUN_WORD_LEFT_SELECT:
cur.selHandle(act == LFUN_WORD_BACKWARD_SELECT ||
act == LFUN_WORD_LEFT_SELECT ||
act == LFUN_LINE_BEGIN_SELECT);
@ -797,13 +819,9 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
}
break;
case LFUN_WORD_FORWARD:
case LFUN_WORD_RIGHT:
case LFUN_LINE_END:
cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
// fall through
case LFUN_WORD_FORWARD_SELECT:
case LFUN_WORD_RIGHT_SELECT:
case LFUN_LINE_END_SELECT:
cur.selHandle(act == LFUN_WORD_FORWARD_SELECT ||
act == LFUN_WORD_RIGHT_SELECT ||
@ -2083,43 +2101,6 @@ void InsetMathNest::completionPosAndDim(Cursor const & cur, int & x, int & y,
}
bool InsetMathNest::cursorMathForward(Cursor & cur)
{
if (cur.pos() != cur.lastpos() && cur.openable(cur.nextAtom())) {
cur.pushBackward(*cur.nextAtom().nucleus());
cur.inset().idxFirst(cur);
return true;
}
if (cur.posForward() || idxForward(cur))
return true;
// try to pop forwards --- but don't pop out of math! leave that to
// the FINISH lfuns
int s = cur.depth() - 2;
if (s >= 0 && cur[s].inset().asInsetMath())
return cur.popForward();
return false;
}
bool InsetMathNest::cursorMathBackward(Cursor & cur)
{
if (cur.pos() != 0 && cur.openable(cur.prevAtom())) {
cur.posBackward();
cur.push(*cur.nextAtom().nucleus());
cur.inset().idxLast(cur);
return true;
}
if (cur.posBackward() || idxBackward(cur))
return true;
// try to pop backwards --- but don't pop out of math! leave that to
// the FINISH lfuns
int s = cur.depth() - 2;
if (s >= 0 && cur[s].inset().asInsetMath())
return cur.popBackward();
return false;
}
////////////////////////////////////////////////////////////////////
MathCompletionList::MathCompletionList(Cursor const & cur)

View File

@ -191,9 +191,9 @@ private:
/// afterwards if found
bool findMacroToFoldUnfold(Cursor & searchCur, bool fold) const;
/// move cursor forward
bool cursorMathForward(Cursor & cur);
bool cursorMathForward(Cursor & cur, bool enter = true);
/// move cursor backwards
bool cursorMathBackward(Cursor & cur);
bool cursorMathBackward(Cursor & cur, bool enter = true);
protected:
/// we store the cells in a vector