#6401 correct cursor movement for word forward/backward with enabled Mac style (mac_like_cursor_movement)

The change includes a rewrite of the cursor movement when „mac style“ is enabled and don’t change anything otherwise.
The new code for mac uses the document iterator to go forward or backward. The traversal stops at word boundaries.
If going forward the position increments until a word is reached (if not already inside) and stops at the end of the word.
If going backward it does the same in opposite direction. The cursor jumps over non-editable insets and math.
Editable (open) insets are entered and the cursor move detects word boundaries inside them.
This commit is contained in:
Stephan Witt 2020-09-12 14:34:56 +02:00
parent b4f3963ab2
commit 320b6b6656

View File

@ -1146,30 +1146,53 @@ bool Text::cursorForwardOneWord(Cursor & cur)
{
LBUFERR(this == cur.text());
pos_type const lastpos = cur.lastpos();
pit_type pit = cur.pit();
pos_type pos = cur.pos();
Paragraph const & par = cur.paragraph();
// Paragraph boundary is a word boundary
if (pos == lastpos || (pos + 1 == lastpos && par.isEnvSeparator(pos))) {
if (pit != cur.lastpit())
return setCursor(cur, pit + 1, 0);
else
return false;
}
if (lyxrc.mac_like_cursor_movement) {
// Skip through trailing punctuation and spaces.
while (pos != lastpos && (par.isChar(pos) || par.isSpace(pos)))
++pos;
DocIterator dit(cur);
DocIterator prv(cur);
bool inword = false;
bool intext = dit.inTexted();
while (!dit.atEnd()) {
if (dit.inTexted()) { // no paragraphs in mathed
Paragraph const & par = dit.paragraph();
pos_type const pos = dit.pos();
// Skip over either a non-char inset or a full word
if (pos != lastpos && par.isWordSeparator(pos))
++pos;
else while (pos != lastpos && !par.isWordSeparator(pos))
++pos;
if (!par.isDeleted(pos)) {
bool wordsep = par.isWordSeparator(pos);
if (inword && wordsep)
break; // stop at word end
else if (!inword && !wordsep)
inword = true;
}
intext = true;
} else if (intext) {
// move to end of math
while (!dit.inTexted() && !dit.atEnd()) dit.forwardPos();
break;
}
prv = dit;
dit.forwardPosIgnoreCollapsed();
}
if (dit.atEnd()) dit = prv;
if (dit == cur) return false; // we didn't move
Cursor orig(cur);
cur.setCursor(dit);
// see comment above
cur.bv().checkDepm(cur, orig);
return true;
} else {
pos_type const lastpos = cur.lastpos();
pit_type pit = cur.pit();
pos_type pos = cur.pos();
Paragraph const & par = cur.paragraph();
// Paragraph boundary is a word boundary
if (pos == lastpos || (pos + 1 == lastpos && par.isEnvSeparator(pos))) {
if (pit != cur.lastpit())
return setCursor(cur, pit + 1, 0);
else
return false;
}
LASSERT(pos < lastpos, return false); // see above
if (!par.isWordSeparator(pos))
while (pos != lastpos && !par.isWordSeparator(pos))
@ -1183,13 +1206,13 @@ bool Text::cursorForwardOneWord(Cursor & cur)
// Skip over white space
while (pos != lastpos && par.isSpace(pos))
++pos;
// Don't skip a separator inset at the end of a paragraph
if (pos == lastpos && pos && par.isEnvSeparator(pos - 1))
--pos;
return setCursor(cur, pit, pos);
}
// Don't skip a separator inset at the end of a paragraph
if (pos == lastpos && pos && par.isEnvSeparator(pos - 1))
--pos;
return setCursor(cur, pit, pos);
}
@ -1197,34 +1220,55 @@ bool Text::cursorBackwardOneWord(Cursor & cur)
{
LBUFERR(this == cur.text());
pit_type pit = cur.pit();
pos_type pos = cur.pos();
Paragraph & par = cur.paragraph();
// Paragraph boundary is a word boundary
if (pos == 0 && pit != 0) {
Paragraph & prevpar = getPar(pit - 1);
pos = prevpar.size();
// Don't stop after an environment separator
if (pos && prevpar.isEnvSeparator(pos - 1))
--pos;
return setCursor(cur, pit - 1, pos);
}
if (lyxrc.mac_like_cursor_movement) {
// Skip through punctuation and spaces.
while (pos != 0 && (par.isChar(pos - 1) || par.isSpace(pos - 1)))
--pos;
DocIterator dit(cur);
bool inword = false;
bool intext = dit.inTexted();
while (!dit.atBegin()) {
DocIterator prv(dit);
dit.backwardPosIgnoreCollapsed();
if (dit.inTexted()) { // no paragraphs in mathed
Paragraph const & par = dit.paragraph();
pos_type pos = dit.pos();
// Skip over either a non-char inset or a full word
if (pos != 0 && par.isWordSeparator(pos - 1) && !par.isChar(pos - 1))
--pos;
else while (pos != 0 && !par.isWordSeparator(pos - 1))
--pos;
if (!par.isDeleted(pos)) {
bool wordsep = par.isWordSeparator(pos);
if (inword && wordsep) {
dit = prv;
break; // stop at word begin
} else if (!inword && !wordsep)
inword = true;
}
intext = true;
} else if (intext) {
// move to begin of math
while (!dit.inTexted() && !dit.atBegin()) dit.backwardPos();
break;
}
}
if (dit == cur) return false; // we didn't move
Cursor orig(cur);
cur.setCursor(dit);
// see comment above cursorForwardOneWord
cur.bv().checkDepm(cur, orig);
return true;
} else {
Paragraph const & par = cur.paragraph();
pit_type const pit = cur.pit();
pos_type pos = cur.pos();
// Paragraph boundary is a word boundary
if (pos == 0 && pit != 0) {
Paragraph & prevpar = getPar(pit - 1);
pos = prevpar.size();
// Don't stop after an environment separator
if (pos && prevpar.isEnvSeparator(pos - 1))
--pos;
return setCursor(cur, pit - 1, pos);
}
// Skip over white space
while (pos != 0 && par.isSpace(pos - 1))
--pos;
--pos;
if (pos != 0 && !par.isWordSeparator(pos - 1))
while (pos != 0 && !par.isWordSeparator(pos - 1))
@ -1234,9 +1278,9 @@ bool Text::cursorBackwardOneWord(Cursor & cur)
--pos;
else if (pos != 0 && !par.isSpace(pos - 1)) // non-char inset
--pos;
}
return setCursor(cur, pit, pos);
return setCursor(cur, pit, pos);
}
}