diff --git a/.editorconfig b/.editorconfig
index 0de42cbb..ac10945d 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -191,6 +191,7 @@ dotnet_diagnostic.IDE0079.severity = none
dotnet_diagnostic.IDE0090.severity = none
dotnet_diagnostic.IDE0220.severity = none
dotnet_diagnostic.IDE1005.severity = suggestion
+dotnet_diagnostic.IDE0220.severity = none
dotnet_diagnostic.IDE1006.severity = suggestion
dotnet_diagnostic.RS1024.severity = none # Compare symbols correctly
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7c93a9fa..e56f8e92 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,51 +8,56 @@ on:
jobs:
- build_packages:
+ build:
runs-on: ubuntu-20.04
env:
Configuration: Release
TreatWarningsAsErrors: true
WarningsNotAsErrors: 1591
+ Deterministic: true
defaults:
run:
working-directory: src
- outputs:
- version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- - name: Update path
- run: echo ":/github/home/.dotnet/tools" >> $GITHUB_PATH
- - run: dotnet tool install -g GitVersion.Tool --version 5.10.1 --ignore-failed-sources
- - run: dotnet tool install -g dotnet-validate --version 0.0.1-preview.304
- - name: Resolve semantic version
- id: semantic_version
+ - run: dotnet tool install -g GitVersion.Tool --version 5.10.0
+ - name: Resolve version
+ id: version
run: |
- semantic_version=$(dotnet-gitversion /showvariable SemVer)
- echo "semantic_version=$semantic_version" >> $GITHUB_ENV
- working-directory: ./
+ dotnet-gitversion > version.json
+ version="$(jq -r '.SemVer' version.json)"
+ pr_version="$(jq -r '.MajorMinorPatch' version.json)-$(jq -r '.PreReleaseLabel' version.json).${{ github.run_number }}.${{ github.run_attempt }}"
+ if [ "${{ github.event_name }}" = "pull_request" ]; then version=$pr_version; fi
+ echo "Resolved version: $version"
+ echo "Version=${version}" >> "$GITHUB_ENV"
- run: dotnet restore --configfile nuget.config
- run: dotnet format --no-restore --verify-no-changes --severity info --exclude-diagnostics IDE0270
- - run: dotnet build --no-restore /p:Version=${{ env.semantic_version }}
+ - run: dotnet build --no-restore
- run: dotnet test --no-build
- - run: dotnet pack --no-build /p:PackageVersion=${{ env.semantic_version }}
+ - run: dotnet pack --no-build
- uses: actions/upload-artifact@v3
with:
name: nuget_packages
- path: src/CommandLine/bin/Release/*nupkg
+ path: src/CommandLine/bin/Release/*.*nupkg
+ - uses: actions/upload-artifact@v3
+ with:
+ name: nuget_packages
+ path: src/Common/bin/Release/*nupkg
+ - uses: actions/upload-artifact@v3
+ with:
+ name: nuget_packages
+ path: src/FileSystem/bin/Release/*.*nupkg
- release_packages:
+ publish:
runs-on: ubuntu-20.04
- needs: [build_packages]
+ needs: [build]
if: github.ref_type == 'tag'
- env:
- NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
steps:
- uses: actions/download-artifact@v3
with:
name: nuget_packages
path: nuget_packages
- - run: dotnet nuget push "*.nupkg" -k NUGET_API_KEY -s "https://api.nuget.org/v3/index.json"
+ - run: dotnet nuget push "*.nupkg" -k ${{ secrets.NUGET_API_KEY }} -s "https://api.nuget.org/v3/index.json" --skip-duplicate
working-directory: nuget_packages
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 14fe838c..dec37d90 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+### Added
+
+- Add [.NET API](https://josefpihrt.github.io/docs/orang/ref) ([#51](https://github.com/josefpihrt/roslynator/pull/51)).
+
### Changed
- Migrate documentation to [Docusaurus](https://josefpihrt.github.io/docs/orang) ([#48](https://github.com/josefpihrt/roslynator/pull/48)).
diff --git a/src/CommandLine.Core/CommandLine.Core.csproj b/src/CommandLine.Core/CommandLine.Core.csproj
index 3006c371..7ada90ee 100644
--- a/src/CommandLine.Core/CommandLine.Core.csproj
+++ b/src/CommandLine.Core/CommandLine.Core.csproj
@@ -8,7 +8,7 @@
-
+
@@ -16,4 +16,13 @@
+
+
+ <_Parameter1>Orang, PublicKey=$(OrangPublicKey)
+
+
+ <_Parameter1>Orang.DocumentationGenerator, PublicKey=$(OrangPublicKey)
+
+
+
\ No newline at end of file
diff --git a/src/CommandLine.Core/Help/CommandHelp.cs b/src/CommandLine.Core/Help/CommandHelp.cs
index de4126ee..ca7f0a9a 100644
--- a/src/CommandLine.Core/Help/CommandHelp.cs
+++ b/src/CommandLine.Core/Help/CommandHelp.cs
@@ -42,18 +42,18 @@ public CommandHelp(
public static CommandHelp Create(
Command command,
IEnumerable? providers = null,
- Filter? filter = null)
+ Matcher? matcher = null)
{
ImmutableArray arguments = (command.Arguments.Any())
- ? HelpProvider.GetArgumentItems(command.Arguments, filter)
+ ? HelpProvider.GetArgumentItems(command.Arguments, matcher)
: ImmutableArray.Empty;
- ImmutableArray options = HelpProvider.GetOptionItems(command.Options, filter);
+ ImmutableArray options = HelpProvider.GetOptionItems(command.Options, matcher);
ImmutableArray values = HelpProvider.GetOptionValues(
command.Options,
providers ?? ImmutableArray.Empty,
- filter);
+ matcher);
return new CommandHelp(command, arguments, options, values);
}
diff --git a/src/CommandLine.Core/Help/CommandsHelp.cs b/src/CommandLine.Core/Help/CommandsHelp.cs
index 287b0cf5..8f555a4c 100644
--- a/src/CommandLine.Core/Help/CommandsHelp.cs
+++ b/src/CommandLine.Core/Help/CommandsHelp.cs
@@ -23,14 +23,14 @@ public CommandsHelp(
public static CommandsHelp Create(
IEnumerable commands,
IEnumerable? providers = null,
- Filter? filter = null)
+ Matcher? matcher = null)
{
- ImmutableArray commandsHelp = HelpProvider.GetCommandItems(commands, filter);
+ ImmutableArray commandsHelp = HelpProvider.GetCommandItems(commands, matcher);
ImmutableArray values = HelpProvider.GetOptionValues(
commands.SelectMany(f => f.Options),
providers ?? ImmutableArray.Empty,
- filter);
+ matcher);
return new CommandsHelp(commandsHelp, values);
}
diff --git a/src/CommandLine.Core/Help/HelpProvider.cs b/src/CommandLine.Core/Help/HelpProvider.cs
index cbeee953..f3a6640b 100644
--- a/src/CommandLine.Core/Help/HelpProvider.cs
+++ b/src/CommandLine.Core/Help/HelpProvider.cs
@@ -12,7 +12,7 @@ internal static class HelpProvider
{
public const int SeparatorWidth = 2;
- public static ImmutableArray GetCommandItems(IEnumerable commands, Filter? filter = null)
+ public static ImmutableArray GetCommandItems(IEnumerable commands, Matcher? matcher = null)
{
if (!commands.Any())
return ImmutableArray.Empty;
@@ -33,7 +33,7 @@ public static ImmutableArray GetCommandItems(IEnumerable c
var commandItem = new CommandItem(command, syntax, description);
- if (filter?.IsMatch(commandItem.Text) != false)
+ if (matcher?.IsMatch(commandItem.Text) != false)
builder.Add(commandItem);
}
@@ -42,7 +42,7 @@ public static ImmutableArray GetCommandItems(IEnumerable c
public static ImmutableArray GetArgumentItems(
IEnumerable arguments,
- Filter? filter = null)
+ Matcher? matcher = null)
{
int width = CalculateArgumentsWidths(arguments);
@@ -66,7 +66,7 @@ public static ImmutableArray GetArgumentItems(
var argumentItem = new ArgumentItem(argument, syntax, description);
- if (filter?.IsMatch(argumentItem.Text) != false)
+ if (matcher?.IsMatch(argumentItem.Text) != false)
{
builder.Add(argumentItem);
}
@@ -75,7 +75,7 @@ public static ImmutableArray GetArgumentItems(
return builder.ToImmutableArray();
}
- public static ImmutableArray GetOptionItems(IEnumerable options, Filter? filter = null)
+ public static ImmutableArray GetOptionItems(IEnumerable options, Matcher? matcher = null)
{
int width = CalculateOptionsWidths(options);
@@ -119,7 +119,7 @@ public static ImmutableArray GetOptionItems(IEnumerable GetOptionItems(IEnumerable GetOptionValues(
IEnumerable options,
IEnumerable providers,
- Filter? filter = null)
+ Matcher? matcher = null)
{
providers = OptionValueProvider.GetProviders(options, providers).ToImmutableArray();
@@ -147,8 +147,8 @@ public static ImmutableArray GetOptionValues(
builder.Add(new OptionValueItemList(provider.Name, valueItems));
}
- return (filter is not null)
- ? FilterOptionValues(builder, filter)
+ return (matcher is not null)
+ ? FilterOptionValues(builder, matcher)
: builder.ToImmutableArray();
}
@@ -192,20 +192,20 @@ public static ImmutableArray GetOptionValueItems(
private static ImmutableArray FilterOptionValues(
IEnumerable values,
- Filter filter)
+ Matcher matcher)
{
ImmutableArray.Builder builder = ImmutableArray.CreateBuilder();
foreach (OptionValueItemList valueList in values)
{
- if (filter.IsMatch(valueList.MetaValue))
+ if (matcher.IsMatch(valueList.MetaValue))
{
builder.Add(valueList);
}
else
{
ImmutableArray valueItems = valueList.Values
- .Where(f => filter.IsMatch(f.Text))
+ .Where(f => matcher.IsMatch(f.Text))
.ToImmutableArray();
if (valueItems.Any())
@@ -261,15 +261,15 @@ public static ImmutableArray GetExpressionLines(string? variableName = n
variableName ??= "x";
builder.Add(($"{variableName}=n", ""));
- builder.Add(($"{variableName}n", ""));
- builder.Add(($"{variableName}<=n", ""));
- builder.Add(($"{variableName}>=n", ""));
- builder.Add(($"{variableName}=", "Inclusive interval"));
- builder.Add(($"{variableName}=(min;max)", "Exclusive interval"));
+ builder.Add(($@"""{variableName}n""", ""));
+ builder.Add(($@"""{variableName}<=n""", ""));
+ builder.Add(($@" ""{variableName}>=n""", ""));
+ builder.Add(($@" ""{variableName}=""", "Inclusive interval"));
+ builder.Add(($@" ""{variableName}=(min;max)""", "Exclusive interval"));
if (includeDate)
- builder.Add(($"{variableName}=-d|[d.]hh:mm[:ss]", $"{variableName} is greater than actual date - "));
+ builder.Add(($@"""{variableName}=-d|[d.]hh:mm[:ss]""", $"{variableName} is greater than actual date - "));
return builder.ToImmutableArray();
}
diff --git a/src/CommandLine.Core/Help/HelpWriter.cs b/src/CommandLine.Core/Help/HelpWriter.cs
index b4ed1de5..a6f1effa 100644
--- a/src/CommandLine.Core/Help/HelpWriter.cs
+++ b/src/CommandLine.Core/Help/HelpWriter.cs
@@ -27,7 +27,7 @@ public virtual void WriteCommand(CommandHelp commandHelp)
WriteArguments(arguments);
WriteEndArguments(commandHelp);
}
- else if (Options.Filter is not null
+ else if (Options.Matcher is not null
&& commandHelp.Command.Arguments.Any())
{
WriteLine();
@@ -42,7 +42,7 @@ public virtual void WriteCommand(CommandHelp commandHelp)
WriteOptions(options);
WriteEndOptions(commandHelp);
}
- else if (Options.Filter is not null
+ else if (Options.Matcher is not null
&& commandHelp.Command.Options.Any())
{
WriteLine();
@@ -114,7 +114,7 @@ public virtual void WriteCommands(CommandsHelp commandsHelp)
WriteEndCommands(commandsHelp);
}
- else if (Options.Filter is not null)
+ else if (Options.Matcher is not null)
{
WriteLine("No command found");
}
@@ -171,6 +171,23 @@ public void WriteValues(IEnumerable optionValues)
}
}
+ public void WriteExpressionSyntax(IEnumerable optionValues)
+ {
+ ImmutableArray expressions = HelpProvider.GetExpressionItems(optionValues);
+
+ if (!expressions.IsEmpty)
+ {
+ WriteLine();
+ WriteHeading("Expression syntax");
+
+ foreach (string expression in expressions)
+ {
+ Write(Options.Indent);
+ WriteLine(expression);
+ }
+ }
+ }
+
private void WriteValues(ImmutableArray values)
{
foreach (OptionValueItem value in values)
diff --git a/src/CommandLine.Core/Help/HelpWriterOptions.cs b/src/CommandLine.Core/Help/HelpWriterOptions.cs
index 8ce5981a..4bb6a948 100644
--- a/src/CommandLine.Core/Help/HelpWriterOptions.cs
+++ b/src/CommandLine.Core/Help/HelpWriterOptions.cs
@@ -8,13 +8,13 @@ public class HelpWriterOptions
public HelpWriterOptions(
string indent = " ",
- Filter? filter = null)
+ Matcher? matcher = null)
{
Indent = indent;
- Filter = filter;
+ Matcher = matcher;
}
public string Indent { get; }
- public Filter? Filter { get; }
+ public Matcher? Matcher { get; }
}
diff --git a/src/CommandLine.Core/Properties/AssemblyInfo.cs b/src/CommandLine.Core/Properties/AssemblyInfo.cs
deleted file mode 100644
index 73afcbeb..00000000
--- a/src/CommandLine.Core/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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.
-
-using System.Runtime.CompilerServices;
-
-#pragma warning disable RCS0056
-
-[assembly: InternalsVisibleTo("Orang, PublicKey=00240000048000009400000006020000002400005253413100040000010001009ff202171ab25d708192b490c52c1a373c74a2849c734fd9f545bfedc92b61d4e10d356cd26213ef6d96af669a9b570cd6277d590c338cfc00ccc9a15d6ad5b08ac3a8a09db3eae536d653f4acb9c7e992162129b67b4bc72c08af7d67a48ecde99c53a5d2cd44b1e8179368f6db2ec7665061e3ef4029703df4b49952bd0de4")]
-[assembly: InternalsVisibleTo("Orang.DocumentationGenerator, PublicKey=00240000048000009400000006020000002400005253413100040000010001009ff202171ab25d708192b490c52c1a373c74a2849c734fd9f545bfedc92b61d4e10d356cd26213ef6d96af669a9b570cd6277d590c338cfc00ccc9a15d6ad5b08ac3a8a09db3eae536d653f4acb9c7e992162129b67b4bc72c08af7d67a48ecde99c53a5d2cd44b1e8179368f6db2ec7665061e3ef4029703df4b49952bd0de4")]
diff --git a/src/CommandLine/Aggregation/StorageSectionComparer.cs b/src/CommandLine/Aggregation/StorageSectionComparer.cs
index 20bf40dc..1ab05111 100644
--- a/src/CommandLine/Aggregation/StorageSectionComparer.cs
+++ b/src/CommandLine/Aggregation/StorageSectionComparer.cs
@@ -20,12 +20,12 @@ private class PathStorageSectionComparer : StorageSectionComparer
{
public override int Compare([AllowNull] StorageSection x, [AllowNull] StorageSection y)
{
- return FileSystemHelpers.Comparer.Compare(x.FileMatch?.Path, y.FileMatch?.Path);
+ return FileSystemUtilities.Comparer.Compare(x.FileMatch?.Path, y.FileMatch?.Path);
}
public override bool Equals([AllowNull] StorageSection x, [AllowNull] StorageSection y)
{
- return FileSystemHelpers.Comparer.Equals(x.FileMatch?.Path, y.FileMatch?.Path);
+ return FileSystemUtilities.Comparer.Equals(x.FileMatch?.Path, y.FileMatch?.Path);
}
public override int GetHashCode([DisallowNull] StorageSection obj)
@@ -35,7 +35,7 @@ public override int GetHashCode([DisallowNull] StorageSection obj)
if (path is null)
return 0;
- return FileSystemHelpers.Comparer.GetHashCode(path);
+ return FileSystemUtilities.Comparer.GetHashCode(path);
}
}
}
diff --git a/src/CommandLine/CommandLine.csproj b/src/CommandLine/CommandLine.csproj
index b6ed5512..0428f53e 100644
--- a/src/CommandLine/CommandLine.csproj
+++ b/src/CommandLine/CommandLine.csproj
@@ -8,32 +8,12 @@
+ true
true
orang
Orang.DotNet.Cli
- Search, replace, rename and delete directories, files and its content using the power of .NET regular expressions.
- https://github.com/JosefPihrt/Orang
- Apache-2.0
- icon.png
- RegularExpression;Regex;RegExp;CLI
- docs/README.md
- https://github.com/JosefPihrt/Orang.git
- git
- false
-
- true
- true
- true
- true
- snupkg
-
-
-
-
-
-
@@ -41,7 +21,7 @@
-
+
@@ -54,4 +34,13 @@
+
+
+ <_Parameter1>Orang.DocumentationGenerator, PublicKey=$(OrangPublicKey)
+
+
+ <_Parameter1>Orang.CommandLine.Tests, PublicKey=$(OrangPublicKey)
+
+
+
diff --git a/src/CommandLine/CommandLineExtensions.cs b/src/CommandLine/CommandLineExtensions.cs
index 1284edfe..58e35ed2 100644
--- a/src/CommandLine/CommandLineExtensions.cs
+++ b/src/CommandLine/CommandLineExtensions.cs
@@ -72,7 +72,7 @@ public static void WriteFileError(
if (!string.IsNullOrEmpty(path)
&& !string.IsNullOrEmpty(message)
- && !message.Contains(path, FileSystemHelpers.Comparison))
+ && !message.Contains(path, FileSystemUtilities.Comparison))
{
logger.WriteLine($"{indent}PATH: {path}", Colors.Message_Warning, verbosity);
}
@@ -84,7 +84,7 @@ public static void WriteFileError(
public static void WriteSearchedFilesAndDirectories(
this Logger logger,
- CommandLine.SearchTelemetry telemetry,
+ SearchTelemetry telemetry,
SearchTarget searchTarget,
Verbosity verbosity = Verbosity.Detailed)
{
@@ -134,7 +134,7 @@ public static void WriteSearchedFilesAndDirectories(
public static void WriteProcessedFilesAndDirectories(
this Logger logger,
- CommandLine.SearchTelemetry telemetry,
+ SearchTelemetry telemetry,
SearchTarget searchTarget,
string processedFilesTitle,
string processedDirectoriesTitle,
diff --git a/src/CommandLine/CommandLineOptions/CommonCopyCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/CommonCopyCommandLineOptions.cs
index 843adf0c..d7c65003 100644
--- a/src/CommandLine/CommandLineOptions/CommonCopyCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/CommonCopyCommandLineOptions.cs
@@ -43,7 +43,7 @@ public bool TryParse(CommonCopyCommandOptions options, ParseContext context)
Name,
OptionNames.Name,
OptionValueProviders.PatternOptionsProvider,
- out Filter? nameFilter,
+ out Matcher? nameFilter,
out FileNamePart namePart,
allowNull: true))
{
diff --git a/src/CommandLine/CommandLineOptions/CommonFindCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/CommonFindCommandLineOptions.cs
index f39459a1..7257f281 100644
--- a/src/CommandLine/CommandLineOptions/CommonFindCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/CommonFindCommandLineOptions.cs
@@ -1,6 +1,5 @@
// 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.
-using System;
using System.Collections.Generic;
using CommandLine;
using Orang.CommandLine.Annotations;
@@ -62,7 +61,7 @@ public bool TryParse(CommonFindCommandOptions options, ParseContext context)
Content,
OptionNames.Content,
OptionValueProviders.PatternOptionsWithoutPartProvider,
- out Filter? contentFilter,
+ out Matcher? contentFilter,
allowNull: true,
allowEmptyPattern: true))
{
@@ -196,7 +195,7 @@ public bool TryParse(CommonFindCommandOptions options, ParseContext context)
options.Format = new OutputDisplayFormat(
contentDisplayStyle: contentDisplayStyle
- ?? ((ReferenceEquals(contentFilter, Filter.EntireInput)) ? ContentDisplayStyle.AllLines : DefaultContentDisplayStyle),
+ ?? ((ReferenceEquals(contentFilter, Matcher.EntireInput)) ? ContentDisplayStyle.AllLines : DefaultContentDisplayStyle),
pathDisplayStyle: pathDisplayStyle ?? PathDisplayStyle.Full,
lineOptions: lineDisplayOptions,
lineContext: lineContext,
diff --git a/src/CommandLine/CommandLineOptions/CommonReplaceCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/CommonReplaceCommandLineOptions.cs
index 0303ef8e..98d935ee 100644
--- a/src/CommandLine/CommandLineOptions/CommonReplaceCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/CommonReplaceCommandLineOptions.cs
@@ -114,7 +114,7 @@ public bool TryParse(CommonReplaceCommandOptions options, ParseContext context)
options = (CommonReplaceCommandOptions)baseOptions;
- Filter? contentFilter = null;
+ Matcher? contentFilter = null;
if (!Content.Any())
{
contentFilter = GetDefaultContentFilter();
@@ -322,7 +322,7 @@ public bool TryParse(CommonReplaceCommandOptions options, ParseContext context)
return true;
}
- protected virtual Filter? GetDefaultContentFilter()
+ protected virtual Matcher? GetDefaultContentFilter()
{
return null;
}
diff --git a/src/CommandLine/CommandLineOptions/CopyCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/CopyCommandLineOptions.cs
index 32553ca5..3f3e1609 100644
--- a/src/CommandLine/CommandLineOptions/CopyCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/CopyCommandLineOptions.cs
@@ -58,8 +58,8 @@ public bool TryParse(CopyCommandOptions options, ParseContext context)
if (!context.TryParseAsEnumFlags(
Compare,
OptionNames.Compare,
- out FileCompareOptions compareOptions,
- FileCompareOptions.None,
+ out FileCompareProperties compareProperties,
+ FileCompareProperties.None,
OptionValueProviders.FileCompareOptionsProvider))
{
return false;
@@ -78,7 +78,7 @@ public bool TryParse(CopyCommandOptions options, ParseContext context)
return false;
}
- options.CompareOptions = compareOptions;
+ options.CompareProperties = compareProperties;
options.DryRun = DryRun;
options.Flat = Flat;
options.ConflictResolution = conflictResolution;
diff --git a/src/CommandLine/CommandLineOptions/DeleteCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/DeleteCommandLineOptions.cs
index 6c143775..93d992a4 100644
--- a/src/CommandLine/CommandLineOptions/DeleteCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/DeleteCommandLineOptions.cs
@@ -80,7 +80,7 @@ public bool TryParse(DeleteCommandOptions options, ParseContext context)
Name,
OptionNames.Name,
OptionValueProviders.PatternOptionsProvider,
- out Filter? nameFilter,
+ out Matcher? nameFilter,
out FileNamePart namePart,
allowNull: true))
{
@@ -100,7 +100,7 @@ public bool TryParse(DeleteCommandOptions options, ParseContext context)
Content,
OptionNames.Content,
OptionValueProviders.PatternOptionsWithoutPartProvider,
- out Filter? contentFilter,
+ out Matcher? contentFilter,
allowNull: true,
allowEmptyPattern: true))
{
@@ -207,7 +207,7 @@ public bool TryParse(DeleteCommandOptions options, ParseContext context)
options.Format = new OutputDisplayFormat(
contentDisplayStyle: contentDisplayStyle
- ?? ((ReferenceEquals(contentFilter, Filter.EntireInput)) ? ContentDisplayStyle.AllLines : ContentDisplayStyle.Omit),
+ ?? ((ReferenceEquals(contentFilter, Matcher.EntireInput)) ? ContentDisplayStyle.AllLines : ContentDisplayStyle.Omit),
pathDisplayStyle: pathDisplayStyle ?? PathDisplayStyle.Full,
lineOptions: lineDisplayOptions,
lineContext: lineContext,
diff --git a/src/CommandLine/CommandLineOptions/FileSystemCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/FileSystemCommandLineOptions.cs
index c16f2b08..8795f4c3 100644
--- a/src/CommandLine/CommandLineOptions/FileSystemCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/FileSystemCommandLineOptions.cs
@@ -218,7 +218,7 @@ public bool TryParse(FileSystemCommandOptions options, ParseContext context)
IncludeDirectory,
OptionNames.IncludeDirectory,
OptionValueProviders.PatternOptionsProvider,
- out Filter? directoryFilter,
+ out Matcher? directoryFilter,
out FileNamePart directoryNamePart,
allowNull: true,
namePartProvider: OptionValueProviders.NamePartKindProvider_WithoutExtension))
@@ -230,7 +230,7 @@ public bool TryParse(FileSystemCommandOptions options, ParseContext context)
Extension,
OptionNames.Extension,
OptionValueProviders.ExtensionOptionsProvider,
- out Filter? extensionFilter,
+ out Matcher? extensionFilter,
allowNull: true,
defaultNamePart: FileNamePart.Extension,
includedPatternOptions: PatternOptions.List | PatternOptions.Equals | PatternOptions.IgnoreCase))
@@ -324,7 +324,7 @@ protected virtual bool TryParsePaths(out ImmutableArray paths, ParseCo
if (PathsFrom is not null)
{
- if (!FileSystemHelpers.TryReadAllText(PathsFrom, out string? content, ex => context.WriteError(ex)))
+ if (!FileSystemUtilities.TryReadAllText(PathsFrom, out string? content, ex => context.WriteError(ex)))
return false;
IEnumerable lines = TextHelpers.ReadLines(content).Where(f => !string.IsNullOrWhiteSpace(f));
diff --git a/src/CommandLine/CommandLineOptions/HelpCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/HelpCommandLineOptions.cs
index 243ae525..a7c980ba 100644
--- a/src/CommandLine/CommandLineOptions/HelpCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/HelpCommandLineOptions.cs
@@ -43,7 +43,7 @@ public bool TryParse(HelpCommandOptions options, ParseContext context)
Filter,
OptionNames.Filter,
OptionValueProviders.PatternOptions_List_Provider,
- out Filter? filter,
+ out Matcher? matcher,
allowNull: true,
includedPatternOptions: PatternOptions.IgnoreCase))
{
@@ -51,7 +51,7 @@ public bool TryParse(HelpCommandOptions options, ParseContext context)
}
options.Command = Command.ToArray();
- options.Filter = filter;
+ options.Matcher = matcher;
options.Manual = Manual;
options.Online = Online;
diff --git a/src/CommandLine/CommandLineOptions/MoveCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/MoveCommandLineOptions.cs
index 6de2b80b..db1b8e4e 100644
--- a/src/CommandLine/CommandLineOptions/MoveCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/MoveCommandLineOptions.cs
@@ -58,8 +58,8 @@ public bool TryParse(MoveCommandOptions options, ParseContext context)
if (!context.TryParseAsEnumFlags(
Compare,
OptionNames.Compare,
- out FileCompareOptions compareOptions,
- FileCompareOptions.None,
+ out FileCompareProperties compareProperties,
+ FileCompareProperties.None,
OptionValueProviders.FileCompareOptionsProvider))
{
return false;
@@ -78,7 +78,7 @@ public bool TryParse(MoveCommandOptions options, ParseContext context)
return false;
}
- options.CompareOptions = compareOptions;
+ options.CompareProperties = compareProperties;
options.DryRun = DryRun;
options.Flat = Flat;
options.ConflictResolution = conflictResolution;
diff --git a/src/CommandLine/CommandLineOptions/RegexListCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/RegexListCommandLineOptions.cs
index 9721bd70..cbdad31a 100644
--- a/src/CommandLine/CommandLineOptions/RegexListCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/RegexListCommandLineOptions.cs
@@ -82,14 +82,14 @@ public bool TryParse(RegexListCommandOptions options, ParseContext context)
Filter,
OptionNames.Filter,
OptionValueProviders.PatternOptions_List_Provider,
- out Filter? filter,
+ out Matcher? matcher,
allowNull: true,
includedPatternOptions: PatternOptions.IgnoreCase))
{
return false;
}
- options.Filter = filter;
+ options.Matcher = matcher;
options.Value = value;
options.RegexOptions = regexOptions;
options.InCharGroup = CharGroup;
diff --git a/src/CommandLine/CommandLineOptions/RegexMatchCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/RegexMatchCommandLineOptions.cs
index 094d20cb..b74b5d45 100644
--- a/src/CommandLine/CommandLineOptions/RegexMatchCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/RegexMatchCommandLineOptions.cs
@@ -42,7 +42,7 @@ public bool TryParse(RegexMatchCommandOptions options, ParseContext context)
Content,
OptionNames.Content,
OptionValueProviders.PatternOptions_Match_Provider,
- out Filter? filter))
+ out Matcher? matcher))
{
return false;
}
@@ -56,7 +56,7 @@ public bool TryParse(RegexMatchCommandOptions options, ParseContext context)
return false;
}
- options.Filter = filter!;
+ options.Matcher = matcher!;
options.HighlightOptions = highlightOptions;
options.MaxCount = MaxCount;
diff --git a/src/CommandLine/CommandLineOptions/RegexSplitCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/RegexSplitCommandLineOptions.cs
index afe33f68..3ec34eb9 100644
--- a/src/CommandLine/CommandLineOptions/RegexSplitCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/RegexSplitCommandLineOptions.cs
@@ -49,7 +49,7 @@ public bool TryParse(RegexSplitCommandOptions options, ParseContext context)
Content,
OptionNames.Content,
OptionValueProviders.PatternOptionsWithoutGroupAndPartAndNegativeProvider,
- out Filter? filter))
+ out Matcher? matcher))
{
return false;
}
@@ -63,7 +63,7 @@ public bool TryParse(RegexSplitCommandOptions options, ParseContext context)
return false;
}
- options.Filter = filter!;
+ options.Matcher = matcher!;
options.HighlightOptions = highlightOptions;
options.OmitGroups = NoGroups;
options.MaxCount = MaxCount;
diff --git a/src/CommandLine/CommandLineOptions/RenameCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/RenameCommandLineOptions.cs
index dae0bf81..dcd940f7 100644
--- a/src/CommandLine/CommandLineOptions/RenameCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/RenameCommandLineOptions.cs
@@ -111,7 +111,7 @@ public bool TryParse(RenameCommandOptions options, ParseContext context)
Name,
OptionNames.Name,
OptionValueProviders.PatternOptionsWithoutGroupAndNegativeProvider,
- out Filter? nameFilter,
+ out Matcher? nameFilter,
out FileNamePart namePart,
namePartProvider: OptionValueProviders.NamePartKindProvider_WithoutFullName))
{
@@ -122,7 +122,7 @@ public bool TryParse(RenameCommandOptions options, ParseContext context)
Content,
OptionNames.Content,
OptionValueProviders.PatternOptionsWithoutPartProvider,
- out Filter? contentFilter,
+ out Matcher? contentFilter,
allowNull: true,
allowEmptyPattern: true))
{
@@ -148,7 +148,7 @@ public bool TryParse(RenameCommandOptions options, ParseContext context)
OptionNames.Modify,
replacement,
matchEvaluator,
- out ReplaceOptions? replaceOptions))
+ out Replacer? replacer))
{
return false;
}
@@ -263,7 +263,7 @@ public bool TryParse(RenameCommandOptions options, ParseContext context)
options.Format = new OutputDisplayFormat(
contentDisplayStyle: contentDisplayStyle
- ?? ((ReferenceEquals(contentFilter, Filter.EntireInput)) ? ContentDisplayStyle.AllLines : ContentDisplayStyle.Omit),
+ ?? ((ReferenceEquals(contentFilter, Matcher.EntireInput)) ? ContentDisplayStyle.AllLines : ContentDisplayStyle.Omit),
pathDisplayStyle: pathDisplayStyle ?? PathDisplayStyle.Full,
lineOptions: lineDisplayOptions,
lineContext: lineContext,
@@ -273,7 +273,7 @@ public bool TryParse(RenameCommandOptions options, ParseContext context)
options.HighlightOptions = highlightOptions;
options.SearchTarget = GetSearchTarget();
- options.ReplaceOptions = replaceOptions;
+ options.Replacer = replacer;
options.AskMode = (Ask) ? AskMode.File : AskMode.None;
options.DryRun = DryRun;
options.NameFilter = nameFilter;
diff --git a/src/CommandLine/CommandLineOptions/ReplaceCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/ReplaceCommandLineOptions.cs
index 45aa156a..f8b68967 100644
--- a/src/CommandLine/CommandLineOptions/ReplaceCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/ReplaceCommandLineOptions.cs
@@ -72,16 +72,16 @@ public bool TryParse(ReplaceCommandOptions options, ParseContext context)
OptionNames.Modify,
replacement,
matchEvaluator,
- out ReplaceOptions? replaceOptions))
+ out Replacer? replacer))
{
return false;
}
- options.Replacer = replaceOptions;
+ options.Replacer = replacer;
#if DEBUG // --find
if (Find)
{
- options.Replacer = ReplaceOptions.Empty;
+ options.Replacer = Replacer.Empty;
options.HighlightOptions = HighlightOptions.Match;
options.DryRun = true;
}
diff --git a/src/CommandLine/CommandLineOptions/SpellcheckCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/SpellcheckCommandLineOptions.cs
index 63987cc2..eb18ab97 100644
--- a/src/CommandLine/CommandLineOptions/SpellcheckCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/SpellcheckCommandLineOptions.cs
@@ -72,7 +72,7 @@ public bool TryParse(SpellcheckCommandOptions options, ParseContext context)
Word,
OptionNames.Word,
OptionValueProviders.PatternOptions_Word_Provider,
- out Filter? wordFilter))
+ out Matcher? wordFilter))
{
return false;
}
@@ -100,8 +100,8 @@ public bool TryParse(SpellcheckCommandOptions options, ParseContext context)
return true;
}
- protected override Filter? GetDefaultContentFilter()
+ protected override Matcher? GetDefaultContentFilter()
{
- return Filter.EntireInput;
+ return Matcher.EntireInput;
}
}
diff --git a/src/CommandLine/CommandLineOptions/SyncCommandLineOptions.cs b/src/CommandLine/CommandLineOptions/SyncCommandLineOptions.cs
index ba39146d..b84b0ff4 100644
--- a/src/CommandLine/CommandLineOptions/SyncCommandLineOptions.cs
+++ b/src/CommandLine/CommandLineOptions/SyncCommandLineOptions.cs
@@ -61,8 +61,11 @@ public bool TryParse(SyncCommandOptions options, ParseContext context)
if (!context.TryParseAsEnumFlags(
Compare,
OptionNames.Compare,
- out FileCompareOptions compareOptions,
- FileCompareOptions.Attributes | FileCompareOptions.Content | FileCompareOptions.ModifiedTime | FileCompareOptions.Size,
+ out FileCompareProperties compareProperties,
+ FileCompareProperties.Attributes
+ | FileCompareProperties.Content
+ | FileCompareProperties.ModifiedTime
+ | FileCompareProperties.Size,
OptionValueProviders.FileCompareOptionsProvider))
{
return false;
@@ -79,7 +82,7 @@ public bool TryParse(SyncCommandOptions options, ParseContext context)
}
options.SearchTarget = SearchTarget.All;
- options.CompareOptions = compareOptions;
+ options.CompareProperties = compareProperties;
options.DryRun = DryRun;
options.Target = second;
options.ConflictResolution = conflictResolution;
diff --git a/src/CommandLine/CommandOptions/CommonCopyCommandOptions.cs b/src/CommandLine/CommandOptions/CommonCopyCommandOptions.cs
index 3f99d25f..1c7b1924 100644
--- a/src/CommandLine/CommandOptions/CommonCopyCommandOptions.cs
+++ b/src/CommandLine/CommandOptions/CommonCopyCommandOptions.cs
@@ -14,9 +14,19 @@ protected CommonCopyCommandOptions()
public TimeSpan AllowedTimeDiff { get; internal set; }
- public FileAttributes NoCompareAttributes { get; internal set; }
+ public FileAttributes? NoCompareAttributes { get; internal set; }
- public FileCompareOptions CompareOptions { get; internal set; }
+ public FileAttributes? CompareAttributes
+ {
+ get
+ {
+ return (NoCompareAttributes is not null)
+ ? FileSystemUtilities.AllFileAttributes & ~NoCompareAttributes
+ : null;
+ }
+ }
+
+ public FileCompareProperties CompareProperties { get; internal set; }
public bool DryRun { get; internal set; }
diff --git a/src/CommandLine/CommandOptions/DeleteCommandOptions.cs b/src/CommandLine/CommandOptions/DeleteCommandOptions.cs
index 52538574..305129dc 100644
--- a/src/CommandLine/CommandOptions/DeleteCommandOptions.cs
+++ b/src/CommandLine/CommandOptions/DeleteCommandOptions.cs
@@ -12,10 +12,6 @@ internal DeleteCommandOptions()
public bool IncludingBom { get; internal set; }
- public bool FilesOnly { get; internal set; }
-
- public bool DirectoriesOnly { get; internal set; }
-
protected override void WriteDiagnosticCore(DiagnosticWriter writer)
{
writer.WriteDeleteCommand(this);
diff --git a/src/CommandLine/CommandOptions/FileSystemCommandOptions.cs b/src/CommandLine/CommandOptions/FileSystemCommandOptions.cs
index d940389e..e7872b4b 100644
--- a/src/CommandLine/CommandOptions/FileSystemCommandOptions.cs
+++ b/src/CommandLine/CommandOptions/FileSystemCommandOptions.cs
@@ -18,15 +18,15 @@ internal FileSystemCommandOptions()
public ImmutableArray Paths { get; internal set; }
- public Filter? NameFilter { get; internal set; }
+ public Matcher? NameFilter { get; internal set; }
public FileNamePart NamePart { get; internal set; }
- public Filter? ExtensionFilter { get; internal set; }
+ public Matcher? ExtensionFilter { get; internal set; }
- public Filter? ContentFilter { get; internal set; }
+ public Matcher? ContentFilter { get; internal set; }
- public Filter? DirectoryFilter { get; internal set; }
+ public Matcher? DirectoryFilter { get; internal set; }
public FileNamePart DirectoryNamePart { get; internal set; }
@@ -70,15 +70,15 @@ internal FileSystemCommandOptions()
public string Indent => Format.Indent;
- internal MatchOutputInfo? CreateOutputInfo(string input, Match match, Filter filter)
+ internal MatchOutputInfo? CreateOutputInfo(string input, Match match, Matcher matcher)
{
if (ContentDisplayStyle != ContentDisplayStyle.ValueDetail)
return null;
- int groupNumber = filter.GroupNumber;
+ int groupNumber = matcher.GroupNumber;
return MatchOutputInfo.Create(
- MatchData.Create(input, filter.Regex, match),
+ MatchData.Create(input, matcher.Regex, match),
groupNumber,
includeGroupNumber: groupNumber >= 0,
includeCaptureNumber: false,
diff --git a/src/CommandLine/CommandOptions/HelpCommandOptions.cs b/src/CommandLine/CommandOptions/HelpCommandOptions.cs
index 20ab4a52..c2cf3549 100644
--- a/src/CommandLine/CommandOptions/HelpCommandOptions.cs
+++ b/src/CommandLine/CommandOptions/HelpCommandOptions.cs
@@ -10,7 +10,7 @@ internal HelpCommandOptions()
public string[] Command { get; internal set; } = null!;
- public Filter? Filter { get; internal set; }
+ public Matcher? Matcher { get; internal set; }
public bool Manual { get; internal set; }
diff --git a/src/CommandLine/CommandOptions/RegexCommandOptions.cs b/src/CommandLine/CommandOptions/RegexCommandOptions.cs
index 37ff6db5..a7cfa96b 100644
--- a/src/CommandLine/CommandOptions/RegexCommandOptions.cs
+++ b/src/CommandLine/CommandOptions/RegexCommandOptions.cs
@@ -10,7 +10,7 @@ internal RegexCommandOptions()
{
}
- public Filter Filter { get; internal set; } = null!;
+ public Matcher Matcher { get; internal set; } = null!;
public string Input { get; internal set; } = null!;
diff --git a/src/CommandLine/CommandOptions/RegexListCommandOptions.cs b/src/CommandLine/CommandOptions/RegexListCommandOptions.cs
index 842b2d4e..19682773 100644
--- a/src/CommandLine/CommandOptions/RegexListCommandOptions.cs
+++ b/src/CommandLine/CommandOptions/RegexListCommandOptions.cs
@@ -14,7 +14,7 @@ internal RegexListCommandOptions()
public char? Value { get; internal set; }
- public Filter? Filter { get; internal set; }
+ public Matcher? Matcher { get; internal set; }
public bool InCharGroup { get; internal set; }
diff --git a/src/CommandLine/CommandOptions/RenameCommandOptions.cs b/src/CommandLine/CommandOptions/RenameCommandOptions.cs
index 4b7a669c..ebefd5e2 100644
--- a/src/CommandLine/CommandOptions/RenameCommandOptions.cs
+++ b/src/CommandLine/CommandOptions/RenameCommandOptions.cs
@@ -14,7 +14,7 @@ internal RenameCommandOptions()
public ConflictResolution ConflictResolution { get; internal set; }
- public ReplaceOptions ReplaceOptions { get; internal set; } = null!;
+ public Replacer Replacer { get; internal set; } = null!;
protected override void WriteDiagnosticCore(DiagnosticWriter writer)
{
diff --git a/src/CommandLine/Commands/CommonCopyCommand`1.cs b/src/CommandLine/Commands/CommonCopyCommand`1.cs
index a69b0d7c..0b44a503 100644
--- a/src/CommandLine/Commands/CommonCopyCommand`1.cs
+++ b/src/CommandLine/Commands/CommonCopyCommand`1.cs
@@ -34,7 +34,7 @@ public ConflictResolution ConflictResolution
private PathWriter? PathWriter { get; }
- protected override void OnSearchCreating(FileSystemSearch search)
+ protected override void OnSearchCreating(SearchState search)
{
if (Options.SearchTarget != SearchTarget.Files
&& !Options.StructureOnly)
@@ -43,9 +43,9 @@ protected override void OnSearchCreating(FileSystemSearch search)
}
}
- protected override NameFilter? CreateAdditionalDirectoryFilter()
+ protected override Func? CreateExcludeDirectoryPredicate(Func? predicate = null)
{
- return FileSystem.NameFilter.CreateFromDirectoryPath(Target, isNegative: true);
+ return DirectoryPredicate.Create(Target);
}
protected abstract string GetQuestionText(bool isDirectory);
@@ -54,7 +54,7 @@ protected override void OnSearchCreating(FileSystemSearch search)
protected override void ExecuteDirectory(string directoryPath, SearchContext context)
{
- if (FileSystemHelpers.IsSubdirectory(Target, directoryPath))
+ if (FileSystemUtilities.IsSubdirectory(Target, directoryPath))
{
_logger.WriteWarning("Source directory cannot be subdirectory of a destination directory.");
return;
@@ -84,7 +84,7 @@ private void ExecuteOperation(
if (fileMatch.IsDirectory
|| (baseDirectoryPath is not null && !Options.Flat))
{
- Debug.Assert(sourcePath.StartsWith(baseDirectoryPath!, FileSystemHelpers.Comparison));
+ Debug.Assert(sourcePath.StartsWith(baseDirectoryPath!, FileSystemUtilities.Comparison));
string relativePath = sourcePath.Substring(baseDirectoryPath!.Length + 1);
@@ -128,7 +128,7 @@ private void ExecuteOperation(
else if (directoryExists)
{
if (Options.StructureOnly
- && FileSystemHelpers.AttributeEquals(sourcePath, destinationPath, Options.NoCompareAttributes))
+ && FileSystemUtilities.AttributeEquals(sourcePath, destinationPath, Options.CompareAttributes))
{
return null;
}
@@ -138,12 +138,12 @@ private void ExecuteOperation(
}
else if (fileExists)
{
- if (Options.CompareOptions != FileCompareOptions.None
- && FileSystemHelpers.FileEquals(
+ if (Options.CompareProperties != FileCompareProperties.None
+ && FileSystemUtilities.FileEquals(
sourcePath,
destinationPath,
- Options.CompareOptions,
- Options.NoCompareAttributes,
+ Options.CompareProperties,
+ Options.CompareAttributes,
Options.AllowedTimeDiff))
{
return null;
@@ -166,7 +166,7 @@ private void ExecuteOperation(
&& ((isDirectory && directoryExists)
|| (!isDirectory && fileExists)))
{
- destinationPath = FileSystemHelpers.CreateNewFilePath(destinationPath);
+ destinationPath = FileSystemUtilities.CreateNewFilePath(destinationPath);
}
if (!Options.OmitPath)
@@ -238,7 +238,7 @@ private void ExecuteOperation(
{
if (Options.StructureOnly)
{
- FileSystemHelpers.UpdateAttributes(sourcePath, destinationPath);
+ FileSystemUtilities.UpdateAttributes(sourcePath, destinationPath);
}
else
{
diff --git a/src/CommandLine/Commands/CommonFindCommand`1.cs b/src/CommandLine/Commands/CommonFindCommand`1.cs
index 7649c2fd..123ee8f4 100644
--- a/src/CommandLine/Commands/CommonFindCommand`1.cs
+++ b/src/CommandLine/Commands/CommonFindCommand`1.cs
@@ -28,7 +28,7 @@ protected CommonFindCommand(TOptions options, Logger logger) : base(options, log
}
}
- public Filter? ContentFilter => Options.ContentFilter;
+ public Matcher? ContentFilter => Options.ContentFilter;
private OutputSymbols Symbols => _symbols ??= OutputSymbols.Create(Options.HighlightOptions);
@@ -99,7 +99,7 @@ protected virtual ContentWriterOptions CreateContentWriterOptions(string indent)
HighlightOptions highlightOptions = Options.HighlightOptions;
- if (ReferenceEquals(ContentFilter, Filter.EntireInput))
+ if (ReferenceEquals(ContentFilter, Matcher.EntireInput))
highlightOptions &= ~HighlightOptions.DefaultOrMatch;
return new ContentWriterOptions(
@@ -199,7 +199,7 @@ protected virtual void ExecuteMatchWithContentCore(
ColumnWidths? columnWidths = null)
{
if (!fileMatch.IsDirectory
- && ContentFilter?.IsNegative == false
+ && ContentFilter?.Invert == false
&& !Options.OmitContent
&& _logger.ShouldWrite(Verbosity.Normal))
{
@@ -210,7 +210,7 @@ protected virtual void ExecuteMatchWithContentCore(
if (isPathDisplayed)
WritePath(context, fileMatch, baseDirectoryPath, indent, columnWidths, includeNewline: false);
- if (ContentFilter!.IsNegative
+ if (ContentFilter!.Invert
|| fileMatch.IsDirectory)
{
_logger.WriteLineIf(isPathDisplayed, Verbosity.Minimal);
@@ -356,13 +356,13 @@ private void WritePath(
ColumnWidths? columnWidths)
{
if (Options.PathDisplayStyle == PathDisplayStyle.Match
- && fileMatch.NameMatch is not null
- && !object.ReferenceEquals(fileMatch.NameMatch, Match.Empty))
+ && fileMatch.Name is not null
+ && !object.ReferenceEquals(fileMatch.Name, Match.Empty))
{
if (_logger.ShouldWrite(Verbosity.Minimal))
{
_logger.Write(indent, Verbosity.Minimal);
- _logger.Write(fileMatch.NameMatch.Value, (Options.HighlightMatch) ? Colors.Match_Path : default, Verbosity.Minimal);
+ _logger.Write(fileMatch.Name.Value, (Options.HighlightMatch) ? Colors.Match_Path : default, Verbosity.Minimal);
}
}
else
@@ -383,7 +383,7 @@ private void WriteContent(
try
{
- Match match = fileMatch.ContentMatch!;
+ Match match = fileMatch.Content!;
contentWriter = CommandLine.ContentWriter.CreateFind(
contentDisplayStyle: Options.ContentDisplayStyle,
diff --git a/src/CommandLine/Commands/CommonReplaceCommand`1.cs b/src/CommandLine/Commands/CommonReplaceCommand`1.cs
index 1bf7461f..0c13d027 100644
--- a/src/CommandLine/Commands/CommonReplaceCommand`1.cs
+++ b/src/CommandLine/Commands/CommonReplaceCommand`1.cs
@@ -18,7 +18,7 @@ internal class CommonReplaceCommand : CommonFindCommand wher
public CommonReplaceCommand(TOptions options, Logger logger) : base(options, logger)
{
- Debug.Assert(!options.ContentFilter!.IsNegative);
+ Debug.Assert(!options.ContentFilter!.Invert);
}
protected override bool CanDisplaySummary => Options.Input is null;
@@ -51,7 +51,7 @@ private void ExecuteInput(SearchContext context, string input)
{
int count = 0;
var maxReason = MaxReason.None;
- Filter contentFilter = ContentFilter!;
+ Matcher contentFilter = ContentFilter!;
Match? match = contentFilter.Match(input);
if (match is not null)
@@ -144,7 +144,7 @@ protected override void ExecuteMatchWithContentCore(
groups = ListCache.GetInstance();
MaxReason maxReason = GetCaptures(
- fileMatch.ContentMatch!,
+ fileMatch.Content!,
writerOptions.GroupNumber,
context,
isPathDisplayed: false,
@@ -232,7 +232,7 @@ private void ExecuteMatchWithContentCore(
{
MatchOutputInfo? outputInfo = Options.CreateOutputInfo(
fileMatch.ContentText,
- fileMatch.ContentMatch!,
+ fileMatch.Content!,
ContentFilter!);
if (Options.AskMode == AskMode.Value
diff --git a/src/CommandLine/Commands/CopyCommand.cs b/src/CommandLine/Commands/CopyCommand.cs
index f101320a..6c0eb063 100644
--- a/src/CommandLine/Commands/CopyCommand.cs
+++ b/src/CommandLine/Commands/CopyCommand.cs
@@ -1,6 +1,7 @@
// 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.
using System.IO;
+using Orang.FileSystem;
namespace Orang.CommandLine;
diff --git a/src/CommandLine/Commands/DeleteCommand.cs b/src/CommandLine/Commands/DeleteCommand.cs
index 323cf32b..db3dee11 100644
--- a/src/CommandLine/Commands/DeleteCommand.cs
+++ b/src/CommandLine/Commands/DeleteCommand.cs
@@ -12,7 +12,7 @@ public DeleteCommand(DeleteCommandOptions options, Logger logger) : base(options
{
}
- protected override void OnSearchCreating(FileSystemSearch search)
+ protected override void OnSearchCreating(SearchState search)
{
search.CanRecurseMatch = false;
}
@@ -38,12 +38,10 @@ protected override void ExecuteMatchCore(
{
if (!Options.DryRun)
{
- FileSystemHelpers.Delete(
+ FileSystemUtilities.Delete(
fileMatch,
contentOnly: Options.ContentOnly,
- includingBom: Options.IncludingBom,
- filesOnly: Options.FilesOnly,
- directoriesOnly: Options.DirectoriesOnly);
+ includingBom: Options.IncludingBom);
}
if (fileMatch.IsDirectory)
diff --git a/src/CommandLine/Commands/FileSystemCommand`1.cs b/src/CommandLine/Commands/FileSystemCommand`1.cs
index 947c59bb..08fd3b48 100644
--- a/src/CommandLine/Commands/FileSystemCommand`1.cs
+++ b/src/CommandLine/Commands/FileSystemCommand`1.cs
@@ -17,14 +17,14 @@ protected FileSystemCommand(TOptions options, Logger logger) : base(options, log
{
}
- private FileSystemSearch? _search;
+ private SearchState? _search;
private ProgressReporter? _progressReporter;
- protected FileSystemSearch Search => _search ??= CreateSearch();
+ protected SearchState Search => _search ??= CreateSearch();
private ProgressReporter? ProgressReporter => _progressReporter ??= CreateProgressReporter();
- public Filter? NameFilter => Options.NameFilter;
+ public Matcher? NameFilter => Options.NameFilter;
protected virtual bool CanDisplaySummary => true;
@@ -32,60 +32,166 @@ protected FileSystemCommand(TOptions options, Logger logger) : base(options, log
public virtual bool CanUseResults => true;
- protected virtual void OnSearchCreating(FileSystemSearch search)
+ protected virtual void OnSearchCreating(SearchState search)
{
}
- private FileSystemSearch CreateSearch()
+ private SearchState CreateSearch()
{
- var filter = new FileSystemFilter(
- name: Options.NameFilter,
- part: Options.NamePart,
- extension: Options.ExtensionFilter,
- content: Options.ContentFilter,
- properties: new FilePropertyFilter(
- Options.FilePropertyOptions.CreationTimePredicate,
- Options.FilePropertyOptions.ModifiedTimePredicate,
- Options.FilePropertyOptions.SizePredicate),
- attributes: Options.Attributes,
- attributesToSkip: Options.AttributesToSkip,
- emptyOption: Options.EmptyOption);
+ FilePropertyOptions properties = Options.FilePropertyOptions;
+ Func? filePredicate = null;
+ Func? directoryPredicate = null;
- var directoryFilters = new List();
+ if (Options.SearchTarget == SearchTarget.Directories)
+ {
+ if (properties.CreationTimePredicate is not null)
+ {
+ if (properties.ModifiedTimePredicate is not null)
+ {
+ directoryPredicate = di => properties.CreationTimePredicate(di.CreationTime)
+ && properties.ModifiedTimePredicate(di.LastWriteTime);
+ }
+ else
+ {
+ directoryPredicate = di => properties.CreationTimePredicate(di.CreationTime);
+ }
+ }
+ else if (properties.ModifiedTimePredicate is not null)
+ {
+ directoryPredicate = di => properties.ModifiedTimePredicate(di.LastWriteTime);
+ }
+ }
+ else if (properties.CreationTimePredicate is not null)
+ {
+ if (properties.ModifiedTimePredicate is not null)
+ {
+ if (properties.SizePredicate is not null)
+ {
+ filePredicate = fi => properties.CreationTimePredicate(fi.CreationTime)
+ && properties.ModifiedTimePredicate(fi.LastWriteTime)
+ && properties.SizePredicate(fi.Length);
+ }
+ else
+ {
+ filePredicate = fi => properties.CreationTimePredicate(fi.CreationTime)
+ && properties.ModifiedTimePredicate(fi.LastWriteTime);
+ }
+ }
+ else if (properties.SizePredicate is not null)
+ {
+ filePredicate = fi => properties.CreationTimePredicate(fi.CreationTime)
+ && properties.SizePredicate(fi.Length);
+ }
+ else
+ {
+ filePredicate = fi => properties.CreationTimePredicate(fi.CreationTime);
+ }
+ }
+ else if (properties.ModifiedTimePredicate is not null)
+ {
+ if (properties.SizePredicate is not null)
+ {
+ filePredicate = fi => properties.ModifiedTimePredicate(fi.LastWriteTime)
+ && properties.SizePredicate(fi.Length);
+ }
+ else
+ {
+ filePredicate = fi => properties.ModifiedTimePredicate(fi.LastWriteTime);
+ }
+ }
+ else if (properties.SizePredicate is not null)
+ {
+ filePredicate = fi => properties.SizePredicate(fi.Length);
+ }
- if (Options.DirectoryFilter is not null)
+ FileMatcher? fileMatcher = null;
+ DirectoryMatcher? directoryMatcher = null;
+
+ if (Options.SearchTarget != SearchTarget.Directories)
{
- var directoryFilter = new NameFilter(
- name: Options.DirectoryFilter,
- part: Options.DirectoryNamePart);
+ fileMatcher = new FileMatcher()
+ {
+ Name = Options.NameFilter,
+ NamePart = Options.NamePart,
+ Extension = Options.ExtensionFilter,
+ Content = Options.ContentFilter,
+ MatchFileInfo = filePredicate,
+ WithAttributes = Options.Attributes,
+ WithoutAttributes = Options.AttributesToSkip,
+ EmptyOption = Options.EmptyOption
+ };
+ }
- directoryFilters.Add(directoryFilter);
+ if (Options.SearchTarget != SearchTarget.Files)
+ {
+ directoryMatcher = new DirectoryMatcher()
+ {
+ Name = Options.NameFilter,
+ NamePart = Options.NamePart,
+ MatchDirectoryInfo = directoryPredicate,
+ WithAttributes = Options.Attributes,
+ WithoutAttributes = Options.AttributesToSkip,
+ EmptyOption = Options.EmptyOption
+ };
}
- NameFilter? additionalDirectoryFilter = CreateAdditionalDirectoryFilter();
+ Func? includeDirectory = null;
+ Func? excludeDirectory = null;
- if (additionalDirectoryFilter is not null)
- directoryFilters.Add(additionalDirectoryFilter);
+ Matcher? directoryFilter = Options.DirectoryFilter;
- var options = new FileSystemSearchOptions(
- searchTarget: Options.SearchTarget,
- recurseSubdirectories: Options.RecurseSubdirectories,
- defaultEncoding: Options.DefaultEncoding);
+ if (directoryFilter is not null)
+ {
+ if (directoryFilter.Invert)
+ {
+ excludeDirectory = DirectoryPredicate.Create(directoryFilter, Options.DirectoryNamePart);
+ }
+ else
+ {
+ includeDirectory = DirectoryPredicate.Create(directoryFilter, Options.DirectoryNamePart);
+ }
+ }
- var search = new FileSystemSearch(
- filter: filter,
- directoryFilters: directoryFilters,
- searchProgress: ProgressReporter,
- options: options);
+ includeDirectory = CombinePredicates(includeDirectory, CreateIncludeDirectoryPredicate());
+ excludeDirectory = CombinePredicates(excludeDirectory, CreateExcludeDirectoryPredicate());
+
+ var search = new SearchState(fileMatcher, directoryMatcher)
+ {
+ IncludeDirectory = includeDirectory,
+ ExcludeDirectory = excludeDirectory,
+ LogProgress = (ProgressReporter is not null) ? p => ProgressReporter.Report(p) : null,
+ RecurseSubdirectories = Options.RecurseSubdirectories,
+ DefaultEncoding = Options.DefaultEncoding,
+ };
OnSearchCreating(search);
return search;
+
+ static Func? CombinePredicates(Func? predicate, Func? predicate2)
+ {
+ if (predicate is not null)
+ {
+ if (predicate2 is not null)
+ {
+ return path => predicate(path) && predicate2(path);
+ }
+
+ return predicate;
+ }
+
+ return predicate2;
+ }
+ }
+
+ protected virtual Func? CreateIncludeDirectoryPredicate(Func? predicate = null)
+ {
+ return predicate;
}
- protected virtual NameFilter? CreateAdditionalDirectoryFilter()
+ protected virtual Func? CreateExcludeDirectoryPredicate(Func? predicate = null)
{
- return null;
+ return predicate;
}
protected abstract void ExecuteDirectory(string directoryPath, SearchContext context);
@@ -473,7 +579,7 @@ protected void WriteProperties(SearchContext context, FileMatch fileMatch, Colum
&& Options.FilePropertyOptions.IncludeSize)
{
size = (fileMatch.IsDirectory)
- ? (context.DirectorySizeMap?[fileMatch.Path] ?? FileSystemHelpers.GetDirectorySize(fileMatch.Path))
+ ? (context.DirectorySizeMap?[fileMatch.Path] ?? FileSystemUtilities.GetDirectorySize(fileMatch.Path))
: new FileInfo(fileMatch.Path).Length;
context.Telemetry.FilesTotalSize += size;
@@ -497,7 +603,7 @@ protected void WriteProperties(SearchContext context, FileMatch fileMatch, Colum
if (size == -1)
{
size = (fileMatch.IsDirectory)
- ? (context.DirectorySizeMap?[fileMatch.Path] ?? FileSystemHelpers.GetDirectorySize(fileMatch.Path))
+ ? (context.DirectorySizeMap?[fileMatch.Path] ?? FileSystemUtilities.GetDirectorySize(fileMatch.Path))
: new FileInfo(fileMatch.Path).Length;
}
diff --git a/src/CommandLine/Commands/FindCommand`1.cs b/src/CommandLine/Commands/FindCommand`1.cs
index eadd43e1..c0046364 100644
--- a/src/CommandLine/Commands/FindCommand`1.cs
+++ b/src/CommandLine/Commands/FindCommand`1.cs
@@ -109,7 +109,7 @@ protected override void ExecuteMatchWithContentCore(
if (isPathDisplayed)
WritePath(context, fileMatch, baseDirectoryPath, indent, columnWidths, includeNewline: false);
- if (ContentFilter!.IsNegative
+ if (ContentFilter!.Invert
|| fileMatch.IsDirectory)
{
_logger.WriteLineIf(isPathDisplayed, Verbosity.Minimal);
@@ -118,7 +118,7 @@ protected override void ExecuteMatchWithContentCore(
{
WriteContent(
context,
- fileMatch.ContentMatch!,
+ fileMatch.Content!,
fileMatch.ContentText,
writerOptions,
fileMatch,
@@ -150,10 +150,10 @@ protected override void ExecuteMatchCore(
}
if (_aggregate?.Storage is not null
- && fileMatch.NameMatch is not null
- && !object.ReferenceEquals(fileMatch.NameMatch, Match.Empty))
+ && fileMatch.Name is not null
+ && !object.ReferenceEquals(fileMatch.Name, Match.Empty))
{
- _aggregate.Storage.Add(fileMatch.NameMatch.Value);
+ _aggregate.Storage.Add(fileMatch.Name.Value);
_aggregate.Sections?.Add(new StorageSection(fileMatch, baseDirectoryPath, 0));
}
diff --git a/src/CommandLine/Commands/HelpCommand.cs b/src/CommandLine/Commands/HelpCommand.cs
index 1e1b519b..5126afa5 100644
--- a/src/CommandLine/Commands/HelpCommand.cs
+++ b/src/CommandLine/Commands/HelpCommand.cs
@@ -28,7 +28,7 @@ protected override CommandResult ExecuteCore(CancellationToken cancellationToken
online: Options.Online,
manual: Options.Manual,
verbose: _logger.ConsoleOut.Verbosity > Verbosity.Normal,
- filter: Options.Filter);
+ matcher: Options.Matcher);
}
catch (ArgumentException ex)
{
@@ -44,7 +44,7 @@ private void WriteHelp(
bool online,
bool manual,
bool verbose,
- Filter? filter = null)
+ Matcher? matcher = null)
{
var isCompoundCommand = false;
string? commandName2 = commandName.FirstOrDefault();
@@ -71,15 +71,15 @@ private void WriteHelp(
if (command is null)
throw new InvalidOperationException($"Command '{string.Join(' ', commandName)}' does not exist.");
- WriteCommandHelp(command, _logger, verbose: verbose, filter: filter);
+ WriteCommandHelp(command, _logger, verbose: verbose, matcher: matcher);
}
else if (manual)
{
- WriteManual(_logger, verbose: verbose, filter: filter);
+ WriteManual(_logger, verbose: verbose, matcher: matcher);
}
else
{
- WriteCommandsHelp(_logger, verbose: verbose, filter: filter);
+ WriteCommandsHelp(_logger, verbose: verbose, matcher: matcher);
}
}
@@ -124,9 +124,9 @@ private void OpenHelpInBrowser(string? commandName)
}
}
- public static void WriteCommandHelp(Command command, Logger logger, bool verbose = false, Filter? filter = null)
+ public static void WriteCommandHelp(Command command, Logger logger, bool verbose = false, Matcher? matcher = null)
{
- var writer = new ConsoleHelpWriter(logger, new HelpWriterOptions(filter: filter));
+ var writer = new ConsoleHelpWriter(logger, new HelpWriterOptions(matcher: matcher));
IEnumerable options = command.Options;
@@ -141,7 +141,7 @@ public static void WriteCommandHelp(Command command, Logger logger, bool verbose
command = command.WithOptions(options);
- CommandHelp commandHelp = CommandHelp.Create(command, OptionValueProviders.Providers, filter: filter);
+ CommandHelp commandHelp = CommandHelp.Create(command, OptionValueProviders.Providers, matcher: matcher);
writer.WriteCommand(commandHelp);
@@ -166,13 +166,13 @@ public static void WriteCommandHelp(Command command, Logger logger, bool verbose
}
}
- public static void WriteCommandsHelp(Logger logger, bool verbose = false, Filter? filter = null)
+ public static void WriteCommandsHelp(Logger logger, bool verbose = false, Matcher? matcher = null)
{
IEnumerable commands = LoadCommands().Where(f => f.Name != "help");
- CommandsHelp commandsHelp = CommandsHelp.Create(commands, OptionValueProviders.Providers, filter: filter);
+ CommandsHelp commandsHelp = CommandsHelp.Create(commands, OptionValueProviders.Providers, matcher: matcher);
- var writer = new ConsoleHelpWriter(logger, new HelpWriterOptions(filter: filter));
+ var writer = new ConsoleHelpWriter(logger, new HelpWriterOptions(matcher: matcher));
writer.WriteCommands(commandsHelp);
@@ -183,13 +183,13 @@ public static void WriteCommandsHelp(Logger logger, bool verbose = false, Filter
logger.WriteLine(GetFooterText());
}
- private static void WriteManual(Logger logger, bool verbose = false, Filter? filter = null)
+ private static void WriteManual(Logger logger, bool verbose = false, Matcher? matcher = null)
{
IEnumerable commands = LoadCommands();
- var writer = new ConsoleHelpWriter(logger, new HelpWriterOptions(filter: filter));
+ var writer = new ConsoleHelpWriter(logger, new HelpWriterOptions(matcher: matcher));
- IEnumerable commandHelps = commands.Select(f => CommandHelp.Create(f, filter: filter))
+ IEnumerable commandHelps = commands.Select(f => CommandHelp.Create(f, matcher: matcher))
.Where(f => f.Arguments.Any() || f.Options.Any())
.ToImmutableArray();
@@ -202,7 +202,7 @@ private static void WriteManual(Logger logger, bool verbose = false, Filter? fil
values = HelpProvider.GetOptionValues(
commandHelps.SelectMany(f => f.Command.Options),
OptionValueProviders.Providers,
- filter);
+ matcher);
var commandsHelp = new CommandsHelp(commandItems, values);
@@ -239,7 +239,7 @@ private static void WriteManual(Logger logger, bool verbose = false, Filter? fil
values = HelpProvider.GetOptionValues(
commands.Select(f => CommandHelp.Create(f)).SelectMany(f => f.Command.Options),
OptionValueProviders.Providers,
- filter);
+ matcher);
}
}
diff --git a/src/CommandLine/Commands/MoveCommand.cs b/src/CommandLine/Commands/MoveCommand.cs
index 057f47ca..620389c8 100644
--- a/src/CommandLine/Commands/MoveCommand.cs
+++ b/src/CommandLine/Commands/MoveCommand.cs
@@ -1,6 +1,7 @@
// 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.
using System.IO;
+using Orang.FileSystem;
namespace Orang.CommandLine;
diff --git a/src/CommandLine/Commands/RegexListCommand.cs b/src/CommandLine/Commands/RegexListCommand.cs
index 1f1b21a9..42251132 100644
--- a/src/CommandLine/Commands/RegexListCommand.cs
+++ b/src/CommandLine/Commands/RegexListCommand.cs
@@ -35,7 +35,7 @@ private CommandResult ListPatterns()
{
IEnumerable items = SyntaxItems.Load();
- Filter? filter = Options.Filter;
+ Matcher? matcher = Options.Matcher;
ImmutableArray sections = Options.Sections;
@@ -46,10 +46,10 @@ private CommandResult ListPatterns()
.ToImmutableArray();
}
- if (filter is not null)
+ if (matcher is not null)
{
- items = items.Where(f => filter.IsMatch(f.Text)
- || filter.IsMatch(f.Description));
+ items = items.Where(f => matcher.IsMatch(f.Text)
+ || matcher.IsMatch(f.Description));
}
if (sections.Any())
@@ -191,12 +191,12 @@ private IEnumerable GetPatterns(char ch)
inCharGroup: Options.InCharGroup,
options: Options.RegexOptions);
- Filter? filter = Options.Filter;
+ Matcher? matcher = Options.Matcher;
- if (filter is not null)
+ if (matcher is not null)
{
- patterns = patterns.Where(f => filter.IsMatch(f.Pattern)
- || (!string.IsNullOrEmpty(f.Description) && filter.IsMatch(f.Description)));
+ patterns = patterns.Where(f => matcher.IsMatch(f.Pattern)
+ || (!string.IsNullOrEmpty(f.Description) && matcher.IsMatch(f.Description)));
}
ImmutableArray sections = Options.Sections;
diff --git a/src/CommandLine/Commands/RegexMatchCommand.cs b/src/CommandLine/Commands/RegexMatchCommand.cs
index 95db7a94..0099203c 100644
--- a/src/CommandLine/Commands/RegexMatchCommand.cs
+++ b/src/CommandLine/Commands/RegexMatchCommand.cs
@@ -15,7 +15,7 @@ protected override CommandResult ExecuteCore(CancellationToken cancellationToken
{
MatchData matchData = MatchData.Create(
Options.Input,
- Options.Filter.Regex,
+ Options.Matcher.Regex,
Options.MaxCount,
cancellationToken);
diff --git a/src/CommandLine/Commands/RegexSplitCommand.cs b/src/CommandLine/Commands/RegexSplitCommand.cs
index 03e28b63..df670d3a 100644
--- a/src/CommandLine/Commands/RegexSplitCommand.cs
+++ b/src/CommandLine/Commands/RegexSplitCommand.cs
@@ -14,7 +14,7 @@ public RegexSplitCommand(RegexSplitCommandOptions options, Logger logger) : base
protected override CommandResult ExecuteCore(CancellationToken cancellationToken = default)
{
SplitData splitData = SplitData.Create(
- Options.Filter.Regex,
+ Options.Matcher.Regex,
Options.Input,
Options.MaxCount,
omitGroups: Options.OmitGroups,
diff --git a/src/CommandLine/Commands/RenameCommand.cs b/src/CommandLine/Commands/RenameCommand.cs
index 5c79ab51..b80ee11c 100644
--- a/src/CommandLine/Commands/RenameCommand.cs
+++ b/src/CommandLine/Commands/RenameCommand.cs
@@ -1,7 +1,6 @@
// 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.
using System;
-using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Orang.FileSystem;
@@ -13,7 +12,7 @@ internal class RenameCommand : DeleteOrRenameCommand
{
public RenameCommand(RenameCommandOptions options, Logger logger) : base(options, logger)
{
- Debug.Assert(options.NameFilter?.IsNegative == false);
+ Debug.Assert(options.NameFilter?.Invert == false);
if (_logger.ShouldWrite(Verbosity.Minimal))
{
@@ -35,10 +34,9 @@ public ConflictResolution ConflictResolution
private PathWriter? PathWriter { get; }
- protected override void OnSearchCreating(FileSystemSearch search)
+ protected override void OnSearchCreating(SearchState search)
{
- search.DisallowEnumeration = !Options.DryRun;
- search.MatchPartOnly = true;
+ search.SupportsEnumeration = Options.DryRun;
base.OnSearchCreating(search);
}
@@ -51,35 +49,36 @@ protected override void ExecuteMatchCore(
{
string indent = GetPathIndent(baseDirectoryPath);
- (List replaceItems, MaxReason maxReason) = ReplaceHelpers.GetReplaceItems(
- fileMatch.NameMatch!,
- Options.ReplaceOptions,
+ ReplaceResult result = fileMatch.GetReplaceResult(
+ Options.Replacer,
count: Options.MaxMatchesInFile,
predicate: NameFilter!.Predicate,
cancellationToken: context.CancellationToken);
- string path = fileMatch.Path;
-
- string newName = ReplaceHelpers.GetNewName(fileMatch, replaceItems);
+ string newValue = result.NewName;
- if (string.IsNullOrWhiteSpace(newName))
+ if (string.IsNullOrWhiteSpace(newValue))
{
_logger.WriteLine($"{indent}New file name cannot be empty or contains only white-space.", Colors.Message_Warning);
return;
}
+ string path = fileMatch.Path;
+
bool changed = string.Compare(
path,
fileMatch.NameSpan.Start,
- newName,
+ newValue,
0,
- Math.Max(fileMatch.NameSpan.Length, newName.Length),
+ Math.Max(fileMatch.NameSpan.Length, newValue.Length),
StringComparison.Ordinal) != 0;
bool isInvalidName = changed
- && FileSystemHelpers.ContainsInvalidFileNameChars(newName);
+ && FileSystemUtilities.ContainsInvalidFileNameChars(newValue);
- string newPath = path.Substring(0, fileMatch.NameSpan.Start) + newName;
+ string newPath = path.Substring(0, fileMatch.NameSpan.Start)
+ + newValue
+ + path.Substring(fileMatch.NameSpan.Start + fileMatch.NameSpan.Length);
if (Options.Interactive
|| (!Options.OmitPath && changed))
@@ -91,28 +90,28 @@ protected override void ExecuteMatchCore(
PathWriter?.WritePath(
fileMatch,
- replaceItems,
+ result.Items,
replaceColors,
baseDirectoryPath,
indent);
WriteProperties(context, fileMatch, columnWidths);
- _logger.WriteFilePathEnd(replaceItems.Count, maxReason, Options.IncludeCount);
+ _logger.WriteFilePathEnd(result.Count, result.MaxReason, Options.IncludeCount);
}
- ListCache.Free(replaceItems);
+ ListCache.Free(result.Items);
if (Options.Interactive)
{
- string newName2 = ConsoleHelpers.ReadUserInput(newName, indent + "New name: ");
+ string newName2 = ConsoleHelpers.ReadUserInput(newValue, indent + "New name: ");
- newPath = newPath.Substring(0, newPath.Length - newName.Length) + newName2;
+ newPath = newPath.Substring(0, newPath.Length - newValue.Length) + newName2;
changed = !string.Equals(path, newPath, StringComparison.Ordinal);
if (changed)
{
- isInvalidName = FileSystemHelpers.ContainsInvalidFileNameChars(newName2);
+ isInvalidName = FileSystemUtilities.ContainsInvalidFileNameChars(newName2);
if (isInvalidName)
{
diff --git a/src/CommandLine/Commands/ReplaceCommand.cs b/src/CommandLine/Commands/ReplaceCommand.cs
index 0223fa5d..a83a8bd0 100644
--- a/src/CommandLine/Commands/ReplaceCommand.cs
+++ b/src/CommandLine/Commands/ReplaceCommand.cs
@@ -8,6 +8,6 @@ internal class ReplaceCommand : CommonReplaceCommand
{
public ReplaceCommand(ReplaceCommandOptions options, Logger logger) : base(options, logger)
{
- Debug.Assert(!options.ContentFilter!.IsNegative);
+ Debug.Assert(!options.ContentFilter!.Invert);
}
}
diff --git a/src/CommandLine/Commands/SpellcheckCommand.cs b/src/CommandLine/Commands/SpellcheckCommand.cs
index 567cd40c..27196ef1 100644
--- a/src/CommandLine/Commands/SpellcheckCommand.cs
+++ b/src/CommandLine/Commands/SpellcheckCommand.cs
@@ -75,9 +75,9 @@ private List GetFilteredSpans(List groups, CancellationToken
foreach (Capture group in groups)
{
- foreach (Filter filter in SpellcheckState.Filters)
+ foreach (Matcher matcher in SpellcheckState.Matchers)
{
- Match? match = filter.Match(group.Value);
+ Match? match = matcher.Match(group.Value);
if (match is not null)
{
@@ -86,9 +86,9 @@ private List GetFilteredSpans(List groups, CancellationToken
MaxReason _ = CaptureFactory.GetCaptures(
ref captures,
match,
- filter.GroupNumber,
+ matcher.GroupNumber,
count: 0,
- filter.Predicate,
+ matcher.Predicate,
cancellationToken);
if (allSpans is null)
diff --git a/src/CommandLine/Commands/SyncCommand.cs b/src/CommandLine/Commands/SyncCommand.cs
index db559722..56926207 100644
--- a/src/CommandLine/Commands/SyncCommand.cs
+++ b/src/CommandLine/Commands/SyncCommand.cs
@@ -45,7 +45,7 @@ protected override string GetQuestionText(bool isDirectory)
return (isDirectory) ? "Sync directory?" : "Sync file?";
}
- protected override void OnSearchCreating(FileSystemSearch search)
+ protected override void OnSearchCreating(SearchState search)
{
search.CanRecurseMatch = true;
}
@@ -55,7 +55,7 @@ protected override void ExecuteDirectory(string directoryPath, SearchContext con
bool secondExists = Directory.Exists(Options.Target);
if (secondExists)
- _destinationPaths = new HashSet(FileSystemHelpers.Comparer);
+ _destinationPaths = new HashSet(FileSystemUtilities.Comparer);
try
{
@@ -123,7 +123,7 @@ void ExecuteOperation()
bool fileExists = File.Exists(destinationPath);
bool directoryExists = !fileExists && Directory.Exists(destinationPath);
bool? preferLeft = null;
- FileCompareOptions? diffProperty = null;
+ FileCompareProperties? diffProperty = null;
if (isDirectory)
{
@@ -134,7 +134,7 @@ void ExecuteOperation()
if (_isSecondToFirst)
return;
- if (FileSystemHelpers.AttributeEquals(sourcePath, destinationPath, Options.NoCompareAttributes))
+ if (FileSystemUtilities.AttributeEquals(sourcePath, destinationPath, Options.CompareAttributes))
return;
}
}
@@ -143,9 +143,9 @@ void ExecuteOperation()
if (_isSecondToFirst)
return;
- if ((Options.CompareOptions & FileCompareOptions.ModifiedTime) != 0)
+ if ((Options.CompareProperties & FileCompareProperties.ModifiedTime) != 0)
{
- int diff = FileSystemHelpers.CompareLastWriteTimeUtc(
+ int diff = FileSystemUtilities.CompareLastWriteTimeUtc(
sourcePath,
destinationPath,
Options.AllowedTimeDiff);
@@ -168,28 +168,28 @@ void ExecuteOperation()
{
if (fileExists)
{
- if (Options.CompareOptions != FileCompareOptions.None)
+ if (Options.CompareProperties != FileCompareProperties.None)
{
- diffProperty = FileSystemHelpers.CompareFiles(
+ diffProperty = FileSystemUtilities.CompareFiles(
sourcePath,
destinationPath,
- Options.CompareOptions,
- Options.NoCompareAttributes,
+ Options.CompareProperties,
+ Options.CompareAttributes,
Options.AllowedTimeDiff);
- if (diffProperty == FileCompareOptions.None)
+ if (diffProperty == FileCompareProperties.None)
return;
}
}
else if (Options.DetectRename
- && (Options.CompareOptions & FileCompareOptions.Content) != 0)
+ && (Options.CompareProperties & FileCompareProperties.Content) != 0)
{
if (_directoryData is null)
{
_directoryData = new DirectoryData();
_directoryData.Load(Path.GetDirectoryName(destinationPath)!);
}
- else if (!FileSystemHelpers.IsParentDirectory(_directoryData.Path!, destinationPath))
+ else if (!FileSystemUtilities.IsParentDirectory(_directoryData.Path!, destinationPath))
{
_directoryData.Load(Path.GetDirectoryName(destinationPath)!);
}
@@ -404,7 +404,7 @@ private void ExecuteFileOperations(
bool fileExists,
bool directoryExists,
bool preferLeft,
- FileCompareOptions? diffProperty,
+ FileCompareProperties? diffProperty,
string indent)
{
if (preferLeft)
@@ -413,7 +413,7 @@ private void ExecuteFileOperations(
{
WritePath(context, destinationPath, OperationKind.Update, indent);
- if (diffProperty == FileCompareOptions.Attributes)
+ if (diffProperty == FileCompareProperties.Attributes)
{
// update attributes
File.SetAttributes(destinationPath, File.GetAttributes(sourcePath));
@@ -440,7 +440,7 @@ private void ExecuteFileOperations(
WritePath(context, destinationPath, OperationKind.Add, indent);
if (!fileExists
- || diffProperty != FileCompareOptions.Attributes)
+ || diffProperty != FileCompareProperties.Attributes)
{
CopyFile(sourcePath, destinationPath);
}
@@ -459,7 +459,7 @@ private void ExecuteFileOperations(
WritePath(context, sourcePath, (fileExists) ? OperationKind.Update : OperationKind.Delete, indent);
if (!fileExists
- || diffProperty != FileCompareOptions.Attributes)
+ || diffProperty != FileCompareProperties.Attributes)
{
DeleteFile(sourcePath);
@@ -469,7 +469,7 @@ private void ExecuteFileOperations(
if (fileExists)
{
- if (diffProperty == FileCompareOptions.Attributes)
+ if (diffProperty == FileCompareProperties.Attributes)
{
// update attributes
File.SetAttributes(sourcePath, File.GetAttributes(destinationPath));
@@ -541,7 +541,7 @@ private void CopyFile(string sourcePath, string destinationPath)
private void UpdateAttributes(string sourcePath, string destinationPath)
{
if (!DryRun)
- FileSystemHelpers.UpdateAttributes(sourcePath, destinationPath);
+ FileSystemUtilities.UpdateAttributes(sourcePath, destinationPath);
}
protected override void ExecuteOperation(string sourcePath, string destinationPath)
diff --git a/src/CommandLine/ConsoleHelpWriter.cs b/src/CommandLine/ConsoleHelpWriter.cs
index 57e10d60..a7cfd012 100644
--- a/src/CommandLine/ConsoleHelpWriter.cs
+++ b/src/CommandLine/ConsoleHelpWriter.cs
@@ -21,18 +21,18 @@ public ConsoleHelpWriter(Logger logger, HelpWriterOptions? options = null) : bas
public ContentTextWriter ContentWriter { get; }
- public Filter? Filter => Options.Filter;
+ public Matcher? Matcher => Options.Matcher;
internal ContentWriterOptions? ContentWriterOptions
{
get
{
if (_contentWriterOptions is null
- && Filter is not null)
+ && Matcher is not null)
{
_contentWriterOptions = new ContentWriterOptions(
format: new OutputDisplayFormat(ContentDisplayStyle.AllLines),
- (Filter.GroupNumber >= 0) ? new GroupDefinition(Filter.GroupNumber, Filter.GroupName) : default,
+ (Matcher.GroupNumber >= 0) ? new GroupDefinition(Matcher.GroupNumber, Matcher.GroupName) : default,
indent: "");
}
@@ -81,7 +81,7 @@ public override void WriteCommands(CommandsHelp commands)
WriteEndCommands(commands);
}
- else if (Options.Filter is not null)
+ else if (Options.Matcher is not null)
{
WriteLine("No command found");
}
@@ -137,15 +137,15 @@ protected override void WriteTextLine(HelpItem helpItem)
{
string value = helpItem.Text;
- if (Filter is not null)
+ if (Matcher is not null)
{
- Match? match = Filter.Match(value);
+ Match? match = Matcher.Match(value);
if (match is not null)
{
List captures = ListCache.GetInstance();
- CaptureFactory.GetCaptures(ref captures, match, Filter.GroupNumber);
+ CaptureFactory.GetCaptures(ref captures, match, Matcher.GroupNumber);
var writer = new AllLinesContentWriter(value, ContentWriter, ContentWriterOptions!);
diff --git a/src/CommandLine/DiagnosticWriter.cs b/src/CommandLine/DiagnosticWriter.cs
index 7e2acb2d..cfb40369 100644
--- a/src/CommandLine/DiagnosticWriter.cs
+++ b/src/CommandLine/DiagnosticWriter.cs
@@ -154,7 +154,7 @@ internal void WriteCopyCommand(CopyCommandOptions options)
WriteOption("ask", options.AskMode);
WriteOption("attributes", options.Attributes);
WriteOption("attributes to skip", options.AttributesToSkip);
- WriteOption("compare", options.CompareOptions);
+ WriteOption("compare", options.CompareProperties);
WriteOption("conflict resolution", options.ConflictResolution);
WriteFilter("content filter", options.ContentFilter);
#if DEBUG
@@ -214,7 +214,6 @@ internal void WriteDeleteCommand(DeleteCommandOptions options)
WriteContext("context", options.Format.LineContext);
WriteOption("count", options.Format.Includes(DisplayParts.Count));
WriteEncoding("default encoding", options.DefaultEncoding);
- WriteOption("directories only", options.DirectoriesOnly);
WriteFilter("directory filter", options.DirectoryFilter, options.DirectoryNamePart);
WriteOption("dry run", options.DryRun);
WriteOption("empty", options.EmptyOption);
@@ -224,7 +223,6 @@ internal void WriteDeleteCommand(DeleteCommandOptions options)
options.SizePredicate,
options.CreationTimePredicate,
options.ModifiedTimePredicate);
- WriteOption("files only", options.FilesOnly);
WriteOption("highlight options", options.HighlightOptions);
WriteOption("including bom", options.IncludingBom);
WriteOption("line number", options.Format.Includes(LineDisplayOptions.IncludeLineNumber));
@@ -287,7 +285,7 @@ internal void WriteHelpCommand(HelpCommandOptions options)
{
WriteOption("command", string.Join(' ', options.Command));
WriteOption("manual", options.Manual);
- WriteFilter("filter", options.Filter);
+ WriteFilter("filter", options.Matcher);
}
internal void WriteMoveCommand(MoveCommandOptions options)
@@ -299,7 +297,7 @@ internal void WriteMoveCommand(MoveCommandOptions options)
WriteOption("ask", options.AskMode);
WriteOption("attributes", options.Attributes);
WriteOption("attributes to skip", options.AttributesToSkip);
- WriteOption("compare", options.CompareOptions);
+ WriteOption("compare", options.CompareProperties);
WriteOption("conflict resolution", options.ConflictResolution);
WriteFilter("content filter", options.ContentFilter);
#if DEBUG
@@ -357,7 +355,7 @@ internal void WriteRegexMatchCommand(RegexMatchCommandOptions options)
#if DEBUG
WriteOption("content separator", options.Format.Separator);
#endif
- WriteFilter("filter", options.Filter);
+ WriteFilter("filter", options.Matcher);
WriteOption("highlight options", options.HighlightOptions);
WriteInput(options.Input);
WriteOption("max count", options.MaxCount);
@@ -368,7 +366,7 @@ internal void WriteRegexListCommand(RegexListCommandOptions options)
{
WriteOption("char", options.Value);
WriteOption("char group", options.InCharGroup);
- WriteFilter("filter", options.Filter);
+ WriteFilter("filter", options.Matcher);
WriteOption("regex options", options.RegexOptions);
WriteOption("sections", options.Sections);
}
@@ -382,7 +380,7 @@ internal void WriteRegexSplitCommand(RegexSplitCommandOptions options)
#if DEBUG
WriteOption("content separator", options.Format.Separator);
#endif
- WriteFilter("filter", options.Filter);
+ WriteFilter("filter", options.Matcher);
WriteOption("highlight options", options.HighlightOptions);
WriteInput(options.Input);
WriteOption("max count", options.MaxCount);
@@ -411,7 +409,7 @@ internal void WriteRenameCommand(RenameCommandOptions options)
WriteFilter("directory filter", options.DirectoryFilter, options.DirectoryNamePart);
WriteOption("dry run", options.DryRun);
WriteOption("empty", options.EmptyOption);
- WriteEvaluator("evaluator", options.ReplaceOptions.MatchEvaluator);
+ WriteEvaluator("evaluator", options.Replacer.MatchEvaluator);
WriteFilter("extension filter", options.ExtensionFilter);
WriteFilePropertyFilter(
"file properties",
@@ -422,14 +420,14 @@ internal void WriteRenameCommand(RenameCommandOptions options)
WriteOption("interactive", options.Interactive);
WriteOption("line number", options.Format.Includes(LineDisplayOptions.IncludeLineNumber));
WriteOption("max matching files", options.MaxMatchingFiles);
- WriteReplaceModify("modify", options.ReplaceOptions);
+ WriteReplaceModify("modify", options.Replacer);
WriteFilter("name filter", options.NameFilter, options.NamePart);
WriteOption("path mode", options.Format.PathDisplayStyle);
WritePaths("paths", options.Paths);
WriteOption("progress", options.Progress);
WriteProperties(options);
WriteOption("recurse subdirectories", options.RecurseSubdirectories);
- WriteOption("replacement", options.ReplaceOptions.Replacement);
+ WriteOption("replacement", options.Replacer.Replacement);
WriteOption("search target", options.SearchTarget);
WriteSortOptions("sort", options.SortOptions);
WriteOption("summary", options.Format.Includes(DisplayParts.Summary));
@@ -437,7 +435,7 @@ internal void WriteRenameCommand(RenameCommandOptions options)
internal void WriteReplaceCommand(ReplaceCommandOptions options)
{
- var replaceOptions = (ReplaceOptions)options.Replacer;
+ var replacer = (Replacer)options.Replacer;
WriteOption("align columns", options.AlignColumns);
WriteOption("ask", options.AskMode);
@@ -457,7 +455,7 @@ internal void WriteReplaceCommand(ReplaceCommandOptions options)
WriteFilter("directory filter", options.DirectoryFilter, options.DirectoryNamePart);
WriteOption("dry run", options.DryRun);
WriteOption("empty", options.EmptyOption);
- WriteEvaluator("evaluator", replaceOptions.MatchEvaluator);
+ WriteEvaluator("evaluator", replacer.MatchEvaluator);
WriteFilter("extension filter", options.ExtensionFilter);
WriteFilePropertyFilter(
"file properties",
@@ -470,14 +468,14 @@ internal void WriteReplaceCommand(ReplaceCommandOptions options)
WriteOption("line number", options.Format.Includes(LineDisplayOptions.IncludeLineNumber));
WriteOption("max matching files", options.MaxMatchingFiles);
WriteOption("max matches in file", options.MaxMatchesInFile);
- WriteReplaceModify("modify", replaceOptions);
+ WriteReplaceModify("modify", replacer);
WriteFilter("name filter", options.NameFilter, options.NamePart);
WriteOption("path mode", options.Format.PathDisplayStyle);
WritePaths("paths", options.Paths);
WriteOption("progress", options.Progress);
WriteProperties(options);
WriteOption("recurse subdirectories", options.RecurseSubdirectories);
- WriteOption("replacement", replaceOptions.Replacement);
+ WriteOption("replacement", replacer.Replacement);
WriteOption("search target", options.SearchTarget);
WriteSortOptions("sort", options.SortOptions);
WriteOption("summary", options.Format.Includes(DisplayParts.Summary));
@@ -545,7 +543,7 @@ internal void WriteSyncCommand(SyncCommandOptions options)
WriteOption("ask", options.AskMode);
WriteOption("attributes", options.Attributes);
WriteOption("attributes to skip", options.AttributesToSkip);
- WriteOption("compare", options.CompareOptions);
+ WriteOption("compare", options.CompareProperties);
WriteOption("conflict resolution", options.ConflictResolution);
WriteFilter("content filter", options.ContentFilter);
#if DEBUG
@@ -653,6 +651,13 @@ private void WriteOption(string name, TEnum value) where TEnum : Enum
WriteLine();
}
+ private void WriteOption(string name, object? value)
+ {
+ WriteName(name);
+ WriteValue(value?.ToString());
+ WriteLine();
+ }
+
private void WriteOption(string name, ImmutableArray values) where TEnum : Enum
{
WriteName(name);
@@ -685,27 +690,27 @@ private void WriteEncoding(string name, Encoding encoding)
WriteLine();
}
- private void WriteFilter(string name, Filter? filter, FileNamePart? part = null)
+ private void WriteFilter(string name, Matcher? matcher, FileNamePart? part = null)
{
WriteName(name);
- if (filter is null)
+ if (matcher is null)
{
WriteNullValue();
WriteLine();
return;
}
- WriteRegex(filter.Regex);
+ WriteRegex(matcher.Regex);
WriteIndent();
WriteName("negative");
WriteIndent();
- WriteLine(filter.IsNegative.ToString().ToLowerInvariant());
+ WriteLine(matcher.Invert.ToString().ToLowerInvariant());
WriteIndent();
WriteName("group");
- if (string.IsNullOrEmpty(filter.GroupName))
+ if (string.IsNullOrEmpty(matcher.GroupName))
{
WriteNullValue();
WriteLine();
@@ -713,7 +718,7 @@ private void WriteFilter(string name, Filter? filter, FileNamePart? part = null)
else
{
WriteIndent();
- WriteLine(filter.GroupName);
+ WriteLine(matcher.GroupName);
}
if (part is not null)
@@ -903,24 +908,24 @@ private void WriteEvaluator(string name, MatchEvaluator? matchEvaluator)
}
}
- private void WriteReplaceModify(string name, ReplaceOptions options)
+ private void WriteReplaceModify(string name, Replacer replacer)
{
WriteName(name);
- if (options.Functions != ReplaceFunctions.None)
+ if (replacer.Functions != ReplaceFunctions.None)
{
- if (options.CultureInvariant)
+ if (replacer.CultureInvariant)
{
- WriteValue(nameof(options.CultureInvariant) + ", " + options.Functions.ToString());
+ WriteValue(nameof(replacer.CultureInvariant) + ", " + replacer.Functions.ToString());
}
else
{
- WriteValue(options.Functions.ToString());
+ WriteValue(replacer.Functions.ToString());
}
}
- else if (options.CultureInvariant)
+ else if (replacer.CultureInvariant)
{
- WriteValue(nameof(options.CultureInvariant));
+ WriteValue(nameof(replacer.CultureInvariant));
}
else
{
diff --git a/src/CommandLine/OptionValueProviders.cs b/src/CommandLine/OptionValueProviders.cs
index d2c66521..7f8ca573 100644
--- a/src/CommandLine/OptionValueProviders.cs
+++ b/src/CommandLine/OptionValueProviders.cs
@@ -541,15 +541,15 @@ internal static class OptionValueProviders
public static OptionValueProvider FileCompareOptionsProvider { get; } = new(
MetaValues.CompareOptions,
- SimpleOptionValue.Create(FileCompareOptions.None, description: "Compare files only by name."),
- SimpleOptionValue.Create(FileCompareOptions.Attributes, description: "Compare file attributes."),
- SimpleOptionValue.Create(FileCompareOptions.Content, description: "Compare file content."),
+ SimpleOptionValue.Create(FileCompareProperties.None, description: "Compare files only by name."),
+ SimpleOptionValue.Create(FileCompareProperties.Attributes, description: "Compare file attributes."),
+ SimpleOptionValue.Create(FileCompareProperties.Content, description: "Compare file content."),
SimpleOptionValue.Create(
- FileCompareOptions.ModifiedTime,
+ FileCompareProperties.ModifiedTime,
shortValue: "mt",
helpValue: "m[odified-]t[ime]",
description: "Compare time a file was last modified."),
- SimpleOptionValue.Create(FileCompareOptions.Size, description: "Compare file size.")
+ SimpleOptionValue.Create(FileCompareProperties.Size, description: "Compare file size.")
);
public static OptionValueProvider SyncConflictResolutionProvider { get; } = new(
diff --git a/src/CommandLine/OutputWriter/OutputWriter.cs b/src/CommandLine/OutputWriter/OutputWriter.cs
index cef19eb1..2a93cb48 100644
--- a/src/CommandLine/OutputWriter/OutputWriter.cs
+++ b/src/CommandLine/OutputWriter/OutputWriter.cs
@@ -36,7 +36,7 @@ public int WriteMatches(
if (matchItems.Count == 0)
return default;
- int groupNumber = options.Filter.GroupNumber;
+ int groupNumber = options.Matcher.GroupNumber;
OutputSymbols symbols = OutputSymbols.Create(HighlightOptions);
@@ -64,7 +64,7 @@ public int WriteMatches(
.ThenBy(f => f.Number)
.SelectMany(f => f.CaptureItems)
.Select(f => f.Value)
- .Where(f => options.Filter.Predicate?.Invoke(f) != false)
+ .Where(f => options.Matcher.Predicate?.Invoke(f) != false)
.Modify(options.ModifyOptions)
.GetEnumerator())
{
@@ -121,7 +121,7 @@ public int WriteMatches(
{
CaptureItem captureItem = groupItem.CaptureItems[j];
- if (options.Filter.Predicate?.Invoke(captureItem.Value) == false)
+ if (options.Matcher.Predicate?.Invoke(captureItem.Value) == false)
continue;
if (addSeparator)
@@ -168,7 +168,7 @@ public int WriteMatches(
{
cancellationToken.ThrowIfCancellationRequested();
- if (options.Filter.Predicate?.Invoke(matchItem.Value) == false)
+ if (options.Matcher.Predicate?.Invoke(matchItem.Value) == false)
continue;
valueWriter.Write(input, lastPos, matchItem.Index - lastPos, symbols: null);
@@ -224,7 +224,7 @@ public int WriteSplits(
{
cancellationToken.ThrowIfCancellationRequested();
- bool success = options.Filter.Predicate?.Invoke(en.Current) != false;
+ bool success = options.Matcher.Predicate?.Invoke(en.Current) != false;
if (success)
{
@@ -272,7 +272,7 @@ public int WriteSplits(
SplitItem item = en.Current;
- bool success = options.Filter.Predicate?.Invoke(item.Value) != false;
+ bool success = options.Matcher.Predicate?.Invoke(item.Value) != false;
if (success)
{
@@ -308,7 +308,7 @@ public int WriteSplits(
{
cancellationToken.ThrowIfCancellationRequested();
- if (options.Filter.Predicate?.Invoke(item.Value) == false)
+ if (options.Matcher.Predicate?.Invoke(item.Value) == false)
continue;
valueWriter.Write(input, lastPos, item.Index - lastPos, symbols: null);
diff --git a/src/CommandLine/ParseContext.cs b/src/CommandLine/ParseContext.cs
index a78eb901..1aa0f5ac 100644
--- a/src/CommandLine/ParseContext.cs
+++ b/src/CommandLine/ParseContext.cs
@@ -534,7 +534,7 @@ public bool TryParseModifier(
}
if ((options & ModifierOptions.FromFile) != 0
- && !FileSystemHelpers.TryReadAllText(value, out value!, ex => Logger.WriteError(ex)))
+ && !FileSystemUtilities.TryReadAllText(value, out value!, ex => Logger.WriteError(ex)))
{
return false;
}
@@ -567,9 +567,9 @@ public bool TryParseReplaceOptions(
string optionName,
string? replacement,
MatchEvaluator? matchEvaluator,
- [NotNullWhen(true)] out ReplaceOptions? replaceOptions)
+ [NotNullWhen(true)] out Replacer? replacer)
{
- replaceOptions = null;
+ replacer = null;
var replaceFlags = ReplaceFlags.None;
if (values is not null
@@ -598,14 +598,14 @@ public bool TryParseReplaceOptions(
if (matchEvaluator is not null)
{
- replaceOptions = new ReplaceOptions(
+ replacer = new Replacer(
matchEvaluator: matchEvaluator,
functions: functions,
cultureInvariant: (replaceFlags & ReplaceFlags.CultureInvariant) != 0);
}
else
{
- replaceOptions = new ReplaceOptions(
+ replacer = new Replacer(
replacement: replacement,
functions: functions,
cultureInvariant: (replaceFlags & ReplaceFlags.CultureInvariant) != 0);
@@ -872,7 +872,7 @@ public bool TryParseReplacement(
}
if ((options & ReplacementOptions.FromFile) != 0
- && !FileSystemHelpers.TryReadAllText(value, out value!, ex => Logger.WriteError(ex)))
+ && !FileSystemUtilities.TryReadAllText(value, out value!, ex => Logger.WriteError(ex)))
{
return false;
}
@@ -1314,7 +1314,7 @@ public bool TryEnsureFullPath(string path, [NotNullWhen(true)] out string? fullP
{
try
{
- fullPath = FileSystemHelpers.EnsureFullPath(path);
+ fullPath = FileSystemUtilities.EnsureFullPath(path);
return true;
}
catch (ArgumentException ex)
@@ -1362,7 +1362,7 @@ public bool TryParseFilter(
IEnumerable values,
string optionName,
OptionValueProvider provider,
- out Filter? filter,
+ out Matcher? matcher,
bool allowNull = false,
bool allowEmptyPattern = false,
OptionValueProvider? namePartProvider = null,
@@ -1373,7 +1373,7 @@ public bool TryParseFilter(
values: values,
optionName: optionName,
provider: provider,
- filter: out filter,
+ matcher: out matcher,
namePart: out _,
allowNull: allowNull,
allowEmptyPattern: allowEmptyPattern,
@@ -1386,7 +1386,7 @@ public bool TryParseFilter(
IEnumerable values,
string optionName,
OptionValueProvider provider,
- out Filter? filter,
+ out Matcher? matcher,
out FileNamePart namePart,
bool allowNull = false,
bool allowEmptyPattern = false,
@@ -1394,7 +1394,7 @@ public bool TryParseFilter(
FileNamePart defaultNamePart = FileNamePart.Name,
PatternOptions includedPatternOptions = PatternOptions.None)
{
- filter = null;
+ matcher = null;
namePart = defaultNamePart;
string? pattern = values.FirstOrDefault();
@@ -1505,7 +1505,7 @@ public bool TryParseFilter(
if (pattern.Length == 0
&& allowEmptyPattern)
{
- filter = new Filter(new Regex(".+", RegexOptions.Singleline), predicate: predicate);
+ matcher = new Matcher(new Regex(".+", RegexOptions.Singleline), predicate: predicate);
return true;
}
@@ -1544,7 +1544,7 @@ public bool TryParseFilter(
if ((patternOptions & PatternOptions.FromFile) != 0)
{
- if (!FileSystemHelpers.TryReadAllText(pattern, out pattern, ex => Logger.WriteError(ex)))
+ if (!FileSystemUtilities.TryReadAllText(pattern, out pattern, ex => Logger.WriteError(ex)))
return false;
if (pattern.Length == 0
@@ -1598,10 +1598,10 @@ public bool TryParseFilter(
}
}
- filter = new Filter(
+ matcher = new Matcher(
regex,
- isNegative: (patternOptions & PatternOptions.Negative) != 0,
- groupNumber: groupIndex,
+ invert: (patternOptions & PatternOptions.Negative) != 0,
+ group: groupIndex,
predicate: predicate);
return true;
@@ -1818,7 +1818,7 @@ internal bool TryParseProperties(
name,
OptionNames.Name,
OptionValueProviders.PatternOptionsProvider,
- out Filter? nameFilter,
+ out Matcher? nameFilter,
out FileNamePart namePart,
allowNull: true,
allowEmptyPattern: allowEmptyPattern))
diff --git a/src/CommandLine/PathWriter.cs b/src/CommandLine/PathWriter.cs
index 6c71ee21..4c290b6e 100644
--- a/src/CommandLine/PathWriter.cs
+++ b/src/CommandLine/PathWriter.cs
@@ -49,7 +49,7 @@ public void WritePath(
string path = fileMatch.Path;
if (RelativePath
- && string.Equals(path, basePath, FileSystemHelpers.Comparison))
+ && string.Equals(path, basePath, FileSystemUtilities.Comparison))
{
_logger.Write(".", PathColors, Verbosity);
return;
@@ -95,7 +95,7 @@ public void WritePath(
_logger.Write(indent ?? Indent, Verbosity);
if (RelativePath
- && string.Equals(path, basePath, FileSystemHelpers.Comparison))
+ && string.Equals(path, basePath, FileSystemUtilities.Comparison))
{
_logger.Write(".", PathColors, Verbosity);
}
@@ -129,14 +129,14 @@ public void WritePath(
{
Match match = item.Match;
- _logger.Write(path, startIndex, fileMatch.NameSpan.Start + match.Index - startIndex, Verbosity);
+ _logger.Write(path, startIndex, match.Index - startIndex, Verbosity);
if (!MatchColors.IsDefault)
_logger.Write(match.Value, MatchColors, Verbosity);
_logger.Write(item.Value, replacementColors, Verbosity);
- startIndex = fileMatch.NameSpan.Start + match.Index + match.Length;
+ startIndex = match.Index + match.Length;
}
_logger.Write(path, startIndex, path.Length - startIndex, Verbosity);
@@ -146,11 +146,11 @@ protected int GetBasePathLength(string path, string? basePath)
{
if (basePath is not null
&& path.Length > basePath.Length
- && path.StartsWith(basePath, FileSystemHelpers.Comparison))
+ && path.StartsWith(basePath, FileSystemUtilities.Comparison))
{
int length = basePath.Length;
- if (FileSystemHelpers.IsDirectorySeparator(path[length]))
+ if (FileSystemUtilities.IsDirectorySeparator(path[length]))
length++;
return length;
diff --git a/src/CommandLine/Progress/DiagnosticProgressReporter.cs b/src/CommandLine/Progress/DiagnosticProgressReporter.cs
index 22a1ff13..005b7cb1 100644
--- a/src/CommandLine/Progress/DiagnosticProgressReporter.cs
+++ b/src/CommandLine/Progress/DiagnosticProgressReporter.cs
@@ -122,17 +122,17 @@ private static ReadOnlySpan GetPath(
string? basePath,
bool relativePath)
{
- if (string.Equals(path, basePath, FileSystemHelpers.Comparison))
+ if (string.Equals(path, basePath, FileSystemUtilities.Comparison))
return (relativePath) ? "." : path;
if (relativePath
&& basePath is not null
&& path.Length > basePath.Length
- && path.StartsWith(basePath, FileSystemHelpers.Comparison))
+ && path.StartsWith(basePath, FileSystemUtilities.Comparison))
{
int startIndex = basePath.Length;
- if (FileSystemHelpers.IsDirectorySeparator(path[startIndex]))
+ if (FileSystemUtilities.IsDirectorySeparator(path[startIndex]))
startIndex++;
return path.AsSpan(startIndex);
diff --git a/src/CommandLine/Properties/AssemblyInfo.cs b/src/CommandLine/Properties/AssemblyInfo.cs
deleted file mode 100644
index 344d1e2c..00000000
--- a/src/CommandLine/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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.
-
-using System.Runtime.CompilerServices;
-
-#pragma warning disable RCS0056
-
-[assembly: InternalsVisibleTo("Orang.DocumentationGenerator, PublicKey=00240000048000009400000006020000002400005253413100040000010001009ff202171ab25d708192b490c52c1a373c74a2849c734fd9f545bfedc92b61d4e10d356cd26213ef6d96af669a9b570cd6277d590c338cfc00ccc9a15d6ad5b08ac3a8a09db3eae536d653f4acb9c7e992162129b67b4bc72c08af7d67a48ecde99c53a5d2cd44b1e8179368f6db2ec7665061e3ef4029703df4b49952bd0de4")]
-[assembly: InternalsVisibleTo("Orang.CommandLine.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001009ff202171ab25d708192b490c52c1a373c74a2849c734fd9f545bfedc92b61d4e10d356cd26213ef6d96af669a9b570cd6277d590c338cfc00ccc9a15d6ad5b08ac3a8a09db3eae536d653f4acb9c7e992162129b67b4bc72c08af7d67a48ecde99c53a5d2cd44b1e8179368f6db2ec7665061e3ef4029703df4b49952bd0de4")]
diff --git a/src/CommandLine/SearchResult.cs b/src/CommandLine/SearchResult.cs
index a37dbb1a..35c1d36b 100644
--- a/src/CommandLine/SearchResult.cs
+++ b/src/CommandLine/SearchResult.cs
@@ -32,7 +32,7 @@ public SearchResult(
public bool IsDirectory => FileMatch.IsDirectory;
- public Match? ContentMatch => FileMatch.ContentMatch;
+ public Match? ContentMatch => FileMatch.Content;
public string ContentText => FileMatch.ContentText;
@@ -45,7 +45,7 @@ public long GetSize()
{
return _size
?? (_size = (IsDirectory)
- ? FileSystemHelpers.GetDirectorySize(Path)
+ ? FileSystemUtilities.GetDirectorySize(Path)
: ((FileInfo)FileSystemInfo).Length).Value;
}
}
diff --git a/src/CommandLine/SearchResultComparer.cs b/src/CommandLine/SearchResultComparer.cs
index 8e623afb..b80b9016 100644
--- a/src/CommandLine/SearchResultComparer.cs
+++ b/src/CommandLine/SearchResultComparer.cs
@@ -52,8 +52,8 @@ public override int Compare(SearchResult? x, SearchResult? y)
while (true)
{
- int l1 = FileSystemHelpers.IndexOfDirectorySeparator(path1, ++i1) - i1;
- int l2 = FileSystemHelpers.IndexOfDirectorySeparator(path2, ++i2) - i2;
+ int l1 = FileSystemUtilities.IndexOfDirectorySeparator(path1, ++i1) - i1;
+ int l2 = FileSystemUtilities.IndexOfDirectorySeparator(path2, ++i2) - i2;
bool isLast1 = i1 + l1 == path1.Length;
bool isLast2 = i2 + l2 == path2.Length;
@@ -185,8 +185,8 @@ public override int Compare(SearchResult? x, SearchResult? y)
return 1;
return string.Compare(
- x.FileMatch.NameMatch!.Value,
- y.FileMatch.NameMatch!.Value,
+ x.FileMatch.Name!.Value,
+ y.FileMatch.Name!.Value,
StringComparison);
}
}
diff --git a/src/CommandLine/SearchTelemetry.cs b/src/CommandLine/SearchTelemetry.cs
deleted file mode 100644
index 02559722..00000000
--- a/src/CommandLine/SearchTelemetry.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-using System;
-
-namespace Orang.CommandLine;
-
-public class SearchTelemetry
-{
- internal SearchTelemetry()
- {
- }
-
- public int SearchedDirectoryCount { get; internal set; }
-
- public int FileCount { get; internal set; }
-
- public int DirectoryCount { get; internal set; }
-
- public int MatchingFileCount { get; internal set; }
-
- public int MatchingDirectoryCount { get; internal set; }
-
- internal int MatchingFileDirectoryCount => MatchingFileCount + MatchingDirectoryCount;
-
- public int ProcessedFileCount { get; internal set; }
-
- public int ProcessedDirectoryCount { get; internal set; }
-
- public int MatchCount { get; internal set; }
-
- public int ProcessedMatchCount { get; internal set; }
-
- public int MatchingLineCount { get; internal set; }
-
- public TimeSpan Elapsed { get; internal set; }
-
- public long FilesTotalSize { get; internal set; }
-
- public int UpdatedCount { get; internal set; }
-
- public int AddedCount { get; internal set; }
-
- public int RenamedCount { get; internal set; }
-
- public int DeletedCount { get; internal set; }
-}
diff --git a/src/CommandLine/Spelling/SpellcheckState.cs b/src/CommandLine/Spelling/SpellcheckState.cs
index a2e90ea5..2b8b1fb7 100644
--- a/src/CommandLine/Spelling/SpellcheckState.cs
+++ b/src/CommandLine/Spelling/SpellcheckState.cs
@@ -12,11 +12,11 @@ internal class SpellcheckState : IReplacer
public SpellcheckState(
Spellchecker spellchecker,
SpellingData data,
- IEnumerable? filters = null)
+ IEnumerable? matchers = null)
{
Spellchecker = spellchecker;
Data = data;
- Filters = filters?.ToImmutableArray() ?? ImmutableArray.Empty;
+ Matchers = matchers?.ToImmutableArray() ?? ImmutableArray.Empty;
OriginalFixes = data.Fixes;
}
@@ -25,7 +25,7 @@ public SpellcheckState(
public SpellingData Data { get; internal set; }
- public ImmutableArray Filters { get; }
+ public ImmutableArray Matchers { get; }
internal FixList OriginalFixes { get; }
diff --git a/src/Core/.editorconfig b/src/Common/.editorconfig
similarity index 100%
rename from src/Core/.editorconfig
rename to src/Common/.editorconfig
diff --git a/src/Common/Common.csproj b/src/Common/Common.csproj
new file mode 100644
index 00000000..9e83911d
--- /dev/null
+++ b/src/Common/Common.csproj
@@ -0,0 +1,36 @@
+
+
+
+ netstandard2.1
+ Orang.Common
+ Orang
+
+
+
+ true
+ Orang.Common
+ A shared package used by Orang. Do not install this package manually, it will be added as a prerequisite by other packages that require it.
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ <_Parameter1>Orang, PublicKey=$(OrangPublicKey)
+
+
+ <_Parameter1>Orang.FileSystem, PublicKey=$(OrangPublicKey)
+
+
+ <_Parameter1>Orang.CommandLine.Core, PublicKey=$(OrangPublicKey)
+
+
+
+
diff --git a/src/Core/CoreExtensions.cs b/src/Common/CoreExtensions.cs
similarity index 100%
rename from src/Core/CoreExtensions.cs
rename to src/Common/CoreExtensions.cs
diff --git a/src/Core/ICapture.cs b/src/Common/ICapture.cs
similarity index 100%
rename from src/Core/ICapture.cs
rename to src/Common/ICapture.cs
diff --git a/src/Core/ListCache`1.cs b/src/Common/ListCache`1.cs
similarity index 100%
rename from src/Core/ListCache`1.cs
rename to src/Common/ListCache`1.cs
diff --git a/src/Core/Logging/ConsoleColors.cs b/src/Common/Logging/ConsoleColors.cs
similarity index 100%
rename from src/Core/Logging/ConsoleColors.cs
rename to src/Common/Logging/ConsoleColors.cs
diff --git a/src/Core/Logging/ConsoleWriter.cs b/src/Common/Logging/ConsoleWriter.cs
similarity index 100%
rename from src/Core/Logging/ConsoleWriter.cs
rename to src/Common/Logging/ConsoleWriter.cs
diff --git a/src/Core/Logging/ILogWriter.cs b/src/Common/Logging/ILogWriter.cs
similarity index 100%
rename from src/Core/Logging/ILogWriter.cs
rename to src/Common/Logging/ILogWriter.cs
diff --git a/src/Core/Logging/LogWriter.cs b/src/Common/Logging/LogWriter.cs
similarity index 100%
rename from src/Core/Logging/LogWriter.cs
rename to src/Common/Logging/LogWriter.cs
diff --git a/src/Core/Logging/Logger.cs b/src/Common/Logging/Logger.cs
similarity index 100%
rename from src/Core/Logging/Logger.cs
rename to src/Common/Logging/Logger.cs
diff --git a/src/Core/Logging/LoggingExtensions.cs b/src/Common/Logging/LoggingExtensions.cs
similarity index 100%
rename from src/Core/Logging/LoggingExtensions.cs
rename to src/Common/Logging/LoggingExtensions.cs
diff --git a/src/Core/Logging/Verbosity.cs b/src/Common/Logging/Verbosity.cs
similarity index 100%
rename from src/Core/Logging/Verbosity.cs
rename to src/Common/Logging/Verbosity.cs
diff --git a/src/Core/Filter.cs b/src/Common/Matcher.cs
similarity index 56%
rename from src/Core/Filter.cs
rename to src/Common/Matcher.cs
index 452acfb5..ee654fe5 100644
--- a/src/Core/Filter.cs
+++ b/src/Common/Matcher.cs
@@ -2,56 +2,72 @@
using System;
using System.Diagnostics;
-using System.Linq;
using System.Text.RegularExpressions;
namespace Orang;
[DebuggerDisplay("{DebuggerDisplay,nq}")]
-public class Filter
+public class Matcher
{
- internal static Filter EntireInput { get; } = new(@"\A.+\z", RegexOptions.Singleline);
+ internal static Matcher EntireInput { get; } = new(@"\A.+\z", RegexOptions.Singleline);
- public Filter(
+ public Matcher(
string pattern,
- bool isNegative = false) : this(pattern, RegexOptions.None, isNegative: isNegative)
+ RegexOptions options = RegexOptions.None,
+ bool invert = false,
+ object? group = null,
+ Func? predicate = null) : this(new Regex(pattern, options), invert, group, predicate)
{
}
- public Filter(
- string pattern,
- RegexOptions options,
- bool isNegative = false) : this(new Regex(pattern, options), isNegative: isNegative)
- {
- }
-
- public Filter(
+ internal Matcher(
Regex regex,
- bool isNegative = false,
- int groupNumber = -1,
+ bool invert = false,
+ object? group = null,
Func? predicate = null)
{
Regex = regex ?? throw new ArgumentNullException(nameof(regex));
- Debug.Assert(groupNumber < 0 || regex.GetGroupNumbers().Contains(groupNumber), groupNumber.ToString());
+ if (group is string groupName)
+ {
+ GroupNumber = regex.GroupNumberFromName(groupName);
+
+ if (GroupNumber == -1)
+ throw new ArgumentException($"Group name '{groupName}' was not found.", nameof(groupName));
+ }
+ else
+ {
+ GroupNumber = -1;
+ }
+
+ if (group is int groupNumber)
+ {
+ GroupName = regex.GroupNameFromNumber(groupNumber);
+
+ if (GroupName.Length == 0)
+ throw new ArgumentException($"Group number '{groupNumber}' was not found.", nameof(groupNumber));
+ }
+ else
+ {
+ GroupName = "";
+ }
- GroupNumber = groupNumber;
- IsNegative = isNegative;
+ Invert = invert;
Predicate = predicate;
}
public Regex Regex { get; }
- public bool IsNegative { get; }
+ public bool Invert { get; }
public int GroupNumber { get; }
- public Func? Predicate { get; }
+ public string GroupName { get; }
- public string GroupName => Regex.GroupNameFromNumber(GroupNumber);
+ public Func? Predicate { get; }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
- private string DebuggerDisplay => $"{nameof(IsNegative)} = {IsNegative} {Regex}";
+ private string DebuggerDisplay => Regex.ToString();
public Match? Match(string input)
{
@@ -69,7 +85,7 @@ public Filter(
while (match.Success)
{
if (Predicate.Invoke(match.Value))
- return (IsNegative) ? null : match;
+ return (Invert) ? null : match;
match = match.NextMatch();
}
@@ -83,7 +99,7 @@ public Filter(
if (group.Success
&& Predicate.Invoke(group.Value))
{
- return (IsNegative) ? null : match;
+ return (Invert) ? null : match;
}
match = match.NextMatch();
@@ -93,17 +109,17 @@ public Filter(
else if (GroupNumber < 1)
{
if (match.Success)
- return (IsNegative) ? null : match;
+ return (Invert) ? null : match;
}
else
{
Group group = match.Groups[GroupNumber];
if (group.Success)
- return (IsNegative) ? null : match;
+ return (Invert) ? null : match;
}
- return (IsNegative)
+ return (Invert)
? System.Text.RegularExpressions.Match.Empty
: null;
}
@@ -112,9 +128,4 @@ internal bool IsMatch(string input)
{
return Match(input) is not null;
}
-
- internal bool IsMatch(Match match)
- {
- return Match(match) is not null;
- }
}
diff --git a/src/Common/Pattern.cs b/src/Common/Pattern.cs
new file mode 100644
index 00000000..80bc215e
--- /dev/null
+++ b/src/Common/Pattern.cs
@@ -0,0 +1,131 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Orang.Text.RegularExpressions;
+
+namespace Orang;
+
+public static class Pattern
+{
+ public static string Create(
+ string value,
+ PatternOptions options)
+ {
+ if (value is null)
+ throw new ArgumentNullException(nameof(value));
+
+ if ((options & PatternOptions.Literal) != 0)
+ value = RegexEscape.Escape(value);
+
+ return CreateCore(value, options);
+ }
+
+ public static string Any(
+ string value1,
+ string value2,
+ PatternOptions options = PatternOptions.None)
+ {
+ return Any(new string[] { value1, value2 }, options);
+ }
+
+ public static string Any(
+ string value1,
+ string value2,
+ string value3,
+ PatternOptions options = PatternOptions.None)
+ {
+ return Any(new string[] { value1, value2, value3 }, options);
+ }
+
+ public static string Any(
+ IEnumerable values,
+ PatternOptions options = PatternOptions.None)
+ {
+ if (values is null)
+ throw new ArgumentNullException(nameof(values));
+
+ string text = JoinValues(values, (options & PatternOptions.Literal) != 0);
+
+ return CreateCore(text, options);
+
+ static string JoinValues(IEnumerable values, bool literal)
+ {
+ using (IEnumerator en = values.GetEnumerator())
+ {
+ if (en.MoveNext())
+ {
+ string value = en.Current;
+
+ if (en.MoveNext())
+ {
+ StringBuilder sb = StringBuilderCache.GetInstance();
+
+ AppendValue(value, literal, sb);
+
+ do
+ {
+ sb.Append("|");
+ AppendValue(en.Current, literal, sb);
+ }
+ while (en.MoveNext());
+
+ return StringBuilderCache.GetStringAndFree(sb);
+ }
+
+ return (literal) ? RegexEscape.Escape(value) : value;
+ }
+
+ return "";
+ }
+ }
+
+ static void AppendValue(string value, bool literal, StringBuilder sb)
+ {
+ if (literal)
+ {
+ sb.Append(RegexEscape.Escape(value));
+ }
+ else
+ {
+ sb.Append("(?:");
+ sb.Append(value);
+ sb.Append(")");
+ }
+ }
+ }
+
+ private static string CreateCore(string value, PatternOptions options)
+ {
+ if ((options & (PatternOptions.WholeLine | PatternOptions.WholeWord)) == (PatternOptions.WholeLine | PatternOptions.WholeWord))
+ {
+ throw new InvalidOperationException($"'{nameof(PatternOptions)}.{PatternOptions.WholeLine}' "
+ + $"and '{nameof(PatternOptions)}.{nameof(PatternOptions.WholeWord)}' cannot be set both at the same time.");
+ }
+
+ if ((options & PatternOptions.WholeLine) != 0)
+ {
+ value = @"(?:\A|(?<=\n))(?:" + value + @")(?:\z|(?=\r?\n))";
+ }
+ else if ((options & PatternOptions.WholeWord) != 0)
+ {
+ value = @"\b(?:" + value + @")\b";
+ }
+
+ if ((options & PatternOptions.Equals) == PatternOptions.Equals)
+ {
+ return @"\A(?:" + value + @")\z";
+ }
+ else if ((options & PatternOptions.StartsWith) != 0)
+ {
+ return @"\A(?:" + value + ")";
+ }
+ else if ((options & PatternOptions.EndsWith) != 0)
+ {
+ return "(?:" + value + @")\z";
+ }
+
+ return value;
+ }
+}
diff --git a/src/Common/PatternOptions.cs b/src/Common/PatternOptions.cs
new file mode 100644
index 00000000..16255cad
--- /dev/null
+++ b/src/Common/PatternOptions.cs
@@ -0,0 +1,17 @@
+// 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.
+
+using System;
+
+namespace Orang;
+
+[Flags]
+public enum PatternOptions
+{
+ None = 0,
+ Literal = 1,
+ StartsWith = 1 << 1,
+ EndsWith = 1 << 2,
+ WholeWord = 1 << 3,
+ WholeLine = 1 << 4,
+ Equals = StartsWith | EndsWith,
+}
diff --git a/src/Core/StringBuilderCache.cs b/src/Common/StringBuilderCache.cs
similarity index 100%
rename from src/Core/StringBuilderCache.cs
rename to src/Common/StringBuilderCache.cs
diff --git a/src/Core/Text/EncodingHelpers.cs b/src/Common/Text/EncodingHelpers.cs
similarity index 100%
rename from src/Core/Text/EncodingHelpers.cs
rename to src/Common/Text/EncodingHelpers.cs
diff --git a/src/Core/Text/RegularExpressions/CaptureItem.cs b/src/Common/Text/RegularExpressions/CaptureItem.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/CaptureItem.cs
rename to src/Common/Text/RegularExpressions/CaptureItem.cs
diff --git a/src/Core/Text/RegularExpressions/CaptureItemCollection.cs b/src/Common/Text/RegularExpressions/CaptureItemCollection.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/CaptureItemCollection.cs
rename to src/Common/Text/RegularExpressions/CaptureItemCollection.cs
diff --git a/src/Core/Text/RegularExpressions/CharEscapeMode.cs b/src/Common/Text/RegularExpressions/CharEscapeMode.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/CharEscapeMode.cs
rename to src/Common/Text/RegularExpressions/CharEscapeMode.cs
diff --git a/src/Core/Text/RegularExpressions/GroupDefinition.cs b/src/Common/Text/RegularExpressions/GroupDefinition.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/GroupDefinition.cs
rename to src/Common/Text/RegularExpressions/GroupDefinition.cs
diff --git a/src/Core/Text/RegularExpressions/GroupDefinitionCollection.cs b/src/Common/Text/RegularExpressions/GroupDefinitionCollection.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/GroupDefinitionCollection.cs
rename to src/Common/Text/RegularExpressions/GroupDefinitionCollection.cs
diff --git a/src/Core/Text/RegularExpressions/GroupDefinitionEqualityComparer.cs b/src/Common/Text/RegularExpressions/GroupDefinitionEqualityComparer.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/GroupDefinitionEqualityComparer.cs
rename to src/Common/Text/RegularExpressions/GroupDefinitionEqualityComparer.cs
diff --git a/src/Core/Text/RegularExpressions/GroupItem.cs b/src/Common/Text/RegularExpressions/GroupItem.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/GroupItem.cs
rename to src/Common/Text/RegularExpressions/GroupItem.cs
diff --git a/src/Core/Text/RegularExpressions/GroupItemCollection.cs b/src/Common/Text/RegularExpressions/GroupItemCollection.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/GroupItemCollection.cs
rename to src/Common/Text/RegularExpressions/GroupItemCollection.cs
diff --git a/src/Core/Text/RegularExpressions/MatchData.cs b/src/Common/Text/RegularExpressions/MatchData.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/MatchData.cs
rename to src/Common/Text/RegularExpressions/MatchData.cs
diff --git a/src/Core/Text/RegularExpressions/MatchItem.cs b/src/Common/Text/RegularExpressions/MatchItem.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/MatchItem.cs
rename to src/Common/Text/RegularExpressions/MatchItem.cs
diff --git a/src/Core/Text/RegularExpressions/MatchItemCollection.cs b/src/Common/Text/RegularExpressions/MatchItemCollection.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/MatchItemCollection.cs
rename to src/Common/Text/RegularExpressions/MatchItemCollection.cs
diff --git a/src/Core/Text/RegularExpressions/RegexCapture.cs b/src/Common/Text/RegularExpressions/RegexCapture.cs
similarity index 95%
rename from src/Core/Text/RegularExpressions/RegexCapture.cs
rename to src/Common/Text/RegularExpressions/RegexCapture.cs
index f37e5d31..2bd3439b 100644
--- a/src/Core/Text/RegularExpressions/RegexCapture.cs
+++ b/src/Common/Text/RegularExpressions/RegexCapture.cs
@@ -7,7 +7,7 @@
namespace Orang.Text.RegularExpressions;
[DebuggerDisplay("{DebuggerDisplay,nq}")]
-public class RegexCapture : ICapture
+internal class RegexCapture : ICapture
{
public RegexCapture(Capture capture)
{
diff --git a/src/Core/Text/RegularExpressions/RegexEscape.cs b/src/Common/Text/RegularExpressions/RegexEscape.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/RegexEscape.cs
rename to src/Common/Text/RegularExpressions/RegexEscape.cs
diff --git a/src/Core/Text/RegularExpressions/ReplaceData.cs b/src/Common/Text/RegularExpressions/ReplaceData.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/ReplaceData.cs
rename to src/Common/Text/RegularExpressions/ReplaceData.cs
diff --git a/src/Core/Text/RegularExpressions/ReplaceItem.cs b/src/Common/Text/RegularExpressions/ReplaceItem.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/ReplaceItem.cs
rename to src/Common/Text/RegularExpressions/ReplaceItem.cs
diff --git a/src/Core/Text/RegularExpressions/ReplaceItemCollection.cs b/src/Common/Text/RegularExpressions/ReplaceItemCollection.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/ReplaceItemCollection.cs
rename to src/Common/Text/RegularExpressions/ReplaceItemCollection.cs
diff --git a/src/Core/Text/RegularExpressions/SplitCapture.cs b/src/Common/Text/RegularExpressions/SplitCapture.cs
similarity index 95%
rename from src/Core/Text/RegularExpressions/SplitCapture.cs
rename to src/Common/Text/RegularExpressions/SplitCapture.cs
index d67c2e23..d3cb3ef3 100644
--- a/src/Core/Text/RegularExpressions/SplitCapture.cs
+++ b/src/Common/Text/RegularExpressions/SplitCapture.cs
@@ -7,7 +7,7 @@
namespace Orang.Text.RegularExpressions;
[DebuggerDisplay("{DebuggerDisplay,nq}")]
-public class SplitCapture : ICapture
+internal class SplitCapture : ICapture
{
public SplitCapture(string value, int index)
{
diff --git a/src/Core/Text/RegularExpressions/SplitData.cs b/src/Common/Text/RegularExpressions/SplitData.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/SplitData.cs
rename to src/Common/Text/RegularExpressions/SplitData.cs
diff --git a/src/Core/Text/RegularExpressions/SplitItem.cs b/src/Common/Text/RegularExpressions/SplitItem.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/SplitItem.cs
rename to src/Common/Text/RegularExpressions/SplitItem.cs
diff --git a/src/Core/Text/RegularExpressions/SplitItemCollection.cs b/src/Common/Text/RegularExpressions/SplitItemCollection.cs
similarity index 100%
rename from src/Core/Text/RegularExpressions/SplitItemCollection.cs
rename to src/Common/Text/RegularExpressions/SplitItemCollection.cs
diff --git a/src/Core/TextHelpers.cs b/src/Common/TextHelpers.cs
similarity index 100%
rename from src/Core/TextHelpers.cs
rename to src/Common/TextHelpers.cs
diff --git a/src/Common/docs/NuGetReadme.md b/src/Common/docs/NuGetReadme.md
new file mode 100644
index 00000000..e7cd03f4
--- /dev/null
+++ b/src/Common/docs/NuGetReadme.md
@@ -0,0 +1,3 @@
+# Orang.Common
+
+A shared package used by Orang. Do not install this package manually, it will be added as a prerequisite by other packages that require it.
diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj
deleted file mode 100644
index c6e02386..00000000
--- a/src/Core/Core.csproj
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- netstandard2.1
- Orang.Core
- Orang
- false
-
-
-
diff --git a/src/Core/Properties/AssemblyInfo.cs b/src/Core/Properties/AssemblyInfo.cs
deleted file mode 100644
index eb0153d3..00000000
--- a/src/Core/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-// 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.
-
-using System.Runtime.CompilerServices;
-
-#pragma warning disable RCS0056
-
-[assembly: InternalsVisibleTo("Orang, PublicKey=00240000048000009400000006020000002400005253413100040000010001009ff202171ab25d708192b490c52c1a373c74a2849c734fd9f545bfedc92b61d4e10d356cd26213ef6d96af669a9b570cd6277d590c338cfc00ccc9a15d6ad5b08ac3a8a09db3eae536d653f4acb9c7e992162129b67b4bc72c08af7d67a48ecde99c53a5d2cd44b1e8179368f6db2ec7665061e3ef4029703df4b49952bd0de4")]
-[assembly: InternalsVisibleTo("Orang.CommandLine.Core, PublicKey=00240000048000009400000006020000002400005253413100040000010001009ff202171ab25d708192b490c52c1a373c74a2849c734fd9f545bfedc92b61d4e10d356cd26213ef6d96af669a9b570cd6277d590c338cfc00ccc9a15d6ad5b08ac3a8a09db3eae536d653f4acb9c7e992162129b67b4bc72c08af7d67a48ecde99c53a5d2cd44b1e8179368f6db2ec7665061e3ef4029703df4b49952bd0de4")]
-[assembly: InternalsVisibleTo("Orang.FileSystem, PublicKey=00240000048000009400000006020000002400005253413100040000010001009ff202171ab25d708192b490c52c1a373c74a2849c734fd9f545bfedc92b61d4e10d356cd26213ef6d96af669a9b570cd6277d590c338cfc00ccc9a15d6ad5b08ac3a8a09db3eae536d653f4acb9c7e992162129b67b4bc72c08af7d67a48ecde99c53a5d2cd44b1e8179368f6db2ec7665061e3ef4029703df4b49952bd0de4")]
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 95eb4404..5ac0e0c7 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -5,8 +5,35 @@
true
$(MSBuildThisFileDirectory)Orang.snk
Josef Pihrt
- Copyright (c) 2019-2022 Josef Pihrt
+ Copyright (c) 2019-2023 Josef Pihrt
+ 00240000048000009400000006020000002400005253413100040000010001009ff202171ab25d708192b490c52c1a373c74a2849c734fd9f545bfedc92b61d4e10d356cd26213ef6d96af669a9b570cd6277d590c338cfc00ccc9a15d6ad5b08ac3a8a09db3eae536d653f4acb9c7e992162129b67b4bc72c08af7d67a48ecde99c53a5d2cd44b1e8179368f6db2ec7665061e3ef4029703df4b49952bd0de4
enable
+
+ 1.0.0
+ false
+ Search, replace, rename and delete directories, files and its content using the power of .NET regular expressions.
+ https://github.com/JosefPihrt/Orang
+ Apache-2.0
+ icon.png
+ FileSystem;RegularExpression;Regex;RegExp
+ docs/README.md
+ https://github.com/JosefPihrt/Orang.git
+ git
+ false
+
+
+
+ true
+ true
+ true
+ true
+ snupkg
+
+
+
+
+
+
diff --git a/src/DocumentationGenerator/DocumentationGenerator.csproj b/src/DocumentationGenerator/DocumentationGenerator.csproj
index f3a24e3c..30480c46 100644
--- a/src/DocumentationGenerator/DocumentationGenerator.csproj
+++ b/src/DocumentationGenerator/DocumentationGenerator.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/DocumentationGenerator/DocumentationWriter.cs b/src/DocumentationGenerator/DocumentationWriter.cs
index 1b16b4ea..9692b054 100644
--- a/src/DocumentationGenerator/DocumentationWriter.cs
+++ b/src/DocumentationGenerator/DocumentationWriter.cs
@@ -36,7 +36,7 @@ public override void WriteOptionDescription(CommandOption option)
string metaValueUrl = provider2.Name;
- _writer.WriteLink(provider2.Name, "../option-values" + MarkdownHelpers.CreateGitHubHeadingLink(metaValueUrl));
+ _writer.WriteLink(provider2.Name, "../options-values" + MarkdownHelpers.CreateGitHubHeadingLink(metaValueUrl));
_writer.WriteString(": ");
@@ -60,7 +60,7 @@ public override void WriteOptionDescription(CommandOption option)
_writer.WriteInlineCode(value.Remove(metaValueMatch.Index));
_writer.WriteLink(
metaValueMatch.Value,
- "../option-values" + MarkdownHelpers.CreateGitHubHeadingLink(metaValueMatch.Value));
+ "../options-values" + MarkdownHelpers.CreateGitHubHeadingLink(metaValueMatch.Value));
}
else
{
diff --git a/src/DocumentationGenerator/Program.cs b/src/DocumentationGenerator/Program.cs
index bf6864c7..1f6b26f9 100644
--- a/src/DocumentationGenerator/Program.cs
+++ b/src/DocumentationGenerator/Program.cs
@@ -9,6 +9,7 @@
using System.Text;
using System.Text.RegularExpressions;
using DotMarkdown;
+using DotMarkdown.Docusaurus;
using DotMarkdown.Linq;
using Orang.CommandLine;
using Orang.CommandLine.Annotations;
@@ -60,7 +61,8 @@ private static void Main(params string[] args)
var settings = new MarkdownWriterSettings(markdownFormat);
using (var sw = new StreamWriter(filePath, append: false, Encoding.UTF8))
- using (MarkdownWriter mw = MarkdownWriter.Create(sw, settings))
+ using (MarkdownWriter mw2 = MarkdownWriter.Create(sw, settings))
+ using (var mw = new DocusaurusMarkdownWriter(mw2))
{
WriteFrontMatter(mw, 0, "Orang CLI");
@@ -95,6 +97,8 @@ private static void Main(params string[] args)
GenerateOptionValues(commands, destinationDirectoryPath, settings);
+ GenerateExpressionSyntax(destinationDirectoryPath, settings);
+
foreach (Command command in application.Commands)
{
filePath = Path.GetFullPath(Path.Combine(destinationDirectoryPath, "cli/commands", $"{command.Name}.md"));
@@ -102,16 +106,12 @@ private static void Main(params string[] args)
Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
using (var sw = new StreamWriter(filePath, append: false, Encoding.UTF8))
- using (MarkdownWriter mw = MarkdownWriter.Create(sw, settings))
+ using (MarkdownWriter mw2 = MarkdownWriter.Create(sw, settings))
+ using (var mw = new DocusaurusMarkdownWriter(mw2))
{
var writer = new DocumentationWriter(mw);
- mw.WriteRaw("---");
- mw.WriteLine();
- mw.WriteRaw($"sidebar_label: {command.DisplayName}");
- mw.WriteLine();
- mw.WriteRaw("---");
- mw.WriteLine();
+ WriteFrontMatter(mw, label: command.DisplayName);
writer.WriteCommandHeading(command, application);
writer.WriteCommandDescription(command);
@@ -142,7 +142,8 @@ private static void GenerateCommands(IEnumerable commands, string desti
Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
using (var sw = new StreamWriter(filePath, append: false, Encoding.UTF8))
- using (MarkdownWriter mw = MarkdownWriter.Create(sw, settings))
+ using (MarkdownWriter mw2 = MarkdownWriter.Create(sw, settings))
+ using (var mw = new DocusaurusMarkdownWriter(mw2))
{
WriteFrontMatter(mw, 0, "Commands");
@@ -164,7 +165,7 @@ private static void GenerateOptionValues(
string destinationDirectoryPath,
MarkdownWriterSettings settings)
{
- string filePath = Path.GetFullPath(Path.Combine(destinationDirectoryPath, "cli/option-values.md"));
+ string filePath = Path.GetFullPath(Path.Combine(destinationDirectoryPath, "cli/options-values.md"));
ImmutableArray providers = OptionValueProvider.GetProviders(
commands.SelectMany(f => f.Options),
@@ -184,8 +185,19 @@ private static void GenerateOptionValues(
};
}));
- document.Add(
- Heading2("Expression Syntax"),
+ AddFootnote(document);
+
+ File.WriteAllText(filePath, document.ToString(settings));
+ }
+
+ private static void GenerateExpressionSyntax(
+ string destinationDirectoryPath,
+ MarkdownWriterSettings settings)
+ {
+ string filePath = Path.GetFullPath(Path.Combine(destinationDirectoryPath, "cli/expression-syntax.md"));
+
+ MDocument document = Document(
+ Heading1("Expression Syntax"),
Table(
TableRow("Expression", "Description"),
HelpProvider.GetExpressionItems(includeDate: true)
@@ -235,7 +247,7 @@ private static MTableRow CreateTableRow(
string description = _removeNewlineRegex.Replace(optionValue.Description ?? "", " ");
return TableRow(
- value,
+ value!,
(string.IsNullOrEmpty(shortValue)) ? " " : shortValue,
(string.IsNullOrEmpty(description)) ? " " : description);
}
@@ -250,27 +262,20 @@ private static void AddFootnote(MDocument document)
}
#pragma warning restore IDE0060, RCS1163
- private static void WriteFrontMatter(MarkdownWriter mw, int? position = null, string? label = null)
+ private static void WriteFrontMatter(DocusaurusMarkdownWriter mw, int? position = null, string? label = null)
{
if (position is not null
|| label is not null)
{
- mw.WriteRaw("---");
- mw.WriteLine();
+ var items = new List<(string, object)>();
+
if (position is not null)
- {
- mw.WriteRaw($"sidebar_position: {position}");
- mw.WriteLine();
- }
+ items.Add(("sidebar_position", position));
if (label is not null)
- {
- mw.WriteRaw($"sidebar_label: {label}");
- mw.WriteLine();
- }
+ items.Add(("sidebar_label", label));
- mw.WriteRaw("---");
- mw.WriteLine();
+ mw.WriteDocusaurusFrontMatter(items);
}
}
}
diff --git a/src/DocumentationGenerator/Properties/launchSettings.json b/src/DocumentationGenerator/Properties/launchSettings.json
index b063935d..f6bf92b4 100644
--- a/src/DocumentationGenerator/Properties/launchSettings.json
+++ b/src/DocumentationGenerator/Properties/launchSettings.json
@@ -2,7 +2,7 @@
"profiles": {
"DocumentationGenerator": {
"commandName": "Project",
- "commandLineArgs": "\"../../../../../docs/cli\" \"../../../data\""
+ "commandLineArgs": "\"../../../../../tools/build\" \"../../../data\""
}
}
}
\ No newline at end of file
diff --git a/src/DocumentationGenerator/data/readme_bottom.md b/src/DocumentationGenerator/data/readme_bottom.md
index a0d55e3f..6403983f 100644
--- a/src/DocumentationGenerator/data/readme_bottom.md
+++ b/src/DocumentationGenerator/data/readme_bottom.md
@@ -30,30 +30,17 @@ a user cannot specify argument (usually path(s)) as a last value of a command
if the argument is preceded with multi-value parameter.
Following command is invalid because path `C:/Documents` is treated as a value of multi-value parameter `-c | --content`.
-```
+```sh
orang find -c "^abc" i m "C:/Documents"
```
To fix this problem you can either add parameter `--paths`
-```
+```sh
orang find -c "abc" i m --paths "C:/Documents"
```
or you can specify path right after the command name:
-```
+```sh
orang find "C:/Documents" -c "abc" i m
```
-
-## Links
-
-* [List of Option Values](cli/option-values)
-* [How to's](cli/how-to)
-
-## External Links
-
-* [.NET Core Global Tools Overview](https://docs.microsoft.com/dotnet/core/tools/global-tools)
-* [Create a .NET Core Global Tool Using the .NET Core CLI](https://docs.microsoft.com/dotnet/core/tools/global-tools-how-to-create)
-* [.NET Core 2.1 Global Tools](https://natemcmaster.com/blog/2018/05/12/dotnet-global-tools/)
-* [Windows CMD Shell](https://ss64.com/nt/syntax.html)
-* [Parsing C++ Command-Line Arguments](https://docs.microsoft.com/cpp/cpp/parsing-cpp-command-line-arguments?view=vs-2019)
diff --git a/src/FileSystem.ApiTest/Class.cs b/src/FileSystem.ApiTest/Class.cs
deleted file mode 100644
index ae528790..00000000
--- a/src/FileSystem.ApiTest/Class.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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.
-
-using System.Text.RegularExpressions;
-using Orang;
-using Orang.FileSystem;
-
-namespace N;
-
-public class C
-{
- public void M()
- {
- var regex = new Regex("pattern", RegexOptions.IgnoreCase);
-
- var name = new Filter(regex);
-
- var filter = new FileSystemFilter(name);
-
- var searchOptions = new FileSystemSearchOptions(recurseSubdirectories: false);
-
- var search = new FileSystemSearch(filter, options: searchOptions);
-
- search.Replace("directoryPath", ReplaceOptions.Empty);
- }
-
- public void M2()
- {
- var name = new Filter("pattern", RegexOptions.IgnoreCase);
-
- _ = new FileSystemFilter(name);
-
- //FileSystemSearch.Replace("directoryPath", filter, recurseSubdirectories: false);
- }
-
- public static void SM()
- {
- }
-}
diff --git a/src/FileSystem.ApiTest/FileSystem.ApiTest.csproj b/src/FileSystem.ApiTest/FileSystem.ApiTest.csproj
index ee89899b..b89c11a0 100644
--- a/src/FileSystem.ApiTest/FileSystem.ApiTest.csproj
+++ b/src/FileSystem.ApiTest/FileSystem.ApiTest.csproj
@@ -1,15 +1,15 @@
- netstandard2.1
+ netcoreapp3.1
+ Exe
Orang.FileSystem.ApiTest
Orang.FileSystem
- false
false
-
+
diff --git a/src/FileSystem.ApiTest/Program.cs b/src/FileSystem.ApiTest/Program.cs
new file mode 100644
index 00000000..20267d14
--- /dev/null
+++ b/src/FileSystem.ApiTest/Program.cs
@@ -0,0 +1,56 @@
+// 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.
+
+using System;
+using System.Threading;
+using Orang;
+using Orang.FileSystem;
+using Orang.FileSystem.Fluent;
+
+namespace N;
+
+public static class Program
+{
+ public static void Main()
+ {
+ const string directoryPath = "";
+
+ IOperationResult result = new SearchBuilder()
+ .MatchDirectory(d => d
+ .Name(Pattern.Any("bin", "obj", PatternOptions.Equals | PatternOptions.WholeWord | PatternOptions.WholeLine))
+ .NonEmpty())
+ .SkipDirectory(Pattern.Any(".git", ".vs", PatternOptions.Equals | PatternOptions.Literal))
+ .Delete(d => d
+ .ContentOnly()
+ .DryRun()
+ .LogOperation(o => Console.WriteLine(o.Path)))
+ .Run(directoryPath, CancellationToken.None);
+
+ Console.WriteLine(result.Telemetry.MatchingDirectoryCount);
+
+ var search = new Search(
+ new DirectoryMatcher()
+ {
+ Name = new Matcher(@"\A(bin|obj)\z"),
+ EmptyOption = FileEmptyOption.NonEmpty,
+ },
+ new SearchOptions()
+ {
+ SearchDirectory = new DirectoryMatcher()
+ {
+ Name = new Matcher(@"\A(\.git|\.vs)\z", invert: true)
+ }
+ });
+
+ result = search.Delete(
+ directoryPath,
+ new DeleteOptions()
+ {
+ ContentOnly = true,
+ DryRun = true,
+ LogOperation = o => Console.WriteLine(o.Path),
+ },
+ CancellationToken.None);
+
+ Console.WriteLine(result.Telemetry.MatchingDirectoryCount);
+ }
+}
diff --git a/src/FileSystem/DirectoryPredicate.cs b/src/FileSystem/DirectoryPredicate.cs
new file mode 100644
index 00000000..cf82756b
--- /dev/null
+++ b/src/FileSystem/DirectoryPredicate.cs
@@ -0,0 +1,75 @@
+// 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.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
+using Orang.FileSystem;
+using Orang.Text.RegularExpressions;
+
+namespace Orang;
+
+internal static class DirectoryPredicate
+{
+ public static Func Create(Matcher matcher, FileNamePart part = FileNamePart.FullName)
+ {
+ return path => (matcher.Invert) ? !IsMatch(matcher, part, path) : IsMatch(matcher, part, path);
+ }
+
+ public static Func Create(string path, FileNamePart part = FileNamePart.FullName)
+ {
+ Matcher matcher = CreateFilter(path);
+
+ return path => IsMatch(matcher, part, path);
+ }
+
+ public static Func Create(Func? predicate, string path)
+ {
+ Matcher directoryFilter = CreateFilter(path);
+
+ if (predicate is not null)
+ {
+ return path =>
+ {
+ return predicate(path)
+ && IsMatch(directoryFilter, FileNamePart.FullName, path);
+ };
+ }
+ else
+ {
+ return path => IsMatch(directoryFilter, FileNamePart.FullName, path);
+ }
+ }
+
+ private static Matcher CreateFilter(string path)
+ {
+ string pattern = RegexEscape.Escape(path);
+
+ var options = RegexOptions.ExplicitCapture;
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ pattern = Regex.Replace(pattern, @"(/|\\\\)", @"(/|\\)", options);
+
+ pattern = $@"\A{pattern}(?=(/";
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ pattern += @"|\\)";
+ }
+ else
+ {
+ pattern += ")";
+ }
+
+ pattern += @"|\z)";
+
+ if (!FileSystemUtilities.IsCaseSensitive)
+ options |= RegexOptions.IgnoreCase;
+
+ return new Matcher(pattern, options);
+ }
+
+ private static bool IsMatch(Matcher matcher, FileNamePart part, string path)
+ {
+ return matcher.IsDirectoryMatch(path, part);
+ }
+}
diff --git a/src/FileSystem/Extensions.cs b/src/FileSystem/Extensions.cs
new file mode 100644
index 00000000..9ec11bdc
--- /dev/null
+++ b/src/FileSystem/Extensions.cs
@@ -0,0 +1,24 @@
+// 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.
+
+using System.Text.RegularExpressions;
+using Orang.FileSystem;
+
+namespace Orang;
+
+internal static class Extensions
+{
+ public static Match? Match(this Matcher matcher, FileNameSpan name)
+ {
+ return matcher.Match(matcher.Regex.Match(name.Path, name.Start, name.Length));
+ }
+
+ public static bool IsMatch(this Matcher matcher, FileNameSpan name)
+ {
+ return Match(matcher, name) is not null;
+ }
+
+ internal static bool IsDirectoryMatch(this Matcher matcher, string path, FileNamePart part)
+ {
+ return IsMatch(matcher, FileNameSpan.FromDirectory(path, part));
+ }
+}
diff --git a/src/FileSystem/FileSystem.csproj b/src/FileSystem/FileSystem.csproj
index 9967aa0b..c4dab376 100644
--- a/src/FileSystem/FileSystem.csproj
+++ b/src/FileSystem/FileSystem.csproj
@@ -1,26 +1,23 @@
-
+
netstandard2.1
Orang.FileSystem
- Orang.FileSystem
+ Orang
+ true
Orang.FileSystem
- 0.3.1
- Search, replace, rename and delete directories, files and its content using the power of .NET regular expressions.
- https://github.com/JosefPihrt/Orang
- Apache-2.0
- icon.png
- FileSystem;RegularExpression;Regex;RegExp
- https://github.com/JosefPihrt/Orang.git
- git
- false
+
+
+
+ true
+
@@ -28,7 +25,13 @@
-
+
+
+
+
+
+ <_Parameter1>Orang, PublicKey=$(OrangPublicKey)
+
diff --git a/src/FileSystem/FileSystem/Commands/Command.cs b/src/FileSystem/FileSystem/Commands/Command.cs
new file mode 100644
index 00000000..32100b37
--- /dev/null
+++ b/src/FileSystem/FileSystem/Commands/Command.cs
@@ -0,0 +1,79 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Threading;
+
+namespace Orang.FileSystem.Commands;
+
+internal abstract class Command
+{
+ protected Command()
+ {
+ Telemetry = new SearchTelemetry();
+ }
+
+ public abstract OperationKind OperationKind { get; }
+
+ public SearchTelemetry Telemetry { get; }
+
+ public TerminationReason TerminationReason { get; set; }
+
+ public int MaxMatchingFiles { get; set; }
+
+ public Action? LogOperation { get; set; }
+
+ public bool DryRun { get; set; }
+
+ public CancellationToken CancellationToken { get; set; }
+
+ protected abstract void ExecuteMatch(FileMatch fileMatch, string directoryPath);
+
+ protected virtual void OnSearchStateCreating(SearchState search)
+ {
+ }
+
+ public void Execute(string directoryPath, Search search, CancellationToken cancellationToken)
+ {
+ directoryPath = FileSystemUtilities.EnsureFullPath(directoryPath);
+
+ if (!System.IO.Directory.Exists(directoryPath))
+ throw new DirectoryNotFoundException($"Directory not found: {directoryPath}");
+
+ var state = new SearchState(search.FileMatcher, search.DirectoryMatcher)
+ {
+ IncludeDirectory = search.Options.IncludeDirectoryPredicate,
+ ExcludeDirectory = search.Options.ExcludeDirectoryPredicate,
+ LogProgress = search.Options.LogProgress,
+ RecurseSubdirectories = !search.Options.TopDirectoryOnly,
+ DefaultEncoding = search.Options.DefaultEncoding,
+ IgnoreInaccessible = search.Options.IgnoreInaccessible,
+ Telemetry = Telemetry,
+ };
+
+ OnSearchStateCreating(state);
+
+ foreach (FileMatch fileMatch in state.Find(directoryPath, this as INotifyDirectoryChanged, cancellationToken))
+ {
+ Telemetry.IncrementMatchingCount(fileMatch.IsDirectory);
+
+ ExecuteMatch(fileMatch, directoryPath);
+
+ if (MaxMatchingFiles == Telemetry.MatchingFileDirectoryCount)
+ {
+ TerminationReason = TerminationReason.MaxReached;
+ break;
+ }
+ }
+ }
+
+ protected void Log(FileMatch fileMatch, Exception? exception = null)
+ {
+ Log(fileMatch, newPath: null, exception);
+ }
+
+ protected void Log(FileMatch fileMatch, string? newPath, Exception? exception = null)
+ {
+ LogOperation?.Invoke(new OperationProgress(fileMatch, newPath, OperationKind, exception));
+ }
+}
diff --git a/src/FileSystem/FileSystem/Commands/CommonCopyCommand.cs b/src/FileSystem/FileSystem/Commands/CommonCopyCommand.cs
new file mode 100644
index 00000000..50f805b4
--- /dev/null
+++ b/src/FileSystem/FileSystem/Commands/CommonCopyCommand.cs
@@ -0,0 +1,299 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+
+namespace Orang.FileSystem.Commands;
+
+internal abstract class CommonCopyCommand : CommonFindCommand
+{
+ protected CommonCopyCommand()
+ {
+ }
+
+ public string DestinationPath { get; set; } = null!;
+
+ public IDialogProvider? DialogProvider { get; set; }
+
+ public CopyOptions CopyOptions { get; set; } = null!;
+
+ public ConflictResolution ConflictResolution { get; set; }
+
+ protected override void OnSearchStateCreating(SearchState search)
+ {
+ search.ExcludeDirectory = DirectoryPredicate.Create(search.ExcludeDirectory, DestinationPath);
+ }
+
+ protected abstract void ExecuteOperation(string sourcePath, string destinationPath);
+
+ protected override void ExecuteMatch(
+ FileMatch fileMatch,
+ string directoryPath)
+ {
+ string sourcePath = fileMatch.Path;
+ string destinationPath;
+
+ if (fileMatch.IsDirectory
+ || (directoryPath is not null && !CopyOptions.Flat))
+ {
+ Debug.Assert(sourcePath.StartsWith(directoryPath, FileSystemUtilities.Comparison));
+
+ string relativePath = sourcePath.Substring(directoryPath.Length + 1);
+
+ destinationPath = Path.Combine(DestinationPath, relativePath);
+ }
+ else
+ {
+ string fileName = Path.GetFileName(sourcePath);
+
+ destinationPath = Path.Combine(DestinationPath, fileName);
+ }
+
+ try
+ {
+ ExecuteOperation(fileMatch, fileMatch.Path, destinationPath, fileMatch.IsDirectory);
+ }
+ catch (Exception ex) when (ex is IOException
+ || ex is UnauthorizedAccessException)
+ {
+ Log(fileMatch, destinationPath, ex);
+ }
+ }
+
+ private DialogResult? ExecuteOperation(FileMatch? fileMatch, string sourcePath, string destinationPath, bool isDirectory)
+ {
+ bool fileExists = File.Exists(destinationPath);
+ bool directoryExists = !fileExists && Directory.Exists(destinationPath);
+ var ask = false;
+
+ if (isDirectory)
+ {
+ if (fileExists)
+ {
+ ask = true;
+ }
+ else if (directoryExists)
+ {
+ if (CopyOptions.StructureOnly
+ && File.GetAttributes(sourcePath) == File.GetAttributes(destinationPath))
+ {
+ return null;
+ }
+
+ if (CopyOptions.CompareDirectory?.Invoke(sourcePath, destinationPath) != false)
+ return null;
+ }
+ }
+ else if (fileExists)
+ {
+ if (CopyOptions.ComparedProperties != FileCompareProperties.None
+ && FileSystemUtilities.FileEquals(
+ sourcePath,
+ destinationPath,
+ CopyOptions.ComparedProperties,
+ CopyOptions.ComparedAttributes,
+ CopyOptions.AllowedTimeDiff))
+ {
+ return null;
+ }
+
+ if (CopyOptions.CompareFile?.Invoke(sourcePath, destinationPath) != false)
+ return null;
+
+ ask = true;
+ }
+ else if (directoryExists)
+ {
+ ask = true;
+ }
+
+ if (ask
+ && ConflictResolution == ConflictResolution.Skip)
+ {
+ return null;
+ }
+
+ if (ConflictResolution == ConflictResolution.Suffix
+ && ((isDirectory && directoryExists)
+ || (!isDirectory && fileExists)))
+ {
+ destinationPath = FileSystemUtilities.CreateNewFilePath(destinationPath);
+ }
+
+ if (ask
+ && ConflictResolution == ConflictResolution.Ask)
+ {
+ DialogResult dialogResult = DialogProvider!.GetResult(
+ new ConflictInfo(sourcePath, destinationPath));
+
+ switch (dialogResult)
+ {
+ case DialogResult.Yes:
+ {
+ break;
+ }
+ case DialogResult.YesToAll:
+ {
+ ConflictResolution = ConflictResolution.Overwrite;
+ break;
+ }
+ case DialogResult.No:
+ case DialogResult.None:
+ {
+ return null;
+ }
+ case DialogResult.NoToAll:
+ {
+ ConflictResolution = ConflictResolution.Skip;
+ return DialogResult.NoToAll;
+ }
+ case DialogResult.Cancel:
+ {
+ throw new OperationCanceledException();
+ }
+ default:
+ {
+ throw new InvalidOperationException($"Unknown enum value '{dialogResult}'.");
+ }
+ }
+ }
+
+ if (fileMatch is not null)
+ Log(fileMatch, destinationPath);
+
+ if (isDirectory)
+ {
+ if (directoryExists)
+ {
+ if (!DryRun)
+ {
+ if (CopyOptions.StructureOnly)
+ {
+ FileSystemUtilities.UpdateAttributes(sourcePath, destinationPath);
+ }
+ else
+ {
+ CopyDirectory(sourcePath, destinationPath);
+ }
+ }
+ }
+ else
+ {
+ if (fileExists
+ && !DryRun)
+ {
+ File.Delete(destinationPath);
+ }
+
+ if (!DryRun)
+ {
+ if (CopyOptions.StructureOnly)
+ {
+ Directory.CreateDirectory(destinationPath);
+ }
+ else
+ {
+ CopyDirectory(sourcePath, destinationPath);
+ }
+ }
+ }
+
+ Telemetry.ProcessedDirectoryCount++;
+ }
+ else
+ {
+ if (!DryRun)
+ {
+ if (fileExists)
+ {
+ File.Delete(destinationPath);
+ }
+ else if (directoryExists)
+ {
+ Directory.Delete(destinationPath, recursive: true);
+ }
+ else
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
+ }
+
+ ExecuteOperation(sourcePath, destinationPath);
+ }
+
+ Telemetry.ProcessedFileCount++;
+ }
+
+ return null;
+ }
+
+ private void CopyDirectory(
+ string sourcePath,
+ string destinationPath)
+ {
+ var directories = new Stack<(string, string)>();
+
+ directories.Push((sourcePath, destinationPath));
+
+ CopyDirectory(directories);
+ }
+
+ private void CopyDirectory(Stack<(string, string)> directories)
+ {
+ while (directories.Count > 0)
+ {
+ (string sourcePath, string destinationPath) = directories.Pop();
+
+ var isEmpty = true;
+
+ using (IEnumerator en = Directory.EnumerateFiles(sourcePath).GetEnumerator())
+ {
+ if (en.MoveNext())
+ {
+ isEmpty = false;
+
+ do
+ {
+ string newFilePath = Path.Combine(destinationPath, Path.GetFileName(en.Current));
+
+ DialogResult? result = ExecuteOperation(
+ null,
+ en.Current,
+ newFilePath,
+ isDirectory: false);
+
+ if (result == DialogResult.NoToAll
+ || result == DialogResult.Cancel)
+ {
+ return;
+ }
+ }
+ while (en.MoveNext());
+ }
+ }
+
+ using (IEnumerator en = Directory.EnumerateDirectories(sourcePath).GetEnumerator())
+ {
+ if (en.MoveNext())
+ {
+ isEmpty = false;
+
+ do
+ {
+ string newDirectoryPath = Path.Combine(destinationPath, Path.GetFileName(en.Current));
+
+ directories.Push((en.Current, newDirectoryPath));
+ }
+ while (en.MoveNext());
+ }
+ }
+
+ if (isEmpty
+ && !DryRun)
+ {
+ Directory.CreateDirectory(destinationPath);
+ }
+ }
+ }
+}
diff --git a/src/FileSystem/Operations/CommonFindOperation.cs b/src/FileSystem/FileSystem/Commands/CommonFindCommand.cs
similarity index 89%
rename from src/FileSystem/Operations/CommonFindOperation.cs
rename to src/FileSystem/FileSystem/Commands/CommonFindCommand.cs
index 906d79d8..cb7ecef2 100644
--- a/src/FileSystem/Operations/CommonFindOperation.cs
+++ b/src/FileSystem/FileSystem/Commands/CommonFindCommand.cs
@@ -5,11 +5,11 @@
using System.Diagnostics;
using System.Text.RegularExpressions;
-namespace Orang.Operations;
+namespace Orang.FileSystem.Commands;
-internal abstract class CommonFindOperation : FileSystemOperation
+internal abstract class CommonFindCommand : Command
{
- protected CommonFindOperation()
+ protected CommonFindCommand()
{
}
@@ -60,7 +60,7 @@ protected MaxReason GetCaptures(
&& maxTotalMatches > 0
&& (maxMatchesInFile == 0 || maxTotalMatches <= maxMatchesInFile))
{
- TerminationReason = FileSystem.TerminationReason.MaxReached;
+ TerminationReason = TerminationReason.MaxReached;
}
return maxReason;
diff --git a/src/FileSystem/Operations/CopyOperation.cs b/src/FileSystem/FileSystem/Commands/CopyCommand.cs
similarity index 79%
rename from src/FileSystem/Operations/CopyOperation.cs
rename to src/FileSystem/FileSystem/Commands/CopyCommand.cs
index f0a6e3d6..48c6b1fc 100644
--- a/src/FileSystem/Operations/CopyOperation.cs
+++ b/src/FileSystem/FileSystem/Commands/CopyCommand.cs
@@ -1,11 +1,10 @@
// 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.
using System.IO;
-using Orang.FileSystem;
-namespace Orang.Operations;
+namespace Orang.FileSystem.Commands;
-internal class CopyOperation : CommonCopyOperation
+internal class CopyCommand : CommonCopyCommand
{
public override OperationKind OperationKind => OperationKind.Copy;
diff --git a/src/FileSystem/Operations/DeleteOperation.cs b/src/FileSystem/FileSystem/Commands/DeleteCommand.cs
similarity index 76%
rename from src/FileSystem/Operations/DeleteOperation.cs
rename to src/FileSystem/FileSystem/Commands/DeleteCommand.cs
index 160a7d90..305fede6 100644
--- a/src/FileSystem/Operations/DeleteOperation.cs
+++ b/src/FileSystem/FileSystem/Commands/DeleteCommand.cs
@@ -2,15 +2,19 @@
using System;
using System.IO;
-using Orang.FileSystem;
-namespace Orang.Operations;
+namespace Orang.FileSystem.Commands;
-internal class DeleteOperation : DeleteOrRenameOperation
+internal class DeleteCommand : DeleteOrRenameCommand
{
+ public DeleteOptions DeleteOptions { get; set; } = null!;
+
public override OperationKind OperationKind => OperationKind.Delete;
- public DeleteOptions DeleteOptions { get; set; } = null!;
+ protected override void OnSearchStateCreating(SearchState search)
+ {
+ search.CanRecurseMatch = false;
+ }
protected override void ExecuteMatch(
FileMatch fileMatch,
@@ -20,7 +24,7 @@ protected override void ExecuteMatch(
{
if (!DryRun)
{
- FileSystemHelpers.Delete(
+ FileSystemUtilities.Delete(
fileMatch,
contentOnly: DeleteOptions.ContentOnly,
includingBom: DeleteOptions.IncludingBom,
@@ -28,14 +32,14 @@ protected override void ExecuteMatch(
directoriesOnly: DeleteOptions.DirectoriesOnly);
}
- Report(fileMatch);
+ Log(fileMatch);
Telemetry.IncrementProcessedCount(fileMatch.IsDirectory);
}
catch (Exception ex) when (ex is IOException
|| ex is UnauthorizedAccessException)
{
- Report(fileMatch, ex);
+ Log(fileMatch, ex);
}
}
}
diff --git a/src/FileSystem/Operations/DeleteOrRenameOperation.cs b/src/FileSystem/FileSystem/Commands/DeleteOrRenameCommand.cs
similarity index 68%
rename from src/FileSystem/Operations/DeleteOrRenameOperation.cs
rename to src/FileSystem/FileSystem/Commands/DeleteOrRenameCommand.cs
index 2d193780..70aa76b0 100644
--- a/src/FileSystem/Operations/DeleteOrRenameOperation.cs
+++ b/src/FileSystem/FileSystem/Commands/DeleteOrRenameCommand.cs
@@ -1,13 +1,12 @@
// 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.
using System;
-using Orang.FileSystem;
-namespace Orang.Operations;
+namespace Orang.FileSystem.Commands;
-internal abstract class DeleteOrRenameOperation : FileSystemOperation, INotifyDirectoryChanged
+internal abstract class DeleteOrRenameCommand : Command, INotifyDirectoryChanged
{
- protected DeleteOrRenameOperation()
+ protected DeleteOrRenameCommand()
{
}
diff --git a/src/FileSystem/Operations/MoveOperation.cs b/src/FileSystem/FileSystem/Commands/MoveCommand.cs
similarity index 79%
rename from src/FileSystem/Operations/MoveOperation.cs
rename to src/FileSystem/FileSystem/Commands/MoveCommand.cs
index c1588552..f180400d 100644
--- a/src/FileSystem/Operations/MoveOperation.cs
+++ b/src/FileSystem/FileSystem/Commands/MoveCommand.cs
@@ -1,11 +1,10 @@
// 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.
using System.IO;
-using Orang.FileSystem;
-namespace Orang.Operations;
+namespace Orang.FileSystem.Commands;
-internal class MoveOperation : CommonCopyOperation
+internal class MoveCommand : CommonCopyCommand
{
public override OperationKind OperationKind => OperationKind.Move;
diff --git a/src/FileSystem/Operations/RenameOperation.cs b/src/FileSystem/FileSystem/Commands/RenameCommand.cs
similarity index 55%
rename from src/FileSystem/Operations/RenameOperation.cs
rename to src/FileSystem/FileSystem/Commands/RenameCommand.cs
index 65446752..2f4534f2 100644
--- a/src/FileSystem/Operations/RenameOperation.cs
+++ b/src/FileSystem/FileSystem/Commands/RenameCommand.cs
@@ -1,86 +1,84 @@
// 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.
using System;
-using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
-using Orang.FileSystem;
-using Orang.Text.RegularExpressions;
-namespace Orang.Operations;
+namespace Orang.FileSystem.Commands;
-internal class RenameOperation : DeleteOrRenameOperation
+internal class RenameCommand : DeleteOrRenameCommand
{
- public override OperationKind OperationKind => OperationKind.Rename;
-
public RenameOptions RenameOptions { get; set; } = null!;
+ public Replacer Replacer { get; set; } = null!;
+
public ConflictResolution ConflictResolution { get; set; }
- public IDialogProvider? DialogProvider { get; set; }
+ public IDialogProvider? DialogProvider { get; set; }
- protected override void ExecuteDirectory(string directoryPath)
- {
- Debug.Assert(!NameFilter!.IsNegative);
+ public Matcher? FileMatcher { get; set; }
+
+ public Matcher? DirectoryMatcher { get; set; }
- base.ExecuteDirectory(directoryPath);
+ public override OperationKind OperationKind => OperationKind.Rename;
+
+ protected override void OnSearchStateCreating(SearchState search)
+ {
+ search.SupportsEnumeration = DryRun;
}
protected override void ExecuteMatch(
FileMatch fileMatch,
string directoryPath)
{
- (List replaceItems, MaxReason maxReason) = ReplaceHelpers.GetReplaceItems(
- fileMatch.NameMatch!,
- RenameOptions,
- predicate: NameFilter?.Predicate,
+ string newValue = fileMatch.GetReplacement(
+ Replacer,
+ count: 0,
+ predicate: (fileMatch.IsDirectory) ? DirectoryMatcher!.Predicate : FileMatcher!.Predicate,
cancellationToken: CancellationToken);
- string path = fileMatch.Path;
-
- string newName = ReplaceHelpers.GetNewName(fileMatch, replaceItems);
-
- ListCache.Free(replaceItems);
-
- if (string.IsNullOrWhiteSpace(newName))
+ if (string.IsNullOrWhiteSpace(newValue))
{
- Report(fileMatch, null, new IOException("New file name cannot be empty or contains only white-space."));
+ Log(fileMatch, null, new IOException("New file name cannot be empty or contains only white-space."));
return;
}
- if (string.Compare(
+ string path = fileMatch.Path;
+
+ bool changed = string.Compare(
path,
fileMatch.NameSpan.Start,
- newName,
+ newValue,
0,
- fileMatch.NameSpan.Length,
- StringComparison.Ordinal) == 0)
- {
+ Math.Max(fileMatch.NameSpan.Length, newValue.Length),
+ StringComparison.Ordinal) != 0;
+
+ bool isInvalidName = changed
+ && FileSystemUtilities.ContainsInvalidFileNameChars(newValue);
+
+ string newPath = path.Substring(0, fileMatch.NameSpan.Start)
+ + newValue
+ + path.Substring(fileMatch.NameSpan.Start + fileMatch.NameSpan.Length);
+
+ if (!changed)
return;
- }
- if (FileSystemHelpers.ContainsInvalidFileNameChars(newName))
+ if (isInvalidName)
{
- Report(fileMatch, newName, new IOException("New file name contains invalid characters."));
+ Log(fileMatch, newValue, new IOException("New file name contains invalid characters."));
return;
}
- string newPath = path.Substring(0, fileMatch.NameSpan.Start) + newName;
-
- if (File.Exists(newPath))
+ if (File.Exists(newPath)
+ || Directory.Exists(newPath))
{
if (ConflictResolution == ConflictResolution.Skip)
- {
return;
- }
- else if (ConflictResolution == ConflictResolution.Suffix)
- {
- newPath = FileSystemHelpers.CreateNewFilePath(newPath);
- }
- else if (ConflictResolution == ConflictResolution.Ask)
+
+ if (ConflictResolution == ConflictResolution.Ask
+ && !DryRun
+ && !AskToOverwrite(fileMatch, newPath))
{
- if (!AskToOverwrite(fileMatch, newPath))
- return;
+ return;
}
}
@@ -90,6 +88,15 @@ protected override void ExecuteMatch(
{
if (!DryRun)
{
+ if (File.Exists(newPath))
+ {
+ File.Delete(newPath);
+ }
+ else if (Directory.Exists(newPath))
+ {
+ Directory.Delete(newPath, recursive: true);
+ }
+
if (fileMatch.IsDirectory)
{
Directory.Move(path, newPath);
@@ -102,14 +109,21 @@ protected override void ExecuteMatch(
renamed = true;
}
- Report(fileMatch, newPath);
+ if (fileMatch.IsDirectory)
+ {
+ Telemetry.ProcessedDirectoryCount++;
+ }
+ else
+ {
+ Telemetry.ProcessedFileCount++;
+ }
- Telemetry.IncrementProcessedCount(fileMatch.IsDirectory);
+ Log(fileMatch, newPath);
}
catch (Exception ex) when (ex is IOException
|| ex is UnauthorizedAccessException)
{
- Report(fileMatch, newPath, ex);
+ Log(fileMatch, newPath, ex);
}
if (fileMatch.IsDirectory
@@ -121,7 +135,7 @@ protected override void ExecuteMatch(
private bool AskToOverwrite(FileMatch fileMatch, string newPath)
{
- DialogResult result = DialogProvider!.GetResult(new OperationProgress(fileMatch, newPath, OperationKind));
+ DialogResult result = DialogProvider!.GetResult(new ConflictInfo(fileMatch.Path, newPath));
switch (result)
{
diff --git a/src/FileSystem/Operations/ReplaceOperation.cs b/src/FileSystem/FileSystem/Commands/ReplaceCommand.cs
similarity index 79%
rename from src/FileSystem/Operations/ReplaceOperation.cs
rename to src/FileSystem/FileSystem/Commands/ReplaceCommand.cs
index 8f6f02ce..507a9607 100644
--- a/src/FileSystem/Operations/ReplaceOperation.cs
+++ b/src/FileSystem/FileSystem/Commands/ReplaceCommand.cs
@@ -2,22 +2,24 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
-using Orang.FileSystem;
-namespace Orang.Operations;
+namespace Orang.FileSystem.Commands;
-internal class ReplaceOperation : CommonFindOperation
+internal class ReplaceCommand : CommonFindCommand
{
- public override OperationKind OperationKind => OperationKind.Replace;
-
public ReplaceOptions ReplaceOptions { get; set; } = null!;
- protected override void ExecuteDirectory(string path)
+ public Replacer Replacer { get; set; } = null!;
+
+ public Matcher ContentFilter { get; set; } = null!;
+
+ public override OperationKind OperationKind => OperationKind.Replace;
+
+ protected override void OnSearchStateCreating(SearchState search)
{
- Debug.Assert(ContentFilter?.IsNegative == false);
+ search.CanRecurseMatch = false;
}
protected override void ExecuteMatch(
@@ -32,7 +34,7 @@ protected override void ExecuteMatch(
captures = ListCache.GetInstance();
GetCaptures(
- fileMatch.ContentMatch!,
+ fileMatch.Content!,
ContentFilter!.GroupNumber,
predicate: ContentFilter.Predicate,
captures: captures);
@@ -41,9 +43,11 @@ protected override void ExecuteMatch(
{
textWriter = new StreamWriter(fileMatch.Path, false, fileMatch.Encoding);
- WriteMatches(fileMatch.ContentText, captures, ReplaceOptions, textWriter);
+ WriteMatches(fileMatch.ContentText, captures, Replacer, textWriter);
}
+ fileMatch.FileContent = default;
+
int fileMatchCount = captures.Count;
int fileReplacementCount = fileMatchCount;
Telemetry.MatchCount += fileMatchCount;
@@ -52,12 +56,12 @@ protected override void ExecuteMatch(
if (fileReplacementCount > 0)
Telemetry.ProcessedFileCount++;
- Report(fileMatch);
+ Log(fileMatch);
}
catch (Exception ex) when (ex is IOException
|| ex is UnauthorizedAccessException)
{
- Report(fileMatch, ex);
+ Log(fileMatch, ex);
}
finally
{
@@ -71,7 +75,7 @@ protected override void ExecuteMatch(
private void WriteMatches(
string input,
IEnumerable captures,
- ReplaceOptions replaceOptions,
+ Replacer replacer,
TextWriter textWriter)
{
int index = 0;
@@ -80,7 +84,7 @@ private void WriteMatches(
{
textWriter.Write(input.AsSpan(index, capture.Index - index));
- string result = replaceOptions.Replace((Match)capture);
+ string result = replacer.Replace((Match)capture);
textWriter.Write(result);
diff --git a/src/FileSystem/FileSystem/ConflictInfo.cs b/src/FileSystem/FileSystem/ConflictInfo.cs
new file mode 100644
index 00000000..d6931602
--- /dev/null
+++ b/src/FileSystem/FileSystem/ConflictInfo.cs
@@ -0,0 +1,22 @@
+// 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.
+
+using System.Diagnostics;
+
+namespace Orang.FileSystem;
+
+[DebuggerDisplay("{DebuggerDisplay,nq}")]
+public readonly struct ConflictInfo
+{
+ internal ConflictInfo(string sourcePath, string destinationPath)
+ {
+ SourcePath = sourcePath;
+ DestinationPath = destinationPath;
+ }
+
+ public string SourcePath { get; }
+
+ public string DestinationPath { get; }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay => $"{SourcePath} {DestinationPath}";
+}
diff --git a/src/FileSystem/FileSystem/ConflictResolution.cs b/src/FileSystem/FileSystem/ConflictResolution.cs
index 529264d3..7fd8e5f6 100644
--- a/src/FileSystem/FileSystem/ConflictResolution.cs
+++ b/src/FileSystem/FileSystem/ConflictResolution.cs
@@ -2,11 +2,10 @@
namespace Orang.FileSystem;
-// Stop, Throw
public enum ConflictResolution
{
- Overwrite = 0,
- Skip = 1,
- Ask = 2,
- Suffix = 3,
+ Overwrite,
+ Skip,
+ Ask,
+ Suffix,
}
diff --git a/src/FileSystem/FileSystem/CopyOptions.cs b/src/FileSystem/FileSystem/CopyOptions.cs
index af100fce..af24433f 100644
--- a/src/FileSystem/FileSystem/CopyOptions.cs
+++ b/src/FileSystem/FileSystem/CopyOptions.cs
@@ -1,31 +1,33 @@
// 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.
-using System.Diagnostics;
+using System;
+using System.IO;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
namespace Orang.FileSystem;
-[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class CopyOptions
{
- internal static CopyOptions Default { get; } = new();
+ public ConflictResolution ConflictResolution { get; set; } = ConflictResolution.Skip;
+
+ public FileCompareProperties ComparedProperties { get; set; }
+
+ internal Func? CompareFile { get; set; }
+
+ internal Func? CompareDirectory { get; set; }
+
+ public FileAttributes? ComparedAttributes { get; set; }
+
+ public TimeSpan? AllowedTimeDiff { get; set; }
- public CopyOptions(
- ConflictResolution conflictResolution = ConflictResolution.Skip,
- FileCompareOptions compareOptions = FileCompareOptions.None,
- bool flat = false)
- {
- ConflictResolution = conflictResolution;
- CompareOptions = compareOptions;
- Flat = flat;
- }
+ public bool Flat { get; set; }
- public ConflictResolution ConflictResolution { get; }
+ internal bool StructureOnly { get; set; }
- public FileCompareOptions CompareOptions { get; }
+ public bool DryRun { get; set; }
- public bool Flat { get; }
+ public Action? LogOperation { get; set; }
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- private string DebuggerDisplay
- => $"{nameof(ConflictResolution)} = {ConflictResolution} {nameof(CompareOptions)} = {CompareOptions}";
+ public IDialogProvider? DialogProvider { get; set; }
}
diff --git a/src/FileSystem/FileSystem/DeleteOptions.cs b/src/FileSystem/FileSystem/DeleteOptions.cs
index 81990923..cd657c77 100644
--- a/src/FileSystem/FileSystem/DeleteOptions.cs
+++ b/src/FileSystem/FileSystem/DeleteOptions.cs
@@ -1,5 +1,6 @@
// 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.
+using System;
using System.Diagnostics;
namespace Orang.FileSystem;
@@ -7,27 +8,17 @@ namespace Orang.FileSystem;
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class DeleteOptions
{
- internal static DeleteOptions Default { get; } = new();
+ public bool ContentOnly { get; set; }
- public DeleteOptions(
- bool contentOnly = false,
- bool includingBom = false,
- bool filesOnly = false,
- bool directoriesOnly = false)
- {
- ContentOnly = contentOnly;
- IncludingBom = includingBom;
- FilesOnly = filesOnly;
- DirectoriesOnly = directoriesOnly;
- }
+ public bool IncludingBom { get; set; }
- public bool ContentOnly { get; }
+ internal bool FilesOnly { get; set; }
- public bool IncludingBom { get; }
+ internal bool DirectoriesOnly { get; set; }
- public bool FilesOnly { get; }
+ public bool DryRun { get; set; }
- public bool DirectoriesOnly { get; }
+ public Action? LogOperation { get; set; }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay => $"{nameof(ContentOnly)} = {ContentOnly} {nameof(IncludingBom)} = {IncludingBom}";
diff --git a/src/FileSystem/FileSystem/DirectoryMatcher.cs b/src/FileSystem/FileSystem/DirectoryMatcher.cs
new file mode 100644
index 00000000..14a4f325
--- /dev/null
+++ b/src/FileSystem/FileSystem/DirectoryMatcher.cs
@@ -0,0 +1,83 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+#pragma warning disable RCS1223
+
+namespace Orang.FileSystem;
+
+public class DirectoryMatcher
+{
+ public Matcher? Name { get; set; }
+
+ public FileNamePart NamePart { get; set; }
+
+ public FileAttributes WithAttributes { get; set; }
+
+ public FileAttributes WithoutAttributes { get; set; }
+
+ public FileEmptyOption EmptyOption { get; set; }
+
+ internal Func? MatchDirectoryInfo { get; set; }
+
+ internal (FileMatch? FileMatch, Exception? Exception) Match(string path)
+ {
+ FileNameSpan span = FileNameSpan.FromDirectory(path, NamePart);
+ Match? match = null;
+
+ if (Name is not null)
+ {
+ match = Name.Match(span);
+
+ if (match is null)
+ return default;
+ }
+
+ DirectoryInfo? directoryInfo = null;
+
+ if (WithAttributes != 0
+ || EmptyOption != FileEmptyOption.None
+ || MatchDirectoryInfo is not null)
+ {
+ try
+ {
+ directoryInfo = new DirectoryInfo(path);
+
+ if (WithAttributes != 0
+ && (directoryInfo.Attributes & WithAttributes) != WithAttributes)
+ {
+ return default;
+ }
+
+ if (MatchDirectoryInfo?.Invoke(directoryInfo) == false)
+ return default;
+
+ if (EmptyOption == FileEmptyOption.Empty)
+ {
+ if (!IsEmptyDirectory(path))
+ return default;
+ }
+ else if (EmptyOption == FileEmptyOption.NonEmpty)
+ {
+ if (IsEmptyDirectory(path))
+ return default;
+ }
+ }
+ catch (Exception ex) when (ex is IOException
+ || ex is UnauthorizedAccessException)
+ {
+ return (null, ex);
+ }
+ }
+
+ return (new FileMatch(span, match, directoryInfo, isDirectory: true), null);
+
+ static bool IsEmptyDirectory(string path)
+ {
+ return !Directory.EnumerateFileSystemEntries(path).Any();
+ }
+ }
+}
diff --git a/src/FileSystem/FileSystem/FileCompareOptions.cs b/src/FileSystem/FileSystem/FileCompareProperties.cs
similarity index 90%
rename from src/FileSystem/FileSystem/FileCompareOptions.cs
rename to src/FileSystem/FileSystem/FileCompareProperties.cs
index cfd8d734..f43cb72c 100644
--- a/src/FileSystem/FileSystem/FileCompareOptions.cs
+++ b/src/FileSystem/FileSystem/FileCompareProperties.cs
@@ -5,7 +5,7 @@
namespace Orang.FileSystem;
[Flags]
-public enum FileCompareOptions
+public enum FileCompareProperties
{
None = 0,
Size = 1,
diff --git a/src/FileSystem/FileSystem/FileContent.cs b/src/FileSystem/FileSystem/FileContent.cs
index 7f578f8c..d4a85801 100644
--- a/src/FileSystem/FileSystem/FileContent.cs
+++ b/src/FileSystem/FileSystem/FileContent.cs
@@ -7,9 +7,9 @@
namespace Orang.FileSystem;
[DebuggerDisplay("{DebuggerDisplay,nq}")]
-public readonly struct FileContent
+internal readonly struct FileContent
{
- public FileContent(string text, Encoding encoding, bool hasBom)
+ internal FileContent(string text, Encoding encoding, bool hasBom)
{
Text = text ?? throw new ArgumentNullException(nameof(text));
Encoding = encoding ?? throw new ArgumentNullException(nameof(encoding));
@@ -22,6 +22,8 @@ public FileContent(string text, Encoding encoding, bool hasBom)
public bool HasBom { get; }
+ public override string ToString() => Text;
+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay
{
@@ -32,6 +34,4 @@ private string DebuggerDisplay
: "Uninitialized";
}
}
-
- public override string ToString() => Text;
}
diff --git a/src/FileSystem/FileSystem/FileEmptyOption.cs b/src/FileSystem/FileSystem/FileEmptyOption.cs
index 7b3c64a2..c698186e 100644
--- a/src/FileSystem/FileSystem/FileEmptyOption.cs
+++ b/src/FileSystem/FileSystem/FileEmptyOption.cs
@@ -4,7 +4,7 @@ namespace Orang.FileSystem;
public enum FileEmptyOption
{
- None = 0,
- Empty = 1,
- NonEmpty = 2,
+ None,
+ Empty,
+ NonEmpty,
}
diff --git a/src/FileSystem/FileSystem/FileMatch.cs b/src/FileSystem/FileSystem/FileMatch.cs
index 2ef3807a..8bbb1bb2 100644
--- a/src/FileSystem/FileSystem/FileMatch.cs
+++ b/src/FileSystem/FileSystem/FileMatch.cs
@@ -13,37 +13,37 @@ public class FileMatch
private FileSystemInfo? _fileSystemInfo;
internal FileMatch(
- in FileNameSpan nameSpan,
- Match? nameMatch,
+ FileNameSpan nameSpan,
+ Match? name,
FileSystemInfo? fileSystemInfo = null,
bool isDirectory = false)
- : this(nameSpan, nameMatch, default(FileContent), default(Match), fileSystemInfo, isDirectory)
+ : this(name, nameSpan, default(Match), default(FileContent), fileSystemInfo, isDirectory)
{
}
internal FileMatch(
- in FileNameSpan nameSpan,
- Match? nameMatch,
- in FileContent content,
- Match? contentMatch,
+ Match? name,
+ FileNameSpan nameSpan,
+ Match? content,
+ FileContent fileContent,
FileSystemInfo? fileSystemInfo = null,
bool isDirectory = false)
{
- NameMatch = nameMatch;
+ Name = name;
NameSpan = nameSpan;
+ FileContent = fileContent;
Content = content;
- ContentMatch = contentMatch;
IsDirectory = isDirectory;
_fileSystemInfo = fileSystemInfo;
}
public FileNameSpan NameSpan { get; }
- public Match? NameMatch { get; }
+ public Match? Name { get; }
- public FileContent Content { get; }
+ internal FileContent FileContent { get; set; }
- public Match? ContentMatch { get; }
+ public Match? Content { get; }
public bool IsDirectory { get; }
@@ -69,13 +69,13 @@ internal FileSystemInfo FileSystemInfo
public string Path => NameSpan.Path;
- internal int Index => (NameMatch?.Success == true) ? NameMatch.Index : -1;
+ internal int Index => (Name?.Success == true) ? Name.Index : -1;
- internal int Length => (NameMatch?.Success == true) ? NameMatch.Length : -1;
+ internal int Length => (Name?.Success == true) ? Name.Length : -1;
- internal string ContentText => Content.Text;
+ internal string ContentText => FileContent.Text;
- internal Encoding Encoding => Content.Encoding;
+ internal Encoding Encoding => FileContent.Encoding;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay => $"{Path}";
diff --git a/src/FileSystem/FileSystem/FileMatcher.cs b/src/FileSystem/FileSystem/FileMatcher.cs
new file mode 100644
index 00000000..1f491d12
--- /dev/null
+++ b/src/FileSystem/FileSystem/FileMatcher.cs
@@ -0,0 +1,160 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using Orang.Text;
+
+#pragma warning disable RCS1223
+
+namespace Orang.FileSystem;
+
+public class FileMatcher
+{
+ public Matcher? Name { get; set; }
+
+ public FileNamePart NamePart { get; set; }
+
+ public Matcher? Extension { get; set; }
+
+ public Matcher? Content { get; set; }
+
+ public FileAttributes WithAttributes { get; set; }
+
+ public FileAttributes WithoutAttributes { get; set; }
+
+ public FileEmptyOption EmptyOption { get; set; }
+
+ internal Func? MatchFileInfo { get; set; }
+
+ internal (FileMatch? FileMatch, Exception? Exception) Match(string path, Encoding? defaultEncoding = null)
+ {
+ if (Extension?.IsMatch(FileNameSpan.FromFile(path, FileNamePart.Extension)) == false)
+ return default;
+
+ FileNameSpan span = FileNameSpan.FromFile(path, NamePart);
+ Match? match = null;
+
+ if (Name is not null)
+ {
+ match = Name.Match(span);
+
+ if (match is null)
+ return default;
+ }
+
+ FileEmptyOption emptyOption = EmptyOption;
+ var isEmpty = false;
+ FileInfo? fileInfo = null;
+
+ if (WithAttributes != 0
+ || emptyOption != FileEmptyOption.None
+ || MatchFileInfo is not null)
+ {
+ try
+ {
+ fileInfo = new FileInfo(path);
+
+ if (WithAttributes != 0
+ && (fileInfo.Attributes & WithAttributes) != WithAttributes)
+ {
+ return default;
+ }
+
+ if (MatchFileInfo?.Invoke(fileInfo) == false)
+ return default;
+
+ if (emptyOption != FileEmptyOption.None)
+ {
+ if (fileInfo.Length == 0)
+ {
+ if (emptyOption == FileEmptyOption.NonEmpty)
+ return default;
+
+ isEmpty = true;
+ }
+ else if (fileInfo.Length > 4)
+ {
+ if (emptyOption == FileEmptyOption.Empty)
+ return default;
+
+ emptyOption = FileEmptyOption.None;
+ }
+ }
+ }
+ catch (Exception ex) when (ex is IOException
+ || ex is UnauthorizedAccessException)
+ {
+ return (null, ex);
+ }
+ }
+
+ if (Content is not null
+ || emptyOption != FileEmptyOption.None)
+ {
+ FileContent fileContent = default;
+
+ if (isEmpty)
+ {
+ fileContent = new FileContent("", defaultEncoding ?? EncodingHelpers.UTF8NoBom, hasBom: false);
+ }
+ else
+ {
+ try
+ {
+ using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
+ {
+ Encoding? bomEncoding = FileSystemUtilities.DetectEncoding(stream);
+
+ if (emptyOption != FileEmptyOption.None)
+ {
+ if (bomEncoding?.Preamble.Length == stream.Length)
+ {
+ if (emptyOption == FileEmptyOption.NonEmpty)
+ return default;
+ }
+ else if (emptyOption == FileEmptyOption.Empty)
+ {
+ return default;
+ }
+ }
+
+ if (Content is not null)
+ {
+ using (var reader = new StreamReader(
+ stream: stream,
+ encoding: bomEncoding ?? defaultEncoding ?? EncodingHelpers.UTF8NoBom,
+ detectEncodingFromByteOrderMarks: bomEncoding is null))
+ {
+ string content = reader.ReadToEnd();
+
+ fileContent = new FileContent(
+ content,
+ reader.CurrentEncoding,
+ hasBom: bomEncoding is not null);
+ }
+ }
+ }
+ }
+ catch (Exception ex) when (ex is IOException
+ || ex is UnauthorizedAccessException)
+ {
+ return (null, ex);
+ }
+ }
+
+ if (Content is not null)
+ {
+ Match? contentMatch = Content.Match(fileContent.Text);
+
+ if (contentMatch is null)
+ return default;
+
+ return (new FileMatch(match, span, contentMatch, fileContent, fileInfo), null);
+ }
+ }
+
+ return (new FileMatch(span, match, fileInfo), null);
+ }
+}
diff --git a/src/FileSystem/FileSystem/FileNamePart.cs b/src/FileSystem/FileSystem/FileNamePart.cs
index 9d82782e..305be02f 100644
--- a/src/FileSystem/FileSystem/FileNamePart.cs
+++ b/src/FileSystem/FileSystem/FileNamePart.cs
@@ -2,7 +2,6 @@
namespace Orang.FileSystem;
-//TODO: PathPart, FilePathPart
public enum FileNamePart
{
Name = 0,
diff --git a/src/FileSystem/FileSystem/FileNameSpan.cs b/src/FileSystem/FileSystem/FileNameSpan.cs
index 9e2b6c65..e9c3ed4c 100644
--- a/src/FileSystem/FileSystem/FileNameSpan.cs
+++ b/src/FileSystem/FileSystem/FileNameSpan.cs
@@ -2,11 +2,10 @@
using System;
using System.Diagnostics;
-using static Orang.FileSystem.FileSystemHelpers;
+using static Orang.FileSystem.FileSystemUtilities;
namespace Orang.FileSystem;
-//TODO: PathSpan, FilePathSpan
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public readonly struct FileNameSpan
{
@@ -38,7 +37,7 @@ internal FileNameSpan(string path, int start, int length, FileNamePart part)
public override string ToString() => Path.Substring(Start, Length);
- public static FileNameSpan FromFile(string path, FileNamePart part)
+ internal static FileNameSpan FromFile(string path, FileNamePart part)
{
if (path is null)
throw new ArgumentNullException(nameof(path));
@@ -68,9 +67,7 @@ public static FileNameSpan FromFile(string path, FileNamePart part)
int dotIndex = GetExtensionIndex(path);
if (dotIndex >= path.Length - 1)
- {
return new FileNameSpan(path, path.Length, 0, part);
- }
return new FileNameSpan(path, dotIndex + 1, path.Length - dotIndex - 1, part);
}
@@ -81,7 +78,7 @@ public static FileNameSpan FromFile(string path, FileNamePart part)
}
}
- public static FileNameSpan FromDirectory(string path, FileNamePart part)
+ internal static FileNameSpan FromDirectory(string path, FileNamePart part)
{
if (path is null)
throw new ArgumentNullException(nameof(path));
@@ -99,7 +96,6 @@ public static FileNameSpan FromDirectory(string path, FileNamePart part)
{
return new FileNameSpan(path, 0, path.Length, part);
}
- //case NamePartKind.Extension:
default:
{
throw new ArgumentException("", nameof(part));
diff --git a/src/FileSystem/FileSystem/FilePropertyFilter.cs b/src/FileSystem/FileSystem/FilePropertyFilter.cs
deleted file mode 100644
index befc2e5e..00000000
--- a/src/FileSystem/FileSystem/FilePropertyFilter.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-
-using System;
-
-#pragma warning disable RCS1223
-
-namespace Orang.FileSystem;
-
-public class FilePropertyFilter
-{
- public FilePropertyFilter(
- Func? creationTimePredicate = null,
- Func? modifiedTimePredicate = null,
- Func? sizePredicate = null)
- {
- CreationTimePredicate = creationTimePredicate;
- ModifiedTimePredicate = modifiedTimePredicate;
- SizePredicate = sizePredicate;
- }
-
- public Func? CreationTimePredicate { get; }
-
- public Func? ModifiedTimePredicate { get; }
-
- public Func? SizePredicate { get; }
-}
diff --git a/src/FileSystem/FileSystem/FileSystemExtensions.cs b/src/FileSystem/FileSystem/FileSystemExtensions.cs
new file mode 100644
index 00000000..6398ac32
--- /dev/null
+++ b/src/FileSystem/FileSystem/FileSystemExtensions.cs
@@ -0,0 +1,96 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading;
+using Orang.Text.RegularExpressions;
+
+namespace Orang.FileSystem;
+
+internal static class FileSystemExtensions
+{
+ internal static bool IsMatch(this DirectoryMatcher matcher, string path)
+ {
+ return matcher.Match(path).FileMatch is not null;
+ }
+
+ internal static string GetReplacement(
+ this FileMatch fileMatch,
+ Replacer replacer,
+ int count = 0,
+ Func? predicate = null,
+ CancellationToken cancellationToken = default)
+ {
+ ReplaceResult result = GetReplaceResult(fileMatch, replacer, count, predicate, cancellationToken);
+
+ ListCache.Free(result.Items);
+
+ return result.NewName;
+ }
+
+ internal static ReplaceResult GetReplaceResult(
+ this FileMatch fileMatch,
+ Replacer replacer,
+ int count = 0,
+ Func? predicate = null,
+ CancellationToken cancellationToken = default)
+ {
+ List captures = ListCache.GetInstance();
+
+ MaxReason maxReason = CaptureFactory.GetCaptures(
+ ref captures,
+ fileMatch.Name!,
+ count: count,
+ predicate: predicate,
+ cancellationToken: cancellationToken);
+
+ int offset = 0;
+ List replaceItems = ListCache.GetInstance();
+
+ if (replaceItems.Capacity < captures.Count)
+ replaceItems.Capacity = captures.Count;
+
+ foreach (Match match in captures)
+ {
+ string value = replacer.Replace(match);
+
+ replaceItems.Add(new ReplaceItem(match, value, match.Index + offset));
+
+ offset += value.Length - match.Length;
+
+ cancellationToken.ThrowIfCancellationRequested();
+ }
+
+ ListCache.Free(captures);
+
+ string newName = GetNewValue(fileMatch, replaceItems);
+
+ return new ReplaceResult(replaceItems, maxReason, newName);
+ }
+
+ private static string GetNewValue(FileMatch fileMatch, List replaceItems)
+ {
+ StringBuilder sb = StringBuilderCache.GetInstance();
+
+ string path = fileMatch.Path;
+ FileNameSpan span = fileMatch.NameSpan;
+
+ int lastPos = span.Start;
+
+ foreach (ReplaceItem item in replaceItems)
+ {
+ Match match = item.Match;
+
+ sb.Append(path, lastPos, match.Index - lastPos);
+ sb.Append(item.Value);
+
+ lastPos = match.Index + match.Length;
+ }
+
+ sb.Append(path, lastPos, span.Start + span.Length - lastPos);
+
+ return StringBuilderCache.GetStringAndFree(sb);
+ }
+}
diff --git a/src/FileSystem/FileSystem/FileSystemFilter.cs b/src/FileSystem/FileSystem/FileSystemFilter.cs
deleted file mode 100644
index 1a9efa47..00000000
--- a/src/FileSystem/FileSystem/FileSystemFilter.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-using System.IO;
-
-#pragma warning disable RCS1223
-
-namespace Orang.FileSystem;
-
-public class FileSystemFilter
-{
- public FileSystemFilter(
- Filter? name = null,
- FileNamePart part = FileNamePart.Name,
- Filter? extension = null,
- Filter? content = null,
- FilePropertyFilter? properties = null,
- FileAttributes attributes = default,
- FileAttributes attributesToSkip = default,
- FileEmptyOption emptyOption = FileEmptyOption.None)
- {
- Name = name;
- Part = part;
- Extension = extension;
- Content = content;
- Properties = properties;
- Attributes = attributes;
- AttributesToSkip = attributesToSkip;
- EmptyOption = emptyOption;
- }
-
- public Filter? Name { get; }
-
- public FileNamePart Part { get; }
-
- public Filter? Extension { get; }
-
- public Filter? Content { get; }
-
- public FilePropertyFilter? Properties { get; }
-
- public FileAttributes Attributes { get; }
-
- public FileAttributes AttributesToSkip { get; }
-
- public FileEmptyOption EmptyOption { get; }
-}
diff --git a/src/FileSystem/FileSystem/FileSystemSearch.Static.cs b/src/FileSystem/FileSystem/FileSystemSearch.Static.cs
deleted file mode 100644
index e296999d..00000000
--- a/src/FileSystem/FileSystem/FileSystemSearch.Static.cs
+++ /dev/null
@@ -1,303 +0,0 @@
-// 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.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.IO;
-using System.Threading;
-using Orang.Operations;
-using static Orang.FileSystem.FileSystemHelpers;
-
-namespace Orang.FileSystem;
-
-public partial class FileSystemSearch
-{
- internal static void Replace(
- string directoryPath,
- FileSystemFilter filter,
- IEnumerable? directoryFilters = null,
- ReplaceOptions? replaceOptions = null,
- SearchTarget searchTarget = SearchTarget.Files,
- bool recurseSubdirectories = true,
- bool dryRun = false,
- CancellationToken cancellationToken = default)
- {
- if (directoryPath is null)
- throw new ArgumentNullException(nameof(directoryPath));
-
- var searchOptions = new FileSystemSearchOptions(
- searchTarget: searchTarget,
- recurseSubdirectories: recurseSubdirectories);
-
- var search = new FileSystemSearch(
- filter,
- directoryFilters: directoryFilters?.ToImmutableArray() ?? ImmutableArray.Empty,
- searchProgress: null,
- options: searchOptions);
-
- if (filter.Content is null)
- throw new InvalidOperationException("Content filter is not defined.");
-
- if (filter.Content.IsNegative)
- throw new InvalidOperationException("Content filter cannot be negative.");
-
- var command = new ReplaceOperation()
- {
- Search = search,
- ReplaceOptions = replaceOptions ?? ReplaceOptions.Empty,
- Progress = null,
- DryRun = dryRun,
- CancellationToken = cancellationToken,
- MaxMatchingFiles = 0,
- MaxMatchesInFile = 0,
- MaxTotalMatches = 0,
- };
-
- command.Execute(directoryPath);
- }
-
- internal static void Delete(
- string directoryPath,
- FileSystemFilter filter,
- IEnumerable? directoryFilters = null,
- DeleteOptions? deleteOptions = null,
- SearchTarget searchTarget = SearchTarget.Files,
- IProgress? progress = null,
- bool recurseSubdirectories = true,
- bool dryRun = false,
- CancellationToken cancellationToken = default)
- {
- if (directoryPath is null)
- throw new ArgumentNullException(nameof(directoryPath));
-
- var searchOptions = new FileSystemSearchOptions(
- searchTarget: searchTarget,
- recurseSubdirectories: recurseSubdirectories);
-
- var search = new FileSystemSearch(
- filter,
- directoryFilters: directoryFilters?.ToImmutableArray() ?? ImmutableArray.Empty,
- searchProgress: null,
- options: searchOptions)
- {
- CanRecurseMatch = false
- };
-
- var command = new DeleteOperation()
- {
- Search = search,
- DeleteOptions = deleteOptions ?? DeleteOptions.Default,
- Progress = progress,
- DryRun = dryRun,
- CancellationToken = cancellationToken,
- MaxMatchingFiles = 0,
- };
-
- command.Execute(directoryPath);
- }
-
- internal static void Rename(
- string directoryPath,
- FileSystemFilter filter,
- IEnumerable? directoryFilters = null,
- RenameOptions? renameOptions = null,
- SearchTarget searchTarget = SearchTarget.Files,
- IDialogProvider? dialogProvider = null,
- IProgress? progress = null,
- bool recurseSubdirectories = true,
- bool dryRun = false,
- CancellationToken cancellationToken = default)
- {
- if (directoryPath is null)
- throw new ArgumentNullException(nameof(directoryPath));
-
- if (directoryPath is null)
- throw new ArgumentNullException(nameof(directoryPath));
-
- var searchOptions = new FileSystemSearchOptions(
- searchTarget: searchTarget,
- recurseSubdirectories: recurseSubdirectories);
-
- var search = new FileSystemSearch(
- filter,
- directoryFilters: directoryFilters?.ToImmutableArray() ?? ImmutableArray.Empty,
- searchProgress: null,
- options: searchOptions)
- {
- DisallowEnumeration = !dryRun,
- MatchPartOnly = true
- };
-
- if (filter.Part == FileNamePart.FullName)
- throw new InvalidOperationException($"Invalid file name part '{nameof(FileNamePart.FullName)}'.");
-
- if (filter.Name is null)
- throw new InvalidOperationException("Name filter is not defined.");
-
- if (filter.Name.IsNegative)
- throw new InvalidOperationException("Name filter cannot be negative.");
-
- renameOptions ??= new RenameOptions(replacement: "");
-
- VerifyConflictResolution(renameOptions.ConflictResolution, dialogProvider);
-
- var command = new RenameOperation()
- {
- Search = search,
- RenameOptions = renameOptions,
- Progress = progress,
- DryRun = dryRun,
- CancellationToken = cancellationToken,
- DialogProvider = dialogProvider,
- MaxMatchingFiles = 0,
- };
-
- command.Execute(directoryPath);
- }
-
- internal static void Copy(
- string directoryPath,
- string destinationPath,
- FileSystemFilter filter,
- IEnumerable? directoryFilters = null,
- CopyOptions? copyOptions = null,
- SearchTarget searchTarget = SearchTarget.Files,
- IDialogProvider? dialogProvider = null,
- IProgress? progress = null,
- bool recurseSubdirectories = true,
- bool dryRun = false,
- CancellationToken cancellationToken = default)
- {
- if (directoryPath is null)
- throw new ArgumentNullException(nameof(directoryPath));
-
- var searchOptions = new FileSystemSearchOptions(
- searchTarget: searchTarget,
- recurseSubdirectories: recurseSubdirectories);
-
- ImmutableArray directoryFilters2 = directoryFilters?.ToImmutableArray() ?? ImmutableArray.Empty;
-
- directoryFilters2 = directoryFilters2.Add(NameFilter.CreateFromDirectoryPath(destinationPath, isNegative: true));
-
- var search = new FileSystemSearch(
- filter,
- directoryFilters: directoryFilters2,
- searchProgress: null,
- options: searchOptions);
-
- copyOptions ??= CopyOptions.Default;
-
- VerifyCopyMoveArguments(directoryPath, destinationPath, copyOptions, dialogProvider);
-
- var command = new CopyOperation()
- {
- Search = search,
- DestinationPath = destinationPath,
- CopyOptions = copyOptions,
- Progress = progress,
- DryRun = dryRun,
- CancellationToken = cancellationToken,
- DialogProvider = dialogProvider,
- MaxMatchingFiles = 0,
- MaxMatchesInFile = 0,
- MaxTotalMatches = 0,
- ConflictResolution = copyOptions.ConflictResolution,
- };
-
- command.Execute(directoryPath);
- }
-
- internal static void Move(
- string directoryPath,
- string destinationPath,
- FileSystemFilter filter,
- IEnumerable? directoryFilters = null,
- CopyOptions? copyOptions = null,
- SearchTarget searchTarget = SearchTarget.Files,
- IDialogProvider? dialogProvider = null,
- IProgress? progress = null,
- bool recurseSubdirectories = true,
- bool dryRun = false,
- CancellationToken cancellationToken = default)
- {
- if (directoryPath is null)
- throw new ArgumentNullException(nameof(directoryPath));
-
- var searchOptions = new FileSystemSearchOptions(
- searchTarget: searchTarget,
- recurseSubdirectories: recurseSubdirectories);
-
- ImmutableArray directoryFilters2 = directoryFilters?.ToImmutableArray() ?? ImmutableArray.Empty;
-
- directoryFilters2 = directoryFilters2.Add(NameFilter.CreateFromDirectoryPath(destinationPath, isNegative: true));
-
- var search = new FileSystemSearch(
- filter,
- directoryFilters: directoryFilters2,
- searchProgress: null,
- options: searchOptions);
-
- copyOptions ??= CopyOptions.Default;
-
- VerifyCopyMoveArguments(directoryPath, destinationPath, copyOptions, dialogProvider);
-
- var command = new MoveOperation()
- {
- Search = search,
- DestinationPath = destinationPath,
- CopyOptions = copyOptions,
- Progress = progress,
- DryRun = dryRun,
- CancellationToken = cancellationToken,
- DialogProvider = dialogProvider,
- MaxMatchingFiles = 0,
- MaxMatchesInFile = 0,
- MaxTotalMatches = 0,
- ConflictResolution = copyOptions.ConflictResolution,
- };
-
- command.Execute(directoryPath);
- }
-
- private static void VerifyCopyMoveArguments(
- string directoryPath,
- string destinationPath,
- CopyOptions copyOptions,
- IDialogProvider? dialogProvider)
- {
- if (directoryPath is null)
- throw new ArgumentNullException(nameof(directoryPath));
-
- if (destinationPath is null)
- throw new ArgumentNullException(nameof(destinationPath));
-
- if (!System.IO.Directory.Exists(directoryPath))
- throw new DirectoryNotFoundException($"Directory not found: {directoryPath}");
-
- if (!System.IO.Directory.Exists(destinationPath))
- throw new DirectoryNotFoundException($"Directory not found: {destinationPath}");
-
- if (IsSubdirectory(destinationPath, directoryPath))
- {
- throw new ArgumentException(
- "Source directory cannot be subdirectory of a destination directory.",
- nameof(directoryPath));
- }
-
- VerifyConflictResolution(copyOptions.ConflictResolution, dialogProvider);
- }
-
- private static void VerifyConflictResolution(
- ConflictResolution conflictResolution,
- IDialogProvider? dialogProvider)
- {
- if (conflictResolution == ConflictResolution.Ask
- && dialogProvider is null)
- {
- throw new ArgumentNullException(
- nameof(dialogProvider),
- $"'{nameof(dialogProvider)}' cannot be null when {nameof(ConflictResolution)} "
- + $"is set to {nameof(ConflictResolution.Ask)}.");
- }
- }
-}
diff --git a/src/FileSystem/FileSystem/FileSystemSearch.cs b/src/FileSystem/FileSystem/FileSystemSearch.cs
deleted file mode 100644
index 4a52e07f..00000000
--- a/src/FileSystem/FileSystem/FileSystemSearch.cs
+++ /dev/null
@@ -1,551 +0,0 @@
-// 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.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Security;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using static Orang.FileSystem.FileSystemHelpers;
-
-#pragma warning disable RCS1223
-
-namespace Orang.FileSystem;
-
-//TODO: FileSearch, Search
-public partial class FileSystemSearch
-{
- private readonly bool _allDirectoryFiltersArePositive;
-
- public FileSystemSearch(
- FileSystemFilter filter,
- NameFilter? directoryFilter = null,
- IProgress? searchProgress = null,
- FileSystemSearchOptions? options = null)
- : this(
- filter,
- (directoryFilter is not null) ? ImmutableArray.Create(directoryFilter) : ImmutableArray.Empty,
- searchProgress,
- options)
- {
- }
-
- public FileSystemSearch(
- FileSystemFilter filter,
- IEnumerable directoryFilters,
- IProgress? searchProgress = null,
- FileSystemSearchOptions? options = null)
- {
- if (directoryFilters is null)
- throw new ArgumentNullException(nameof(directoryFilters));
-
- foreach (NameFilter directoryFilter in directoryFilters)
- {
- if (directoryFilter is null)
- throw new ArgumentException("", nameof(directoryFilter));
-
- if (directoryFilter?.Part == FileNamePart.Extension)
- {
- throw new ArgumentException(
- $"Directory filter has invalid part '{FileNamePart.Extension}'.",
- nameof(directoryFilter));
- }
- }
-
- Filter = filter ?? throw new ArgumentNullException(nameof(filter));
- DirectoryFilters = directoryFilters.ToImmutableArray();
- SearchProgress = searchProgress;
- Options = options ?? FileSystemSearchOptions.Default;
-
- _allDirectoryFiltersArePositive = DirectoryFilters.All(f => !f.IsNegative);
- }
-
- public FileSystemFilter Filter { get; }
-
- public ImmutableArray DirectoryFilters { get; }
-
- public FileSystemSearchOptions Options { get; }
-
- public IProgress? SearchProgress { get; }
-
- internal bool DisallowEnumeration { get; set; }
-
- internal bool MatchPartOnly { get; set; }
-
- internal bool CanRecurseMatch { get; set; } = true;
-
- private FileNamePart Part => Filter.Part;
-
- private Filter? Name => Filter.Name;
-
- private Filter? Extension => Filter.Extension;
-
- private Filter? Content => Filter.Content;
-
- private FilePropertyFilter? Properties => Filter.Properties;
-
- private FileAttributes Attributes => Filter.Attributes;
-
- private FileAttributes AttributesToSkip => Filter.AttributesToSkip;
-
- private FileEmptyOption EmptyOption => Filter.EmptyOption;
-
- private SearchTarget SearchTarget => Options.SearchTarget;
-
- private bool RecurseSubdirectories => Options.RecurseSubdirectories;
-
- public IEnumerable Find(
- string directoryPath,
- CancellationToken cancellationToken = default)
- {
- return Find(directoryPath, default(INotifyDirectoryChanged), cancellationToken);
- }
-
- internal IEnumerable Find(
- string directoryPath,
- INotifyDirectoryChanged? notifyDirectoryChanged = null,
- CancellationToken cancellationToken = default)
- {
- var enumerationOptions = new EnumerationOptions()
- {
- AttributesToSkip = AttributesToSkip,
- IgnoreInaccessible = Options.IgnoreInaccessible,
- MatchCasing = MatchCasing.PlatformDefault,
- MatchType = MatchType.Simple,
- RecurseSubdirectories = false,
- ReturnSpecialDirectories = false
- };
-
- var directories = new Queue();
- Queue? subdirectories = (RecurseSubdirectories) ? new Queue() : null;
-
- string? currentDirectory = null;
-
- if (notifyDirectoryChanged is not null)
- {
- notifyDirectoryChanged.DirectoryChanged
- += (object sender, DirectoryChangedEventArgs e) => currentDirectory = e.NewName;
- }
-
- MatchStatus matchStatus = (DirectoryFilters.Any()) ? MatchStatus.Unknown : MatchStatus.Success;
-
- foreach (NameFilter directoryFilter in DirectoryFilters.Where(f => !f.IsNegative))
- {
- if (IsMatch(directoryPath, directoryFilter))
- {
- matchStatus = MatchStatus.Success;
- }
- else
- {
- matchStatus = MatchStatus.FailFromPositive;
- break;
- }
- }
-
- var directory = new Directory(directoryPath, matchStatus);
-
- while (true)
- {
- Report(directory.Path, SearchProgressKind.SearchDirectory, isDirectory: true);
-
- if (SearchTarget != SearchTarget.Directories
- && !directory.IsFail)
- {
- IEnumerator fi = null!;
-
- try
- {
- fi = (DisallowEnumeration)
- ? ((IEnumerable)GetFiles(directory.Path, enumerationOptions)).GetEnumerator()
- : EnumerateFiles(directory.Path, enumerationOptions).GetEnumerator();
- }
- catch (Exception ex) when (IsWellKnownException(ex))
- {
- Debug.Fail(ex.ToString());
- Report(directory.Path, SearchProgressKind.SearchDirectory, isDirectory: true, ex);
- }
-
- if (fi is not null)
- {
- using (fi)
- {
- while (fi.MoveNext())
- {
- FileMatch? match = MatchFile(fi.Current);
-
- if (match is not null)
- yield return match;
-
- cancellationToken.ThrowIfCancellationRequested();
- }
- }
- }
- }
-
- IEnumerator di = null!;
-
- try
- {
- di = (DisallowEnumeration)
- ? ((IEnumerable)GetDirectories(directory.Path, enumerationOptions)).GetEnumerator()
- : EnumerateDirectories(directory.Path, enumerationOptions).GetEnumerator();
- }
- catch (Exception ex) when (IsWellKnownException(ex))
- {
- Debug.Fail(ex.ToString());
- Report(directory.Path, SearchProgressKind.SearchDirectory, isDirectory: true, ex);
- }
-
- if (di is not null)
- {
- using (di)
- {
- while (di.MoveNext())
- {
- currentDirectory = di.Current;
-
- matchStatus = (_allDirectoryFiltersArePositive && directory.IsSuccess)
- ? MatchStatus.Success
- : MatchStatus.Unknown;
-
- if (!directory.IsFail
- && SearchTarget != SearchTarget.Files
- && Part != FileNamePart.Extension)
- {
- if (matchStatus == MatchStatus.Unknown
- && DirectoryFilters.Any())
- {
- matchStatus = IncludeDirectory(currentDirectory);
- }
-
- if (matchStatus == MatchStatus.Success
- || matchStatus == MatchStatus.Unknown)
- {
- FileMatch? match = MatchDirectory(currentDirectory);
-
- if (match is not null)
- {
- yield return match;
-
- if (!CanRecurseMatch)
- currentDirectory = null;
- }
- }
- }
-
- if (currentDirectory is not null
- && RecurseSubdirectories)
- {
- if (matchStatus == MatchStatus.Unknown
- && DirectoryFilters.Any())
- {
- matchStatus = IncludeDirectory(currentDirectory);
- }
-
- if (matchStatus != MatchStatus.FailFromNegative)
- subdirectories!.Enqueue(new Directory(currentDirectory, matchStatus));
- }
-
- cancellationToken.ThrowIfCancellationRequested();
- }
- }
-
- if (RecurseSubdirectories)
- {
- while (subdirectories!.Count > 0)
- directories.Enqueue(subdirectories.Dequeue());
- }
- }
-
- if (directories.Count > 0)
- {
- directory = directories.Dequeue();
- }
- else
- {
- break;
- }
- }
- }
-
- public FileMatch? MatchFile(string path)
- {
- (FileMatch? fileMatch, Exception? exception) = MatchFileImpl(path);
-
- Report(path, SearchProgressKind.File, exception: exception);
-
- return fileMatch;
- }
-
- private (FileMatch? fileMatch, Exception? exception) MatchFileImpl(string path)
- {
- if (Extension?.IsMatch(FileNameSpan.FromFile(path, FileNamePart.Extension)) == false)
- return default;
-
- FileNameSpan span = FileNameSpan.FromFile(path, Part);
- Match? match = null;
-
- if (Name is not null)
- {
- match = Name.Match(span, MatchPartOnly);
-
- if (match is null)
- return default;
- }
-
- FileEmptyOption emptyOption = EmptyOption;
- var isEmpty = false;
- FileInfo? fileInfo = null;
-
- if (Attributes != 0
- || emptyOption != FileEmptyOption.None
- || Properties is not null)
- {
- try
- {
- fileInfo = new FileInfo(path);
-
- if (Attributes != 0
- && (fileInfo.Attributes & Attributes) != Attributes)
- {
- return default;
- }
-
- if (Properties is not null)
- {
- if (Properties.SizePredicate?.Invoke(fileInfo.Length) == false)
- return default;
-
- if (Properties.CreationTimePredicate?.Invoke(fileInfo.CreationTime) == false)
- return default;
-
- if (Properties.ModifiedTimePredicate?.Invoke(fileInfo.LastWriteTime) == false)
- return default;
- }
-
- if (emptyOption != FileEmptyOption.None)
- {
- if (fileInfo.Length == 0)
- {
- if (emptyOption == FileEmptyOption.NonEmpty)
- return default;
-
- isEmpty = true;
- }
- else if (fileInfo.Length > 4)
- {
- if (emptyOption == FileEmptyOption.Empty)
- return default;
-
- emptyOption = FileEmptyOption.None;
- }
- }
- }
- catch (Exception ex) when (ex is IOException
- || ex is UnauthorizedAccessException)
- {
- return (null, ex);
- }
- }
-
- if (Content is not null
- || emptyOption != FileEmptyOption.None)
- {
- FileContent fileContent = default;
-
- if (isEmpty)
- {
- fileContent = new FileContent("", Options.DefaultEncoding, hasBom: false);
- }
- else
- {
- try
- {
- using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
- {
- Encoding? bomEncoding = DetectEncoding(stream);
-
- if (emptyOption != FileEmptyOption.None)
- {
- if (bomEncoding?.Preamble.Length == stream.Length)
- {
- if (emptyOption == FileEmptyOption.NonEmpty)
- return default;
- }
- else if (emptyOption == FileEmptyOption.Empty)
- {
- return default;
- }
- }
-
- if (Content is not null)
- {
- using (var reader = new StreamReader(
- stream: stream,
- encoding: bomEncoding ?? Options.DefaultEncoding,
- detectEncodingFromByteOrderMarks: bomEncoding is null))
- {
- string content = reader.ReadToEnd();
-
- fileContent = new FileContent(
- content,
- reader.CurrentEncoding,
- hasBom: bomEncoding is not null);
- }
- }
- }
- }
- catch (Exception ex) when (ex is IOException
- || ex is UnauthorizedAccessException)
- {
- return (null, ex);
- }
- }
-
- if (Content is not null)
- {
- Match? contentMatch = Content.Match(fileContent.Text);
-
- if (contentMatch is null)
- return default;
-
- return (new FileMatch(span, match, fileContent, contentMatch, fileInfo), null);
- }
- }
-
- return (new FileMatch(span, match, fileInfo), null);
- }
-
- public FileMatch? MatchDirectory(string path)
- {
- (FileMatch? fileMatch, Exception? exception) = MatchDirectoryImpl(path);
-
- Report(path, SearchProgressKind.Directory, isDirectory: true, exception);
-
- return fileMatch;
- }
-
- private (FileMatch? fileMatch, Exception? exception) MatchDirectoryImpl(string path)
- {
- FileNameSpan span = FileNameSpan.FromDirectory(path, Part);
- Match? match = null;
-
- if (Name is not null)
- {
- match = Name.Match(span, MatchPartOnly);
-
- if (match is null)
- return default;
- }
-
- DirectoryInfo? directoryInfo = null;
-
- if (Attributes != 0
- || EmptyOption != FileEmptyOption.None
- || Properties is not null)
- {
- try
- {
- directoryInfo = new DirectoryInfo(path);
-
- if (Attributes != 0
- && (directoryInfo.Attributes & Attributes) != Attributes)
- {
- return default;
- }
-
- if (Properties is not null)
- {
- if (Properties.CreationTimePredicate?.Invoke(directoryInfo.CreationTime) == false)
- return default;
-
- if (Properties.ModifiedTimePredicate?.Invoke(directoryInfo.LastWriteTime) == false)
- return default;
- }
-
- if (EmptyOption == FileEmptyOption.Empty)
- {
- if (!IsEmptyDirectory(path))
- return default;
- }
- else if (EmptyOption == FileEmptyOption.NonEmpty)
- {
- if (IsEmptyDirectory(path))
- return default;
- }
- }
- catch (Exception ex) when (ex is IOException
- || ex is UnauthorizedAccessException)
- {
- return (null, ex);
- }
- }
-
- return (new FileMatch(span, match, directoryInfo, isDirectory: true), null);
- }
-
- private MatchStatus IncludeDirectory(string path)
- {
- Debug.Assert(DirectoryFilters.Any());
-
- foreach (NameFilter filter in DirectoryFilters)
- {
- if (!IsMatch(path, filter))
- return (filter.IsNegative) ? MatchStatus.FailFromNegative : MatchStatus.FailFromPositive;
- }
-
- return MatchStatus.Success;
- }
-
- public static bool IsMatch(string directoryPath, NameFilter filter)
- {
- return filter.Name.IsMatch(FileNameSpan.FromDirectory(directoryPath, filter.Part));
- }
-
- private void Report(string path, SearchProgressKind kind, bool isDirectory = false, Exception? exception = null)
- {
- SearchProgress?.Report(path, kind, isDirectory: isDirectory, exception);
- }
-
- private static bool IsWellKnownException(Exception ex)
- {
- return ex is IOException
- || ex is ArgumentException
- || ex is UnauthorizedAccessException
- || ex is SecurityException
- || ex is NotSupportedException;
- }
-
- [DebuggerDisplay("{DebuggerDisplay,nq}")]
- private readonly struct Directory
- {
- public Directory(string path, MatchStatus status)
- {
- Path = path;
- Status = status;
- }
-
- public string Path { get; }
-
- public MatchStatus Status { get; }
-
- public bool IsSuccess => Status == MatchStatus.Success;
-
- public bool IsFail => Status == MatchStatus.FailFromPositive || Status == MatchStatus.FailFromNegative;
-
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- private string DebuggerDisplay => Path;
- }
-
- private enum MatchStatus
- {
- Unknown = 0,
- Success = 1,
- FailFromPositive = 2,
- FailFromNegative = 3,
- }
-}
diff --git a/src/FileSystem/FileSystem/FileSystemSearchOptions.cs b/src/FileSystem/FileSystem/FileSystemSearchOptions.cs
deleted file mode 100644
index 6d534c3a..00000000
--- a/src/FileSystem/FileSystem/FileSystemSearchOptions.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-using System.Diagnostics;
-using System.Text;
-using Orang.Text;
-
-namespace Orang.FileSystem;
-
-//TODO: FileSearchOptions, SearchOptions
-[DebuggerDisplay("{DebuggerDisplay,nq}")]
-public class FileSystemSearchOptions
-{
- public static FileSystemSearchOptions Default { get; } = new();
-
- public FileSystemSearchOptions(
- SearchTarget searchTarget = SearchTarget.Files,
- bool recurseSubdirectories = true,
- bool ignoreInaccessible = true,
- Encoding? defaultEncoding = null)
- {
- SearchTarget = searchTarget;
- RecurseSubdirectories = recurseSubdirectories;
- IgnoreInaccessible = ignoreInaccessible;
- DefaultEncoding = defaultEncoding ?? EncodingHelpers.UTF8NoBom;
- }
-
- public SearchTarget SearchTarget { get; }
-
- public bool RecurseSubdirectories { get; }
-
- public bool IgnoreInaccessible { get; }
-
- public Encoding DefaultEncoding { get; }
-
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- private string DebuggerDisplay => $"{SearchTarget} {nameof(RecurseSubdirectories)} = {RecurseSubdirectories}";
-}
diff --git a/src/FileSystem/FileSystem/FileSystemHelpers.cs b/src/FileSystem/FileSystem/FileSystemUtilities.cs
similarity index 85%
rename from src/FileSystem/FileSystem/FileSystemHelpers.cs
rename to src/FileSystem/FileSystem/FileSystemUtilities.cs
index dadf7213..1769fef2 100644
--- a/src/FileSystem/FileSystem/FileSystemHelpers.cs
+++ b/src/FileSystem/FileSystem/FileSystemUtilities.cs
@@ -13,8 +13,10 @@
namespace Orang.FileSystem;
-internal static class FileSystemHelpers
+internal static class FileSystemUtilities
{
+ internal static FileAttributes AllFileAttributes { get; } = GetAllFileAttributes();
+
private static ImmutableHashSet? _invalidFileNameChars;
private static readonly EnumerationOptions _enumerationOptionsNoRecurse = new()
@@ -94,34 +96,34 @@ private static bool GetIsCaseSensitive()
internal static bool FileEquals(
string path1,
string path2,
- FileCompareOptions options,
- FileAttributes ignoredAttributes = 0,
+ FileCompareProperties properties,
+ FileAttributes? compareAttributes = null,
TimeSpan? allowedTimeDiff = null)
{
- if ((options & FileCompareOptions.ModifiedTime) != 0
+ if ((properties & FileCompareProperties.ModifiedTime) != 0
&& !LastWriteTimeUtcEquals(path1, path2, allowedTimeDiff))
{
return false;
}
- if ((options & FileCompareOptions.Attributes) != 0
- && !AttributeEquals(path1, path2, ignoredAttributes))
+ if ((properties & FileCompareProperties.Attributes) != 0
+ && !AttributeEquals(path1, path2, compareAttributes))
{
return false;
}
- if ((options & (FileCompareOptions.Size | FileCompareOptions.Content)) != 0)
+ if ((properties & (FileCompareProperties.Size | FileCompareProperties.Content)) != 0)
{
using (var fs1 = new FileStream(path1, FileMode.Open, FileAccess.Read))
using (var fs2 = new FileStream(path2, FileMode.Open, FileAccess.Read))
{
- if ((options & FileCompareOptions.Size) != 0
+ if ((properties & FileCompareProperties.Size) != 0
&& fs1.Length != fs2.Length)
{
return false;
}
- if ((options & FileCompareOptions.Content) != 0
+ if ((properties & FileCompareProperties.Content) != 0
&& !StreamComparer.Default.ByteEquals(fs1, fs2))
{
return false;
@@ -132,73 +134,73 @@ internal static bool FileEquals(
return true;
}
- internal static FileCompareOptions CompareFiles(
+ internal static FileCompareProperties CompareFiles(
string path1,
string path2,
- FileCompareOptions options,
- FileAttributes ignoredAttributes = 0,
+ FileCompareProperties properties,
+ FileAttributes? attributes = null,
TimeSpan? allowedTimeDiff = null)
{
- if ((options & FileCompareOptions.ModifiedTime) != 0
+ if ((properties & FileCompareProperties.ModifiedTime) != 0
&& !LastWriteTimeUtcEquals(path1, path2, allowedTimeDiff))
{
- return FileCompareOptions.ModifiedTime;
+ return FileCompareProperties.ModifiedTime;
}
- if ((options & FileCompareOptions.Attributes) != 0
- && !AttributeEquals(path1, path2, ignoredAttributes))
+ if ((properties & FileCompareProperties.Attributes) != 0
+ && !AttributeEquals(path1, path2, attributes))
{
- if ((options & (FileCompareOptions.Size | FileCompareOptions.Content)) != 0)
+ if ((properties & (FileCompareProperties.Size | FileCompareProperties.Content)) != 0)
{
using (var fs1 = new FileStream(path1, FileMode.Open, FileAccess.Read))
using (var fs2 = new FileStream(path2, FileMode.Open, FileAccess.Read))
{
- if ((options & FileCompareOptions.Size) != 0
+ if ((properties & FileCompareProperties.Size) != 0
&& fs1.Length != fs2.Length)
{
- return FileCompareOptions.Size;
+ return FileCompareProperties.Size;
}
- if ((options & FileCompareOptions.Content) != 0
+ if ((properties & FileCompareProperties.Content) != 0
&& !StreamComparer.Default.ByteEquals(fs1, fs2))
{
- return FileCompareOptions.Content;
+ return FileCompareProperties.Content;
}
}
}
- return FileCompareOptions.Attributes;
+ return FileCompareProperties.Attributes;
}
- if ((options & (FileCompareOptions.Size | FileCompareOptions.Content)) != 0)
+ if ((properties & (FileCompareProperties.Size | FileCompareProperties.Content)) != 0)
{
using (var fs1 = new FileStream(path1, FileMode.Open, FileAccess.Read))
using (var fs2 = new FileStream(path2, FileMode.Open, FileAccess.Read))
{
- if ((options & FileCompareOptions.Size) != 0
+ if ((properties & FileCompareProperties.Size) != 0
&& fs1.Length != fs2.Length)
{
- return FileCompareOptions.Size;
+ return FileCompareProperties.Size;
}
- if ((options & FileCompareOptions.Content) != 0
+ if ((properties & FileCompareProperties.Content) != 0
&& !StreamComparer.Default.ByteEquals(fs1, fs2))
{
- return FileCompareOptions.Content;
+ return FileCompareProperties.Content;
}
}
}
- return FileCompareOptions.None;
+ return FileCompareProperties.None;
}
internal static bool AttributeEquals(
string path1,
string path2,
- FileAttributes ignoredAttributes = 0)
+ FileAttributes? attributes = null)
{
- FileAttributes attr1 = File.GetAttributes(path1) & ~ignoredAttributes;
- FileAttributes attr2 = File.GetAttributes(path2) & ~ignoredAttributes;
+ FileAttributes attr1 = File.GetAttributes(path1) & (attributes ?? AllFileAttributes);
+ FileAttributes attr2 = File.GetAttributes(path2) & (attributes ?? AllFileAttributes);
return attr1 == attr2;
}
@@ -331,13 +333,14 @@ public static void DeleteFile(string filePath, bool contentOnly, bool includingB
{
if (contentOnly)
{
- FileAccess fileAccess = (includingBom) ? FileAccess.Write : FileAccess.ReadWrite;
-
- using (var stream = new FileStream(filePath, FileMode.Open, fileAccess))
+ using (var stream = new FileStream(
+ filePath,
+ FileMode.Open,
+ (includingBom) ? FileAccess.Write : FileAccess.ReadWrite))
{
int length = 0;
- if (includingBom)
+ if (!includingBom)
{
Encoding? encoding = DetectEncoding(stream);
@@ -439,9 +442,7 @@ public static long GetDirectorySize(string directoryPath)
long size = 0;
foreach (string filePath in EnumerateFiles(directoryPath, _enumerationOptionsRecurse))
- {
size += new FileInfo(filePath).Length;
- }
return size;
}
@@ -583,4 +584,16 @@ public static string EnsureFullPath(string path)
{
return (Path.IsPathRooted(path)) ? path : Path.GetFullPath(path);
}
+
+ private static FileAttributes GetAllFileAttributes()
+ {
+ var attributes = (FileAttributes)0;
+
+ foreach (FileAttributes value in Enum.GetValues(typeof(FileAttributes)).Cast())
+ {
+ attributes |= value;
+ }
+
+ return attributes;
+ }
}
diff --git a/src/FileSystem/FileSystem/Fluent/CopyOperation.cs b/src/FileSystem/FileSystem/Fluent/CopyOperation.cs
new file mode 100644
index 00000000..11640d8a
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/CopyOperation.cs
@@ -0,0 +1,32 @@
+// 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.
+
+using System;
+using System.Threading;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class CopyOperation
+{
+ internal CopyOperation(Search search, CopyOptions options)
+ {
+ Search = search ?? throw new ArgumentNullException(nameof(search));
+ Options = options ?? throw new ArgumentNullException(nameof(options));
+ }
+
+ public Search Search { get; }
+
+ public CopyOptions Options { get; }
+
+ public IOperationResult Run(string directoryPath, string destinationPath, CancellationToken cancellationToken = default)
+ {
+ if (directoryPath is null)
+ throw new ArgumentNullException(nameof(directoryPath));
+
+ if (destinationPath is null)
+ throw new ArgumentNullException(nameof(destinationPath));
+
+ return Search.Copy(directoryPath, destinationPath, Options, cancellationToken);
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/CopyOperationBuilder.cs b/src/FileSystem/FileSystem/Fluent/CopyOperationBuilder.cs
new file mode 100644
index 00000000..ad856bd5
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/CopyOperationBuilder.cs
@@ -0,0 +1,111 @@
+// 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.
+
+using System;
+using System.IO;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class CopyOperationBuilder
+{
+ private ConflictResolution _conflictResolution = ConflictResolution.Skip;
+ private bool _dryRun;
+ private Action? _logOperation;
+ private FileCompareProperties _comparedProperties;
+ private FileAttributes? _comparedAttributes;
+ private TimeSpan? _allowedTimeDiff;
+ private bool _flat;
+ private IDialogProvider? _dialogProvider;
+ private Func? _compareFile;
+ private Func? _compareDirectory;
+
+ internal CopyOperationBuilder()
+ {
+ }
+
+ public CopyOperationBuilder WithConflictResolution(ConflictResolution conflictResolution)
+ {
+ _conflictResolution = conflictResolution;
+ return this;
+ }
+
+ public CopyOperationBuilder CompareSize()
+ {
+ _comparedProperties |= FileCompareProperties.Size;
+ return this;
+ }
+
+ public CopyOperationBuilder CompareModifiedTime(TimeSpan? allowedTimeDiff = null)
+ {
+ _comparedProperties |= FileCompareProperties.ModifiedTime;
+ _allowedTimeDiff = allowedTimeDiff;
+ return this;
+ }
+
+ public CopyOperationBuilder CompareAttributes(FileAttributes? attributes = null)
+ {
+ _comparedProperties |= FileCompareProperties.Attributes;
+ _comparedAttributes = attributes;
+ return this;
+ }
+
+ public CopyOperationBuilder CompareContent()
+ {
+ _comparedProperties |= FileCompareProperties.Content;
+ return this;
+ }
+
+ internal CopyOperationBuilder CompareFile(Func comparer)
+ {
+ _compareFile = comparer;
+ return this;
+ }
+
+ internal CopyOperationBuilder CompareDirectory(Func comparer)
+ {
+ _compareDirectory = comparer;
+ return this;
+ }
+
+ public CopyOperationBuilder Flat()
+ {
+ _flat = true;
+ return this;
+ }
+
+ public CopyOperationBuilder DryRun()
+ {
+ _dryRun = true;
+ return this;
+ }
+
+ public CopyOperationBuilder LogOperation(Action logOperation)
+ {
+ _logOperation = logOperation;
+ return this;
+ }
+
+ public CopyOperationBuilder WithDialogProvider(IDialogProvider dialogProvider)
+ {
+ _dialogProvider = dialogProvider;
+ return this;
+ }
+
+ internal CopyOptions CreateOptions()
+ {
+ return new CopyOptions()
+ {
+ ConflictResolution = _conflictResolution,
+ ComparedProperties = _comparedProperties,
+ ComparedAttributes = _comparedAttributes,
+ AllowedTimeDiff = _allowedTimeDiff,
+ Flat = _flat,
+ DryRun = _dryRun,
+ LogOperation = _logOperation,
+ DialogProvider = _dialogProvider,
+ CompareFile = _compareFile,
+ CompareDirectory = _compareDirectory,
+ };
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/DeleteOperation.cs b/src/FileSystem/FileSystem/Fluent/DeleteOperation.cs
new file mode 100644
index 00000000..47042259
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/DeleteOperation.cs
@@ -0,0 +1,46 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class DeleteOperation
+{
+ internal DeleteOperation(Search search, DeleteOptions options)
+ {
+ Search = search ?? throw new ArgumentNullException(nameof(search));
+ Options = options ?? throw new ArgumentNullException(nameof(options));
+ }
+
+ public Search Search { get; }
+
+ public DeleteOptions Options { get; }
+
+ public IOperationResult Run(string directoryPath, CancellationToken cancellationToken = default)
+ {
+ if (directoryPath is null)
+ throw new ArgumentNullException(nameof(directoryPath));
+
+ return Search.Delete(directoryPath, Options, cancellationToken);
+ }
+
+ public IOperationResult Run(IEnumerable directoryPaths, CancellationToken cancellationToken = default)
+ {
+ if (directoryPaths is null)
+ throw new ArgumentNullException(nameof(directoryPaths));
+
+ var telemetry = new SearchTelemetry();
+
+ foreach (string directoryPath in directoryPaths)
+ {
+ IOperationResult result = Search.Delete(directoryPath, Options, cancellationToken);
+ telemetry.Add(result.Telemetry);
+ }
+
+ return new OperationResult(telemetry);
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/DeleteOperationBuilder.cs b/src/FileSystem/FileSystem/Fluent/DeleteOperationBuilder.cs
new file mode 100644
index 00000000..2df19c4a
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/DeleteOperationBuilder.cs
@@ -0,0 +1,54 @@
+// 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.
+
+using System;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class DeleteOperationBuilder
+{
+ private bool _contentOnly;
+ private bool _includingBom;
+ private bool _dryRun;
+ private Action? _logOperation;
+
+ internal DeleteOperationBuilder()
+ {
+ }
+
+ public DeleteOperationBuilder ContentOnly()
+ {
+ _contentOnly = true;
+ return this;
+ }
+
+ public DeleteOperationBuilder IncludingBom()
+ {
+ _includingBom = true;
+ return this;
+ }
+
+ public DeleteOperationBuilder DryRun()
+ {
+ _dryRun = true;
+ return this;
+ }
+
+ public DeleteOperationBuilder LogOperation(Action logOperation)
+ {
+ _logOperation = logOperation;
+ return this;
+ }
+
+ internal DeleteOptions CreateOptions()
+ {
+ return new DeleteOptions()
+ {
+ ContentOnly = _contentOnly,
+ IncludingBom = _includingBom,
+ DryRun = _dryRun,
+ LogOperation = _logOperation
+ };
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/DirectoryMatcherBuilder.cs b/src/FileSystem/FileSystem/Fluent/DirectoryMatcherBuilder.cs
new file mode 100644
index 00000000..733358fc
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/DirectoryMatcherBuilder.cs
@@ -0,0 +1,81 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Text.RegularExpressions;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class DirectoryMatcherBuilder
+{
+ private Matcher? _name;
+ private FileNamePart? _namePart;
+ private FileAttributes? _attributes;
+ private FileAttributes? _attributesToSkip;
+ private FileEmptyOption? _emptyOption;
+
+ internal DirectoryMatcherBuilder()
+ {
+ }
+
+ public DirectoryMatcherBuilder Name(
+ string pattern,
+ RegexOptions options = RegexOptions.None,
+ bool invert = false,
+ object? group = null,
+ Func? predicate = null)
+ {
+ _name = new Matcher(pattern, options, invert, group, predicate);
+
+ return this;
+ }
+
+ public DirectoryMatcherBuilder NamePart(FileNamePart namePart)
+ {
+ _namePart = namePart;
+
+ return this;
+ }
+
+ public DirectoryMatcherBuilder WithAttributes(FileAttributes attributes)
+ {
+ _attributes = attributes;
+
+ return this;
+ }
+
+ public DirectoryMatcherBuilder WithoutAttributes(FileAttributes attributes)
+ {
+ _attributesToSkip = attributes;
+
+ return this;
+ }
+
+ public DirectoryMatcherBuilder Empty()
+ {
+ _emptyOption = FileEmptyOption.Empty;
+
+ return this;
+ }
+
+ public DirectoryMatcherBuilder NonEmpty()
+ {
+ _emptyOption = FileEmptyOption.NonEmpty;
+
+ return this;
+ }
+
+ internal DirectoryMatcher Build()
+ {
+ return new DirectoryMatcher()
+ {
+ Name = _name,
+ NamePart = _namePart ?? FileNamePart.Name,
+ WithAttributes = _attributes ?? 0,
+ WithoutAttributes = _attributesToSkip ?? 0,
+ EmptyOption = _emptyOption ?? FileEmptyOption.None,
+ };
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/FileMatcherBuilder.cs b/src/FileSystem/FileSystem/Fluent/FileMatcherBuilder.cs
new file mode 100644
index 00000000..e43e8375
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/FileMatcherBuilder.cs
@@ -0,0 +1,149 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Text.RegularExpressions;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class FileMatcherBuilder
+{
+ private Matcher? _name;
+ private FileNamePart? _namePart;
+ private Matcher? _content;
+ private static Matcher? _extension;
+ private FileAttributes? _withAttributes;
+ private FileAttributes? _withoutAttributes;
+ private FileEmptyOption? _emptyOption;
+
+ internal FileMatcherBuilder()
+ {
+ }
+
+ public FileMatcherBuilder Extension(
+ string pattern,
+ RegexOptions options = RegexOptions.None,
+ bool invert = false,
+ object? group = null,
+ Func? predicate = null)
+ {
+ _extension = new Matcher(pattern, options, invert, group, predicate);
+
+ return this;
+ }
+
+ public FileMatcherBuilder WithExtensions(params string[] extensions)
+ {
+ _extension = GetExtensionMatcher(extensions, invert: false);
+
+ return this;
+ }
+
+ public FileMatcherBuilder WithoutExtensions(params string[] extensions)
+ {
+ _extension = GetExtensionMatcher(extensions, invert: true);
+
+ return this;
+ }
+
+ private static Matcher? GetExtensionMatcher(string[] extensions, bool invert)
+ {
+ if (extensions.Length == 0)
+ {
+ return null;
+ }
+ else if (extensions.Length == 1)
+ {
+ return new Matcher(
+ Pattern.Create(
+ extensions[0],
+ PatternOptions.Equals | PatternOptions.Literal),
+ (FileSystemUtilities.IsCaseSensitive) ? RegexOptions.None : RegexOptions.IgnoreCase,
+ invert: invert);
+ }
+ else
+ {
+ return new Matcher(
+ Pattern.Any(
+ extensions,
+ PatternOptions.Equals | PatternOptions.Literal),
+ (FileSystemUtilities.IsCaseSensitive) ? RegexOptions.None : RegexOptions.IgnoreCase,
+ invert: invert);
+ }
+ }
+
+ public FileMatcherBuilder Name(
+ string pattern,
+ RegexOptions options = RegexOptions.None,
+ bool invert = false,
+ object? group = null,
+ Func? predicate = null)
+ {
+ _name = new Matcher(pattern, options, invert, group, predicate);
+
+ return this;
+ }
+
+ public FileMatcherBuilder NamePart(FileNamePart namePart)
+ {
+ _namePart = namePart;
+
+ return this;
+ }
+
+ public FileMatcherBuilder Content(
+ string pattern,
+ RegexOptions options = RegexOptions.None,
+ bool invert = false,
+ object? group = null,
+ Func? predicate = null)
+ {
+ _content = new Matcher(pattern, options, invert, group, predicate);
+
+ return this;
+ }
+
+ public FileMatcherBuilder WithAttributes(FileAttributes attributes)
+ {
+ _withAttributes = attributes;
+
+ return this;
+ }
+
+ public FileMatcherBuilder WithoutAttributes(FileAttributes attributes)
+ {
+ _withoutAttributes = attributes;
+
+ return this;
+ }
+
+ public FileMatcherBuilder Empty()
+ {
+ _emptyOption = FileEmptyOption.Empty;
+
+ return this;
+ }
+
+ public FileMatcherBuilder NonEmpty()
+ {
+ _emptyOption = FileEmptyOption.NonEmpty;
+
+ return this;
+ }
+
+ internal FileMatcher Build()
+ {
+ return new FileMatcher()
+ {
+ Name = _name,
+ NamePart = _namePart ?? FileNamePart.Name,
+ Extension = _extension,
+ Content = _content,
+ WithAttributes = _withAttributes ?? 0,
+ WithoutAttributes = _withoutAttributes ?? 0,
+ EmptyOption = _emptyOption ?? FileEmptyOption.None,
+ };
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/MoveOperation.cs b/src/FileSystem/FileSystem/Fluent/MoveOperation.cs
new file mode 100644
index 00000000..0a72eb2a
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/MoveOperation.cs
@@ -0,0 +1,32 @@
+// 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.
+
+using System;
+using System.Threading;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class MoveOperation
+{
+ internal MoveOperation(Search search, CopyOptions options)
+ {
+ Search = search ?? throw new ArgumentNullException(nameof(search));
+ Options = options ?? throw new ArgumentNullException(nameof(options));
+ }
+
+ public Search Search { get; }
+
+ public CopyOptions Options { get; }
+
+ public IOperationResult Run(string directoryPath, string destinationPath, CancellationToken cancellationToken = default)
+ {
+ if (directoryPath is null)
+ throw new ArgumentNullException(nameof(directoryPath));
+
+ if (destinationPath is null)
+ throw new ArgumentNullException(nameof(destinationPath));
+
+ return Search.Move(directoryPath, destinationPath, Options, cancellationToken);
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/MoveOperationBuilder.cs b/src/FileSystem/FileSystem/Fluent/MoveOperationBuilder.cs
new file mode 100644
index 00000000..15c97ca4
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/MoveOperationBuilder.cs
@@ -0,0 +1,111 @@
+// 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.
+
+using System;
+using System.IO;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class MoveOperationBuilder
+{
+ private ConflictResolution _conflictResolution = ConflictResolution.Skip;
+ private bool _dryRun;
+ private bool _flat;
+ private Action? _logOperation;
+ private FileCompareProperties _comparedProperties;
+ private FileAttributes? _comparedAttributes;
+ private TimeSpan? _allowedTimeDiff;
+ private IDialogProvider? _dialogProvider;
+ private Func? _compareFile;
+ private Func? _compareDirectory;
+
+ internal MoveOperationBuilder()
+ {
+ }
+
+ public MoveOperationBuilder WithConflictResolution(ConflictResolution conflictResolution)
+ {
+ _conflictResolution = conflictResolution;
+ return this;
+ }
+
+ public MoveOperationBuilder CompareSize()
+ {
+ _comparedProperties |= FileCompareProperties.Size;
+ return this;
+ }
+
+ public MoveOperationBuilder CompareModifiedTime(TimeSpan? allowedTimeDiff = null)
+ {
+ _comparedProperties |= FileCompareProperties.ModifiedTime;
+ _allowedTimeDiff = allowedTimeDiff;
+ return this;
+ }
+
+ public MoveOperationBuilder CompareAttributes(FileAttributes? attributes = null)
+ {
+ _comparedProperties |= FileCompareProperties.Attributes;
+ _comparedAttributes = attributes;
+ return this;
+ }
+
+ public MoveOperationBuilder CompareContent()
+ {
+ _comparedProperties |= FileCompareProperties.Content;
+ return this;
+ }
+
+ internal MoveOperationBuilder CompareFile(Func comparer)
+ {
+ _compareFile = comparer;
+ return this;
+ }
+
+ internal MoveOperationBuilder CompareDirectory(Func comparer)
+ {
+ _compareDirectory = comparer;
+ return this;
+ }
+
+ public MoveOperationBuilder Flat()
+ {
+ _flat = true;
+ return this;
+ }
+
+ public MoveOperationBuilder DryRun()
+ {
+ _dryRun = true;
+ return this;
+ }
+
+ public MoveOperationBuilder LogOperation(Action logOperation)
+ {
+ _logOperation = logOperation;
+ return this;
+ }
+
+ public MoveOperationBuilder WithDialogProvider(IDialogProvider dialogProvider)
+ {
+ _dialogProvider = dialogProvider;
+ return this;
+ }
+
+ internal CopyOptions CreateOptions()
+ {
+ return new CopyOptions()
+ {
+ ConflictResolution = _conflictResolution,
+ ComparedProperties = _comparedProperties,
+ ComparedAttributes = _comparedAttributes,
+ AllowedTimeDiff = _allowedTimeDiff,
+ Flat = _flat,
+ DryRun = _dryRun,
+ LogOperation = _logOperation,
+ DialogProvider = _dialogProvider,
+ CompareFile = _compareFile,
+ CompareDirectory = _compareDirectory,
+ };
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/RenameOperation.cs b/src/FileSystem/FileSystem/Fluent/RenameOperation.cs
new file mode 100644
index 00000000..6b18e7b6
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/RenameOperation.cs
@@ -0,0 +1,77 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Threading;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class RenameOperation
+{
+ internal RenameOperation(Search search, RenameOptions options)
+ {
+ Search = search ?? throw new ArgumentNullException(nameof(search));
+ Options = options ?? throw new ArgumentNullException(nameof(options));
+ }
+
+ public Search Search { get; }
+
+ public RenameOptions Options { get; }
+
+ public IOperationResult Run(string directoryPath, string? replacement = null, CancellationToken cancellationToken = default)
+ {
+ if (directoryPath is null)
+ throw new ArgumentNullException(nameof(directoryPath));
+
+ return Search.Rename(directoryPath, replacement, Options, cancellationToken);
+ }
+
+ public IOperationResult Run(string directoryPath, MatchEvaluator matchEvaluator, CancellationToken cancellationToken = default)
+ {
+ if (directoryPath is null)
+ throw new ArgumentNullException(nameof(directoryPath));
+
+ return Search.Rename(directoryPath, matchEvaluator, Options, cancellationToken);
+ }
+
+ public IOperationResult Run(
+ IEnumerable directoryPaths,
+ string? replacement = null,
+ CancellationToken cancellationToken = default)
+ {
+ if (directoryPaths is null)
+ throw new ArgumentNullException(nameof(directoryPaths));
+
+ var telemetry = new SearchTelemetry();
+
+ foreach (string directoryPath in directoryPaths)
+ {
+ IOperationResult result = Search.Rename(directoryPath, replacement, Options, cancellationToken);
+ telemetry.Add(result.Telemetry);
+ }
+
+ return new OperationResult(telemetry);
+ }
+
+ public IOperationResult Run(
+ IEnumerable directoryPaths,
+ MatchEvaluator matchEvaluator,
+ CancellationToken cancellationToken = default)
+ {
+ if (directoryPaths is null)
+ throw new ArgumentNullException(nameof(directoryPaths));
+
+ var telemetry = new SearchTelemetry();
+
+ foreach (string directoryPath in directoryPaths)
+ {
+ IOperationResult result = Search.Rename(directoryPath, matchEvaluator, Options, cancellationToken);
+ telemetry.Add(result.Telemetry);
+ }
+
+ return new OperationResult(telemetry);
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/RenameOperationBuilder.cs b/src/FileSystem/FileSystem/Fluent/RenameOperationBuilder.cs
new file mode 100644
index 00000000..039f9031
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/RenameOperationBuilder.cs
@@ -0,0 +1,70 @@
+// 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.
+
+using System;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class RenameOperationBuilder
+{
+ private ReplaceFunctions _functions;
+ private bool _cultureInvariant;
+ private bool _dryRun;
+ private Action? _logOperation;
+ private IDialogProvider? _dialogProvider;
+ private ConflictResolution _conflictResolution = ConflictResolution.Skip;
+
+ internal RenameOperationBuilder()
+ {
+ }
+
+ internal RenameOperationBuilder WithFunctions(ReplaceFunctions functions)
+ {
+ _functions = functions;
+ return this;
+ }
+
+ public RenameOperationBuilder CultureInvariant()
+ {
+ _cultureInvariant = true;
+ return this;
+ }
+
+ public RenameOperationBuilder DryRun()
+ {
+ _dryRun = true;
+ return this;
+ }
+
+ public RenameOperationBuilder LogOperation(Action logOperation)
+ {
+ _logOperation = logOperation;
+ return this;
+ }
+
+ public RenameOperationBuilder WithDialogProvider(IDialogProvider dialogProvider)
+ {
+ _dialogProvider = dialogProvider;
+ return this;
+ }
+
+ public RenameOperationBuilder WithConflictResolution(ConflictResolution conflictResolution)
+ {
+ _conflictResolution = conflictResolution;
+ return this;
+ }
+
+ internal RenameOptions CreateOptions()
+ {
+ return new RenameOptions()
+ {
+ ReplaceFunctions = _functions,
+ CultureInvariant = _cultureInvariant,
+ DryRun = _dryRun,
+ LogOperation = _logOperation,
+ DialogProvider = _dialogProvider,
+ ConflictResolution = _conflictResolution,
+ };
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/ReplaceOperation.cs b/src/FileSystem/FileSystem/Fluent/ReplaceOperation.cs
new file mode 100644
index 00000000..96409580
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/ReplaceOperation.cs
@@ -0,0 +1,83 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Threading;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class ReplaceOperation
+{
+ internal ReplaceOperation(Search search, ReplaceOptions options)
+ {
+ Search = search ?? throw new ArgumentNullException(nameof(search));
+ Options = options ?? throw new ArgumentNullException(nameof(options));
+ }
+
+ public Search Search { get; }
+
+ public ReplaceOptions Options { get; }
+
+ public IOperationResult Run(string directoryPath, string? replacement = null, CancellationToken cancellationToken = default)
+ {
+ if (directoryPath is null)
+ throw new ArgumentNullException(nameof(directoryPath));
+
+ return Search.Replace(directoryPath, replacement, Options, cancellationToken);
+ }
+
+ public IOperationResult Run(string directoryPath, MatchEvaluator matchEvaluator, CancellationToken cancellationToken = default)
+ {
+ if (directoryPath is null)
+ throw new ArgumentNullException(nameof(directoryPath));
+
+ if (matchEvaluator is null)
+ throw new ArgumentNullException(nameof(matchEvaluator));
+
+ return Search.Replace(directoryPath, matchEvaluator, Options, cancellationToken);
+ }
+
+ public IOperationResult Run(
+ IEnumerable directoryPaths,
+ string? replacement = null,
+ CancellationToken cancellationToken = default)
+ {
+ if (directoryPaths is null)
+ throw new ArgumentNullException(nameof(directoryPaths));
+
+ var telemetry = new SearchTelemetry();
+
+ foreach (string directoryPath in directoryPaths)
+ {
+ IOperationResult result = Search.Replace(directoryPath, replacement, Options, cancellationToken);
+ telemetry.Add(result.Telemetry);
+ }
+
+ return new OperationResult(telemetry);
+ }
+
+ public IOperationResult Run(
+ IEnumerable directoryPaths,
+ MatchEvaluator matchEvaluator,
+ CancellationToken cancellationToken = default)
+ {
+ if (directoryPaths is null)
+ throw new ArgumentNullException(nameof(directoryPaths));
+
+ if (matchEvaluator is null)
+ throw new ArgumentNullException(nameof(matchEvaluator));
+
+ var telemetry = new SearchTelemetry();
+
+ foreach (string directoryPath in directoryPaths)
+ {
+ IOperationResult result = Search.Replace(directoryPath, matchEvaluator, Options, cancellationToken);
+ telemetry.Add(result.Telemetry);
+ }
+
+ return new OperationResult(telemetry);
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/ReplaceOperationBuilder.cs b/src/FileSystem/FileSystem/Fluent/ReplaceOperationBuilder.cs
new file mode 100644
index 00000000..7aafd1f8
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/ReplaceOperationBuilder.cs
@@ -0,0 +1,54 @@
+// 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.
+
+using System;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class ReplaceOperationBuilder
+{
+ private ReplaceFunctions _functions;
+ private bool _cultureInvariant;
+ private bool _dryRun;
+ private Action? _logOperation;
+
+ internal ReplaceOperationBuilder()
+ {
+ }
+
+ internal ReplaceOperationBuilder WithFunctions(ReplaceFunctions functions)
+ {
+ _functions = functions;
+ return this;
+ }
+
+ public ReplaceOperationBuilder CultureInvariant()
+ {
+ _cultureInvariant = true;
+ return this;
+ }
+
+ public ReplaceOperationBuilder DryRun()
+ {
+ _dryRun = true;
+ return this;
+ }
+
+ public ReplaceOperationBuilder LogOperation(Action logOperation)
+ {
+ _logOperation = logOperation;
+ return this;
+ }
+
+ internal ReplaceOptions CreateOptions()
+ {
+ return new ReplaceOptions()
+ {
+ ReplaceFunctions = _functions,
+ CultureInvariant = _cultureInvariant,
+ DryRun = _dryRun,
+ LogOperation = _logOperation,
+ };
+ }
+}
diff --git a/src/FileSystem/FileSystem/Fluent/SearchBuilder.cs b/src/FileSystem/FileSystem/Fluent/SearchBuilder.cs
new file mode 100644
index 00000000..3d7a47af
--- /dev/null
+++ b/src/FileSystem/FileSystem/Fluent/SearchBuilder.cs
@@ -0,0 +1,262 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading;
+
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+namespace Orang.FileSystem.Fluent;
+
+public class SearchBuilder
+{
+ private FileMatcher? _file;
+ private DirectoryMatcher? _directory;
+ private DirectoryMatcher? _searchDirectory;
+
+ private bool _topDirectoryOnly;
+ private Action? _logProgress;
+ private Encoding? _defaultEncoding;
+
+ public SearchBuilder MatchFile(Action configure)
+ {
+ var builder = new FileMatcherBuilder();
+
+ configure(builder);
+
+ _file = builder.Build();
+
+ return this;
+ }
+
+ public SearchBuilder MatchDirectory(Action configure)
+ {
+ var builder = new DirectoryMatcherBuilder();
+
+ configure(builder);
+
+ _directory = builder.Build();
+
+ return this;
+ }
+
+ public SearchBuilder SearchDirectory(Action configure)
+ {
+ var builder = new DirectoryMatcherBuilder();
+
+ configure(builder);
+
+ _searchDirectory = builder.Build();
+
+ return this;
+ }
+
+ public SearchBuilder SkipDirectory(
+ string pattern,
+ RegexOptions options = RegexOptions.None,
+ object? group = null,
+ Func? predicate = null)
+ {
+ _searchDirectory = new DirectoryMatcher()
+ {
+ Name = new Matcher(pattern, options, invert: true, group, predicate)
+ };
+
+ return this;
+ }
+
+ public SearchBuilder FileExtension(
+ string pattern,
+ RegexOptions options = RegexOptions.None,
+ bool invert = false,
+ object? group = null,
+ Func? predicate = null)
+ {
+ if (_file is null)
+ _file = new FileMatcher();
+
+ _file.Extension = new Matcher(pattern, options, invert, group, predicate);
+
+ return this;
+ }
+
+ public SearchBuilder FileName(
+ string pattern,
+ RegexOptions options = RegexOptions.None,
+ bool invert = false,
+ object? group = null,
+ Func? predicate = null)
+ {
+ if (_file is null)
+ _file = new FileMatcher();
+
+ _file.Name = new Matcher(pattern, options, invert, group, predicate);
+
+ return this;
+ }
+
+ public SearchBuilder FileContent(
+ string pattern,
+ RegexOptions options = RegexOptions.None,
+ bool invert = false,
+ object? group = null,
+ Func? predicate = null)
+ {
+ if (_file is null)
+ _file = new FileMatcher();
+
+ _file.Name = new Matcher(pattern, options, invert, group, predicate);
+
+ return this;
+ }
+
+ public SearchBuilder DirectoryName(
+ string pattern,
+ RegexOptions options = RegexOptions.None,
+ bool invert = false,
+ object? group = null,
+ Func? predicate = null)
+ {
+ if (_directory is null)
+ _directory = new DirectoryMatcher();
+
+ _directory.Name = new Matcher(pattern, options, invert, group, predicate);
+
+ return this;
+ }
+
+ public SearchBuilder TopDirectoryOnly()
+ {
+ _topDirectoryOnly = true;
+
+ return this;
+ }
+
+ public SearchBuilder LogProgress(Action logProgress)
+ {
+ _logProgress = logProgress;
+
+ return this;
+ }
+
+ public SearchBuilder WithDefaultEncoding(Encoding encoding)
+ {
+ _defaultEncoding = encoding;
+
+ return this;
+ }
+
+ public Search ToSearch()
+ {
+ var options = new SearchOptions()
+ {
+ SearchDirectory = _searchDirectory,
+ LogProgress = _logProgress,
+ TopDirectoryOnly = _topDirectoryOnly,
+ DefaultEncoding = _defaultEncoding,
+ };
+
+ FileMatcher? fileMatcher = _file;
+ DirectoryMatcher? directoryMatcher = _directory;
+
+ if (fileMatcher is not null)
+ {
+ return (directoryMatcher is not null)
+ ? new Search(fileMatcher, directoryMatcher, options)
+ : new Search(fileMatcher, options);
+ }
+ else if (directoryMatcher is not null)
+ {
+ return new Search(directoryMatcher, options);
+ }
+ else
+ {
+ throw new InvalidOperationException("File matcher or directory matcher must be specified.");
+ }
+ }
+
+ public IEnumerable Matches(
+ string directoryPath,
+ CancellationToken cancellationToken = default)
+ {
+ return ToSearch().Matches(directoryPath, cancellationToken);
+ }
+
+ public IEnumerable Matches(
+ IEnumerable directoryPaths,
+ CancellationToken cancellationToken = default)
+ {
+ if (directoryPaths is null)
+ throw new ArgumentNullException(nameof(directoryPaths));
+
+ return Matches();
+
+ IEnumerable Matches()
+ {
+ Search search = ToSearch();
+
+ foreach (string directoryPath in directoryPaths)
+ {
+ foreach (FileMatch fileMatch in search.Matches(directoryPath, cancellationToken))
+ yield return fileMatch;
+ }
+ }
+ }
+
+ public DeleteOperation Delete(Action configure)
+ {
+ if (configure is null)
+ throw new ArgumentNullException(nameof(configure));
+
+ var deleteBuilder = new DeleteOperationBuilder();
+ configure(deleteBuilder);
+
+ return new DeleteOperation(ToSearch(), deleteBuilder.CreateOptions());
+ }
+
+ public CopyOperation Copy(Action configure)
+ {
+ if (configure is null)
+ throw new ArgumentNullException(nameof(configure));
+
+ var copyBuilder = new CopyOperationBuilder();
+ configure(copyBuilder);
+
+ return new CopyOperation(ToSearch(), copyBuilder.CreateOptions());
+ }
+
+ public MoveOperation Move(Action configure)
+ {
+ if (configure is null)
+ throw new ArgumentNullException(nameof(configure));
+
+ var moveBuilder = new MoveOperationBuilder();
+ configure(moveBuilder);
+
+ return new MoveOperation(ToSearch(), moveBuilder.CreateOptions());
+ }
+
+ public RenameOperation Rename(Action configure)
+ {
+ if (configure is null)
+ throw new ArgumentNullException(nameof(configure));
+
+ var renameBuilder = new RenameOperationBuilder();
+ configure(renameBuilder);
+
+ return new RenameOperation(ToSearch(), renameBuilder.CreateOptions());
+ }
+
+ public ReplaceOperation Replace(Action configure)
+ {
+ if (configure is null)
+ throw new ArgumentNullException(nameof(configure));
+
+ var replaceBuilder = new ReplaceOperationBuilder();
+ configure(replaceBuilder);
+
+ return new ReplaceOperation(ToSearch(), replaceBuilder.CreateOptions());
+ }
+}
diff --git a/src/FileSystem/FileSystem/IOperationResult.cs b/src/FileSystem/FileSystem/IOperationResult.cs
new file mode 100644
index 00000000..abb16662
--- /dev/null
+++ b/src/FileSystem/FileSystem/IOperationResult.cs
@@ -0,0 +1,8 @@
+// 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.
+
+namespace Orang.FileSystem;
+
+public interface IOperationResult
+{
+ SearchTelemetry Telemetry { get; }
+}
diff --git a/src/FileSystem/FileSystem/NameFilter.cs b/src/FileSystem/FileSystem/NameFilter.cs
deleted file mode 100644
index 40dee0f4..00000000
--- a/src/FileSystem/FileSystem/NameFilter.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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.
-
-using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Text.RegularExpressions;
-using Orang.Text.RegularExpressions;
-
-namespace Orang.FileSystem;
-
-//TODO: NameFilter : Filter
-[DebuggerDisplay("{DebuggerDisplay,nq}")]
-public class NameFilter
-{
- public NameFilter(
- Filter name,
- FileNamePart part = FileNamePart.Name)
- {
- Name = name ?? throw new ArgumentNullException(nameof(name));
- Part = part;
- }
-
- public Filter Name { get; }
-
- public FileNamePart Part { get; }
-
- public bool IsNegative => Name.IsNegative;
-
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- private string DebuggerDisplay => $"{Part} {Name}";
-
- internal static NameFilter CreateFromDirectoryPath(string path, bool isNegative = false)
- {
- string pattern = RegexEscape.Escape(path);
-
- var options = RegexOptions.ExplicitCapture;
-
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- pattern = Regex.Replace(pattern, @"(/|\\\\)", @"(/|\\)", options);
-
- pattern = $@"\A{pattern}(?=(/";
-
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- pattern += @"|\\)";
- }
- else
- {
- pattern += ")";
- }
-
- pattern += @"|\z)";
-
- if (!FileSystemHelpers.IsCaseSensitive)
- options |= RegexOptions.IgnoreCase;
-
- var filter = new Filter(pattern, options, isNegative: isNegative);
-
- return new NameFilter(filter, FileNamePart.FullName);
- }
-}
diff --git a/src/FileSystem/FileSystem/OperationKind.cs b/src/FileSystem/FileSystem/OperationKind.cs
index e589334b..cbb8a163 100644
--- a/src/FileSystem/FileSystem/OperationKind.cs
+++ b/src/FileSystem/FileSystem/OperationKind.cs
@@ -2,11 +2,12 @@
namespace Orang.FileSystem;
-public enum OperationKind : byte
+internal enum OperationKind : byte
{
- Replace = 0,
- Rename = 1,
- Delete = 2,
- Copy = 3,
- Move = 4,
+ None,
+ Copy,
+ Delete,
+ Move,
+ Rename,
+ Replace,
}
diff --git a/src/FileSystem/FileSystem/OperationProgress.cs b/src/FileSystem/FileSystem/OperationProgress.cs
index 13907c82..0ba2ddea 100644
--- a/src/FileSystem/FileSystem/OperationProgress.cs
+++ b/src/FileSystem/FileSystem/OperationProgress.cs
@@ -8,27 +8,29 @@ namespace Orang.FileSystem;
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public readonly struct OperationProgress
{
- internal OperationProgress(FileMatch fileMatch, OperationKind kind, Exception? exception = null)
- : this(fileMatch, null, kind, exception)
+ internal OperationProgress(FileMatch match, OperationKind kind, Exception? exception = null)
+ : this(match, null, kind, exception)
{
}
- internal OperationProgress(FileMatch fileMatch, string? newPath, OperationKind kind, Exception? exception = null)
+ internal OperationProgress(FileMatch match, string? newPath, OperationKind kind, Exception? exception = null)
{
- FileMatch = fileMatch;
+ Match = match;
NewPath = newPath;
Kind = kind;
Exception = exception;
}
- public FileMatch FileMatch { get; }
+ public FileMatch Match { get; }
+
+ public string Path => Match.Path;
public string? NewPath { get; }
- public OperationKind Kind { get; }
+ internal OperationKind Kind { get; }
public Exception? Exception { get; }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
- private string DebuggerDisplay => (FileMatch is not null) ? $"{Kind} {FileMatch.Path}" : "Uninitialized";
+ private string DebuggerDisplay => (Match is not null) ? $"{Kind} {Match.Path}" : "Uninitialized";
}
diff --git a/src/FileSystem/FileSystem/OperationResult.cs b/src/FileSystem/FileSystem/OperationResult.cs
new file mode 100644
index 00000000..51eeff5f
--- /dev/null
+++ b/src/FileSystem/FileSystem/OperationResult.cs
@@ -0,0 +1,13 @@
+// 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.
+
+namespace Orang.FileSystem;
+
+internal class OperationResult : IOperationResult
+{
+ public OperationResult(SearchTelemetry telemetry)
+ {
+ Telemetry = telemetry;
+ }
+
+ public SearchTelemetry Telemetry { get; }
+}
diff --git a/src/FileSystem/FileSystem/RenameOptions.cs b/src/FileSystem/FileSystem/RenameOptions.cs
index 8d88baab..21f51a27 100644
--- a/src/FileSystem/FileSystem/RenameOptions.cs
+++ b/src/FileSystem/FileSystem/RenameOptions.cs
@@ -1,30 +1,22 @@
// 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.
-using System.Text.RegularExpressions;
+using System;
namespace Orang.FileSystem;
-public class RenameOptions : ReplaceOptions
+#pragma warning disable RCS1223 // Mark publicly visible type with DebuggerDisplay attribute.
+
+public class RenameOptions
{
- public RenameOptions(
- string replacement,
- ReplaceFunctions functions = ReplaceFunctions.None,
- bool cultureInvariant = false,
- ConflictResolution conflictResolution = ConflictResolution.Skip)
- : base(replacement, functions, cultureInvariant)
- {
- ConflictResolution = conflictResolution;
- }
-
- public RenameOptions(
- MatchEvaluator matchEvaluator,
- ReplaceFunctions functions = ReplaceFunctions.None,
- bool cultureInvariant = false,
- ConflictResolution conflictResolution = ConflictResolution.Skip)
- : base(matchEvaluator, functions, cultureInvariant)
- {
- ConflictResolution = conflictResolution;
- }
-
- public ConflictResolution ConflictResolution { get; }
+ internal ReplaceFunctions ReplaceFunctions { get; set; }
+
+ public bool CultureInvariant { get; set; }
+
+ public bool DryRun { get; set; }
+
+ public Action? LogOperation { get; set; }
+
+ public IDialogProvider? DialogProvider { get; set; }
+
+ public ConflictResolution ConflictResolution { get; set; } = ConflictResolution.Skip;
}
diff --git a/src/FileSystem/FileSystem/ReplaceHelpers.cs b/src/FileSystem/FileSystem/ReplaceHelpers.cs
deleted file mode 100644
index f2bb5617..00000000
--- a/src/FileSystem/FileSystem/ReplaceHelpers.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-// 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.
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using Orang.Text.RegularExpressions;
-
-namespace Orang.FileSystem;
-
-internal static class ReplaceHelpers
-{
- public static List GetReplaceItems(
- Match match,
- ReplaceOptions replaceOptions,
- CancellationToken cancellationToken = default)
- {
- List matches = GetMatches(match);
-
- int offset = 0;
- List replaceItems = ListCache.GetInstance();
-
- if (replaceItems.Capacity < matches.Count)
- replaceItems.Capacity = matches.Count;
-
- foreach (Match match2 in matches)
- {
- string value = replaceOptions.Replace(match2);
-
- replaceItems.Add(new ReplaceItem(match2, value, match2.Index + offset));
-
- offset += value.Length - match2.Length;
-
- cancellationToken.ThrowIfCancellationRequested();
- }
-
- ListCache.Free(matches);
-
- return replaceItems;
-
- static List GetMatches(Match match)
- {
- List matches = ListCache.GetInstance();
-
- do
- {
- matches.Add(match);
-
- match = match.NextMatch();
- }
- while (match.Success);
-
- if (matches.Count > 1
- && matches[0].Index > matches[1].Index)
- {
- matches.Reverse();
- }
-
- return matches;
- }
- }
-
- public static (List