From a359a9cefc0f6886a0e16b7aced1ecef26b517c5 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 16:10:17 +0200 Subject: [PATCH 01/33] Update workflow --- .github/workflows/build.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c47a0cd33a..bd59d04b55 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -56,6 +56,13 @@ jobs: - run: | dotnet format Roslynator.sln --no-restore --verify-no-changes --severity info - run: dotnet test Roslynator.sln --no-build + - uses: actions/checkout@v3 + with: + repository: josefpihrt/wordb + path: wordb + - run: dotnet tool install -g roslynator.dotnet.cli + - run: ls -R wordb + - run: roslynator spellcheck Roslynator.sln --words ../wordb/en ../wordb/tech.names.txt --dry-run build_core_and_testing: if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') From ba43eceb2801d0b6d9f009584e7b22ba1e298272 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 16:18:49 +0200 Subject: [PATCH 02/33] x --- .github/workflows/build.yml | 10 +-- ...pSpellingService.CSharpSpellingAnalyzer.cs | 6 +- .../CSharp/Spelling/CSharpSpellingService.cs | 4 +- .../CSharp/Spelling/CSharpSpellingWalker.cs | 2 +- src/CommandLine.sln | 21 +---- src/CommandLine/Commands/SpellcheckCommand.cs | 34 ++++---- src/Workspaces.Core/Logging/LogHelpers.cs | 2 +- .../Spelling/ISpellingService.cs | 4 +- ...SpellingFixer.cs => SpellcheckAnalyzer.cs} | 23 ++++-- .../Spelling/SpellcheckOptions.cs | 28 +++++++ .../Spelling/SpellingAnalysisContext.cs | 6 +- .../Spelling/SpellingAnalyzer.cs | 81 ------------------- .../Spelling/SpellingFixerOptions.cs | 57 ------------- .../Spelling/SpellingService.cs | 4 +- 14 files changed, 86 insertions(+), 196 deletions(-) rename src/Workspaces.Core/Spelling/{SpellingFixer.cs => SpellcheckAnalyzer.cs} (96%) create mode 100644 src/Workspaces.Core/Spelling/SpellcheckOptions.cs delete mode 100644 src/Workspaces.Core/Spelling/SpellingAnalyzer.cs delete mode 100644 src/Workspaces.Core/Spelling/SpellingFixerOptions.cs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd59d04b55..d120148980 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,16 +53,16 @@ jobs: echo "version=${version}" >> $GITHUB_OUTPUT - run: dotnet restore Roslynator.sln - run: dotnet build Roslynator.sln --no-restore - - run: | - dotnet format Roslynator.sln --no-restore --verify-no-changes --severity info - - run: dotnet test Roslynator.sln --no-build + # - run: | + # dotnet format Roslynator.sln --no-restore --verify-no-changes --severity info + # - run: dotnet test Roslynator.sln --no-build - uses: actions/checkout@v3 with: repository: josefpihrt/wordb path: wordb - run: dotnet tool install -g roslynator.dotnet.cli - - run: ls -R wordb - - run: roslynator spellcheck Roslynator.sln --words ../wordb/en ../wordb/tech.names.txt --dry-run + - run: ls -R ../wordb + - run: ./CommandLine/bin/Release/net6.0/Roslynator spellcheck Roslynator.sln --words ../wordb/en ../wordb/tech.names.txt --dry-run build_core_and_testing: if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') diff --git a/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingService.CSharpSpellingAnalyzer.cs b/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingService.CSharpSpellingAnalyzer.cs index b761b80dbf..66ddd1d282 100644 --- a/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingService.CSharpSpellingAnalyzer.cs +++ b/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingService.CSharpSpellingAnalyzer.cs @@ -13,14 +13,14 @@ internal partial class CSharpSpellingService [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1001:Missing diagnostic analyzer attribute.")] private class CSharpSpellingAnalyzer : DiagnosticAnalyzer { - private static readonly ImmutableArray _supportedDiagnostics = ImmutableArray.Create(SpellingAnalyzer.DiagnosticDescriptor); + private static readonly ImmutableArray _supportedDiagnostics = ImmutableArray.Create(SpellcheckAnalyzer.DiagnosticDescriptor); private readonly SpellingData _spellingData; - private readonly SpellingFixerOptions _options; + private readonly SpellcheckOptions _options; public CSharpSpellingAnalyzer( SpellingData spellingData, - SpellingFixerOptions options) + SpellcheckOptions options) { _spellingData = spellingData; _options = options; diff --git a/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingService.cs b/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingService.cs index 3176910abc..3d00fc80c6 100644 --- a/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingService.cs +++ b/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingService.cs @@ -24,7 +24,7 @@ internal partial class CSharpSpellingService : SpellingService public override DiagnosticAnalyzer CreateAnalyzer( SpellingData spellingData, - SpellingFixerOptions options) + SpellcheckOptions options) { return new CSharpSpellingAnalyzer(spellingData, options); } @@ -32,7 +32,7 @@ public override DiagnosticAnalyzer CreateAnalyzer( public override ImmutableArray AnalyzeSpelling( SyntaxNode node, SpellingData spellingData, - SpellingFixerOptions options, + SpellcheckOptions options, CancellationToken cancellationToken = default) { var diagnostics = new List(); diff --git a/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingWalker.cs b/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingWalker.cs index 66db12f113..d99918ec02 100644 --- a/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingWalker.cs +++ b/src/CSharp.Workspaces/CSharp/Spelling/CSharpSpellingWalker.cs @@ -15,7 +15,7 @@ internal sealed class CSharpSpellingWalker : CSharpSyntaxWalker private readonly SpellingAnalysisContext _analysisContext; private readonly Stack _stack = new(); - private SpellingFixerOptions Options => _analysisContext.Options; + private SpellcheckOptions Options => _analysisContext.Options; private CSharpSpellingWalker(SpellingAnalysisContext analysisContext, SyntaxWalkerDepth depth) : base(depth) diff --git a/src/CommandLine.sln b/src/CommandLine.sln index dae585da14..50ae20a7a7 100644 --- a/src/CommandLine.sln +++ b/src/CommandLine.sln @@ -4,12 +4,9 @@ VisualStudioVersion = 17.6.33815.320 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8B17331B-D942-4A0C-82AA-23515F4B46C4}" ProjectSection(SolutionItems) = preProject + ..\.github\workflows\build.yml = ..\.github\workflows\build.yml ..\ChangeLog.md = ..\ChangeLog.md - CommandLine\CommandLine.nuspec = CommandLine\CommandLine.nuspec Directory.Build.props = Directory.Build.props - global.ruleset = global.ruleset - ..\docs\HowToFixAllDiagnostics.md = ..\docs\HowToFixAllDiagnostics.md - ..\docs\HowToGenerateDocumentation.md = ..\docs\HowToGenerateDocumentation.md ..\README.md = ..\README.md EndProjectSection EndProject @@ -27,21 +24,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Documentation", "Documentat EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Workspaces.Core", "Workspaces.Core\Workspaces.Core.csproj", "{F8922FB4-67DB-4EA6-932F-AAF9C7503EE7}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CLI", "CLI", "{E5C47A70-19EB-4B95-9B05-DD5CEE67C060}" - ProjectSection(SolutionItems) = preProject - CommandLine\docs\analyze-assembly-command.md = CommandLine\docs\analyze-assembly-command.md - ..\docs\cli\analyze-command.md = ..\docs\cli\analyze-command.md - ..\docs\cli\fix-command.md = ..\docs\cli\fix-command.md - ..\docs\cli\format-command.md = ..\docs\cli\format-command.md - ..\docs\cli\generate-doc-command.md = ..\docs\cli\generate-doc-command.md - ..\docs\cli\generate-doc-root-command.md = ..\docs\cli\generate-doc-root-command.md - ..\docs\cli\list-symbols-command.md = ..\docs\cli\list-symbols-command.md - CommandLine\docs\list-vs-command.md = CommandLine\docs\list-vs-command.md - ..\docs\cli\lloc-command.md = ..\docs\cli\lloc-command.md - ..\docs\cli\loc-command.md = ..\docs\cli\loc-command.md - CommandLine\docs\sln-list-command.md = CommandLine\docs\sln-list-command.md - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisualBasic", "VisualBasic\VisualBasic.csproj", "{05DF2CB8-95FB-4BD9-A9E7-D346470E979A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "Core\Core.csproj", "{D46C9C4D-33D1-467F-96A3-CC05B30BABD0}" @@ -113,7 +95,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {E5C47A70-19EB-4B95-9B05-DD5CEE67C060} = {8B17331B-D942-4A0C-82AA-23515F4B46C4} {669F7A92-C596-4C52-A659-C9A6C66E966B} = {A098889D-10A8-4604-BA34-168E400A1FA6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/src/CommandLine/Commands/SpellcheckCommand.cs b/src/CommandLine/Commands/SpellcheckCommand.cs index 1bc637518b..ca5c9bf1fc 100644 --- a/src/CommandLine/Commands/SpellcheckCommand.cs +++ b/src/CommandLine/Commands/SpellcheckCommand.cs @@ -53,17 +53,19 @@ public override async Task ExecuteAsync(ProjectOrSoluti _ => throw new InvalidOperationException() }; - var options = new SpellingFixerOptions( - scopeFilter: ScopeFilter, - symbolVisibility: visibilityFilter, - minWordLength: Options.MinWordLength, - maxWordLength: Options.MaxWordLength, - includeGeneratedCode: Options.IncludeGeneratedCode, + var options = new SpellcheckOptions() + { + ScopeFilter = ScopeFilter, + SymbolVisibility = visibilityFilter, + MinWordLength = Options.MinWordLength, + MaxWordLength = Options.MaxWordLength, + IncludeGeneratedCode = Options.IncludeGeneratedCode, #if DEBUG - autofix: !Options.NoAutofix, + Autofix = !Options.NoAutofix, #endif - interactive: Options.Interactive, - dryRun: Options.DryRun); + Interactive = Options.Interactive, + DryRun = Options.DryRun, + }; CultureInfo culture = (Options.Culture is not null) ? CultureInfo.GetCultureInfo(Options.Culture) : null; @@ -74,12 +76,12 @@ public override async Task ExecuteAsync(ProjectOrSoluti private async Task FixAsync( ProjectOrSolution projectOrSolution, - SpellingFixerOptions options, + SpellcheckOptions options, ProjectFilter projectFilter, IFormatProvider formatProvider = null, CancellationToken cancellationToken = default) { - SpellingFixer spellingFixer = null; + SpellcheckAnalyzer spellingFixer = null; ImmutableArray results = default; if (projectOrSolution.IsProject) @@ -113,11 +115,15 @@ private async Task FixAsync( WriteSummary(results); - return new SpellcheckCommandResult(CommandStatus.Success, results); + return new SpellcheckCommandResult( + (results.Length == 0 || (!options.DryRun && results.All(f => f.HasFix))) + ? CommandStatus.Success + : CommandStatus.NotSuccess, + results); - SpellingFixer GetSpellingFixer(Solution solution) + SpellcheckAnalyzer GetSpellingFixer(Solution solution) { - return new SpellingFixer( + return new SpellcheckAnalyzer( solution, spellingData: SpellingData, formatProvider: formatProvider, diff --git a/src/Workspaces.Core/Logging/LogHelpers.cs b/src/Workspaces.Core/Logging/LogHelpers.cs index 9147040740..41fc2c2cb5 100644 --- a/src/Workspaces.Core/Logging/LogHelpers.cs +++ b/src/Workspaces.Core/Logging/LogHelpers.cs @@ -80,7 +80,7 @@ public static void WriteDiagnostics( public static void WriteSpellingDiagnostic( SpellingDiagnostic diagnostic, - SpellingFixerOptions options, + SpellcheckOptions options, SourceText sourceText, string baseDirectoryPath, string indentation, diff --git a/src/Workspaces.Core/Spelling/ISpellingService.cs b/src/Workspaces.Core/Spelling/ISpellingService.cs index 80662ee8ed..e93c7c7060 100644 --- a/src/Workspaces.Core/Spelling/ISpellingService.cs +++ b/src/Workspaces.Core/Spelling/ISpellingService.cs @@ -12,12 +12,12 @@ internal interface ISpellingService : ILanguageService { ISyntaxFactsService SyntaxFacts { get; } - DiagnosticAnalyzer CreateAnalyzer(SpellingData spellingData, SpellingFixerOptions options); + DiagnosticAnalyzer CreateAnalyzer(SpellingData spellingData, SpellcheckOptions options); ImmutableArray AnalyzeSpelling( SyntaxNode node, SpellingData spellingData, - SpellingFixerOptions options, + SpellcheckOptions options, CancellationToken cancellationToken); SpellingDiagnostic CreateSpellingDiagnostic(Diagnostic diagnostic); diff --git a/src/Workspaces.Core/Spelling/SpellingFixer.cs b/src/Workspaces.Core/Spelling/SpellcheckAnalyzer.cs similarity index 96% rename from src/Workspaces.Core/Spelling/SpellingFixer.cs rename to src/Workspaces.Core/Spelling/SpellcheckAnalyzer.cs index b95c2a3986..52b32c8355 100644 --- a/src/Workspaces.Core/Spelling/SpellingFixer.cs +++ b/src/Workspaces.Core/Spelling/SpellcheckAnalyzer.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Threading; @@ -17,19 +18,31 @@ namespace Roslynator.Spelling; -internal class SpellingFixer +internal class SpellcheckAnalyzer { - public SpellingFixer( + [SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008:Enable analyzer release tracking")] + public static readonly DiagnosticDescriptor DiagnosticDescriptor = new( + id: CommonDiagnosticIdentifiers.PossibleMisspellingOrTypo, + title: "Possible misspelling or typo", + messageFormat: "Possible misspelling or typo in '{0}'", + category: "Spelling", + defaultSeverity: DiagnosticSeverity.Info, + isEnabledByDefault: true, + description: null, + helpLinkUri: DiagnosticDescriptorUtility.GetHelpLinkUri(CommonDiagnosticIdentifiers.PossibleMisspellingOrTypo), + customTags: Array.Empty()); + + public SpellcheckAnalyzer( Solution solution, SpellingData spellingData, IFormatProvider formatProvider = null, - SpellingFixerOptions options = null) + SpellcheckOptions options = null) { Workspace = solution.Workspace; SpellingData = spellingData; FormatProvider = formatProvider; - Options = options ?? SpellingFixerOptions.Default; + Options = options ?? SpellcheckOptions.Default; } public Workspace Workspace { get; } @@ -38,7 +51,7 @@ public SpellingFixer( public IFormatProvider FormatProvider { get; } - public SpellingFixerOptions Options { get; } + public SpellcheckOptions Options { get; } private Solution CurrentSolution => Workspace.CurrentSolution; diff --git a/src/Workspaces.Core/Spelling/SpellcheckOptions.cs b/src/Workspaces.Core/Spelling/SpellcheckOptions.cs new file mode 100644 index 0000000000..d8ad3c6182 --- /dev/null +++ b/src/Workspaces.Core/Spelling/SpellcheckOptions.cs @@ -0,0 +1,28 @@ +// Copyright (c) Josef Pihrt and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Roslynator.Spelling; + +internal class SpellcheckOptions +{ + public static SpellcheckOptions Default { get; } = new(); + + public SpellingScopeFilter ScopeFilter { get; init; } = SpellingScopeFilter.All; + + public VisibilityFilter SymbolVisibility { get; init; } = VisibilityFilter.All; + + public SplitMode SplitMode { get; init; } = SplitMode.CaseAndHyphen; + + public int MinWordLength { get; init; } = 3; + + public int MaxWordLength { get; init; } = int.MaxValue; + + public int CodeContext { get; init; } = 1; + + public bool IncludeGeneratedCode { get; init; } + + public bool Autofix { get; init; } = true; + + public bool Interactive { get; init; } + + public bool DryRun { get; init; } +} diff --git a/src/Workspaces.Core/Spelling/SpellingAnalysisContext.cs b/src/Workspaces.Core/Spelling/SpellingAnalysisContext.cs index ed6dc5b73d..ef009df6b0 100644 --- a/src/Workspaces.Core/Spelling/SpellingAnalysisContext.cs +++ b/src/Workspaces.Core/Spelling/SpellingAnalysisContext.cs @@ -18,14 +18,14 @@ internal class SpellingAnalysisContext public SpellingData SpellingData { get; } - public SpellingFixerOptions Options { get; } + public SpellcheckOptions Options { get; } public CancellationToken CancellationToken { get; } public SpellingAnalysisContext( Action reportDiagnostic, SpellingData spellingData, - SpellingFixerOptions options, + SpellcheckOptions options, CancellationToken cancellationToken) { SpellingData = spellingData; @@ -82,7 +82,7 @@ private void ProcessMatches( } Diagnostic diagnostic = Diagnostic.Create( - SpellingAnalyzer.DiagnosticDescriptor, + SpellcheckAnalyzer.DiagnosticDescriptor, Location.Create(syntaxTree, new TextSpan(index, match.Value.Length)), properties: properties, messageArgs: match.Value); diff --git a/src/Workspaces.Core/Spelling/SpellingAnalyzer.cs b/src/Workspaces.Core/Spelling/SpellingAnalyzer.cs deleted file mode 100644 index e1e3377d15..0000000000 --- a/src/Workspaces.Core/Spelling/SpellingAnalyzer.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Josef Pihrt and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Roslynator.Host.Mef; - -namespace Roslynator.Spelling; - -internal sealed class SpellingAnalyzer -{ - [SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008:Enable analyzer release tracking")] - public static readonly DiagnosticDescriptor DiagnosticDescriptor = new( - id: CommonDiagnosticIdentifiers.PossibleMisspellingOrTypo, - title: "Possible misspelling or typo", - messageFormat: "Possible misspelling or typo in '{0}'", - category: "Spelling", - defaultSeverity: DiagnosticSeverity.Info, - isEnabledByDefault: true, - description: null, - helpLinkUri: DiagnosticDescriptorUtility.GetHelpLinkUri(CommonDiagnosticIdentifiers.PossibleMisspellingOrTypo), - customTags: Array.Empty()); - - public static async Task> AnalyzeSpellingAsync( - Project project, - SpellingData spellingData, - SpellingFixerOptions options = null, - CancellationToken cancellationToken = default) - { - ISpellingService service = MefWorkspaceServices.Default.GetService(project.Language); - - if (service is null) - return ImmutableArray.Empty; - - ImmutableArray.Builder diagnostics = ImmutableArray.CreateBuilder(); - - foreach (Document document in project.Documents) - { - if (!document.SupportsSyntaxTree) - continue; - - ImmutableArray diagnostics2 = await AnalyzeSpellingAsync( - service, - document, - spellingData, - options, - cancellationToken) - .ConfigureAwait(false); - - diagnostics.AddRange(diagnostics2); - } - - return diagnostics.ToImmutableArray(); - } - - public static async Task> AnalyzeSpellingAsync( - ISpellingService service, - Document document, - SpellingData spellingData, - SpellingFixerOptions options = null, - CancellationToken cancellationToken = default) - { - SyntaxTree tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - - if (tree is null) - return ImmutableArray.Empty; - - if (!options.IncludeGeneratedCode - && GeneratedCodeUtility.IsGeneratedCode(tree, f => service.SyntaxFacts.IsComment(f), cancellationToken)) - { - return ImmutableArray.Empty; - } - - SyntaxNode root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false); - - return service.AnalyzeSpelling(root, spellingData, options, cancellationToken); - } -} diff --git a/src/Workspaces.Core/Spelling/SpellingFixerOptions.cs b/src/Workspaces.Core/Spelling/SpellingFixerOptions.cs deleted file mode 100644 index abce8e6a82..0000000000 --- a/src/Workspaces.Core/Spelling/SpellingFixerOptions.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Josef Pihrt and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Roslynator.Spelling; - -internal class SpellingFixerOptions -{ - public static SpellingFixerOptions Default { get; } = new(); - - public SpellingFixerOptions( - SpellingScopeFilter scopeFilter = SpellingScopeFilter.All, - VisibilityFilter symbolVisibility = VisibilityFilter.All, - SplitMode splitMode = SplitMode.CaseAndHyphen, - int minWordLength = 3, - int maxWordLength = int.MaxValue, - int codeContext = 1, - bool includeGeneratedCode = false, - bool autofix = true, - bool interactive = false, - bool dryRun = false) - { - if (codeContext < 0) - throw new ArgumentOutOfRangeException(nameof(codeContext), codeContext, ""); - - ScopeFilter = scopeFilter; - SymbolVisibility = symbolVisibility; - SplitMode = splitMode; - MinWordLength = minWordLength; - MaxWordLength = maxWordLength; - CodeContext = codeContext; - IncludeGeneratedCode = includeGeneratedCode; - Autofix = autofix; - Interactive = interactive; - DryRun = dryRun; - } - - public SpellingScopeFilter ScopeFilter { get; } - - public VisibilityFilter SymbolVisibility { get; } - - public SplitMode SplitMode { get; } - - public int MinWordLength { get; } - - public int MaxWordLength { get; } - - public int CodeContext { get; } - - public bool IncludeGeneratedCode { get; } - - public bool Autofix { get; } - - public bool Interactive { get; } - - public bool DryRun { get; } -} diff --git a/src/Workspaces.Core/Spelling/SpellingService.cs b/src/Workspaces.Core/Spelling/SpellingService.cs index 8f176dfdc4..e65773b64f 100644 --- a/src/Workspaces.Core/Spelling/SpellingService.cs +++ b/src/Workspaces.Core/Spelling/SpellingService.cs @@ -13,12 +13,12 @@ internal abstract class SpellingService : ISpellingService public abstract DiagnosticAnalyzer CreateAnalyzer( SpellingData spellingData, - SpellingFixerOptions options); + SpellcheckOptions options); public abstract ImmutableArray AnalyzeSpelling( SyntaxNode node, SpellingData spellingData, - SpellingFixerOptions options, + SpellcheckOptions options, CancellationToken cancellationToken); public abstract SpellingDiagnostic CreateSpellingDiagnostic(Diagnostic diagnostic); From 383968761d013e5e3055a5dedc4dd0338c85efa1 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 16:21:42 +0200 Subject: [PATCH 03/33] x --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d120148980..96e6e287f2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,7 +61,7 @@ jobs: repository: josefpihrt/wordb path: wordb - run: dotnet tool install -g roslynator.dotnet.cli - - run: ls -R ../wordb + - run: ls -R ./CommandLine/bin/Release - run: ./CommandLine/bin/Release/net6.0/Roslynator spellcheck Roslynator.sln --words ../wordb/en ../wordb/tech.names.txt --dry-run build_core_and_testing: From 4a6ee9544313e99be7e0eeebb390624a9cc7f4f4 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 16:26:09 +0200 Subject: [PATCH 04/33] x --- src/spellcheck | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/spellcheck diff --git a/src/spellcheck b/src/spellcheck new file mode 100644 index 0000000000..d6f00289a8 --- /dev/null +++ b/src/spellcheck @@ -0,0 +1,33 @@ +Autofix +CorLibReference +cref +csproj +elif +endif +endregion +filterpriority +foofoo +foreach +Goto +href +Josef +langword +Nameof +Pihrt +RCS +RECS +REVB +ROS +singleline +Sln +Stackalloc +tmember +tnode +tsymbol +Tvalue +txt +undef +VSTHRD +XTODO +xvalue +yvalue \ No newline at end of file From 99d760d4456aa573924d7ea2ef55b9f0fd68a32b Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 16:28:41 +0200 Subject: [PATCH 05/33] x --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 96e6e287f2..0d7f3d28b4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,9 +60,9 @@ jobs: with: repository: josefpihrt/wordb path: wordb - - run: dotnet tool install -g roslynator.dotnet.cli + # - run: dotnet tool install -g roslynator.dotnet.cli - run: ls -R ./CommandLine/bin/Release - - run: ./CommandLine/bin/Release/net6.0/Roslynator spellcheck Roslynator.sln --words ../wordb/en ../wordb/tech.names.txt --dry-run + - run: ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --words spellcheck ../wordb/en ../wordb/tech.names.txt --dry-run build_core_and_testing: if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') From 7a402f9231570ae634f8365046048763eef4a22a Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 16:36:36 +0200 Subject: [PATCH 06/33] x --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0d7f3d28b4..7e3359f464 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,8 +61,9 @@ jobs: repository: josefpihrt/wordb path: wordb # - run: dotnet tool install -g roslynator.dotnet.cli - - run: ls -R ./CommandLine/bin/Release - - run: ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --words spellcheck ../wordb/en ../wordb/tech.names.txt --dry-run + - run: ls . + - run: ls ../wordb + - run: ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --words spellcheck ../wordb/en --dry-run build_core_and_testing: if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') From 3ccfc7ea91e0ff3561961101f23e136e1b33d283 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 16:39:48 +0200 Subject: [PATCH 07/33] x --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7e3359f464..aaa234cae3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -63,7 +63,7 @@ jobs: # - run: dotnet tool install -g roslynator.dotnet.cli - run: ls . - run: ls ../wordb - - run: ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --words spellcheck ../wordb/en --dry-run + - run: ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --words spellcheck ../wordb/data/en --dry-run build_core_and_testing: if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') From 0a7a23e77bdebd72cec1d6cfc2d832099147275c Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 16:47:17 +0200 Subject: [PATCH 08/33] x --- .github/workflows/build.yml | 2 +- src/CommandLine/Program.cs | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aaa234cae3..b81d4286cd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -63,7 +63,7 @@ jobs: # - run: dotnet tool install -g roslynator.dotnet.cli - run: ls . - run: ls ../wordb - - run: ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --words spellcheck ../wordb/data/en --dry-run + - run: ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --words spellcheck ../wordb/data/en ../wordb/data/en-us --dry-run build_core_and_testing: if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') diff --git a/src/CommandLine/Program.cs b/src/CommandLine/Program.cs index dbe08bf42f..4e486047c6 100644 --- a/src/CommandLine/Program.cs +++ b/src/CommandLine/Program.cs @@ -630,9 +630,19 @@ private static async Task SpellcheckAsync(SpellcheckCommandLineOptions opti if (!options.TryGetProjectFilter(out ProjectFilter projectFilter)) return ExitCodes.Error; - if (!ParseHelpers.TryEnsureFullPath(options.Words, out ImmutableArray wordListPaths)) + if (!TryEnsureFullPath(options.Words, out ImmutableArray wordListPaths)) return ExitCodes.Error; + foreach (string path in wordListPaths) + { + if (!File.Exists(path) + && !Directory.Exists(path)) + { + WriteLine($"File or directory not found: '{path}'.", ConsoleColors.Yellow, Verbosity.Quiet); + return ExitCodes.Error; + } + } + if (!TryParsePaths(options.Paths, out ImmutableArray paths)) return ExitCodes.Error; From c754d70f6a0eb59d979fdff503058f475b0913b9 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 16:55:55 +0200 Subject: [PATCH 09/33] x --- .github/workflows/build.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b81d4286cd..458c50335f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -63,7 +63,13 @@ jobs: # - run: dotnet tool install -g roslynator.dotnet.cli - run: ls . - run: ls ../wordb - - run: ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --words spellcheck ../wordb/data/en ../wordb/data/en-us --dry-run + - run: > + ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --dry-run --words + spellcheck + ../wordb/data/en + ../wordb/data/en-us + ../wordb/data/en/names.txt + ../wordb/data/en/tech.names.txt build_core_and_testing: if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') From 823fac3cd667c0d803250db3c171e2de46330c8f Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 16:58:52 +0200 Subject: [PATCH 10/33] x --- .github/workflows/build.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 458c50335f..56f4f61098 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,10 +60,7 @@ jobs: with: repository: josefpihrt/wordb path: wordb - # - run: dotnet tool install -g roslynator.dotnet.cli - - run: ls . - - run: ls ../wordb - - run: > + - run: | ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --dry-run --words spellcheck ../wordb/data/en From 8269e2e975ffab00ad72004457b57a4250827b20 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 17:05:12 +0200 Subject: [PATCH 11/33] x --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 56f4f61098..d1ef0aa942 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,11 +61,11 @@ jobs: repository: josefpihrt/wordb path: wordb - run: | - ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --dry-run --words - spellcheck - ../wordb/data/en - ../wordb/data/en-us - ../wordb/data/en/names.txt + ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --dry-run --words \ + spellcheck \ + ../wordb/data/en \ + ../wordb/data/en-us \ + ../wordb/data/en/names.txt \ ../wordb/data/en/tech.names.txt build_core_and_testing: From 86c98a6f1667c301db1f829363c88376ebd85b2a Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 17:07:52 +0200 Subject: [PATCH 12/33] x --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d1ef0aa942..9f19a90cc2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,8 +65,8 @@ jobs: spellcheck \ ../wordb/data/en \ ../wordb/data/en-us \ - ../wordb/data/en/names.txt \ - ../wordb/data/en/tech.names.txt + ../wordb/data/names.txt \ + ../wordb/data/tech.names.txt build_core_and_testing: if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') From 6eecc49cc072365e0d104a43bb41d004e5d20ee9 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 17:13:49 +0200 Subject: [PATCH 13/33] x --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9f19a90cc2..c1743f115b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -66,7 +66,8 @@ jobs: ../wordb/data/en \ ../wordb/data/en-us \ ../wordb/data/names.txt \ - ../wordb/data/tech.names.txt + ../wordb/data/tech.names.txt \ + ../wordb/data/tech.acronyms.txt build_core_and_testing: if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') From e2703606c09ccfb29673e64ee8372486813726e0 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 17:14:52 +0200 Subject: [PATCH 14/33] x --- src/spellcheck | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/src/spellcheck b/src/spellcheck index d6f00289a8..5f282702bb 100644 --- a/src/spellcheck +++ b/src/spellcheck @@ -1,33 +1 @@ -Autofix -CorLibReference -cref -csproj -elif -endif -endregion -filterpriority -foofoo -foreach -Goto -href -Josef -langword -Nameof -Pihrt -RCS -RECS -REVB -ROS -singleline -Sln -Stackalloc -tmember -tnode -tsymbol -Tvalue -txt -undef -VSTHRD -XTODO -xvalue -yvalue \ No newline at end of file + \ No newline at end of file From 8e69ed38ba81dcb9313d62f773b623fb718e502d Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 17:22:19 +0200 Subject: [PATCH 15/33] x --- src/CommandLine/Commands/SpellcheckCommand.cs | 10 ++++-- src/Documentation/Extensions/XmlExtensions.cs | 2 +- src/Documentation/MemberDocumentationParts.cs | 2 +- src/spellcheck | 34 ++++++++++++++++++- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/CommandLine/Commands/SpellcheckCommand.cs b/src/CommandLine/Commands/SpellcheckCommand.cs index ca5c9bf1fc..2d2a4b9626 100644 --- a/src/CommandLine/Commands/SpellcheckCommand.cs +++ b/src/CommandLine/Commands/SpellcheckCommand.cs @@ -212,8 +212,14 @@ private void WriteSummary(ImmutableArray results) WriteMatchingLines(grouping, comparer, ConsoleColors.Green); } - bool any1 = WriteResults(results, SpellingFixKind.Predefined, "Auto fixes:", comparer, isDetailed); - bool any2 = WriteResults(results, SpellingFixKind.User, "User-applied fixes:", comparer, isDetailed); + var any1 = false; + var any2 = false; + + if (!Options.DryRun) + { + any1 = WriteResults(results, SpellingFixKind.Predefined, "Auto fixes:", comparer, isDetailed); + any2 = WriteResults(results, SpellingFixKind.User, "User-applied fixes:", comparer, isDetailed); + } if (!isFirst && !any1 diff --git a/src/Documentation/Extensions/XmlExtensions.cs b/src/Documentation/Extensions/XmlExtensions.cs index 0bd5db332d..c54d179bf1 100644 --- a/src/Documentation/Extensions/XmlExtensions.cs +++ b/src/Documentation/Extensions/XmlExtensions.cs @@ -122,7 +122,7 @@ public static void WriteContentTo(this XElement element, DocumentationWriter wri { ISymbol symbol = writer.DocumentationModel.GetFirstSymbolForDeclarationId(commentId); - //XTODO: repair roslyn documentation + //TODO: repair roslyn documentation Debug.Assert( symbol is not null || commentId == "T:Microsoft.CodeAnalysis.CSharp.SyntaxNode" diff --git a/src/Documentation/MemberDocumentationParts.cs b/src/Documentation/MemberDocumentationParts.cs index e8a3ff0d5a..0019434a54 100644 --- a/src/Documentation/MemberDocumentationParts.cs +++ b/src/Documentation/MemberDocumentationParts.cs @@ -4,7 +4,7 @@ namespace Roslynator.Documentation; -//XTODO: Security +//TODO: Security [Flags] public enum MemberDocumentationParts { diff --git a/src/spellcheck b/src/spellcheck index 5f282702bb..8ed04a4e77 100644 --- a/src/spellcheck +++ b/src/spellcheck @@ -1 +1,33 @@ - \ No newline at end of file +Ascii +Autofix +CorLibReference +cref +csproj +elif +endif +endregion +filterpriority +foofoo +foreach +Goto +href +Josef +langword +Nameof +Pihrt +RCS +RECS +REVB +ROS +singleline +Sln +Stackalloc +tmember +tnode +tsymbol +Tvalue +txt +undef +VSTHRD +xvalue +yvalue \ No newline at end of file From e21ad4a3d3534389e2e185daf7158e78fbde3d1d Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 17:28:33 +0200 Subject: [PATCH 16/33] x --- .../UnncessaryNullForgivingOperatorAnalyzer.cs | 2 +- src/CommandLine/Commands/MSBuildWorkspaceCommand.cs | 12 ++++++------ .../Configuration/VisualStudioCodeAnalysisConfig.cs | 2 +- .../RCS1077OptimizeLinqMethodCallTests.cs | 2 +- .../Analyzers.Tests/RCS1085UseAutoPropertyTests.cs | 2 +- .../RCS1249UnnecessaryNullForgivingOperatorTests.cs | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Analyzers/CSharp/Analysis/UnncessaryNullForgivingOperatorAnalyzer.cs b/src/Analyzers/CSharp/Analysis/UnncessaryNullForgivingOperatorAnalyzer.cs index bf1c8bb9a1..bf12dc135b 100644 --- a/src/Analyzers/CSharp/Analysis/UnncessaryNullForgivingOperatorAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/UnncessaryNullForgivingOperatorAnalyzer.cs @@ -9,7 +9,7 @@ namespace Roslynator.CSharp.Analysis; [DiagnosticAnalyzer(LanguageNames.CSharp)] -public sealed class UnncessaryNullForgivingOperatorAnalyzer : BaseDiagnosticAnalyzer +public sealed class UnnecessaryNullForgivingOperatorAnalyzer : BaseDiagnosticAnalyzer { private static readonly MetadataName System_Diagnostics_CodeAnalysis_MaybeNullWhenAttribute = MetadataName.Parse("System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute"); private static readonly MetadataName System_Diagnostics_CodeAnalysis_NotNullIfNotNullAttribute = MetadataName.Parse("System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute"); diff --git a/src/CommandLine/Commands/MSBuildWorkspaceCommand.cs b/src/CommandLine/Commands/MSBuildWorkspaceCommand.cs index 563b15d0ec..49d222c117 100644 --- a/src/CommandLine/Commands/MSBuildWorkspaceCommand.cs +++ b/src/CommandLine/Commands/MSBuildWorkspaceCommand.cs @@ -277,7 +277,7 @@ private static MSBuildWorkspace CreateMSBuildWorkspace(string msbuildPath, IEnum return MSBuildWorkspace.Create(properties); } - private static bool TryGetVisualStudioInstance(out VisualStudioInstance instance) + private static bool TryGetVisualStudioInstance(out VisualStudioInstance result) { List instances = MSBuildLocator.QueryVisualStudioInstances() .Distinct(VisualStudioInstanceComparer.MSBuildPath) @@ -286,14 +286,14 @@ private static bool TryGetVisualStudioInstance(out VisualStudioInstance instance if (instances.Count == 0) { WriteLine($"MSBuild location not found. Use option '-{OptionShortNames.MSBuildPath}, --{OptionNames.MSBuildPath}' to specify MSBuild location", Verbosity.Quiet); - instance = null; + result = null; return false; } WriteLine("Available MSBuild locations:", Verbosity.Diagnostic); - foreach (VisualStudioInstance vsi in instances.OrderBy(f => f.Version)) - WriteLine($" {vsi.Name}, Version: {vsi.Version}, Path: {vsi.MSBuildPath}", Verbosity.Diagnostic); + foreach (VisualStudioInstance instance in instances.OrderBy(f => f.Version)) + WriteLine($" {instance.Name}, Version: {instance.Version}, Path: {instance.MSBuildPath}", Verbosity.Diagnostic); instances = instances .GroupBy(f => f.Version) @@ -304,11 +304,11 @@ private static bool TryGetVisualStudioInstance(out VisualStudioInstance instance if (instances.Count > 1) { WriteLine($"Cannot choose MSBuild location automatically. Use option '-{OptionShortNames.MSBuildPath}, --{OptionNames.MSBuildPath}' to specify MSBuild location", Verbosity.Quiet); - instance = null; + result = null; return false; } - instance = instances[0]; + result = instances[0]; return true; } diff --git a/src/Common/Configuration/VisualStudioCodeAnalysisConfig.cs b/src/Common/Configuration/VisualStudioCodeAnalysisConfig.cs index 776e7c5ca5..a114f1433a 100644 --- a/src/Common/Configuration/VisualStudioCodeAnalysisConfig.cs +++ b/src/Common/Configuration/VisualStudioCodeAnalysisConfig.cs @@ -25,7 +25,7 @@ public VisualStudioCodeAnalysisConfig( public ImmutableDictionary CodeFixes { get; } - public VisualStudioCodeAnalysisConfig WithPrefixfieldIdentifierWithUnderscore(bool value) + public VisualStudioCodeAnalysisConfig WithPrefixFieldIdentifierWithUnderscore(bool value) { return new VisualStudioCodeAnalysisConfig( value, diff --git a/src/Tests/Analyzers.Tests/RCS1077OptimizeLinqMethodCallTests.cs b/src/Tests/Analyzers.Tests/RCS1077OptimizeLinqMethodCallTests.cs index 463fee4830..33bac3c544 100644 --- a/src/Tests/Analyzers.Tests/RCS1077OptimizeLinqMethodCallTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1077OptimizeLinqMethodCallTests.cs @@ -1107,7 +1107,7 @@ void M() [InlineData("items.FirstOrDefault(_ => true) is null")] [InlineData("items.FirstOrDefault() == null")] [InlineData("items.FirstOrDefault() is null")] - public async Task TestNoDiagnostc_FirstOrDefault_IEnumerableOfNullableType(string source) + public async Task TestNoDiagnostic_FirstOrDefault_IEnumerableOfNullableType(string source) { await VerifyNoDiagnosticAsync(@" using System.Linq; diff --git a/src/Tests/Analyzers.Tests/RCS1085UseAutoPropertyTests.cs b/src/Tests/Analyzers.Tests/RCS1085UseAutoPropertyTests.cs index 7faa1e9606..a8c71f6c0c 100644 --- a/src/Tests/Analyzers.Tests/RCS1085UseAutoPropertyTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1085UseAutoPropertyTests.cs @@ -903,7 +903,7 @@ public double P } [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseAutoProperty)] - public async Task TestNoDiagnostic_BackingFieldHasAttibute() + public async Task TestNoDiagnostic_BackingFieldHasAttribute() { await VerifyNoDiagnosticAsync(@" using System; diff --git a/src/Tests/Analyzers.Tests/RCS1249UnnecessaryNullForgivingOperatorTests.cs b/src/Tests/Analyzers.Tests/RCS1249UnnecessaryNullForgivingOperatorTests.cs index cc97ad5023..2b388a6fed 100644 --- a/src/Tests/Analyzers.Tests/RCS1249UnnecessaryNullForgivingOperatorTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1249UnnecessaryNullForgivingOperatorTests.cs @@ -8,7 +8,7 @@ namespace Roslynator.CSharp.Analysis.Tests; -public class RCS1249UnnecessaryNullForgivingOperatorTests : AbstractCSharpDiagnosticVerifier +public class RCS1249UnnecessaryNullForgivingOperatorTests : AbstractCSharpDiagnosticVerifier { public override DiagnosticDescriptor Descriptor { get; } = DiagnosticRules.UnnecessaryNullForgivingOperator; From e749f7a3efbf4d9bf78d881df4f4c832bacda1ef Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 17:35:24 +0200 Subject: [PATCH 17/33] x --- ChangeLog.md | 1 + src/CommandLine/Commands/SpellcheckCommand.cs | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 258d4c5b82..55d962c3fb 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix [RCS1056](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1056) ([#1154](https://github.com/JosefPihrt/Roslynator/pull/1154)). - Fix [RCS1208](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1208) ([#1153](https://github.com/JosefPihrt/Roslynator/pull/1153)). - Fix [RCS1043](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1043) ([#1176](https://github.com/JosefPihrt/Roslynator/pull/1176)). +- [CLI] Fix `spellcheck` command exit code ([#1177](https://github.com/JosefPihrt/Roslynator/pull/1177)). ## [4.4.0] - 2023-08-01 diff --git a/src/CommandLine/Commands/SpellcheckCommand.cs b/src/CommandLine/Commands/SpellcheckCommand.cs index 2d2a4b9626..a9ff64a62b 100644 --- a/src/CommandLine/Commands/SpellcheckCommand.cs +++ b/src/CommandLine/Commands/SpellcheckCommand.cs @@ -168,8 +168,12 @@ private void WriteSummary(ImmutableArray results) isFirst = true; - foreach (IGrouping grouping in results - .Where(f => !f.HasFix) + IEnumerable filteredResults = results; + + if (!Options.DryRun) + filteredResults = filteredResults.Where(f => !f.HasFix); + + foreach (IGrouping grouping in filteredResults .GroupBy(f => f.Value, comparer) .OrderBy(f => f.Key, comparer)) { From 812369853b5c4fb45ee5135ce060f37c2f8b673a Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 17:43:47 +0200 Subject: [PATCH 18/33] x --- src/CommandLine/Commands/SpellcheckCommand.cs | 2 +- src/Workspaces.Core/Spelling/SpellcheckOptions.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CommandLine/Commands/SpellcheckCommand.cs b/src/CommandLine/Commands/SpellcheckCommand.cs index a9ff64a62b..87635d52c2 100644 --- a/src/CommandLine/Commands/SpellcheckCommand.cs +++ b/src/CommandLine/Commands/SpellcheckCommand.cs @@ -179,7 +179,7 @@ private void WriteSummary(ImmutableArray results) { if (isFirst) { - WriteLine(Verbosity.Normal); + WriteLine("x", Verbosity.Normal); WriteLine("Unknown words:", Verbosity.Normal); isFirst = false; } diff --git a/src/Workspaces.Core/Spelling/SpellcheckOptions.cs b/src/Workspaces.Core/Spelling/SpellcheckOptions.cs index d8ad3c6182..986b57d518 100644 --- a/src/Workspaces.Core/Spelling/SpellcheckOptions.cs +++ b/src/Workspaces.Core/Spelling/SpellcheckOptions.cs @@ -16,7 +16,7 @@ internal class SpellcheckOptions public int MaxWordLength { get; init; } = int.MaxValue; - public int CodeContext { get; init; } = 1; + public int CodeContext { get; init; } public bool IncludeGeneratedCode { get; init; } From f4231462c40ef4dab85ac511d9100c00d54760b2 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 17:47:04 +0200 Subject: [PATCH 19/33] x --- src/CommandLine/Commands/SpellcheckCommand.cs | 2 +- src/spellcheck | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CommandLine/Commands/SpellcheckCommand.cs b/src/CommandLine/Commands/SpellcheckCommand.cs index 87635d52c2..a9ff64a62b 100644 --- a/src/CommandLine/Commands/SpellcheckCommand.cs +++ b/src/CommandLine/Commands/SpellcheckCommand.cs @@ -179,7 +179,7 @@ private void WriteSummary(ImmutableArray results) { if (isFirst) { - WriteLine("x", Verbosity.Normal); + WriteLine(Verbosity.Normal); WriteLine("Unknown words:", Verbosity.Normal); isFirst = false; } diff --git a/src/spellcheck b/src/spellcheck index 8ed04a4e77..053884cca3 100644 --- a/src/spellcheck +++ b/src/spellcheck @@ -13,6 +13,7 @@ Goto href Josef langword +MonoBehaviour Nameof Pihrt RCS From 9d2bfd991b879e519486b64d981849dd9d8f3efc Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 17:50:29 +0200 Subject: [PATCH 20/33] x --- ChangeLog.md | 2 +- src/spellcheck | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 55d962c3fb..1c4f0aa3eb 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -33,7 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix [RCS1056](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1056) ([#1154](https://github.com/JosefPihrt/Roslynator/pull/1154)). - Fix [RCS1208](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1208) ([#1153](https://github.com/JosefPihrt/Roslynator/pull/1153)). - Fix [RCS1043](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1043) ([#1176](https://github.com/JosefPihrt/Roslynator/pull/1176)). -- [CLI] Fix `spellcheck` command exit code ([#1177](https://github.com/JosefPihrt/Roslynator/pull/1177)). +- [CLI] Fix exit code of `spellcheck` command ([#1177](https://github.com/JosefPihrt/Roslynator/pull/1177)). ## [4.4.0] - 2023-08-01 diff --git a/src/spellcheck b/src/spellcheck index 053884cca3..82f560e702 100644 --- a/src/spellcheck +++ b/src/spellcheck @@ -13,7 +13,7 @@ Goto href Josef langword -MonoBehaviour +MonoBehaviourClassName Nameof Pihrt RCS From e41d54863e30564cc2a61f7564aee6dfceb6765a Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 17:55:19 +0200 Subject: [PATCH 21/33] x --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c1743f115b..e2883061f9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,9 +53,9 @@ jobs: echo "version=${version}" >> $GITHUB_OUTPUT - run: dotnet restore Roslynator.sln - run: dotnet build Roslynator.sln --no-restore - # - run: | - # dotnet format Roslynator.sln --no-restore --verify-no-changes --severity info - # - run: dotnet test Roslynator.sln --no-build + - run: | + dotnet format Roslynator.sln --no-restore --verify-no-changes --severity info + - run: dotnet test Roslynator.sln --no-build - uses: actions/checkout@v3 with: repository: josefpihrt/wordb From a345000de414ebd08e5c52617921c596e2d99622 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 18:01:47 +0200 Subject: [PATCH 22/33] x --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e2883061f9..0eff8946ca 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,6 +68,7 @@ jobs: ../wordb/data/names.txt \ ../wordb/data/tech.names.txt \ ../wordb/data/tech.acronyms.txt + name: Spellcheck build_core_and_testing: if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') From 28efc2e6b3e192082580db4b340126f74b6e36ff Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 19:31:54 +0200 Subject: [PATCH 23/33] x --- .github/workflows/build.yml | 3 +-- src/CommandLine/Options/GenerateDocCommandLineOptions.cs | 2 +- src/spellcheck | 7 ++++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0eff8946ca..c663df9eb7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,14 +61,13 @@ jobs: repository: josefpihrt/wordb path: wordb - run: | - ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --dry-run --words \ + ./CommandLine/bin/Release/net7.0/Roslynator spellcheck Roslynator.sln --dry-run --scope all --words \ spellcheck \ ../wordb/data/en \ ../wordb/data/en-us \ ../wordb/data/names.txt \ ../wordb/data/tech.names.txt \ ../wordb/data/tech.acronyms.txt - name: Spellcheck build_core_and_testing: if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') diff --git a/src/CommandLine/Options/GenerateDocCommandLineOptions.cs b/src/CommandLine/Options/GenerateDocCommandLineOptions.cs index a51ee61e38..d55f5bffc9 100644 --- a/src/CommandLine/Options/GenerateDocCommandLineOptions.cs +++ b/src/CommandLine/Options/GenerateDocCommandLineOptions.cs @@ -124,7 +124,7 @@ public class GenerateDocCommandLineOptions : AbstractGenerateDocCommandLineOptio public bool OmitAttributeArguments { get; set; } [Option( - longName: "omit-inherited-atttributes", + longName: "omit-inherited-attributes", HelpText = "Indicates whether inherited attributes should be omitted.")] public bool OmitInheritedAttributes { get; set; } diff --git a/src/spellcheck b/src/spellcheck index 82f560e702..2ac434251e 100644 --- a/src/spellcheck +++ b/src/spellcheck @@ -1,4 +1,9 @@ -Ascii +q[uiet] +m[inimal] +n[ormal] +d[etailed] +diag[nostic] +Ascii Autofix CorLibReference cref From 8331439193f32994b36868c8c65d99f5d07d2618 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 19:54:07 +0200 Subject: [PATCH 24/33] x --- .../Spelling/Core/Spellchecker.cs | 136 +++++++++------- .../Spelling/Core/SpellingData.cs | 4 +- src/Workspaces.Core/Spelling/Core/WordList.cs | 17 +- .../Spelling/Core/WordListLoadOptions.cs | 1 + .../Spelling/Core/WordListLoader.cs | 151 ++++++++---------- .../Spelling/Core/WordListLoaderResult.cs | 2 +- src/spellcheck | 15 +- tools/copy_spelling_from_orang.ps1 | 6 +- 8 files changed, 173 insertions(+), 159 deletions(-) diff --git a/src/Workspaces.Core/Spelling/Core/Spellchecker.cs b/src/Workspaces.Core/Spelling/Core/Spellchecker.cs index 55d80ec4e1..fea471b97b 100644 --- a/src/Workspaces.Core/Spelling/Core/Spellchecker.cs +++ b/src/Workspaces.Core/Spelling/Core/Spellchecker.cs @@ -7,23 +7,6 @@ namespace Roslynator.Spelling; internal class Spellchecker { - private static readonly Regex _wordRegex = new( - @" -\b -\p{L}{2,} -(-\p{L}{2,})* -\p{L}* -( - (?='s\b) -| - ('(d|ll|m|re|t|ve)\b) -| - ('(?!\p{L})\b) -| - \b -)", - RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace); - private const string _splitCasePattern = @" (?<= \p{Lu} @@ -47,53 +30,64 @@ internal class Spellchecker private static readonly Regex _urlRegex = new( @"\bhttps?://[^\s]+(?=\s|\z)", RegexOptions.IgnoreCase); - private readonly Regex _splitRegex; + private readonly Regex _splitRegex = new("-|" + _splitCasePattern, RegexOptions.IgnorePatternWhitespace); public SpellingData Data { get; } - public Regex WordRegex { get; } - public SpellcheckerOptions Options { get; } + internal static Regex WordRegex { get; } = new( + @" +\b +\p{L}{2,} +(-\p{L}{2,})* +\p{L}* +( + (?='s\b) +| + ('(s|d|ll|m|re|t|ve)\b) +| + ('(?!\p{L})\b) +| + \b +)", + RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace); + public Spellchecker( SpellingData data, - Regex wordRegex = null, SpellcheckerOptions options = null) { Data = data; - WordRegex = wordRegex ?? _wordRegex; Options = options ?? SpellcheckerOptions.Default; - - _splitRegex = new Regex("-|" + _splitCasePattern, RegexOptions.IgnorePatternWhitespace); } public ImmutableArray AnalyzeText(string value) { + var context = new SpellingContext(value); + int prevEnd = 0; Match match = _urlRegex.Match(value, prevEnd); - ImmutableArray.Builder builder = null; - while (match.Success) { - AnalyzeText(value, prevEnd, match.Index - prevEnd, ref builder); + AnalyzeText(value, prevEnd, match.Index - prevEnd, ref context); prevEnd = match.Index + match.Length; match = match.NextMatch(); } - AnalyzeText(value, prevEnd, value.Length - prevEnd, ref builder); + AnalyzeText(value, prevEnd, value.Length - prevEnd, ref context); - return builder?.ToImmutableArray() ?? ImmutableArray.Empty; + return context.Builder?.ToImmutableArray() ?? ImmutableArray.Empty; } private void AnalyzeText( string value, int startIndex, int length, - ref ImmutableArray.Builder builder) + ref SpellingContext context) { int sequenceEndIndex = -1; @@ -122,17 +116,9 @@ private void AnalyzeText( continue; } - if (match.Length >= Options.MinWordLength - && match.Length <= Options.MaxWordLength) + if (IsAllowedLength(match.Length)) { - if (_splitRegex is null) - { - AnalyzeValue(match.Value, match.Index, null, 0, ref builder); - } - else - { - AnalyzeSplit(_splitRegex, match.Value, match.Index, 0, ref builder); - } + AnalyzeSplit(_splitRegex, match.Value, match.Index, 0, ref context); } } } @@ -141,11 +127,8 @@ internal ImmutableArray AnalyzeIdentifier( string value, int prefixLength = 0) { - if (value.Length < Options.MinWordLength - || value.Length > Options.MaxWordLength) - { + if (!IsAllowedLength(value.Length)) return ImmutableArray.Empty; - } if (prefixLength > 0 && Data.Contains(value)) @@ -153,11 +136,11 @@ internal ImmutableArray AnalyzeIdentifier( return ImmutableArray.Empty; } - ImmutableArray.Builder builder = null; + var context = new SpellingContext(value); - AnalyzeSplit(_splitIdentifierRegex, value, 0, prefixLength, ref builder); + AnalyzeSplit(_splitIdentifierRegex, value, 0, prefixLength, ref context); - return builder?.ToImmutableArray() ?? ImmutableArray.Empty; + return context.Builder?.ToImmutableArray() ?? ImmutableArray.Empty; } private void AnalyzeSplit( @@ -165,7 +148,7 @@ private void AnalyzeSplit( string input, int offset, int prefixLength, - ref ImmutableArray.Builder builder) + ref SpellingContext context) { Match match = regex.Match(input, prefixLength); @@ -180,11 +163,11 @@ private void AnalyzeSplit( { if (prefixLength > 0) { - AnalyzeValue(input.Substring(prefixLength), offset + prefixLength, input, offset, ref builder); + AnalyzeValue(input.Substring(prefixLength), offset + prefixLength, input, offset, ref context); } else { - AnalyzeValue(input, offset, null, 0, ref builder); + AnalyzeValue(input, offset, null, 0, ref context); } } else if (!Data.Contains(input)) @@ -193,7 +176,7 @@ private void AnalyzeSplit( do { - AnalyzeValue(input.Substring(prevIndex, match.Index - prevIndex), prevIndex + offset, input, offset, ref builder); + AnalyzeValue(input.Substring(prevIndex, match.Index - prevIndex), prevIndex + offset, input, offset, ref context); prevIndex = match.Index + match.Length; @@ -201,7 +184,7 @@ private void AnalyzeSplit( } while (match.Success); - AnalyzeValue(input.Substring(prevIndex), prevIndex + offset, input, offset, ref builder); + AnalyzeValue(input.Substring(prevIndex), prevIndex + offset, input, offset, ref context); } } @@ -210,24 +193,41 @@ private void AnalyzeValue( int valueIndex, string containingValue, int containingValueIndex, - ref ImmutableArray.Builder builder) + ref SpellingContext context) { - if (IsMatch(value)) + if (IsMatch(value) + && !IsContainedInNonWord(value, valueIndex, Data.Words, ref context) + && !IsContainedInNonWord(value, valueIndex, Data.CaseSensitiveWords, ref context)) { var spellingMatch = new SpellingMatch(value, valueIndex, containingValue, containingValueIndex); - (builder ??= ImmutableArray.CreateBuilder()).Add(spellingMatch); + (context.Builder ??= ImmutableArray.CreateBuilder()).Add(spellingMatch); } } - private bool IsMatch(string value) + private bool IsContainedInNonWord(string value, int index, WordList wordList, ref SpellingContext context) { - if (value.Length < Options.MinWordLength - || value.Length > Options.MaxWordLength) + foreach (string nonWord in wordList.NonWords) { - return false; + int i = nonWord.IndexOf(value, wordList.Comparison); + + if (i >= 0 + && index >= i + && index + nonWord.Length - i <= context.Value.Length + && string.Compare(context.Value, index - i, nonWord, 0, nonWord.Length, wordList.Comparison) == 0) + { + return true; + } } + return false; + } + + private bool IsMatch(string value) + { + if (!IsAllowedLength(value.Length)) + return false; + if (IsAllowedNonsensicalWord(value)) return false; @@ -237,6 +237,12 @@ private bool IsMatch(string value) return true; } + private bool IsAllowedLength(int value) + { + return value >= Options.MinWordLength + && value <= Options.MaxWordLength; + } + private static bool IsAllowedNonsensicalWord(string value) { if (value.Length < 3) @@ -376,4 +382,16 @@ bool IsAaaBbbCccSequence() return false; } } + + private class SpellingContext + { + public SpellingContext(string value) + { + Value = value; + } + + public string Value { get; } + + public ImmutableArray.Builder Builder { get; set; } + } } diff --git a/src/Workspaces.Core/Spelling/Core/SpellingData.cs b/src/Workspaces.Core/Spelling/Core/SpellingData.cs index d68c02225f..5f1d54ac6d 100644 --- a/src/Workspaces.Core/Spelling/Core/SpellingData.cs +++ b/src/Workspaces.Core/Spelling/Core/SpellingData.cs @@ -15,8 +15,6 @@ internal class SpellingData private WordCharMap _reversedCharIndexMap; private ImmutableDictionary> _charMap; - public static SpellingData Empty { get; } = new(WordList.Default, WordList.CaseSensitive, FixList.Empty); - public SpellingData( WordList words, WordList caseSensitiveWords, @@ -116,7 +114,7 @@ public WordSequenceMatch GetSequenceMatch(string value, int startIndex, int leng return default; } - private static WordSequenceMatch GetSequenceMatch( + private WordSequenceMatch GetSequenceMatch( string value, int startIndex, int length, diff --git a/src/Workspaces.Core/Spelling/Core/WordList.cs b/src/Workspaces.Core/Spelling/Core/WordList.cs index e64527e7d3..2b2a455b64 100644 --- a/src/Workspaces.Core/Spelling/Core/WordList.cs +++ b/src/Workspaces.Core/Spelling/Core/WordList.cs @@ -12,23 +12,20 @@ namespace Roslynator.Spelling; [DebuggerDisplay("{DebuggerDisplay,nq}")] internal class WordList { - public static StringComparison DefaultComparison { get; } = StringComparison.InvariantCultureIgnoreCase; + public static StringComparison DefaultComparison { get; } = StringComparison.CurrentCultureIgnoreCase; public static StringComparer DefaultComparer { get; } = StringComparerUtility.FromComparison(DefaultComparison); public static WordList Default { get; } = new(null, DefaultComparison); - public static WordList CaseSensitive { get; } = new( - null, - StringComparison.InvariantCulture); - public WordList(IEnumerable values, StringComparison? comparison = null) - : this(values, ImmutableArray.Empty, comparison) + : this(values, null, ImmutableArray.Empty, comparison) { } public WordList( IEnumerable values, + IEnumerable nonWords, IEnumerable sequences, StringComparison? comparison = null) { @@ -36,6 +33,7 @@ public WordList( Comparison = comparison ?? DefaultComparison; Values = values?.ToImmutableHashSet(Comparer) ?? ImmutableHashSet.Empty; + NonWords = nonWords?.ToImmutableHashSet(Comparer) ?? ImmutableHashSet.Empty; Sequences = sequences? .GroupBy(f => f.First, Comparer) @@ -43,8 +41,11 @@ public WordList( ?? ImmutableDictionary>.Empty; } + //TODO: x public ImmutableHashSet Values { get; } + public ImmutableHashSet NonWords { get; } + public ImmutableDictionary> Sequences { get; } public StringComparison Comparison { get; } @@ -128,9 +129,7 @@ public static void Save( if (merge && File.Exists(path)) { - WordListLoaderResult result = WordListLoader.LoadFile(path); - - values = values.Concat(result.List.Values).Concat(result.CaseSensitiveList.Values); + values = values.Concat(WordListLoader.LoadValues(path)); } values = values diff --git a/src/Workspaces.Core/Spelling/Core/WordListLoadOptions.cs b/src/Workspaces.Core/Spelling/Core/WordListLoadOptions.cs index 5b7f78d01a..3ad17bc946 100644 --- a/src/Workspaces.Core/Spelling/Core/WordListLoadOptions.cs +++ b/src/Workspaces.Core/Spelling/Core/WordListLoadOptions.cs @@ -9,4 +9,5 @@ internal enum WordListLoadOptions { None = 0, IgnoreCase = 1, + DetectNonWords = 2, } diff --git a/src/Workspaces.Core/Spelling/Core/WordListLoader.cs b/src/Workspaces.Core/Spelling/Core/WordListLoader.cs index 9a281448b3..978dbe900c 100644 --- a/src/Workspaces.Core/Spelling/Core/WordListLoader.cs +++ b/src/Workspaces.Core/Spelling/Core/WordListLoader.cs @@ -1,6 +1,6 @@ // This code is originally from https://github.com/josefpihrt/orang. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Collections.Concurrent; +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -8,7 +8,6 @@ using System.Linq; using System.Text.RegularExpressions; using System.Threading; -using System.Threading.Tasks; namespace Roslynator.Spelling; @@ -34,92 +33,84 @@ public static WordListLoaderResult Load( } Dictionary> fixes = state.Fixes; + List words = state.Words; + List nonWords = null; - foreach (string word in state.Words) - fixes.Remove(word); - - if (state.CaseSensitiveWords is not null) - { - foreach (string word in state.CaseSensitiveWords) - fixes.Remove(word); - } - - foreach (HashSet values in fixes.Values.ToList()) + if ((options & WordListLoadOptions.DetectNonWords) != 0) { - foreach (string value in values) - fixes.Remove(value); - } - - return new WordListLoaderResult( - new WordList(state.Words, state.Sequences), - new WordList(state.CaseSensitiveWords, state.CaseSensitiveSequences), - FixList.Create(fixes)); - } + nonWords = new List(); - internal static WordListLoaderResult LoadParallel( - IEnumerable paths, - int minWordLength = -1, - int maxWordLength = int.MaxValue, - WordListLoadOptions options = WordListLoadOptions.None, - CancellationToken cancellationToken = default) - { - var states = new ConcurrentBag(); - - var parallelOptions = new ParallelOptions() { CancellationToken = cancellationToken }; - - Parallel.ForEach( - GetFiles(paths), - parallelOptions, - path => + for (int i = words.Count - 1; i >= 0; i--) { - LoadState state = LoadState.Create(options); - LoadFile(path, minWordLength, maxWordLength, state); - states.Add(state); - }); - - bool isCaseSensitive = (options & WordListLoadOptions.IgnoreCase) == 0; - - var words = new List(states.Sum(f => f.Words.Count)); + string word = words[i]; + Match match = Spellchecker.WordRegex.Match(word); - List caseSensitiveWords = null; - List caseSensitiveSequences = null; + if (!match.Success + || match.Index > 0 + || match.Length < word.Length) + { + nonWords.Add(word); + words.RemoveAt(i); + } + } + } - if (isCaseSensitive) + for (int i = words.Count - 1; i >= 0; i--) { - caseSensitiveWords = new List(states.Sum(f => f.CaseSensitiveWords!.Count)); - caseSensitiveSequences = states.SelectMany(f => f.CaseSensitiveSequences).ToList(); + fixes.Remove(words[i]); + + if (words[i].Length < minWordLength + || words[i].Length > maxWordLength) + { + words.RemoveAt(i); + } } - Dictionary> fixes = states.SelectMany(f => f.Fixes).ToDictionary(f => f.Key, f => f.Value); - List sequences = states.SelectMany(f => f.Sequences).ToList(); + List caseSensitiveWords = state.CaseSensitiveWords; + List caseSensitiveNonWords = null; - foreach (LoadState state in states) + if (caseSensitiveWords is not null) { - foreach (string word in state.Words) + if ((options & WordListLoadOptions.DetectNonWords) != 0) { - fixes.Remove(word); - words.Add(word); + caseSensitiveNonWords = new List(); + + for (int i = caseSensitiveWords.Count - 1; i >= 0; i--) + { + string word = caseSensitiveWords[i]; + Match match = Spellchecker.WordRegex.Match(word); + + if (!match.Success + || match.Index > 0 + || match.Length < word.Length) + { + caseSensitiveNonWords.Add(word); + caseSensitiveWords.RemoveAt(i); + } + } } - if (isCaseSensitive) + for (int i = caseSensitiveWords.Count - 1; i >= 0; i--) { - foreach (string word in state.CaseSensitiveWords!) + fixes.Remove(caseSensitiveWords[i]); + + if (caseSensitiveWords[i].Length < minWordLength + || caseSensitiveWords[i].Length > maxWordLength) { - fixes.Remove(word); - caseSensitiveWords!.Add(word); + caseSensitiveWords.RemoveAt(i); } } } - foreach (HashSet values in fixes.Values) + foreach (HashSet values in fixes.Values.ToList()) { foreach (string value in values) fixes.Remove(value); } return new WordListLoaderResult( - new WordList(words, sequences), - new WordList(caseSensitiveWords, caseSensitiveSequences), + new WordList(state.Words, nonWords, state.Sequences, StringComparison.CurrentCultureIgnoreCase), + new WordList(state.CaseSensitiveWords, caseSensitiveNonWords, state.CaseSensitiveSequences, StringComparison.CurrentCulture), FixList.Create(fixes)); } @@ -141,25 +132,23 @@ private static IEnumerable GetFiles(IEnumerable paths) yield return filePath; } } + else + { + throw new InvalidOperationException($"File or directory not found: {path}."); + } } } - public static WordListLoaderResult LoadFile( + public static List LoadValues( string path, int minWordLength = -1, - int maxWordLength = int.MaxValue, - WordListLoadOptions options = WordListLoadOptions.None) + int maxWordLength = int.MaxValue) { - LoadState state = LoadState.Create(options); + LoadState state = LoadState.Create(WordListLoadOptions.IgnoreCase); LoadFile(path, minWordLength, maxWordLength, state); - return new WordListLoaderResult( - new WordList(state.Words, state.Sequences), - ((options & WordListLoadOptions.IgnoreCase) == 0) - ? new WordList(state.CaseSensitiveWords, state.CaseSensitiveSequences) - : WordList.CaseSensitive, - FixList.Create(state.Fixes)); + return state.Words; } private static void LoadFile( @@ -276,18 +265,14 @@ private static void LoadFile( } } } - else if (value.Length >= minWordLength - && value.Length <= maxWordLength) + else if (caseSensitiveWords is not null + && !IsLower(value)) { - if (caseSensitiveWords is not null - && !IsLower(value)) - { - caseSensitiveWords.Add(value); - } - else - { - words.Add(value); - } + caseSensitiveWords.Add(value); + } + else + { + words.Add(value); } } } diff --git a/src/Workspaces.Core/Spelling/Core/WordListLoaderResult.cs b/src/Workspaces.Core/Spelling/Core/WordListLoaderResult.cs index ac68a43ddb..a14c96a212 100644 --- a/src/Workspaces.Core/Spelling/Core/WordListLoaderResult.cs +++ b/src/Workspaces.Core/Spelling/Core/WordListLoaderResult.cs @@ -2,7 +2,7 @@ namespace Roslynator.Spelling; -internal readonly struct WordListLoaderResult +internal class WordListLoaderResult { internal WordListLoaderResult(WordList list, WordList caseSensitiveList, FixList fixList) { diff --git a/src/spellcheck b/src/spellcheck index 2ac434251e..0f75bd89ea 100644 --- a/src/spellcheck +++ b/src/spellcheck @@ -1,8 +1,21 @@ -q[uiet] +completionlist +inheritdoc +listheader +lloc +paramref +RCF +RCSXXXX +roslynatorconfig +seealso +typeparam +typeparamref + +q[uiet] m[inimal] n[ormal] d[etailed] diag[nostic] + Ascii Autofix CorLibReference diff --git a/tools/copy_spelling_from_orang.ps1 b/tools/copy_spelling_from_orang.ps1 index aa70c5a05d..2f4cef2275 100644 --- a/tools/copy_spelling_from_orang.ps1 +++ b/tools/copy_spelling_from_orang.ps1 @@ -10,9 +10,9 @@ orang replace $spellingPath -e cs -c "namespace Orang.Spelling" w l -r "namespac orang replace $spellingPath -e cs -c "[NotNullWhen(true)] " l -t m -orang replace $spellingPath -e cs -c "/[(?[/w/.]+)/././]" -r ".Substring(${x})" +orang replace $spellingPath -e cs -c "\[(?[\w\.]+)\.\.\]" -r ".Substring(`${x})" -orang replace $spellingPath -e cs -c "/[(?[/w/.]+)/./.(?[/w/.]+)/]" -r ".Substring(${x}, ${y} - ${x})" +orang replace $spellingPath -e cs -c "\[(?[\w\.]+)\.\.(?[\w\.]+)\]" -r ".Substring(`${x}, `${y} - `${x})" orang replace $spellingPath -e cs -c " : ICapture" l -t m @@ -21,7 +21,7 @@ orang replace $spellingPath -n WordList.cs e -c "StringComparer.FromComparison" orang replace $spellingPath -n WordChar.cs e -c "HashCode." l -r "Hash." orang replace $spellingPath -e cs ` - -c "// Copyright (c) Josef Pihrt and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information." l ` + -c "// Copyright (c) Josef Pihrt. All rights reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information." l ` -r "// This code is originally from https://github.com/josefpihrt/orang. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information." Write-Host DONE \ No newline at end of file From 7e6ebf8f5245c595048d2939a91ac423047460ea Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 19:59:26 +0200 Subject: [PATCH 25/33] x --- src/Workspaces.Core/Spelling/Core/Spellchecker.cs | 2 +- src/Workspaces.Core/Spelling/Core/SpellingData.cs | 2 +- src/Workspaces.Core/Spelling/Core/WordListLoadOptions.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Workspaces.Core/Spelling/Core/Spellchecker.cs b/src/Workspaces.Core/Spelling/Core/Spellchecker.cs index fea471b97b..0b5f1742f1 100644 --- a/src/Workspaces.Core/Spelling/Core/Spellchecker.cs +++ b/src/Workspaces.Core/Spelling/Core/Spellchecker.cs @@ -205,7 +205,7 @@ private void AnalyzeValue( } } - private bool IsContainedInNonWord(string value, int index, WordList wordList, ref SpellingContext context) + private static bool IsContainedInNonWord(string value, int index, WordList wordList, ref SpellingContext context) { foreach (string nonWord in wordList.NonWords) { diff --git a/src/Workspaces.Core/Spelling/Core/SpellingData.cs b/src/Workspaces.Core/Spelling/Core/SpellingData.cs index 5f1d54ac6d..c45c9c773e 100644 --- a/src/Workspaces.Core/Spelling/Core/SpellingData.cs +++ b/src/Workspaces.Core/Spelling/Core/SpellingData.cs @@ -114,7 +114,7 @@ public WordSequenceMatch GetSequenceMatch(string value, int startIndex, int leng return default; } - private WordSequenceMatch GetSequenceMatch( + private static WordSequenceMatch GetSequenceMatch( string value, int startIndex, int length, diff --git a/src/Workspaces.Core/Spelling/Core/WordListLoadOptions.cs b/src/Workspaces.Core/Spelling/Core/WordListLoadOptions.cs index 3ad17bc946..584b228791 100644 --- a/src/Workspaces.Core/Spelling/Core/WordListLoadOptions.cs +++ b/src/Workspaces.Core/Spelling/Core/WordListLoadOptions.cs @@ -9,5 +9,5 @@ internal enum WordListLoadOptions { None = 0, IgnoreCase = 1, - DetectNonWords = 2, + DetectNonWords = 1 << 1, } From 5ed020b9b475ac12b4f0e77710e9fa2194e977f9 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 20:14:29 +0200 Subject: [PATCH 26/33] x --- src/CommandLine/Program.cs | 7 ++++++- src/CommandLine/Properties/launchSettings.json | 2 +- src/spellcheck | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/CommandLine/Program.cs b/src/CommandLine/Program.cs index 4e486047c6..85d3855d5d 100644 --- a/src/CommandLine/Program.cs +++ b/src/CommandLine/Program.cs @@ -646,11 +646,16 @@ private static async Task SpellcheckAsync(SpellcheckCommandLineOptions opti if (!TryParsePaths(options.Paths, out ImmutableArray paths)) return ExitCodes.Error; + var loadOptions = WordListLoadOptions.DetectNonWords; + + if (!options.CaseSensitive) + loadOptions |= WordListLoadOptions.IgnoreCase; + WordListLoaderResult loaderResult = WordListLoader.Load( wordListPaths, options.MinWordLength, options.MaxWordLength, - (options.CaseSensitive) ? WordListLoadOptions.None : WordListLoadOptions.IgnoreCase); + loadOptions); var data = new SpellingData(loaderResult.List, loaderResult.CaseSensitiveList, loaderResult.FixList); diff --git a/src/CommandLine/Properties/launchSettings.json b/src/CommandLine/Properties/launchSettings.json index 3f374ad18d..bdf00b8577 100644 --- a/src/CommandLine/Properties/launchSettings.json +++ b/src/CommandLine/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "CommandLine": { "commandName": "Project", - "commandLineArgs": "migrate \"E:\\Projects\\Roslynator\\src\\Migration.Test\" --target-version 3.0 --identifier roslynator.analyzers -d" + "commandLineArgs": "spellcheck c:/code/jp/roslynator/src/Roslynator.sln --dry-run --scope all --words c:/code/jp/roslynator/src/spellcheck c:/code/jp/wordb/data/en c:/code/jp/wordb/data/en-us c:/code/jp/wordb/data/names.txt c:/code/jp/wordb/data/tech.names.txt c:/code/jp/wordb/data/tech.acronyms.txt\r\n" } } } \ No newline at end of file diff --git a/src/spellcheck b/src/spellcheck index 0f75bd89ea..2896feb935 100644 --- a/src/spellcheck +++ b/src/spellcheck @@ -9,12 +9,15 @@ roslynatorconfig seealso typeparam typeparamref +ies q[uiet] m[inimal] n[ormal] d[etailed] diag[nostic] +cs[harp] +v[isual-]b[asic] Ascii Autofix From 7eb42df56aec7c5423468d18fcc7219a84b91593 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 20:26:05 +0200 Subject: [PATCH 27/33] x --- .../Spelling/Core/Spellchecker.cs | 4 +- .../Spelling/Core/SpellingData.cs | 46 +++++++++---------- .../Spelling/Core/WordCharMap.cs | 2 +- src/Workspaces.Core/Spelling/Core/WordList.cs | 27 ++++++----- 4 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/Workspaces.Core/Spelling/Core/Spellchecker.cs b/src/Workspaces.Core/Spelling/Core/Spellchecker.cs index 0b5f1742f1..46684c00c9 100644 --- a/src/Workspaces.Core/Spelling/Core/Spellchecker.cs +++ b/src/Workspaces.Core/Spelling/Core/Spellchecker.cs @@ -196,8 +196,8 @@ private void AnalyzeValue( ref SpellingContext context) { if (IsMatch(value) - && !IsContainedInNonWord(value, valueIndex, Data.Words, ref context) - && !IsContainedInNonWord(value, valueIndex, Data.CaseSensitiveWords, ref context)) + && !IsContainedInNonWord(value, valueIndex, Data.WordList, ref context) + && !IsContainedInNonWord(value, valueIndex, Data.CaseSensitiveWordList, ref context)) { var spellingMatch = new SpellingMatch(value, valueIndex, containingValue, containingValueIndex); diff --git a/src/Workspaces.Core/Spelling/Core/SpellingData.cs b/src/Workspaces.Core/Spelling/Core/SpellingData.cs index c45c9c773e..a1b8a655d5 100644 --- a/src/Workspaces.Core/Spelling/Core/SpellingData.cs +++ b/src/Workspaces.Core/Spelling/Core/SpellingData.cs @@ -24,20 +24,20 @@ public SpellingData( } private SpellingData( - WordList words, - WordList caseSensitiveWords, + WordList wordList, + WordList caseSensitiveWordList, FixList fixes, ImmutableHashSet ignoredValues) { - Words = words; - CaseSensitiveWords = caseSensitiveWords; + WordList = wordList; + CaseSensitiveWordList = caseSensitiveWordList; Fixes = fixes ?? FixList.Empty; IgnoredValues = ignoredValues.ToImmutableHashSet(StringComparer.InvariantCulture); } - public WordList Words { get; } + public WordList WordList { get; } - public WordList CaseSensitiveWords { get; } + public WordList CaseSensitiveWordList { get; } public ImmutableHashSet IgnoredValues { get; } @@ -48,7 +48,7 @@ public WordCharMap CharIndexMap get { if (_charIndexMap is null) - Interlocked.CompareExchange(ref _charIndexMap, WordCharMap.CreateCharIndexMap(Words), null); + Interlocked.CompareExchange(ref _charIndexMap, WordCharMap.CreateCharIndexMap(WordList), null); return _charIndexMap; } @@ -59,7 +59,7 @@ public WordCharMap ReversedCharIndexMap get { if (_reversedCharIndexMap is null) - Interlocked.CompareExchange(ref _reversedCharIndexMap, WordCharMap.CreateCharIndexMap(Words, reverse: true), null); + Interlocked.CompareExchange(ref _reversedCharIndexMap, WordCharMap.CreateCharIndexMap(WordList, reverse: true), null); return _reversedCharIndexMap; } @@ -76,7 +76,7 @@ public ImmutableDictionary> CharMap ImmutableDictionary> Create() { - return Words.Values + return WordList.Words .Select(s => { char[] arr = s.ToCharArray(); @@ -85,8 +85,8 @@ ImmutableDictionary> Create() return (value: s, value2: new string(arr)); }) - .GroupBy(f => f.value, Words.Comparer) - .ToImmutableDictionary(f => f.Key, f => f.Select(f => f.value2).ToImmutableHashSet(Words.Comparer)); + .GroupBy(f => f.value, WordList.Comparer) + .ToImmutableDictionary(f => f.Key, f => f.Select(f => f.value2).ToImmutableHashSet(WordList.Comparer)); } } } @@ -94,22 +94,22 @@ ImmutableDictionary> Create() public bool Contains(string value) { return IgnoredValues.Contains(value) - || CaseSensitiveWords.Contains(value) - || Words.Contains(value); + || CaseSensitiveWordList.Contains(value) + || WordList.Contains(value); } public WordSequenceMatch GetSequenceMatch(string value, int startIndex, int length, Match match) { - if (CaseSensitiveWords.Sequences.TryGetValue(match.Value, out ImmutableArray sequences)) + if (CaseSensitiveWordList.Sequences.TryGetValue(match.Value, out ImmutableArray sequences)) { - WordSequenceMatch sequenceMatch = GetSequenceMatch(value, startIndex, length, match, sequences, Words.Comparison); + WordSequenceMatch sequenceMatch = GetSequenceMatch(value, startIndex, length, match, sequences, WordList.Comparison); if (!sequenceMatch.IsDefault) return sequenceMatch; } - if (Words.Sequences.TryGetValue(match.Value, out sequences)) - return GetSequenceMatch(value, startIndex, length, match, sequences, Words.Comparison); + if (WordList.Sequences.TryGetValue(match.Value, out sequences)) + return GetSequenceMatch(value, startIndex, length, match, sequences, WordList.Comparison); return default; } @@ -196,30 +196,30 @@ private static WordSequenceMatch GetSequenceMatch( public SpellingData AddWords(IEnumerable values) { - WordList newList = Words.AddValues(values); + WordList newList = WordList.AddValues(values); - return new SpellingData(newList, CaseSensitiveWords, Fixes, IgnoredValues); + return new SpellingData(newList, CaseSensitiveWordList, Fixes, IgnoredValues); } public SpellingData AddWord(string value) { - return new SpellingData(Words.AddValue(value), CaseSensitiveWords, Fixes, IgnoredValues); + return new SpellingData(WordList.AddValue(value), CaseSensitiveWordList, Fixes, IgnoredValues); } public SpellingData AddFix(string error, SpellingFix fix) { FixList fixList = Fixes.Add(error, fix); - return new SpellingData(Words, CaseSensitiveWords, fixList, IgnoredValues); + return new SpellingData(WordList, CaseSensitiveWordList, fixList, IgnoredValues); } public SpellingData AddIgnoredValue(string value) { - return new SpellingData(Words, CaseSensitiveWords, Fixes, IgnoredValues.Add(value)); + return new SpellingData(WordList, CaseSensitiveWordList, Fixes, IgnoredValues.Add(value)); } public SpellingData AddIgnoredValues(IEnumerable values) { - return new SpellingData(Words, CaseSensitiveWords, Fixes, IgnoredValues.Union(values)); + return new SpellingData(WordList, CaseSensitiveWordList, Fixes, IgnoredValues.Union(values)); } } diff --git a/src/Workspaces.Core/Spelling/Core/WordCharMap.cs b/src/Workspaces.Core/Spelling/Core/WordCharMap.cs index f49794dc49..49161ae2d1 100644 --- a/src/Workspaces.Core/Spelling/Core/WordCharMap.cs +++ b/src/Workspaces.Core/Spelling/Core/WordCharMap.cs @@ -45,7 +45,7 @@ public bool TryGetValue(char ch, int index, out ImmutableHashSet value) public static WordCharMap CreateCharIndexMap(WordList wordList, bool reverse = false) { - ImmutableDictionary> map = wordList.Values + ImmutableDictionary> map = wordList.Words .Select(s => { return ( diff --git a/src/Workspaces.Core/Spelling/Core/WordList.cs b/src/Workspaces.Core/Spelling/Core/WordList.cs index 2b2a455b64..32febbb605 100644 --- a/src/Workspaces.Core/Spelling/Core/WordList.cs +++ b/src/Workspaces.Core/Spelling/Core/WordList.cs @@ -32,7 +32,7 @@ public WordList( Comparer = StringComparerUtility.FromComparison(comparison ?? DefaultComparison); Comparison = comparison ?? DefaultComparison; - Values = values?.ToImmutableHashSet(Comparer) ?? ImmutableHashSet.Empty; + Words = values?.ToImmutableHashSet(Comparer) ?? ImmutableHashSet.Empty; NonWords = nonWords?.ToImmutableHashSet(Comparer) ?? ImmutableHashSet.Empty; Sequences = sequences? @@ -41,8 +41,7 @@ public WordList( ?? ImmutableDictionary>.Empty; } - //TODO: x - public ImmutableHashSet Values { get; } + public ImmutableHashSet Words { get; } public ImmutableHashSet NonWords { get; } @@ -53,16 +52,16 @@ public WordList( public StringComparer Comparer { get; } [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string DebuggerDisplay => $"Words = {Values.Count} Sequences = {Sequences.Sum(f => f.Value.Length)}"; + private string DebuggerDisplay => $"Words = {Words.Count} Sequences = {Sequences.Sum(f => f.Value.Length)}"; public WordList Intersect(WordList wordList, params WordList[] additionalWordLists) { - IEnumerable intersect = Values.Intersect(wordList.Values, Comparer); + IEnumerable intersect = Words.Intersect(wordList.Words, Comparer); if (additionalWordLists?.Length > 0) { intersect = intersect - .Intersect(additionalWordLists.SelectMany(f => f.Values), Comparer); + .Intersect(additionalWordLists.SelectMany(f => f.Words), Comparer); } return WithValues(intersect); @@ -70,12 +69,12 @@ public WordList Intersect(WordList wordList, params WordList[] additionalWordLis public WordList Except(WordList wordList, params WordList[] additionalWordLists) { - IEnumerable except = Values.Except(wordList.Values, Comparer); + IEnumerable except = Words.Except(wordList.Words, Comparer); if (additionalWordLists?.Length > 0) { except = except - .Except(additionalWordLists.SelectMany(f => f.Values), Comparer); + .Except(additionalWordLists.SelectMany(f => f.Words), Comparer); } return WithValues(except); @@ -83,27 +82,27 @@ public WordList Except(WordList wordList, params WordList[] additionalWordLists) public bool Contains(string value) { - return Values.Contains(value); + return Words.Contains(value); } public WordList AddValue(string value) { - return new WordList(Values.Add(value), Comparison); + return new WordList(Words.Add(value), Comparison); } public WordList AddValues(IEnumerable values) { - values = Values.Concat(values).Distinct(Comparer); + values = Words.Concat(values).Distinct(Comparer); return new WordList(values, Comparison); } public WordList AddValues(WordList wordList, params WordList[] additionalWordLists) { - IEnumerable concat = Values.Concat(wordList.Values); + IEnumerable concat = Words.Concat(wordList.Words); if (additionalWordLists?.Length > 0) - concat = concat.Concat(additionalWordLists.SelectMany(f => f.Values)); + concat = concat.Concat(additionalWordLists.SelectMany(f => f.Words)); return WithValues(concat.Distinct(Comparer)); } @@ -117,7 +116,7 @@ public static void Save( string path, WordList wordList) { - Save(path, wordList.Values, wordList.Comparer); + Save(path, wordList.Words, wordList.Comparer); } public static void Save( From 1a77a9826916361e2501da0e5057febc8251d8d4 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 20:28:09 +0200 Subject: [PATCH 28/33] x --- src/Workspaces.Core/Spelling/SpellingFixHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workspaces.Core/Spelling/SpellingFixHelpers.cs b/src/Workspaces.Core/Spelling/SpellingFixHelpers.cs index 1326024ef4..83bf98d12f 100644 --- a/src/Workspaces.Core/Spelling/SpellingFixHelpers.cs +++ b/src/Workspaces.Core/Spelling/SpellingFixHelpers.cs @@ -234,7 +234,7 @@ private static ImmutableArray GetSplitIndexes( // Ienumerable > IEnumerable if ((ch == 'I' || ch == 'T') && diagnostic.Casing == TextCasing.FirstUpper - && spellingData.Words.Contains(value.Substring(1))) + && spellingData.WordList.Contains(value.Substring(1))) { (splitIndexes ??= ImmutableArray.CreateBuilder()).Add(1); } From 13281a230845cff83385aead87dcb6d7ff56421f Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 20:31:35 +0200 Subject: [PATCH 29/33] x --- src/spellcheck | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/spellcheck b/src/spellcheck index 2896feb935..53f6693ba6 100644 --- a/src/spellcheck +++ b/src/spellcheck @@ -1,26 +1,14 @@ -completionlist -inheritdoc -listheader -lloc -paramref -RCF -RCSXXXX -roslynatorconfig -seealso -typeparam -typeparamref -ies - -q[uiet] -m[inimal] -n[ormal] +cs[harp] d[etailed] diag[nostic] -cs[harp] +m[inimal] +n[ormal] +q[uiet] v[isual-]b[asic] Ascii Autofix +completionlist CorLibReference cref csproj @@ -32,15 +20,24 @@ foofoo foreach Goto href +ies +inheritdoc Josef langword +listheader +lloc MonoBehaviourClassName Nameof +paramref Pihrt +RCF RCS +RCSXXXX RECS REVB ROS +roslynatorconfig +seealso singleline Sln Stackalloc @@ -49,7 +46,9 @@ tnode tsymbol Tvalue txt +typeparam +typeparamref undef VSTHRD xvalue -yvalue \ No newline at end of file +yvalue From 8641b378179353c0606ac0087a978ec979a19163 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 20:35:55 +0200 Subject: [PATCH 30/33] x --- src/CommandLine/Properties/launchSettings.json | 2 +- src/Roslynator.sln | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CommandLine/Properties/launchSettings.json b/src/CommandLine/Properties/launchSettings.json index bdf00b8577..484079acb4 100644 --- a/src/CommandLine/Properties/launchSettings.json +++ b/src/CommandLine/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "CommandLine": { "commandName": "Project", - "commandLineArgs": "spellcheck c:/code/jp/roslynator/src/Roslynator.sln --dry-run --scope all --words c:/code/jp/roslynator/src/spellcheck c:/code/jp/wordb/data/en c:/code/jp/wordb/data/en-us c:/code/jp/wordb/data/names.txt c:/code/jp/wordb/data/tech.names.txt c:/code/jp/wordb/data/tech.acronyms.txt\r\n" + "commandLineArgs": "-h" } } } \ No newline at end of file diff --git a/src/Roslynator.sln b/src/Roslynator.sln index 17be6a950a..e3d9aab8ed 100644 --- a/src/Roslynator.sln +++ b/src/Roslynator.sln @@ -11,6 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\ChangeLog.md = ..\ChangeLog.md Directory.Build.props = Directory.Build.props ..\README.md = ..\README.md + spellcheck = spellcheck EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{A1DB0C05-3710-4B69-955F-2F46E330591B}" From 93d9439dde756005830b2ca7aebda54e3447f24a Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 22 Aug 2023 22:46:51 +0200 Subject: [PATCH 31/33] update --- src/Workspaces.Core/Spelling/Core/WordList.cs | 4 +- .../Spelling/Core/WordListLoader.cs | 126 ++++++++---------- 2 files changed, 61 insertions(+), 69 deletions(-) diff --git a/src/Workspaces.Core/Spelling/Core/WordList.cs b/src/Workspaces.Core/Spelling/Core/WordList.cs index 32febbb605..89049c75b0 100644 --- a/src/Workspaces.Core/Spelling/Core/WordList.cs +++ b/src/Workspaces.Core/Spelling/Core/WordList.cs @@ -24,7 +24,7 @@ public WordList(IEnumerable values, StringComparison? comparison = null) } public WordList( - IEnumerable values, + IEnumerable words, IEnumerable nonWords, IEnumerable sequences, StringComparison? comparison = null) @@ -32,7 +32,7 @@ public WordList( Comparer = StringComparerUtility.FromComparison(comparison ?? DefaultComparison); Comparison = comparison ?? DefaultComparison; - Words = values?.ToImmutableHashSet(Comparer) ?? ImmutableHashSet.Empty; + Words = words?.ToImmutableHashSet(Comparer) ?? ImmutableHashSet.Empty; NonWords = nonWords?.ToImmutableHashSet(Comparer) ?? ImmutableHashSet.Empty; Sequences = sequences? diff --git a/src/Workspaces.Core/Spelling/Core/WordListLoader.cs b/src/Workspaces.Core/Spelling/Core/WordListLoader.cs index 978dbe900c..24ca56a58e 100644 --- a/src/Workspaces.Core/Spelling/Core/WordListLoader.cs +++ b/src/Workspaces.Core/Spelling/Core/WordListLoader.cs @@ -33,73 +33,16 @@ public static WordListLoaderResult Load( } Dictionary> fixes = state.Fixes; - List words = state.Words; - List nonWords = null; - - if ((options & WordListLoadOptions.DetectNonWords) != 0) - { - nonWords = new List(); - - for (int i = words.Count - 1; i >= 0; i--) - { - string word = words[i]; - Match match = Spellchecker.WordRegex.Match(word); - - if (!match.Success - || match.Index > 0 - || match.Length < word.Length) - { - nonWords.Add(word); - words.RemoveAt(i); - } - } - } - - for (int i = words.Count - 1; i >= 0; i--) - { - fixes.Remove(words[i]); - if (words[i].Length < minWordLength - || words[i].Length > maxWordLength) - { - words.RemoveAt(i); - } - } + foreach (string word in state.Words) + fixes.Remove(word); List caseSensitiveWords = state.CaseSensitiveWords; - List caseSensitiveNonWords = null; if (caseSensitiveWords is not null) { - if ((options & WordListLoadOptions.DetectNonWords) != 0) - { - caseSensitiveNonWords = new List(); - - for (int i = caseSensitiveWords.Count - 1; i >= 0; i--) - { - string word = caseSensitiveWords[i]; - Match match = Spellchecker.WordRegex.Match(word); - - if (!match.Success - || match.Index > 0 - || match.Length < word.Length) - { - caseSensitiveNonWords.Add(word); - caseSensitiveWords.RemoveAt(i); - } - } - } - - for (int i = caseSensitiveWords.Count - 1; i >= 0; i--) - { - fixes.Remove(caseSensitiveWords[i]); - - if (caseSensitiveWords[i].Length < minWordLength - || caseSensitiveWords[i].Length > maxWordLength) - { - caseSensitiveWords.RemoveAt(i); - } - } + foreach (string word in caseSensitiveWords) + fixes.Remove(word); } foreach (HashSet values in fixes.Values.ToList()) @@ -109,8 +52,12 @@ public static WordListLoaderResult Load( } return new WordListLoaderResult( - new WordList(state.Words, nonWords, state.Sequences, StringComparison.CurrentCultureIgnoreCase), - new WordList(state.CaseSensitiveWords, caseSensitiveNonWords, state.CaseSensitiveSequences, StringComparison.CurrentCulture), + new WordList(state.Words, state.NonWords, state.Sequences, StringComparison.CurrentCultureIgnoreCase), + new WordList( + state.CaseSensitiveWords, + state.CaseSensitiveNonWords, + state.CaseSensitiveSequences, + StringComparison.CurrentCulture), FixList.Create(fixes)); } @@ -158,8 +105,10 @@ private static void LoadFile( LoadState state) { List words = state.Words; - List sequences = state.Sequences; + List nonWords = state.NonWords; List caseSensitiveWords = state.CaseSensitiveWords; + List caseSensitiveNonWords = state.CaseSensitiveNonWords; + List sequences = state.Sequences; List caseSensitiveSequences = state.CaseSensitiveSequences; Dictionary> fixes = state.Fixes; @@ -245,6 +194,9 @@ private static void LoadFile( { string value = line.Substring(startIndex, endIndex - startIndex); + if (value.Length == 0) + continue; + if (whitespaceIndex >= 0 && whitespaceIndex < endIndex) { @@ -268,9 +220,24 @@ private static void LoadFile( else if (caseSensitiveWords is not null && !IsLower(value)) { - caseSensitiveWords.Add(value); + if (caseSensitiveNonWords is not null + && !IsWord(value)) + { + caseSensitiveNonWords.Add(value); + } + else if (value.Length >= minWordLength + && value.Length <= maxWordLength) + { + caseSensitiveWords.Add(value); + } + } + else if (nonWords is not null + && !IsWord(value)) + { + nonWords.Add(value); } - else + else if (value.Length >= minWordLength + && value.Length <= maxWordLength) { words.Add(value); } @@ -278,6 +245,15 @@ private static void LoadFile( } } + private static bool IsWord(string value) + { + Match match = Spellchecker.WordRegex.Match(value); + + return match.Success + && match.Index == 0 + && match.Length == value.Length; + } + private static bool IsLower(string value) { foreach (char ch in value) @@ -296,13 +272,17 @@ private class LoadState { private LoadState( List words, + List nonWords, List caseSensitiveWords, + List caseSensitiveNonWords, List sequences, List caseSensitiveSequences, Dictionary> fixes) { Words = words; + NonWords = nonWords; CaseSensitiveWords = caseSensitiveWords; + CaseSensitiveNonWords = caseSensitiveNonWords; Sequences = sequences; CaseSensitiveSequences = caseSensitiveSequences; Fixes = fixes; @@ -314,22 +294,34 @@ public static LoadState Create(WordListLoadOptions options) var sequences = new List(); var fixes = new Dictionary>(WordList.DefaultComparer); + List nonWords = null; List caseSensitiveWords = null; + List caseSensitiveNonWords = null; List caseSensitiveSequences = null; + if ((options & WordListLoadOptions.DetectNonWords) != 0) + nonWords = new List(); + if ((options & WordListLoadOptions.IgnoreCase) == 0) { caseSensitiveWords = new List(); caseSensitiveSequences = new List(); + + if ((options & WordListLoadOptions.DetectNonWords) != 0) + caseSensitiveNonWords = new List(); } - return new LoadState(words, caseSensitiveWords, sequences, caseSensitiveSequences, fixes); + return new LoadState(words, nonWords, caseSensitiveWords, caseSensitiveNonWords, sequences, caseSensitiveSequences, fixes); } public List Words { get; } + public List NonWords { get; } + public List CaseSensitiveWords { get; } + public List CaseSensitiveNonWords { get; } + public List Sequences { get; } public List CaseSensitiveSequences { get; } From ed1d077e8d18173a5252f508b7ecb6fd1dcc3e21 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Wed, 23 Aug 2023 12:24:29 +0200 Subject: [PATCH 32/33] x --- .../Options/SpellcheckCommandLineOptions.cs | 2 +- .../Spelling/Core/Spellchecker.cs | 2 +- .../Spelling/Core/SpellingData.cs | 2 +- .../Spelling/Core/WordListLoader.cs | 59 +++++++++---------- .../Spelling/Core/WordSequence.cs | 16 ++--- .../Spelling/Core/WordSequenceMatch.cs | 4 +- 6 files changed, 37 insertions(+), 48 deletions(-) diff --git a/src/CommandLine/Options/SpellcheckCommandLineOptions.cs b/src/CommandLine/Options/SpellcheckCommandLineOptions.cs index 5a20f14e7e..f30b5d12ef 100644 --- a/src/CommandLine/Options/SpellcheckCommandLineOptions.cs +++ b/src/CommandLine/Options/SpellcheckCommandLineOptions.cs @@ -82,7 +82,7 @@ public sealed class SpellcheckCommandLineOptions : MSBuildCommandLineOptions [Option( longName: "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 = "")] public IEnumerable Words { get; set; } = null!; } diff --git a/src/Workspaces.Core/Spelling/Core/Spellchecker.cs b/src/Workspaces.Core/Spelling/Core/Spellchecker.cs index 46684c00c9..adf2f3a017 100644 --- a/src/Workspaces.Core/Spelling/Core/Spellchecker.cs +++ b/src/Workspaces.Core/Spelling/Core/Spellchecker.cs @@ -110,7 +110,7 @@ private void AnalyzeText( WordSequenceMatch sequenceMatch = Data.GetSequenceMatch(value, startIndex, length, match); - if (!sequenceMatch.IsDefault) + if (!sequenceMatch.Sequence.Words.IsDefault) { sequenceEndIndex = sequenceMatch.EndIndex; continue; diff --git a/src/Workspaces.Core/Spelling/Core/SpellingData.cs b/src/Workspaces.Core/Spelling/Core/SpellingData.cs index a1b8a655d5..45a39055f2 100644 --- a/src/Workspaces.Core/Spelling/Core/SpellingData.cs +++ b/src/Workspaces.Core/Spelling/Core/SpellingData.cs @@ -104,7 +104,7 @@ public WordSequenceMatch GetSequenceMatch(string value, int startIndex, int leng { WordSequenceMatch sequenceMatch = GetSequenceMatch(value, startIndex, length, match, sequences, WordList.Comparison); - if (!sequenceMatch.IsDefault) + if (!sequenceMatch.Sequence.Words.IsDefault) return sequenceMatch; } diff --git a/src/Workspaces.Core/Spelling/Core/WordListLoader.cs b/src/Workspaces.Core/Spelling/Core/WordListLoader.cs index 24ca56a58e..0c74ad12a9 100644 --- a/src/Workspaces.Core/Spelling/Core/WordListLoader.cs +++ b/src/Workspaces.Core/Spelling/Core/WordListLoader.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Linq; @@ -129,36 +128,35 @@ private static void LoadFile( while (i < line.Length) { - char ch = line[i]; - - if (ch == '#') - { - endIndex = i; - break; - } - else if (separatorIndex == -1) + if (line[i] == ':') { - if (ch == ':') + if (i < line.Length - 1 + && line[i + 1] == ':') { - separatorIndex = i; + i++; } - else if (whitespaceIndex == -1 - && char.IsWhiteSpace(ch)) + else { - whitespaceIndex = i; + separatorIndex = i; + break; } } + else if (char.IsWhiteSpace(line[i])) + { + whitespaceIndex = i; + break; + } i++; } - int j = endIndex - 1; + i = endIndex - 1; - while (j >= startIndex - && char.IsWhiteSpace(line[j])) + while (i >= startIndex + && char.IsWhiteSpace(line[i])) { endIndex--; - j--; + i--; } if (separatorIndex >= 0) @@ -192,7 +190,9 @@ private static void LoadFile( } else { - string value = line.Substring(startIndex, endIndex - startIndex); + string value = line + .Substring(startIndex, endIndex - startIndex) + .Replace("::", ":"); if (value.Length == 0) continue; @@ -200,21 +200,16 @@ private static void LoadFile( if (whitespaceIndex >= 0 && whitespaceIndex < endIndex) { - string[] s = _splitRegex.Split(value); - - Debug.Assert(s.Length > 1, s.Length.ToString()); + string[] values = _splitRegex.Split(value); - if (s.Length > 0) + if (caseSensitiveSequences is not null + && !IsLower(value)) + { + caseSensitiveSequences.Add(new WordSequence(values)); + } + else { - if (caseSensitiveSequences is not null - && !IsLower(value)) - { - caseSensitiveSequences.Add(new WordSequence(s.ToImmutableArray())); - } - else - { - sequences.Add(new WordSequence(s.ToImmutableArray())); - } + sequences.Add(new WordSequence(values)); } } else if (caseSensitiveWords is not null diff --git a/src/Workspaces.Core/Spelling/Core/WordSequence.cs b/src/Workspaces.Core/Spelling/Core/WordSequence.cs index 555826c8ef..485e643423 100644 --- a/src/Workspaces.Core/Spelling/Core/WordSequence.cs +++ b/src/Workspaces.Core/Spelling/Core/WordSequence.cs @@ -1,6 +1,7 @@ // This code is originally from https://github.com/josefpihrt/orang. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -9,15 +10,12 @@ namespace Roslynator.Spelling; [DebuggerDisplay("{DebuggerDisplay,nq}")] internal readonly struct WordSequence { - public WordSequence(ImmutableArray words) + public WordSequence(IEnumerable words) { - if (words.IsDefault - || words.Length <= 1) - { - throw new ArgumentException("", nameof(words)); - } + if (words is null) + throw new ArgumentNullException(nameof(words)); - Words = words; + Words = words.ToImmutableArray(); } public string First => Words[0]; @@ -26,10 +24,8 @@ public WordSequence(ImmutableArray words) public ImmutableArray Words { get; } - public bool IsDefault => Words.IsDefault; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string DebuggerDisplay => (IsDefault) ? "Uninitialized" : $"Count = {Count} {ToString()}"; + private string DebuggerDisplay => (Words.IsDefault) ? "Uninitialized" : $"Count = {Count} {ToString()}"; public override string ToString() { diff --git a/src/Workspaces.Core/Spelling/Core/WordSequenceMatch.cs b/src/Workspaces.Core/Spelling/Core/WordSequenceMatch.cs index 5e5077ca01..6e3592eb95 100644 --- a/src/Workspaces.Core/Spelling/Core/WordSequenceMatch.cs +++ b/src/Workspaces.Core/Spelling/Core/WordSequenceMatch.cs @@ -22,8 +22,6 @@ public WordSequenceMatch(WordSequence sequence, int index, int length) internal int EndIndex => Index + Length; - public bool IsDefault => Sequence.IsDefault; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string DebuggerDisplay => (IsDefault) ? "Uninitialized" : Sequence.ToString(); + private string DebuggerDisplay => (Sequence.Words.IsDefault) ? "Uninitialized" : Sequence.ToString(); } From 01135c3efad678be6fe1abee2fc761fb4b50a109 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Wed, 23 Aug 2023 21:01:47 +0200 Subject: [PATCH 33/33] x --- .../Spelling/Core/Spellchecker.Identifier.cs | 80 ++++++++++ .../Spelling/Core/Spellchecker.cs | 141 ++++++------------ tools/copy_spelling_from_orang.ps1 | 2 +- 3 files changed, 127 insertions(+), 96 deletions(-) create mode 100644 src/Workspaces.Core/Spelling/Core/Spellchecker.Identifier.cs diff --git a/src/Workspaces.Core/Spelling/Core/Spellchecker.Identifier.cs b/src/Workspaces.Core/Spelling/Core/Spellchecker.Identifier.cs new file mode 100644 index 0000000000..5e6f8ac57c --- /dev/null +++ b/src/Workspaces.Core/Spelling/Core/Spellchecker.Identifier.cs @@ -0,0 +1,80 @@ +// This code is originally from https://github.com/josefpihrt/orang. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using System.Text.RegularExpressions; + +namespace Roslynator.Spelling; + +internal partial class Spellchecker +{ + private static readonly Regex _splitIdentifierRegex = new( + @"\P{L}+|" + _splitCasePattern, + RegexOptions.IgnorePatternWhitespace); + + internal ImmutableArray AnalyzeIdentifier(string value, int prefixLength = 0) + { + if (!IsAllowedLength(value.Length)) + return ImmutableArray.Empty; + + if (prefixLength > 0 + && Data.Contains(value)) + { + return ImmutableArray.Empty; + } + + ImmutableArray.Builder builder = null; + + Match match = _splitIdentifierRegex.Match(value, prefixLength); + + if (match.Success + && prefixLength > 0 + && match.Index == prefixLength) + { + match = match.NextMatch(); + } + + if (!match.Success) + { + if (prefixLength > 0) + { + AnalyzeIdentifierValue(value.Substring(prefixLength), prefixLength, value, ref builder); + } + else + { + AnalyzeIdentifierValue(value, 0, null, ref builder); + } + } + else if (prefixLength > 0 + || !Data.Contains(value)) + { + int prevEnd = prefixLength; + + do + { + AnalyzeIdentifierValue(value.Substring(prevEnd, match.Index - prevEnd), prevEnd, value, ref builder); + + prevEnd = match.Index + match.Length; + + match = match.NextMatch(); + } + while (match.Success); + + AnalyzeIdentifierValue(value.Substring(prevEnd), prevEnd, value, ref builder); + } + + return builder?.ToImmutableArray() ?? ImmutableArray.Empty; + } + + private void AnalyzeIdentifierValue( + string value, + int valueIndex, + string parentValue, + ref ImmutableArray.Builder builder) + { + if (IsMatch(value)) + { + var spellingMatch = new SpellingMatch(value, valueIndex, parentValue); + (builder ??= ImmutableArray.CreateBuilder()).Add(spellingMatch); + } + } +} diff --git a/src/Workspaces.Core/Spelling/Core/Spellchecker.cs b/src/Workspaces.Core/Spelling/Core/Spellchecker.cs index adf2f3a017..b8c086f209 100644 --- a/src/Workspaces.Core/Spelling/Core/Spellchecker.cs +++ b/src/Workspaces.Core/Spelling/Core/Spellchecker.cs @@ -5,7 +5,9 @@ namespace Roslynator.Spelling; -internal class Spellchecker +#pragma warning disable RCS1043 + +internal partial class Spellchecker { private const string _splitCasePattern = @" (?<= @@ -23,10 +25,6 @@ internal class Spellchecker ) "; - private static readonly Regex _splitIdentifierRegex = new( - @"\P{L}+|" + _splitCasePattern, - RegexOptions.IgnorePatternWhitespace); - private static readonly Regex _urlRegex = new( @"\bhttps?://[^\s]+(?=\s|\z)", RegexOptions.IgnoreCase); @@ -63,7 +61,7 @@ public Spellchecker( public ImmutableArray AnalyzeText(string value) { - var context = new SpellingContext(value); + ImmutableArray.Builder builder = null; int prevEnd = 0; @@ -71,23 +69,23 @@ public ImmutableArray AnalyzeText(string value) while (match.Success) { - AnalyzeText(value, prevEnd, match.Index - prevEnd, ref context); + AnalyzeTextSegment(value, prevEnd, match.Index - prevEnd, ref builder); prevEnd = match.Index + match.Length; match = match.NextMatch(); } - AnalyzeText(value, prevEnd, value.Length - prevEnd, ref context); + AnalyzeTextSegment(value, prevEnd, value.Length - prevEnd, ref builder); - return context.Builder?.ToImmutableArray() ?? ImmutableArray.Empty; + return builder?.ToImmutableArray() ?? ImmutableArray.Empty; } - private void AnalyzeText( + private void AnalyzeTextSegment( string value, int startIndex, int length, - ref SpellingContext context) + ref ImmutableArray.Builder builder) { int sequenceEndIndex = -1; @@ -116,111 +114,76 @@ private void AnalyzeText( continue; } - if (IsAllowedLength(match.Length)) - { - AnalyzeSplit(_splitRegex, match.Value, match.Index, 0, ref context); - } - } - } - - internal ImmutableArray AnalyzeIdentifier( - string value, - int prefixLength = 0) - { - if (!IsAllowedLength(value.Length)) - return ImmutableArray.Empty; + if (!IsAllowedLength(match.Length)) + continue; - if (prefixLength > 0 - && Data.Contains(value)) - { - return ImmutableArray.Empty; + AnalyzeWord(value, match.Value, match.Index, ref builder); } - - var context = new SpellingContext(value); - - AnalyzeSplit(_splitIdentifierRegex, value, 0, prefixLength, ref context); - - return context.Builder?.ToImmutableArray() ?? ImmutableArray.Empty; } - private void AnalyzeSplit( - Regex regex, + private void AnalyzeWord( string input, - int offset, - int prefixLength, - ref SpellingContext context) + string value, + int index, + ref ImmutableArray.Builder builder) { - Match match = regex.Match(input, prefixLength); - - if (match.Success - && prefixLength > 0 - && match.Index == prefixLength) - { - match = match.NextMatch(); - } + Match match = _splitRegex.Match(value); if (!match.Success) { - if (prefixLength > 0) - { - AnalyzeValue(input.Substring(prefixLength), offset + prefixLength, input, offset, ref context); - } - else - { - AnalyzeValue(input, offset, null, 0, ref context); - } + AnalyzeWordPart(input, value, index, null, 0, ref builder); } - else if (!Data.Contains(input)) + else if (!Data.Contains(value)) { - int prevIndex = prefixLength; + int lastEnd = 0; do { - AnalyzeValue(input.Substring(prevIndex, match.Index - prevIndex), prevIndex + offset, input, offset, ref context); - - prevIndex = match.Index + match.Length; + AnalyzeWordPart(input, value.Substring(lastEnd, match.Index - lastEnd), lastEnd + index, value, index, ref builder); + lastEnd = match.Index + match.Length; match = match.NextMatch(); } while (match.Success); - AnalyzeValue(input.Substring(prevIndex), prevIndex + offset, input, offset, ref context); + AnalyzeWordPart(input, value.Substring(lastEnd), lastEnd + index, value, index, ref builder); } } - private void AnalyzeValue( + private void AnalyzeWordPart( + string input, string value, - int valueIndex, - string containingValue, - int containingValueIndex, - ref SpellingContext context) + int index, + string parentValue, + int parentIndex, + ref ImmutableArray.Builder builder) { if (IsMatch(value) - && !IsContainedInNonWord(value, valueIndex, Data.WordList, ref context) - && !IsContainedInNonWord(value, valueIndex, Data.CaseSensitiveWordList, ref context)) + && !IsContainedInNonWord(input, value, index, Data.WordList) + && !IsContainedInNonWord(input, value, index, Data.CaseSensitiveWordList)) { - var spellingMatch = new SpellingMatch(value, valueIndex, containingValue, containingValueIndex); + var spellingMatch = new SpellingMatch(value, index, parentValue, parentIndex); - (context.Builder ??= ImmutableArray.CreateBuilder()).Add(spellingMatch); + (builder ??= ImmutableArray.CreateBuilder()).Add(spellingMatch); } - } - private static bool IsContainedInNonWord(string value, int index, WordList wordList, ref SpellingContext context) - { - foreach (string nonWord in wordList.NonWords) + static bool IsContainedInNonWord(string input, string value, int index, WordList wordList) { - int i = nonWord.IndexOf(value, wordList.Comparison); - - if (i >= 0 - && index >= i - && index + nonWord.Length - i <= context.Value.Length - && string.Compare(context.Value, index - i, nonWord, 0, nonWord.Length, wordList.Comparison) == 0) + foreach (string nonWord in wordList.NonWords) { - return true; + int i = nonWord.IndexOf(value, wordList.Comparison); + + if (i >= 0 + && index >= i + && index + nonWord.Length - i <= input.Length + && string.Compare(input, index - i, nonWord, 0, nonWord.Length, wordList.Comparison) == 0) + { + return true; + } } - } - return false; + return false; + } } private bool IsMatch(string value) @@ -382,16 +345,4 @@ bool IsAaaBbbCccSequence() return false; } } - - private class SpellingContext - { - public SpellingContext(string value) - { - Value = value; - } - - public string Value { get; } - - public ImmutableArray.Builder Builder { get; set; } - } } diff --git a/tools/copy_spelling_from_orang.ps1 b/tools/copy_spelling_from_orang.ps1 index 2f4cef2275..27fe296231 100644 --- a/tools/copy_spelling_from_orang.ps1 +++ b/tools/copy_spelling_from_orang.ps1 @@ -1,6 +1,6 @@ $spellingPath="../src/Workspaces.Core/Spelling/Core" -orang delete $spellingPath -e cs +orang delete $spellingPath -e cs -n "Spellchecker.Identifier.cs" ne orang copy "../../Orang/src/Spelling/Spelling" --target $spellingPath -e cs