Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,32 @@ public InputTransaction onPickSuggestionManually(SettingsValues settingsValues,
return inputTransaction;
}

// A word can extend before the composing region when it starts with characters that don't
// start composition on their own, such as digits (e.g. "2u2j"): the leading part is
// committed immediately, while only the rest ("u2j") is composing. Committing the picked
// suggestion, which includes the leading part, would then duplicate it. If the picked word
// starts with the whole word before the cursor, extend the composing region to cover it so
// that committing replaces the whole word rather than only the composing part. (#2611)
if (mWordComposer.isComposingWord() && !mWordComposer.isBatchMode()) {
final String typedWord = mWordComposer.getTypedWord();
final int cursor = mConnection.getExpectedSelectionStart();
final CharSequence before = mConnection.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0);
if (before != null && cursor >= 0 && before.length() >= typedWord.length()) {
// Non-separator characters committed right before the composing word still belong
// to the same word (e.g. leading digits), so include them in the word to replace.
int start = before.length() - typedWord.length();
while (start > 0) {
final int cp = Character.codePointBefore(before, start);
if (settingsValues.isWordSeparator(cp) || Character.isWhitespace(cp)) break;
start -= Character.charCount(cp);
}
final String wordBeforeCursor = before.subSequence(start, before.length()).toString();
if (wordBeforeCursor.length() > typedWord.length() && suggestion.startsWith(wordBeforeCursor)) {
mConnection.setComposingRegion(cursor - wordBeforeCursor.length(), cursor);
}
}
}

commitChosenWord(settingsValues, suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR);
mConnection.endBatchEdit();
// Don't allow cancellation of manual pick
Expand Down
15 changes: 15 additions & 0 deletions app/src/test/java/helium314/keyboard/latin/InputLogicTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,21 @@ class InputLogicTest {
assertEquals("example.", text)
}

// #2611: a word starting with a digit has its leading digit committed outside the composing
// region (digits don't start composition), so picking a suggestion that includes it used to
// duplicate the digit ("2u2j" + pick "2u2j@addres.com" -> "22u2j@addres.com").
@Test fun pickSuggestionForWordWithLeadingDigit() {
chainInput("2u2j")
pickSuggestion("2u2j@addres.com")
assertEquals("2u2j@addres.com", text)
}

@Test fun pickSuggestionForWordWithLeadingDigitPartiallyTyped() {
chainInput("2u")
pickSuggestion("2u2j@addres.com")
assertEquals("2u2j@addres.com", text)
}

@Test fun noAutospaceForDetectedUrl() { // "light" version, should work without url detection
latinIME.prefs().edit { putBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, true) }
chainInput("http://example.net")
Expand Down