Skip to content

Commit 8063ed1

Browse files
jensjohaCommit Queue
authored andcommitted
[CFE] Spell checker improvements
- Spell checker in interactive mode shows the 'close words' (if any) when asking if wanting to add a word to the directory. Hopefully this will make it less likely adding wrong words to the dictionary. - When finding 'close' words it now also tries to insert a letter at the end which it erroneously didn't before. The close words method is also tested better. Change-Id: Ic2628fc261ecb4d9c9322a0ab8c462b174707051 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/403863 Commit-Queue: Jens Johansen <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent 86ff64c commit 8063ed1

File tree

4 files changed

+64
-21
lines changed

4 files changed

+64
-21
lines changed

pkg/front_end/test/messages_suite.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class MessageTestSuite extends ChainContext {
8989
final bool fastOnly;
9090
final bool interactive;
9191

92-
final Set<String> reportedWords = {};
92+
final Map<String, List<String>?> reportedWordsAndAlternatives = {};
9393
final Set<String> reportedWordsDenylisted = {};
9494

9595
@override
@@ -103,7 +103,7 @@ class MessageTestSuite extends ChainContext {
103103
}
104104
String suitePath = suiteFile.path;
105105
spell.spellSummarizeAndInteractiveMode(
106-
reportedWords,
106+
reportedWordsAndAlternatives,
107107
reportedWordsDenylisted,
108108
[spell.Dictionaries.cfeMessages],
109109
interactive,
@@ -182,7 +182,8 @@ class MessageTestSuite extends ChainContext {
182182
messageToUse = messageForDenyListed;
183183
reportedWordsDenylisted.add(spellResult.misspelledWords![i]);
184184
} else {
185-
reportedWords.add(spellResult.misspelledWords![i]);
185+
reportedWordsAndAlternatives[spellResult.misspelledWords![i]] =
186+
spellResult.misspelledWordsAlternatives![i];
186187
}
187188
result.add(command_line_reporting.formatErrorMessage(
188189
source!.getTextLine(location.line),

pkg/front_end/test/spell_checking_utils.dart

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,28 +82,36 @@ List<String>? findAlternatives(String word, List<Set<String>> dictionaries) {
8282
(result ??= <String>[]).add(w);
8383
}
8484

85+
void checkInsert(String before, String afterIncluding) {
86+
for (int j = 0; j < 25; j++) {
87+
String c = new String.fromCharCode(97 + j);
88+
String insertedLetter = "${before}${c}${afterIncluding}";
89+
if (check(insertedLetter)) ok(insertedLetter);
90+
}
91+
}
92+
8593
// Delete a letter, insert a letter or change a letter and lookup.
8694
for (int i = 0; i < word.length; i++) {
8795
String before = word.substring(0, i);
88-
String after = word.substring(i + 1);
89-
String afterIncluding = word.substring(i);
96+
String afterExcluding = word.substring(i + 1);
9097

9198
{
92-
String deletedLetter = before + after;
99+
String deletedLetter = "${before}${afterExcluding}";
93100
if (check(deletedLetter)) ok(deletedLetter);
94101
}
102+
103+
checkInsert(before, word.substring(i));
104+
95105
for (int j = 0; j < 25; j++) {
96106
String c = new String.fromCharCode(97 + j);
97-
String insertedLetter = before + c + afterIncluding;
98-
if (check(insertedLetter)) ok(insertedLetter);
99-
}
100-
for (int j = 0; j < 25; j++) {
101-
String c = new String.fromCharCode(97 + j);
102-
String replacedLetter = before + c + after;
107+
String replacedLetter = "${before}${c}${afterExcluding}";
103108
if (check(replacedLetter)) ok(replacedLetter);
104109
}
105110
}
106111

112+
// Check insert at end.
113+
checkInsert(word, "");
114+
107115
return result;
108116
}
109117

@@ -347,7 +355,7 @@ List<String> splitStringIntoWords(String s, List<int> splitOffsets,
347355
}
348356

349357
void spellSummarizeAndInteractiveMode(
350-
Set<String> reportedWords,
358+
Map<String, List<String>?> reportedWordsAndAlternatives,
351359
Set<String> reportedWordsDenylisted,
352360
List<Dictionaries> dictionaries,
353361
bool interactive,
@@ -365,8 +373,8 @@ void spellSummarizeAndInteractiveMode(
365373
}
366374
print("================");
367375
}
368-
if (reportedWords.isNotEmpty) {
369-
bool isSingular = reportedWords.length == 1;
376+
if (reportedWordsAndAlternatives.isNotEmpty) {
377+
bool isSingular = reportedWordsAndAlternatives.length == 1;
370378
String suffix = isSingular ? "" : "s";
371379
String were = isSingular ? "was" : "were";
372380
String are = isSingular ? "is" : "are";
@@ -394,8 +402,15 @@ void spellSummarizeAndInteractiveMode(
394402

395403
if (interactive && dictionaryToUse != null) {
396404
List<String> addedWords = <String>[];
397-
for (String s in reportedWords) {
398-
print("- $s");
405+
for (MapEntry<String, List<String>?> wordAndAlternative
406+
in reportedWordsAndAlternatives.entries) {
407+
String s = wordAndAlternative.key;
408+
List<String>? alternative = wordAndAlternative.value;
409+
if (alternative != null) {
410+
print(" - $s (notice close word(s)): ${alternative.join(", ")})");
411+
} else {
412+
print(" - $s");
413+
}
399414
String answer;
400415
bool? add;
401416
while (true) {
@@ -451,7 +466,7 @@ void spellSummarizeAndInteractiveMode(
451466
dictionaryFile.writeAsStringSync(lines.join("\n"));
452467
}
453468
} else {
454-
for (String s in reportedWords) {
469+
for (String s in reportedWordsAndAlternatives.keys) {
455470
print("$s");
456471
}
457472
if (dictionaries.isNotEmpty) {

pkg/front_end/test/spell_checking_utils_test.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,33 @@ void main() {
9090
"explicitley", ["explicitly"], {"foo", "explicitly", "bar"});
9191
expectAlternative("explicitlqqqqy", null, {"foo", "explicitly", "bar"});
9292

93+
// Insert first letter.
94+
expectAlternative("ar", ["bar"], {"foo", "explicitly", "bar"});
95+
96+
// Insert middle letter.
97+
expectAlternative("br", ["bar"], {"foo", "explicitly", "bar"});
98+
99+
// Insert last letter.
100+
expectAlternative("ba", ["bar"], {"foo", "explicitly", "bar"});
101+
102+
// Delete first letter.
103+
expectAlternative("xbar", ["bar"], {"foo", "explicitly", "bar"});
104+
105+
// Delete middle letter.
106+
expectAlternative("bxar", ["bar"], {"foo", "explicitly", "bar"});
107+
108+
// Delete last letter.
109+
expectAlternative("barx", ["bar"], {"foo", "explicitly", "bar"});
110+
111+
// Replace first letter.
112+
expectAlternative("car", ["bar"], {"foo", "explicitly", "bar"});
113+
114+
// Replace middle letter.
115+
expectAlternative("bcr", ["bar"], {"foo", "explicitly", "bar"});
116+
117+
// Replace last letter.
118+
expectAlternative("bac", ["bar"], {"foo", "explicitly", "bar"});
119+
93120
print("OK");
94121
}
95122

pkg/front_end/test/spelling_test_base.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ abstract class SpellContext extends ChainContext {
3636

3737
String get repoRelativeSuitePath;
3838

39-
Set<String> reportedWords = {};
39+
Map<String, List<String>?> reportedWordsAndAlternatives = {};
4040
Set<String> reportedWordsDenylisted = {};
4141

4242
@override
@@ -54,7 +54,7 @@ abstract class SpellContext extends ChainContext {
5454
}
5555
String suitePath = suiteFile.path;
5656
spell.spellSummarizeAndInteractiveMode(
57-
reportedWords,
57+
reportedWordsAndAlternatives,
5858
reportedWordsDenylisted,
5959
dictionaries,
6060
interactive,
@@ -92,7 +92,7 @@ class SpellTest extends Step<TestDescription, TestDescription, SpellContext> {
9292
context.reportedWordsDenylisted.add(word);
9393
} else {
9494
message = "The word '$word' is not in our dictionary.";
95-
context.reportedWords.add(word);
95+
context.reportedWordsAndAlternatives[word] = alternatives;
9696
}
9797
if (alternatives != null && alternatives.isNotEmpty) {
9898
message += "\n\nThe following word(s) was 'close' "

0 commit comments

Comments
 (0)