Skip to content

Commit

Permalink
[CFE] Spell checker improvements
Browse files Browse the repository at this point in the history
- 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]>
  • Loading branch information
jensjoha authored and Commit Queue committed Jan 13, 2025
1 parent 86ff64c commit 8063ed1
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 21 deletions.
7 changes: 4 additions & 3 deletions pkg/front_end/test/messages_suite.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class MessageTestSuite extends ChainContext {
final bool fastOnly;
final bool interactive;

final Set<String> reportedWords = {};
final Map<String, List<String>?> reportedWordsAndAlternatives = {};
final Set<String> reportedWordsDenylisted = {};

@override
Expand All @@ -103,7 +103,7 @@ class MessageTestSuite extends ChainContext {
}
String suitePath = suiteFile.path;
spell.spellSummarizeAndInteractiveMode(
reportedWords,
reportedWordsAndAlternatives,
reportedWordsDenylisted,
[spell.Dictionaries.cfeMessages],
interactive,
Expand Down Expand Up @@ -182,7 +182,8 @@ class MessageTestSuite extends ChainContext {
messageToUse = messageForDenyListed;
reportedWordsDenylisted.add(spellResult.misspelledWords![i]);
} else {
reportedWords.add(spellResult.misspelledWords![i]);
reportedWordsAndAlternatives[spellResult.misspelledWords![i]] =
spellResult.misspelledWordsAlternatives![i];
}
result.add(command_line_reporting.formatErrorMessage(
source!.getTextLine(location.line),
Expand Down
45 changes: 30 additions & 15 deletions pkg/front_end/test/spell_checking_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,28 +82,36 @@ List<String>? findAlternatives(String word, List<Set<String>> dictionaries) {
(result ??= <String>[]).add(w);
}

void checkInsert(String before, String afterIncluding) {
for (int j = 0; j < 25; j++) {
String c = new String.fromCharCode(97 + j);
String insertedLetter = "${before}${c}${afterIncluding}";
if (check(insertedLetter)) ok(insertedLetter);
}
}

// Delete a letter, insert a letter or change a letter and lookup.
for (int i = 0; i < word.length; i++) {
String before = word.substring(0, i);
String after = word.substring(i + 1);
String afterIncluding = word.substring(i);
String afterExcluding = word.substring(i + 1);

{
String deletedLetter = before + after;
String deletedLetter = "${before}${afterExcluding}";
if (check(deletedLetter)) ok(deletedLetter);
}

checkInsert(before, word.substring(i));

for (int j = 0; j < 25; j++) {
String c = new String.fromCharCode(97 + j);
String insertedLetter = before + c + afterIncluding;
if (check(insertedLetter)) ok(insertedLetter);
}
for (int j = 0; j < 25; j++) {
String c = new String.fromCharCode(97 + j);
String replacedLetter = before + c + after;
String replacedLetter = "${before}${c}${afterExcluding}";
if (check(replacedLetter)) ok(replacedLetter);
}
}

// Check insert at end.
checkInsert(word, "");

return result;
}

Expand Down Expand Up @@ -347,7 +355,7 @@ List<String> splitStringIntoWords(String s, List<int> splitOffsets,
}

void spellSummarizeAndInteractiveMode(
Set<String> reportedWords,
Map<String, List<String>?> reportedWordsAndAlternatives,
Set<String> reportedWordsDenylisted,
List<Dictionaries> dictionaries,
bool interactive,
Expand All @@ -365,8 +373,8 @@ void spellSummarizeAndInteractiveMode(
}
print("================");
}
if (reportedWords.isNotEmpty) {
bool isSingular = reportedWords.length == 1;
if (reportedWordsAndAlternatives.isNotEmpty) {
bool isSingular = reportedWordsAndAlternatives.length == 1;
String suffix = isSingular ? "" : "s";
String were = isSingular ? "was" : "were";
String are = isSingular ? "is" : "are";
Expand Down Expand Up @@ -394,8 +402,15 @@ void spellSummarizeAndInteractiveMode(

if (interactive && dictionaryToUse != null) {
List<String> addedWords = <String>[];
for (String s in reportedWords) {
print("- $s");
for (MapEntry<String, List<String>?> wordAndAlternative
in reportedWordsAndAlternatives.entries) {
String s = wordAndAlternative.key;
List<String>? alternative = wordAndAlternative.value;
if (alternative != null) {
print(" - $s (notice close word(s)): ${alternative.join(", ")})");
} else {
print(" - $s");
}
String answer;
bool? add;
while (true) {
Expand Down Expand Up @@ -451,7 +466,7 @@ void spellSummarizeAndInteractiveMode(
dictionaryFile.writeAsStringSync(lines.join("\n"));
}
} else {
for (String s in reportedWords) {
for (String s in reportedWordsAndAlternatives.keys) {
print("$s");
}
if (dictionaries.isNotEmpty) {
Expand Down
27 changes: 27 additions & 0 deletions pkg/front_end/test/spell_checking_utils_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,33 @@ void main() {
"explicitley", ["explicitly"], {"foo", "explicitly", "bar"});
expectAlternative("explicitlqqqqy", null, {"foo", "explicitly", "bar"});

// Insert first letter.
expectAlternative("ar", ["bar"], {"foo", "explicitly", "bar"});

// Insert middle letter.
expectAlternative("br", ["bar"], {"foo", "explicitly", "bar"});

// Insert last letter.
expectAlternative("ba", ["bar"], {"foo", "explicitly", "bar"});

// Delete first letter.
expectAlternative("xbar", ["bar"], {"foo", "explicitly", "bar"});

// Delete middle letter.
expectAlternative("bxar", ["bar"], {"foo", "explicitly", "bar"});

// Delete last letter.
expectAlternative("barx", ["bar"], {"foo", "explicitly", "bar"});

// Replace first letter.
expectAlternative("car", ["bar"], {"foo", "explicitly", "bar"});

// Replace middle letter.
expectAlternative("bcr", ["bar"], {"foo", "explicitly", "bar"});

// Replace last letter.
expectAlternative("bac", ["bar"], {"foo", "explicitly", "bar"});

print("OK");
}

Expand Down
6 changes: 3 additions & 3 deletions pkg/front_end/test/spelling_test_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ abstract class SpellContext extends ChainContext {

String get repoRelativeSuitePath;

Set<String> reportedWords = {};
Map<String, List<String>?> reportedWordsAndAlternatives = {};
Set<String> reportedWordsDenylisted = {};

@override
Expand All @@ -54,7 +54,7 @@ abstract class SpellContext extends ChainContext {
}
String suitePath = suiteFile.path;
spell.spellSummarizeAndInteractiveMode(
reportedWords,
reportedWordsAndAlternatives,
reportedWordsDenylisted,
dictionaries,
interactive,
Expand Down Expand Up @@ -92,7 +92,7 @@ class SpellTest extends Step<TestDescription, TestDescription, SpellContext> {
context.reportedWordsDenylisted.add(word);
} else {
message = "The word '$word' is not in our dictionary.";
context.reportedWords.add(word);
context.reportedWordsAndAlternatives[word] = alternatives;
}
if (alternatives != null && alternatives.isNotEmpty) {
message += "\n\nThe following word(s) was 'close' "
Expand Down

0 comments on commit 8063ed1

Please sign in to comment.