Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve spellchecker #63

Merged
merged 9 commits into from
Aug 23, 2023
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add parameter `--max-depth` for maximum directory depth ([#44](https://github.com/josefpihrt/roslynator/pull/44)).
- Add property `Orang.FileSystem.DirectoryMatcher.MaxDepth`

### Fixed

- Fix exit code of command `spellcheck` ([#63](https://github.com/josefpihrt/roslynator/pull/63)).

## [0.4.0] - 2023-08-17

## [0.4.0-beta.2] - 2023-07-29
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.IO;
using System.Text.RegularExpressions;
using CommandLine;
using Orang.CommandLine.Annotations;
Expand All @@ -12,9 +12,6 @@ namespace Orang.CommandLine;

[Verb("spellcheck", HelpText = "Searches the files' content for potential misspellings and typos.")]
[CommandGroup("File System", 1)]
#if DEBUG
[OptionValueProvider(nameof(Word), OptionValueProviderNames.PatternOptions_Word)]
#endif
internal sealed class SpellcheckCommandLineOptions : CommonReplaceCommandLineOptions
{
[Option(
Expand Down Expand Up @@ -44,14 +41,10 @@ internal sealed class SpellcheckCommandLineOptions : CommonReplaceCommandLineOpt
[Option(
longName: OptionNames.Words,
Required = true,
HelpText = "Specified path to file and/or directory that contains list of allowed words.",
HelpText = "Specified path to file and/or directory that contains list of known words.",
MetaValue = MetaValues.Path)]
public IEnumerable<string> Words { get; set; } = null!;
#if DEBUG
[Option(
longName: OptionNames.Word)]
public IEnumerable<string> Word { get; set; } = null!;
#endif

public bool TryParse(SpellcheckCommandOptions options, ParseContext context)
{
var baseOptions = (CommonReplaceCommandOptions)options;
Expand All @@ -61,30 +54,29 @@ public bool TryParse(SpellcheckCommandOptions options, ParseContext context)

options = (SpellcheckCommandOptions)baseOptions;

Regex? wordRegex = null;

if (!context.TryEnsureFullPath(Words, out ImmutableArray<string> wordListPaths))
return false;
#if DEBUG
if (Word.Any())

foreach (string path in wordListPaths)
{
if (!context.TryParseFilter(
Word,
OptionNames.Word,
OptionValueProviders.PatternOptions_Word_Provider,
out Matcher? wordFilter))
if (!File.Exists(path)
&& !Directory.Exists(path))
{
context.WriteError($"File or directory not found: '{path}'.");
return false;
}

wordRegex = wordFilter!.Regex;
}
#endif

var loadOptions = WordListLoadOptions.DetectNonWords;

if (!CaseSensitive)
loadOptions |= WordListLoadOptions.IgnoreCase;

WordListLoaderResult result = WordListLoader.Load(
wordListPaths,
minWordLength: MinWordLength,
maxWordLength: MaxWordLength,
(CaseSensitive) ? WordListLoadOptions.None : WordListLoadOptions.IgnoreCase);
loadOptions);

var data = new SpellingData(result.List, result.CaseSensitiveList, result.FixList);

Expand All @@ -93,7 +85,7 @@ public bool TryParse(SpellcheckCommandOptions options, ParseContext context)
MinWordLength,
MaxWordLength);

var spellchecker = new Spellchecker(data, wordRegex, spellcheckerOptions);
var spellchecker = new Spellchecker(data, spellcheckerOptions);

options.Replacer = new SpellcheckState(spellchecker, data);

Expand Down
5 changes: 5 additions & 0 deletions src/CommandLine/Commands/FileSystemCommand`1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,11 @@ protected sealed override CommandResult ExecuteCore(CancellationToken cancellati
if (context.TerminationReason == TerminationReason.Canceled)
return CommandResult.Canceled;

return GetCommandResult(context);
}

protected virtual CommandResult GetCommandResult(SearchContext context)
{
return (context.Telemetry.MatchingFileCount > 0 || context.Telemetry.MatchCount > 0)
? CommandResult.Success
: CommandResult.NoMatch;
Expand Down
25 changes: 21 additions & 4 deletions src/CommandLine/Commands/SpellcheckCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Orang.Spelling;

Expand Down Expand Up @@ -136,6 +137,15 @@ private List<TextSpan> GetFilteredSpans(List<Capture> groups, CancellationToken
return spans;
}

protected override CommandResult GetCommandResult(SearchContext context)
{
List<SpellingFixResult> results = SpellcheckState.Results;

return (results.Count == 0 || (!Options.DryRun && results.All(f => f.HasFix)))
? CommandResult.Success
: CommandResult.NoMatch;
}

protected override void WriteBeforeSummary()
{
if (!_logger.ShouldWrite(Verbosity.Normal))
Expand Down Expand Up @@ -169,8 +179,12 @@ protected override void WriteBeforeSummary()

isFirst = true;

foreach (IGrouping<string, SpellingFixResult> grouping in SpellcheckState.Results
.Where(f => !f.HasFix)
IEnumerable<SpellingFixResult> results = SpellcheckState.Results;

if (!Options.DryRun)
results = results.Where(f => !f.HasFix);

foreach (IGrouping<string, SpellingFixResult> grouping in results
.GroupBy(f => f.Value, comparer)
.OrderBy(f => f.Key, comparer))
{
Expand Down Expand Up @@ -210,8 +224,11 @@ protected override void WriteBeforeSummary()
WriteMatchingLines(grouping, comparer, contentIndent, Colors.Match);
}

WriteResults(SpellingFixKind.Predefined, "Auto fixes:", contentIndent, comparer, isDetailed: isDetailed);
WriteResults(SpellingFixKind.User, "User-applied fixes:", contentIndent, comparer, isDetailed: isDetailed);
if (!Options.DryRun)
{
WriteResults(SpellingFixKind.Predefined, "Auto fixes:", contentIndent, comparer, isDetailed: isDetailed);
WriteResults(SpellingFixKind.User, "User-applied fixes:", contentIndent, comparer, isDetailed: isDetailed);
}
}

private void WriteResults(
Expand Down
5 changes: 1 addition & 4 deletions src/CommandLine/DiagnosticWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -535,10 +535,7 @@ internal void WriteSpellcheckCommand(SpellcheckCommandOptions options)
WriteSortOptions("sort", options.SortOptions);
WriteOption("split mode", spellcheckState.Spellchecker.Options.SplitMode);
WriteOption("summary", options.Format.Includes(DisplayParts.Summary));
#if DEBUG
WriteRegex("word", spellcheckState.Spellchecker.WordRegex);
#endif
WriteOption("words", spellcheckState.Data.Words.Values.Count + spellcheckState.Data.CaseSensitiveWords.Values.Count);
WriteOption("words", spellcheckState.Data.WordList.Words.Count + spellcheckState.Data.CaseSensitiveWordList.Words.Count);
}

internal void WriteSyncCommand(SyncCommandOptions options)
Expand Down
1 change: 0 additions & 1 deletion src/CommandLine/Names/OptionNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ internal static class OptionNames
public const string Verbosity = "verbosity";
public const string WholeLine = "whole-line";
public const string WholeWord = "whole-word";
public const string Word = "word";
public const string Words = "words";

private static ImmutableDictionary<string, string>? _namesToShortNames;
Expand Down
1 change: 0 additions & 1 deletion src/CommandLine/Names/OptionValueProviderNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ public const string PatternOptionsWithoutGroupAndPartAndNegative
public const string PatternOptionsWithoutPart = nameof(PatternOptionsWithoutPart);
public const string PatternOptions_Match = nameof(PatternOptions_Match);
public const string PatternOptions_List = nameof(PatternOptions_List);
public const string PatternOptions_Word = nameof(PatternOptions_Word);
public const string RenameHighlightOptions = nameof(RenameHighlightOptions);
public const string ReplaceHighlightOptions = nameof(ReplaceHighlightOptions);
public const string SplitHighlightOptions = nameof(SplitHighlightOptions);
Expand Down
10 changes: 0 additions & 10 deletions src/CommandLine/OptionValueProviders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,6 @@ internal static class OptionValueProviders
OptionValues.Part,
OptionValues.PatternOptions_Negative);

public static OptionValueProvider PatternOptions_Word_Provider { get; }
= PatternOptionsProvider.WithoutValues(
OptionValueProviderNames.PatternOptions_Word,
OptionValues.Group,
OptionValues.Length,
OptionValues.PatternOptions_Negative,
OptionValues.Part,
OptionValues.PatternOptions_RightToLeft
);

public static OptionValueProvider ExtensionOptionsProvider { get; } = new(
MetaValues.ExtensionOptions,
OptionValues.PatternOptions_CaseSensitive,
Expand Down
5 changes: 3 additions & 2 deletions src/DocumentationGenerator/data/spellcheck_bottom.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

Redirected/piped input will be used either as a text to be searched (default) or as a list of paths separated with newlines (when `--pipe p[aths]` is specified.

## List of Allowed Words
## List of Known Words

* It is required to specify one or more wordlists (parameter `--words`).
* Wordlist is defined as a text file that contains list of values separated with newlines.
* Each value is either a valid word (for example `misspell`) or a fix in a format `<ERROR>: <FIX>` (for example `mispell: misspell`).
* Use double colon (`::`) to specify literal value instead of a fix separator.
* Word matching is case-insensitive by default (use option `--case-sensitive` to specify case-sensitive matching).
* It is recommended to use [Wordb](https://github.com/JosefPihrt/Wordb/tree/main/data) wordlists that are specifically tailored to be used for spellchecking.
* It is possible to use [Wordb](https://github.com/JosefPihrt/Wordb/tree/main/data) wordlists that are specifically tailored to be used for spellchecking.
Loading