Bug 187225 - [macOS] Text replacements that end with symbols are expanded immediately
Summary: [macOS] Text replacements that end with symbols are expanded immediately
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: HTML Editing (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Wenson Hsieh
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2018-06-30 17:04 PDT by Wenson Hsieh
Modified: 2018-07-01 18:22 PDT (History)
9 users (show)

See Also:


Attachments
Patch (68.90 KB, patch)
2018-06-30 18:36 PDT, Wenson Hsieh
no flags Details | Formatted Diff | Diff
Fix macOS build (68.90 KB, patch)
2018-06-30 18:52 PDT, Wenson Hsieh
no flags Details | Formatted Diff | Diff
Fix the iOS build (68.89 KB, patch)
2018-06-30 19:33 PDT, Wenson Hsieh
no flags Details | Formatted Diff | Diff
Win and 32-bit Mac build fix (69.65 KB, patch)
2018-06-30 20:45 PDT, Wenson Hsieh
no flags Details | Formatted Diff | Diff
More 32-bit build fixes (69.78 KB, patch)
2018-06-30 21:20 PDT, Wenson Hsieh
no flags Details | Formatted Diff | Diff
Patch (69.77 KB, patch)
2018-06-30 21:26 PDT, Wenson Hsieh
darin: review+
Details | Formatted Diff | Diff
Patch for landing (69.40 KB, patch)
2018-07-01 16:59 PDT, Wenson Hsieh
wenson_hsieh: commit-queue-
Details | Formatted Diff | Diff
Patch for landing (69.78 KB, patch)
2018-07-01 17:08 PDT, Wenson Hsieh
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Wenson Hsieh 2018-06-30 17:04:01 PDT
<rdar://problem/41112433>
Comment 1 Wenson Hsieh 2018-06-30 17:12:11 PDT
To reproduce:

- Go to System Preferences > Keyboard > Text.
- Add a text replacement from "yt?" to "you there?".
- In Safari (or any other WebKit-based app), focus an editable area.
- Type "yt?", and don't press space or enter.

Expected: The editable area should contain "yt?". Subsequently inserting a space or newline should then replace "yt?" with "you there?".

Observed: Autocorrection kicks in and changes "yt?" to "you there?" immediately.
Comment 2 Wenson Hsieh 2018-06-30 17:12:47 PDT
This also reproduces on shipping macOS, but only if grammar checking is enabled.
Comment 3 Wenson Hsieh 2018-06-30 18:36:44 PDT Comment hidden (obsolete)
Comment 4 Wenson Hsieh 2018-06-30 18:52:50 PDT Comment hidden (obsolete)
Comment 5 Wenson Hsieh 2018-06-30 19:33:34 PDT Comment hidden (obsolete)
Comment 6 Wenson Hsieh 2018-06-30 20:45:50 PDT Comment hidden (obsolete)
Comment 7 Wenson Hsieh 2018-06-30 21:20:50 PDT Comment hidden (obsolete)
Comment 8 EWS Watchlist 2018-06-30 21:23:31 PDT Comment hidden (obsolete)
Comment 9 Wenson Hsieh 2018-06-30 21:26:41 PDT
Created attachment 344042 [details]
Patch
Comment 10 Darin Adler 2018-07-01 14:40:33 PDT
Comment on attachment 344042 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=344042&action=review

> Source/WebCore/editing/Editor.h:296
> +    void markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask, Range* spellingRange, Range* automaticReplacementRange, Range* grammarRange);

Why are these Range* instead of Range& or const Range&? Can all three be null?

> Source/WebCore/editing/TextCheckingHelper.h:82
> +    mutable int m_checkingStart { -1 };
> +    mutable int m_checkingEnd { -1 };
> +    mutable int m_checkingLength { -1 };
> +    mutable int m_automaticReplacementStart { -1 };
> +    mutable int m_automaticReplacementLength { -1 };

At some point we should consider using std::optional here instead of a magic number of -1.

> Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.h:35
> +@interface LayoutTestTextCheckingResult : NSTextCheckingResult {

I think this class should be private and not mentioned in the header. The data structures could just hold NSTextCheckingResult; no need to remember that our special type was used once the object is created.

> Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.h:51
> ++ (instancetype)installIfNecessary;

Seems slightly unnecessarily wordy. Such methods often have simpler names like "checker", with the "set this up so I can use it" part treated as implicit.

> Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.mm:36
> +typedef void (^TextCheckingCompletionHandler)(NSInteger sequenceNumber, NSArray<NSTextCheckingResult *> *results, NSOrthography *orthography, NSInteger wordCount);

New code should typically use "using" instead of "typedef".

> Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.mm:38
> +static NeverDestroyed<RetainPtr<LayoutTestSpellChecker>> globalSpellChecker;

Typically it’s overkill to use NeverDestroyed<RetainPtr>. Instead we just do a leakRef when initializing the global or just skip the adoptNS.
Comment 11 Wenson Hsieh 2018-07-01 15:30:27 PDT
Comment on attachment 344042 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=344042&action=review

>> Source/WebCore/editing/Editor.h:296
>> +    void markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask, Range* spellingRange, Range* automaticReplacementRange, Range* grammarRange);
> 
> Why are these Range* instead of Range& or const Range&? Can all three be null?

It does look like all three may be null (at least one call site passes a null grammarRange, and additionally, there's logic in markAllMisspellingsAndBadGrammarInRanges to bail when !spellingRange).

I think the modern idiom for this would be to make these three ranges RefPtr<Range>&& instead — I can do this in a followup (along with refactoring the cached offsets in TextCheckingParagraph to be `std::optional`s).

>> Source/WebCore/editing/TextCheckingHelper.h:82
>> +    mutable int m_automaticReplacementLength { -1 };
> 
> At some point we should consider using std::optional here instead of a magic number of -1.

Definitely agree! I'll do this in a followup.

>> Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.h:35
>> +@interface LayoutTestTextCheckingResult : NSTextCheckingResult {
> 
> I think this class should be private and not mentioned in the header. The data structures could just hold NSTextCheckingResult; no need to remember that our special type was used once the object is created.

Good catch — moved to the implementation file.

>> Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.h:51
>> ++ (instancetype)installIfNecessary;
> 
> Seems slightly unnecessarily wordy. Such methods often have simpler names like "checker", with the "set this up so I can use it" part treated as implicit.

Ok! Renamed to "checker".

>> Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.mm:36
>> +typedef void (^TextCheckingCompletionHandler)(NSInteger sequenceNumber, NSArray<NSTextCheckingResult *> *results, NSOrthography *orthography, NSInteger wordCount);
> 
> New code should typically use "using" instead of "typedef".

Ah, I just realized that I don't actually need this typedef, so I just removed this.

>> Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.mm:38
>> +static NeverDestroyed<RetainPtr<LayoutTestSpellChecker>> globalSpellChecker;
> 
> Typically it’s overkill to use NeverDestroyed<RetainPtr>. Instead we just do a leakRef when initializing the global or just skip the adoptNS.

Got it — removed the NeverDestroyed<> and adoptNS() here.
Comment 12 Wenson Hsieh 2018-07-01 16:59:35 PDT
Created attachment 344064 [details]
Patch for landing
Comment 13 Wenson Hsieh 2018-07-01 17:08:54 PDT
Created attachment 344065 [details]
Patch for landing
Comment 14 WebKit Commit Bot 2018-07-01 17:47:55 PDT
Comment on attachment 344065 [details]
Patch for landing

Clearing flags on attachment: 344065

Committed r233412: <https://trac.webkit.org/changeset/233412>