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

Commit c7ef305b authored by Jean Chalard's avatar Jean Chalard
Browse files

Try to figure out whether d.quotes open or close.

Bug: 8911672
Change-Id: I5d5635949530a67f95e5208986907251b7bce903
parent 963d97af
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -814,6 +814,17 @@ public final class RichInputConnection {
        return StringUtils.lastPartLooksLikeURL(mCommittedTextBeforeComposingText);
    }

    /**
     * Looks at the text just before the cursor to find out if we are inside a double quote.
     *
     * As with #textBeforeCursorLooksLikeURL, this is dependent on how much text we have cached.
     * However this won't be a concrete problem in most situations, as the cache is almost always
     * long enough for this use.
     */
    public boolean isInsideDoubleQuoteOrAfterDigit() {
        return StringUtils.isInsideDoubleQuoteOrAfterDigit(mCommittedTextBeforeComposingText);
    }

    /**
     * Try to get the text from the editor to expose lies the framework may have been
     * telling us. Concretely, when the device rotates, the frameworks tells us about where the
+21 −5
Original line number Diff line number Diff line
@@ -602,8 +602,21 @@ public final class InputLogic {
        final boolean swapWeakSpace = maybeStripSpace(settingsValues, codePoint, spaceState,
                isFromSuggestionStrip);

        if (SpaceState.PHANTOM == spaceState &&
                settingsValues.isUsuallyPrecededBySpace(codePoint)) {
        final boolean isInsideDoubleQuoteOrAfterDigit = Constants.CODE_DOUBLE_QUOTE == codePoint
                && mConnection.isInsideDoubleQuoteOrAfterDigit();

        final boolean needsPrecedingSpace;
        if (SpaceState.PHANTOM != spaceState) {
            needsPrecedingSpace = false;
        } else if (Constants.CODE_DOUBLE_QUOTE == codePoint) {
            // Double quotes behave like they are usually preceded by space iff we are
            // not inside a double quote or after a digit.
            needsPrecedingSpace = !isInsideDoubleQuoteOrAfterDigit;
        } else {
            needsPrecedingSpace = settingsValues.isUsuallyPrecededBySpace(codePoint);
        }

        if (needsPrecedingSpace) {
            promotePhantomSpace(settingsValues);
        }
        if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
@@ -630,14 +643,17 @@ public final class InputLogic {
            if (swapWeakSpace) {
                swapSwapperAndSpace(keyboardSwitcher);
                mSpaceState = SpaceState.SWAP_PUNCTUATION;
            } else if (SpaceState.PHANTOM == spaceState
                    && settingsValues.isUsuallyFollowedBySpace(codePoint)) {
            } else if ((SpaceState.PHANTOM == spaceState
                    && settingsValues.isUsuallyFollowedBySpace(codePoint))
                    || (Constants.CODE_DOUBLE_QUOTE == codePoint
                            && isInsideDoubleQuoteOrAfterDigit)) {
                // If we are in phantom space state, and the user presses a separator, we want to
                // stay in phantom space state so that the next keypress has a chance to add the
                // space. For example, if I type "Good dat", pick "day" from the suggestion strip
                // then insert a comma and go on to typing the next word, I want the space to be
                // inserted automatically before the next word, the same way it is when I don't
                // input the comma.
                // input the comma. A double quote behaves like it's usually followed by space if
                // we're inside a double quote.
                // The case is a little different if the separator is a space stripper. Such a
                // separator does not normally need a space on the right (that's the difference
                // between swappers and strippers), so we should not stay in phantom space state if
+43 −1
Original line number Diff line number Diff line
@@ -387,6 +387,48 @@ public final class StringUtils {
        return false;
    }

    /**
     * Examines the string and returns whether we're inside a double quote.
     *
     * This is used to decide whether we should put an automatic space before or after a double
     * quote character. If we're inside a quotation, then we want to close it, so we want a space
     * after and not before. Otherwise, we want to open the quotation, so we want a space before
     * and not after. Exception: after a digit, we never want a space because the "inch" or
     * "minutes" use cases is dominant after digits.
     * In the practice, we determine whether we are in a quotation or not by finding the previous
     * double quote character, and looking at whether it's followed by whitespace. If so, that
     * was a closing quotation mark, so we're not inside a double quote. If it's not followed
     * by whitespace, then it was an opening quotation mark, and we're inside a quotation.
     *
     * @param text the text to examine.
     * @return whether we're inside a double quote.
     */
    public static boolean isInsideDoubleQuoteOrAfterDigit(final CharSequence text) {
        int i = text.length();
        if (0 == i) return false;
        int codePoint = Character.codePointBefore(text, i);
        if (Character.isDigit(codePoint)) return true;
        int prevCodePoint = 0;
        while (i > 0) {
            codePoint = Character.codePointBefore(text, i);
            if (Constants.CODE_DOUBLE_QUOTE == codePoint) {
                // If we see a double quote followed by whitespace, then that
                // was a closing quote.
                if (Character.isWhitespace(prevCodePoint)) return false;
            }
            if (Character.isWhitespace(codePoint) && Constants.CODE_DOUBLE_QUOTE == prevCodePoint) {
                // If we see a double quote preceded by whitespace, then that
                // was an opening quote. No need to continue seeking.
                return true;
            }
            i -= Character.charCount(codePoint);
            prevCodePoint = codePoint;
        }
        // We reached the start of text. If the first char is a double quote, then we're inside
        // a double quote. Otherwise we're not.
        return Constants.CODE_DOUBLE_QUOTE == codePoint;
    }

    public static boolean isEmptyStringOrWhiteSpaces(final String s) {
        final int N = codePointCount(s);
        for (int i = 0; i < N; ++i) {
+28 −0
Original line number Diff line number Diff line
@@ -169,4 +169,32 @@ public class PunctuationTests extends InputTestsBase {
                + " ; Suggestions = " + mLatinIME.getSuggestedWords(),
                EXPECTED_RESULT, mEditText.getText().toString());
    }

    public void testAutoSpaceWithDoubleQuotes() {
        final String STRING_TO_TYPE = "He said\"hello\"to me. I replied,\"hi\"."
                + "Then, 5\"passed. He said\"bye\"and left.";
        final String EXPECTED_RESULT = "He said \"hello\" to me. I replied, \"hi\". "
                + "Then, 5\" passed. He said \"bye\" and left. \"";
        // Split by double quote, so that we can type the double quotes individually.
        for (final String partToType : STRING_TO_TYPE.split("\"")) {
            // Split at word boundaries. This regexp means "anywhere that is preceded
            // by a word character but not followed by a word character, OR that is not
            // preceded by a word character but followed by a word character".
            // We need to input word by word because auto-spaces are only active when
            // manually picking or gesturing (which we can't simulate yet), but only words
            // can be picked.
            final String[] wordsToType = partToType.split("(?<=\\w)(?!\\w)|(?<!\\w)(?=\\w)");
            for (final String wordToType : wordsToType) {
                type(wordToType);
                if (wordToType.matches("^\\w+$")) {
                    // Only pick selection if that was a word, because if that was not a word,
                    // then we don't have a composition.
                    pickSuggestionManually(0, wordToType);
                }
            }
            type("\"");
        }
        assertEquals("auto-space with double quotes",
                EXPECTED_RESULT, mEditText.getText().toString());
    }
}