Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6952b83 authored by Roozbeh Pournader's avatar Roozbeh Pournader
Browse files

Expand characters temporarily skipped in spellchecking

An earlier patch (I4d09576a31df551c96f820242fd2cbc675506dae)
special-cased apostrophe as a character to defer spellchecking on,
since it could cause a word break which could later get removed.

This patch updates that earlier patch to include all characters that
could cause such a behavior according the Unicode word breaking
algorithm defined in UAX #29.

Bug: 17641350
Bug: 17673522
Test: manual
Change-Id: I4029e3d91dfcf96665b003f6fdd30d1208b0ac7c
parent 23e0fd6c
Loading
Loading
Loading
Loading
+30 −7
Original line number Original line Diff line number Diff line
@@ -17,6 +17,8 @@
package android.text.method;
package android.text.method;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.icu.lang.UCharacter;
import android.icu.lang.UProperty;
import android.icu.text.BreakIterator;
import android.icu.text.BreakIterator;
import android.text.CharSequenceCharacterIterator;
import android.text.CharSequenceCharacterIterator;
import android.text.Selection;
import android.text.Selection;
@@ -321,6 +323,27 @@ public class WordIterator implements Selection.PositionIterator {
        return false;
        return false;
    }
    }


    /**
     * Indicates if the codepoint is a mid-word-only punctuation.
     *
     * At the moment, this is locale-independent, and includes all the characters in
     * the MidLetter, MidNumLet, and Single_Quote class of Unicode word breaking algorithm (see
     * UAX #29 "Unicode Text Segmentation" at http://unicode.org/reports/tr29/). These are all the
     * characters that according to the rules WB6 and WB7 of UAX #29 prevent word breaks if they are
     * in the middle of a word, but they become word breaks if they happen at the end of a word
     * (accroding to rule WB999 that breaks word in any place that is not prohibited otherwise).
     *
     * @param locale the locale to consider the codepoint in. Presently ignored.
     * @param codePoint the codepoint to check.
     * @return True if the codepoint is a mid-word punctuation.
     */
    public static boolean isMidWordPunctuation(Locale locale, int codePoint) {
        final int wb = UCharacter.getIntPropertyValue(codePoint, UProperty.WORD_BREAK);
        return (wb == UCharacter.WordBreak.MIDLETTER
                || wb == UCharacter.WordBreak.MIDNUMLET
                || wb == UCharacter.WordBreak.SINGLE_QUOTE);
    }

    private boolean isPunctuationStartBoundary(int offset) {
    private boolean isPunctuationStartBoundary(int offset) {
        return isOnPunctuation(offset) && !isAfterPunctuation(offset);
        return isOnPunctuation(offset) && !isAfterPunctuation(offset);
    }
    }
@@ -331,13 +354,13 @@ public class WordIterator implements Selection.PositionIterator {


    private static boolean isPunctuation(int cp) {
    private static boolean isPunctuation(int cp) {
        final int type = Character.getType(cp);
        final int type = Character.getType(cp);
        return (type == Character.CONNECTOR_PUNCTUATION ||
        return (type == Character.CONNECTOR_PUNCTUATION
                type == Character.DASH_PUNCTUATION ||
                || type == Character.DASH_PUNCTUATION
                type == Character.END_PUNCTUATION ||
                || type == Character.END_PUNCTUATION
                type == Character.FINAL_QUOTE_PUNCTUATION ||
                || type == Character.FINAL_QUOTE_PUNCTUATION
                type == Character.INITIAL_QUOTE_PUNCTUATION ||
                || type == Character.INITIAL_QUOTE_PUNCTUATION
                type == Character.OTHER_PUNCTUATION ||
                || type == Character.OTHER_PUNCTUATION
                type == Character.START_PUNCTUATION);
                || type == Character.START_PUNCTUATION);
    }
    }


    private boolean isAfterLetterOrDigit(int offset) {
    private boolean isAfterLetterOrDigit(int offset) {
+9 −8
Original line number Original line Diff line number Diff line
@@ -277,18 +277,19 @@ public class SpellChecker implements SpellCheckerSessionListener {
            // Do not check this word if the user is currently editing it
            // Do not check this word if the user is currently editing it
            final boolean isEditing;
            final boolean isEditing;


            // Defer spell check when typing a word with an interior apostrophe.
            // Defer spell check when typing a word ending with a punctuation like an apostrophe
            // TODO: a better solution to this would be to make the word
            // which could end up being a mid-word punctuation.
            // iterator locale-sensitive and include the apostrophe in
            if (selectionStart == end + 1
            // languages that use it (such as English).
                    && WordIterator.isMidWordPunctuation(
            final boolean apostrophe = (selectionStart == end + 1 && editable.charAt(end) == '\'');
                            mCurrentLocale, Character.codePointBefore(editable, end + 1))) {
            if (mIsSentenceSpellCheckSupported) {
                isEditing = false;
            } else if (mIsSentenceSpellCheckSupported) {
                // Allow the overlap of the cursor and the first boundary of the spell check span
                // Allow the overlap of the cursor and the first boundary of the spell check span
                // no to skip the spell check of the following word because the
                // no to skip the spell check of the following word because the
                // following word will never be spell-checked even if the user finishes composing
                // following word will never be spell-checked even if the user finishes composing
                isEditing = !apostrophe && (selectionEnd <= start || selectionStart > end);
                isEditing = selectionEnd <= start || selectionStart > end;
            } else {
            } else {
                isEditing = !apostrophe && (selectionEnd < start || selectionStart > end);
                isEditing = selectionEnd < start || selectionStart > end;
            }
            }
            if (start >= 0 && end > start && isEditing) {
            if (start >= 0 && end > start && isEditing) {
                spellCheckSpan.setSpellCheckInProgress(true);
                spellCheckSpan.setSpellCheckInProgress(true);