Simplify the space-before and space-after logic.
Bug: 7889078 Bug: 7268000 Change-Id: I6c77b8c9e60ef69f02526b407124d2f5d02818eemain
parent
22959faad4
commit
ae3b96b26e
|
@ -18,15 +18,13 @@
|
||||||
*/
|
*/
|
||||||
-->
|
-->
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<!-- Symbols that should be swapped with a magic space -->
|
<!-- Symbols that are normally preceded by a space (used to add an auto-space before these) -->
|
||||||
<string name="weak_space_swapping_symbols">.,)]}</string>
|
<string name="symbols_preceded_by_space">([{*&;:!?</string>
|
||||||
<!-- Symbols that should strip a magic space -->
|
<!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
|
||||||
|
<string name="symbols_followed_by_space">.,;:!?)]}*&</string>
|
||||||
|
<!-- Symbols that separate words -->
|
||||||
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
|
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
|
||||||
<string name="weak_space_stripping_symbols">"	 \n"\'-/_\"</string>
|
<string name="symbols_word_separators">"	 \n"()[]{}*&<>+=|.,;:!?/_\"</string>
|
||||||
<!-- Symbols that should promote magic spaces into real space -->
|
<!-- Word connectors -->
|
||||||
<string name="phantom_space_promoting_symbols">;:!?([*&@{<>+=|</string>
|
<string name="symbols_word_connectors">\'-</string>
|
||||||
<!-- Symbols that do NOT separate words -->
|
|
||||||
<!-- Note that this is identical to the default value, but since the above ones are different
|
|
||||||
and those variables only make sense together, this is kept here for readability. -->
|
|
||||||
<string name="symbols_excluded_from_word_separators">\'-</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -20,18 +20,15 @@
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<!-- Symbols that are suggested between words -->
|
<!-- Symbols that are suggested between words -->
|
||||||
<string name="suggested_punctuations">!,?,\\,,:,;,\",(,),\',-,/,@,_</string>
|
<string name="suggested_punctuations">!,?,\\,,:,;,\",(,),\',-,/,@,_</string>
|
||||||
<!-- Symbols that should be swapped with a weak space -->
|
<!-- Symbols that are normally preceded by a space (used to add an auto-space before these) -->
|
||||||
<string name="weak_space_swapping_symbols">.,;:!?)]}</string>
|
<string name="symbols_preceded_by_space">([{*&</string>
|
||||||
<!-- Symbols that should strip a weak space -->
|
<!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
|
||||||
|
<string name="symbols_followed_by_space">.,;:!?)]}*&</string>
|
||||||
|
<!-- Symbols that separate words -->
|
||||||
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
|
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
|
||||||
<string name="weak_space_stripping_symbols">"	 \n"/_\'-@\"</string>
|
<string name="symbols_word_separators">"	 \n"()[]{}*&<>+=|.,;:!?/_\"</string>
|
||||||
<!-- Symbols that should convert weak spaces into real space -->
|
<!-- Word connectors -->
|
||||||
<string name="phantom_space_promoting_symbols">([*&{<>+=|</string>
|
<string name="symbols_word_connectors">\'-</string>
|
||||||
<!-- Symbols that do NOT separate words -->
|
|
||||||
<string name="symbols_excluded_from_word_separators">\'-</string>
|
|
||||||
<!-- Word separator list is the union of all symbols except those that are not separators:
|
|
||||||
weak_space_swapping_symbols | weak_space_stripping_symbols
|
|
||||||
\ symbols_excluded_from_word_separators -->
|
|
||||||
<!-- Symbol characters list that should switch back to the main layout -->
|
<!-- Symbol characters list that should switch back to the main layout -->
|
||||||
<!-- U+2018: "‘" LEFT SINGLE QUOTATION MARK
|
<!-- U+2018: "‘" LEFT SINGLE QUOTATION MARK
|
||||||
U+2019: "’" RIGHT SINGLE QUOTATION MARK
|
U+2019: "’" RIGHT SINGLE QUOTATION MARK
|
||||||
|
|
|
@ -1493,12 +1493,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
mSpaceState = SPACE_STATE_PHANTOM;
|
mSpaceState = SPACE_STATE_PHANTOM;
|
||||||
} else {
|
} else {
|
||||||
final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
|
final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
|
||||||
// TODO: reverse this logic. We should have the means to determine whether a character
|
if (mSettings.getCurrent().isUsuallyFollowedBySpace(codePointBeforeCursor)) {
|
||||||
// should usually be followed by a space, and it should be more readable.
|
|
||||||
if (Constants.NOT_A_CODE != codePointBeforeCursor
|
|
||||||
&& !Character.isWhitespace(codePointBeforeCursor)
|
|
||||||
&& !mSettings.getCurrent().isPhantomSpacePromotingSymbol(codePointBeforeCursor)
|
|
||||||
&& !mSettings.getCurrent().isWeakSpaceStripper(codePointBeforeCursor)) {
|
|
||||||
mSpaceState = SPACE_STATE_PHANTOM;
|
mSpaceState = SPACE_STATE_PHANTOM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1775,33 +1770,30 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Strip a trailing space if necessary and returns whether it's a swap weak space situation.
|
||||||
|
*/
|
||||||
private boolean maybeStripSpace(final int code,
|
private boolean maybeStripSpace(final int code,
|
||||||
final int spaceState, final boolean isFromSuggestionStrip) {
|
final int spaceState, final boolean isFromSuggestionStrip) {
|
||||||
if (Constants.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
|
if (Constants.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
|
||||||
mConnection.removeTrailingSpace();
|
mConnection.removeTrailingSpace();
|
||||||
return false;
|
return false;
|
||||||
} else if ((SPACE_STATE_WEAK == spaceState
|
}
|
||||||
|| SPACE_STATE_SWAP_PUNCTUATION == spaceState)
|
if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState)
|
||||||
&& isFromSuggestionStrip) {
|
&& isFromSuggestionStrip) {
|
||||||
if (mSettings.getCurrent().isWeakSpaceSwapper(code)) {
|
if (mSettings.getCurrent().isUsuallyPrecededBySpace(code)) return false;
|
||||||
return true;
|
if (mSettings.getCurrent().isUsuallyFollowedBySpace(code)) return true;
|
||||||
} else {
|
|
||||||
if (mSettings.getCurrent().isWeakSpaceStripper(code)) {
|
|
||||||
mConnection.removeTrailingSpace();
|
mConnection.removeTrailingSpace();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleCharacter(final int primaryCode, final int x,
|
private void handleCharacter(final int primaryCode, final int x,
|
||||||
final int y, final int spaceState) {
|
final int y, final int spaceState) {
|
||||||
boolean isComposingWord = mWordComposer.isComposingWord();
|
boolean isComposingWord = mWordComposer.isComposingWord();
|
||||||
|
|
||||||
if (SPACE_STATE_PHANTOM == spaceState &&
|
if (SPACE_STATE_PHANTOM == spaceState &&
|
||||||
!mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode)) {
|
!mSettings.getCurrent().isWordConnector(primaryCode)) {
|
||||||
if (isComposingWord) {
|
if (isComposingWord) {
|
||||||
// Sanity check
|
// Sanity check
|
||||||
throw new RuntimeException("Should not be composing here");
|
throw new RuntimeException("Should not be composing here");
|
||||||
|
@ -1813,7 +1805,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
// dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
|
// dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
|
||||||
// thread here.
|
// thread here.
|
||||||
if (!isComposingWord && (isAlphabet(primaryCode)
|
if (!isComposingWord && (isAlphabet(primaryCode)
|
||||||
|| mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode))
|
|| mSettings.getCurrent().isWordConnector(primaryCode))
|
||||||
&& mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation) &&
|
&& mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation) &&
|
||||||
!mConnection.isCursorTouchingWord(mSettings.getCurrent())) {
|
!mConnection.isCursorTouchingWord(mSettings.getCurrent())) {
|
||||||
// Reset entirely the composing state anyway, then start composing a new word unless
|
// Reset entirely the composing state anyway, then start composing a new word unless
|
||||||
|
@ -1885,7 +1877,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
Constants.SUGGESTION_STRIP_COORDINATE == x);
|
Constants.SUGGESTION_STRIP_COORDINATE == x);
|
||||||
|
|
||||||
if (SPACE_STATE_PHANTOM == spaceState &&
|
if (SPACE_STATE_PHANTOM == spaceState &&
|
||||||
mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) {
|
mSettings.getCurrent().isUsuallyPrecededBySpace(primaryCode)) {
|
||||||
promotePhantomSpace();
|
promotePhantomSpace();
|
||||||
}
|
}
|
||||||
sendKeyCodePoint(primaryCode);
|
sendKeyCodePoint(primaryCode);
|
||||||
|
@ -1900,16 +1892,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
}
|
}
|
||||||
|
|
||||||
mHandler.startDoubleSpacePeriodTimer();
|
mHandler.startDoubleSpacePeriodTimer();
|
||||||
if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) {
|
|
||||||
mHandler.postUpdateSuggestionStrip();
|
mHandler.postUpdateSuggestionStrip();
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (swapWeakSpace) {
|
if (swapWeakSpace) {
|
||||||
swapSwapperAndSpace();
|
swapSwapperAndSpace();
|
||||||
mSpaceState = SPACE_STATE_SWAP_PUNCTUATION;
|
mSpaceState = SPACE_STATE_SWAP_PUNCTUATION;
|
||||||
} else if (SPACE_STATE_PHANTOM == spaceState
|
} else if (SPACE_STATE_PHANTOM == spaceState
|
||||||
&& !mSettings.getCurrent().isWeakSpaceStripper(primaryCode)
|
&& mSettings.getCurrent().isUsuallyFollowedBySpace(primaryCode)) {
|
||||||
&& !mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) {
|
|
||||||
// If we are in phantom space state, and the user presses a separator, we want to
|
// 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
|
// 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
|
// space. For example, if I type "Good dat", pick "day" from the suggestion strip
|
||||||
|
@ -2158,9 +2147,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
// In the batch input mode, a manually picked suggested word should just replace
|
// In the batch input mode, a manually picked suggested word should just replace
|
||||||
// the current batch input text and there is no need for a phantom space.
|
// the current batch input text and there is no need for a phantom space.
|
||||||
&& !mWordComposer.isBatchMode()) {
|
&& !mWordComposer.isBatchMode()) {
|
||||||
int firstChar = Character.codePointAt(suggestion, 0);
|
final int firstChar = Character.codePointAt(suggestion, 0);
|
||||||
if ((!mSettings.getCurrent().isWeakSpaceStripper(firstChar))
|
if (!mSettings.getCurrent().isWordSeparator(firstChar)
|
||||||
&& (!mSettings.getCurrent().isWeakSpaceSwapper(firstChar))) {
|
|| mSettings.getCurrent().isUsuallyPrecededBySpace(firstChar)) {
|
||||||
promotePhantomSpace();
|
promotePhantomSpace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -577,11 +577,11 @@ public final class RichInputConnection {
|
||||||
final CharSequence before = getTextBeforeCursor(1, 0);
|
final CharSequence before = getTextBeforeCursor(1, 0);
|
||||||
final CharSequence after = getTextAfterCursor(1, 0);
|
final CharSequence after = getTextAfterCursor(1, 0);
|
||||||
if (!TextUtils.isEmpty(before) && !settingsValues.isWordSeparator(before.charAt(0))
|
if (!TextUtils.isEmpty(before) && !settingsValues.isWordSeparator(before.charAt(0))
|
||||||
&& !settingsValues.isSymbolExcludedFromWordSeparators(before.charAt(0))) {
|
&& !settingsValues.isWordConnector(before.charAt(0))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!TextUtils.isEmpty(after) && !settingsValues.isWordSeparator(after.charAt(0))
|
if (!TextUtils.isEmpty(after) && !settingsValues.isWordSeparator(after.charAt(0))
|
||||||
&& !settingsValues.isSymbolExcludedFromWordSeparators(after.charAt(0))) {
|
&& !settingsValues.isWordConnector(after.charAt(0))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -633,12 +633,9 @@ public final class RichInputConnection {
|
||||||
final char firstChar = word.charAt(0); // we just tested that word is not empty
|
final char firstChar = word.charAt(0); // we just tested that word is not empty
|
||||||
if (word.length() == 1 && !Character.isLetter(firstChar)) return null;
|
if (word.length() == 1 && !Character.isLetter(firstChar)) return null;
|
||||||
|
|
||||||
// We only suggest on words that start with a letter or a symbol that is excluded from
|
// We don't restart suggestion if the first character is not a letter, because we don't
|
||||||
// word separators (see #handleCharacterWhileInBatchEdit).
|
// start composing when the first character is not a letter.
|
||||||
if (!(Character.isLetter(firstChar)
|
if (!Character.isLetter(firstChar)) return null;
|
||||||
|| settings.isSymbolExcludedFromWordSeparators(firstChar))) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return word;
|
return word;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,11 +37,10 @@ public final class SettingsValues {
|
||||||
|
|
||||||
// From resources:
|
// From resources:
|
||||||
public final int mDelayUpdateOldSuggestions;
|
public final int mDelayUpdateOldSuggestions;
|
||||||
public final String mWeakSpaceStrippers;
|
public final int[] mSymbolsPrecededBySpace;
|
||||||
public final String mWeakSpaceSwappers;
|
public final int[] mSymbolsFollowedBySpace;
|
||||||
private final String mPhantomSpacePromotingSymbols;
|
public final int[] mWordConnectors;
|
||||||
public final SuggestedWords mSuggestPuncList;
|
public final SuggestedWords mSuggestPuncList;
|
||||||
private final String mSymbolsExcludedFromWordSeparators;
|
|
||||||
public final String mWordSeparators;
|
public final String mWordSeparators;
|
||||||
public final CharSequence mHintToSaveText;
|
public final CharSequence mHintToSaveText;
|
||||||
|
|
||||||
|
@ -79,25 +78,19 @@ public final class SettingsValues {
|
||||||
final InputAttributes inputAttributes) {
|
final InputAttributes inputAttributes) {
|
||||||
// Get the resources
|
// Get the resources
|
||||||
mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
|
mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
|
||||||
mWeakSpaceStrippers = res.getString(R.string.weak_space_stripping_symbols);
|
mSymbolsPrecededBySpace =
|
||||||
mWeakSpaceSwappers = res.getString(R.string.weak_space_swapping_symbols);
|
StringUtils.toCodePointArray(res.getString(R.string.symbols_preceded_by_space));
|
||||||
mPhantomSpacePromotingSymbols = res.getString(R.string.phantom_space_promoting_symbols);
|
Arrays.sort(mSymbolsPrecededBySpace);
|
||||||
if (LatinImeLogger.sDBG) {
|
mSymbolsFollowedBySpace =
|
||||||
final int length = mWeakSpaceStrippers.length();
|
StringUtils.toCodePointArray(res.getString(R.string.symbols_followed_by_space));
|
||||||
for (int i = 0; i < length; i = mWeakSpaceStrippers.offsetByCodePoints(i, 1)) {
|
Arrays.sort(mSymbolsFollowedBySpace);
|
||||||
if (isWeakSpaceSwapper(mWeakSpaceStrippers.codePointAt(i))) {
|
mWordConnectors =
|
||||||
throw new RuntimeException("Char code " + mWeakSpaceStrippers.codePointAt(i)
|
StringUtils.toCodePointArray(res.getString(R.string.symbols_word_connectors));
|
||||||
+ " is both a weak space swapper and stripper.");
|
Arrays.sort(mWordConnectors);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final String[] suggestPuncsSpec = KeySpecParser.parseCsvString(
|
final String[] suggestPuncsSpec = KeySpecParser.parseCsvString(
|
||||||
res.getString(R.string.suggested_punctuations), null);
|
res.getString(R.string.suggested_punctuations), null);
|
||||||
mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
|
mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
|
||||||
mSymbolsExcludedFromWordSeparators =
|
mWordSeparators = res.getString(R.string.symbols_word_separators);
|
||||||
res.getString(R.string.symbols_excluded_from_word_separators);
|
|
||||||
mWordSeparators = createWordSeparators(mWeakSpaceStrippers, mWeakSpaceSwappers,
|
|
||||||
mSymbolsExcludedFromWordSeparators, res);
|
|
||||||
mHintToSaveText = res.getText(R.string.hint_add_to_dictionary);
|
mHintToSaveText = res.getText(R.string.hint_add_to_dictionary);
|
||||||
|
|
||||||
// Store the input attributes
|
// Store the input attributes
|
||||||
|
@ -169,25 +162,16 @@ public final class SettingsValues {
|
||||||
return mWordSeparators.contains(String.valueOf((char)code));
|
return mWordSeparators.contains(String.valueOf((char)code));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSymbolExcludedFromWordSeparators(final int code) {
|
public boolean isWordConnector(final int code) {
|
||||||
return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code));
|
return Arrays.binarySearch(mWordConnectors, code) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use "Phantom" instead of "Weak" in this method name
|
public boolean isUsuallyPrecededBySpace(final int code) {
|
||||||
public boolean isWeakSpaceStripper(final int code) {
|
return Arrays.binarySearch(mSymbolsPrecededBySpace, code) >= 0;
|
||||||
// TODO: this does not work if the code does not fit in a char
|
|
||||||
return mWeakSpaceStrippers.contains(String.valueOf((char)code));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use "Phantom" instead of "Weak" in this method name
|
public boolean isUsuallyFollowedBySpace(final int code) {
|
||||||
public boolean isWeakSpaceSwapper(final int code) {
|
return Arrays.binarySearch(mSymbolsFollowedBySpace, code) >= 0;
|
||||||
// TODO: this does not work if the code does not fit in a char
|
|
||||||
return mWeakSpaceSwappers.contains(String.valueOf((char)code));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPhantomSpacePromotingSymbol(final int code) {
|
|
||||||
// TODO: this does not work if the code does not fit in a char
|
|
||||||
return mPhantomSpacePromotingSymbols.contains(String.valueOf((char)code));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldInsertSpacesAutomatically() {
|
public boolean shouldInsertSpacesAutomatically() {
|
||||||
|
@ -239,18 +223,6 @@ public final class SettingsValues {
|
||||||
false /* isPrediction */);
|
false /* isPrediction */);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String createWordSeparators(final String weakSpaceStrippers,
|
|
||||||
final String weakSpaceSwappers, final String symbolsExcludedFromWordSeparators,
|
|
||||||
final Resources res) {
|
|
||||||
String wordSeparators = weakSpaceStrippers + weakSpaceSwappers
|
|
||||||
+ res.getString(R.string.phantom_space_promoting_symbols);
|
|
||||||
for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) {
|
|
||||||
wordSeparators = wordSeparators.replace(
|
|
||||||
symbolsExcludedFromWordSeparators.substring(i, i + 1), "");
|
|
||||||
}
|
|
||||||
return wordSeparators;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int SUGGESTION_VISIBILITY_SHOW_VALUE =
|
private static final int SUGGESTION_VISIBILITY_SHOW_VALUE =
|
||||||
R.string.prefs_suggestion_visibility_show_value;
|
R.string.prefs_suggestion_visibility_show_value;
|
||||||
private static final int SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE =
|
private static final int SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE =
|
||||||
|
|
Loading…
Reference in New Issue