]> git.lyx.org Git - features.git/commitdiff
#6401 correct cursor movement for word forward/backward with enabled Mac style (mac_l...
authorStephan Witt <switt@lyx.org>
Sat, 12 Sep 2020 12:34:56 +0000 (14:34 +0200)
committerStephan Witt <switt@lyx.org>
Sat, 12 Sep 2020 12:34:56 +0000 (14:34 +0200)
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.

src/Text.cpp

index 59bfbefea968595471fa16d1209be8f64a7e3bc9..575eea62b01c7fc96b5d6e71ad3fc6cf7469ad8d 100644 (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;
-
-               // 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;
+               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();
+
+                               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;
+               // 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);
+               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;
-
-               // 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;
+               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();
+
+                               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);
+       }
 }