()
| 578 | } |
| 579 | |
| 580 | endOfWord(): Cursor { |
| 581 | if (this.isAtEnd()) { |
| 582 | return this |
| 583 | } |
| 584 | |
| 585 | // Use Intl.Segmenter for proper word boundary detection (including CJK) |
| 586 | const wordBoundaries = this.measuredText.getWordBoundaries() |
| 587 | |
| 588 | // Find the current word boundary we're in |
| 589 | for (const boundary of wordBoundaries) { |
| 590 | if (!boundary.isWordLike) continue |
| 591 | |
| 592 | // If we're inside this word but NOT at the last character |
| 593 | if (this.offset >= boundary.start && this.offset < boundary.end - 1) { |
| 594 | // Move to end of this word (last character position) |
| 595 | return new Cursor(this.measuredText, boundary.end - 1) |
| 596 | } |
| 597 | |
| 598 | // If we're at the last character of a word (end - 1), find the next word's end |
| 599 | if (this.offset === boundary.end - 1) { |
| 600 | // Find next word |
| 601 | for (const nextBoundary of wordBoundaries) { |
| 602 | if (nextBoundary.isWordLike && nextBoundary.start > this.offset) { |
| 603 | return new Cursor(this.measuredText, nextBoundary.end - 1) |
| 604 | } |
| 605 | } |
| 606 | return this |
| 607 | } |
| 608 | } |
| 609 | |
| 610 | // If not in a word, find the next word and go to its end |
| 611 | for (const boundary of wordBoundaries) { |
| 612 | if (boundary.isWordLike && boundary.start > this.offset) { |
| 613 | return new Cursor(this.measuredText, boundary.end - 1) |
| 614 | } |
| 615 | } |
| 616 | |
| 617 | return this |
| 618 | } |
| 619 | |
| 620 | prevWord(): Cursor { |
| 621 | if (this.isAtStart()) { |
nothing calls this directly
no test coverage detected