From 01447ad146f7e7f7e77aed7835fadb409694aac0 Mon Sep 17 00:00:00 2001 From: Timothy Bruce Date: Fri, 23 Oct 2026 23:17:02 -0400 Subject: [PATCH 1/3] test(ed): require Expressions provider type --- tests/Ed.Shared.Tests/src/EditorEngineTests.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Ed.Shared.Tests/src/EditorEngineTests.cs b/tests/Ed.Shared.Tests/src/EditorEngineTests.cs index 29e30fd..55122cb 100644 --- a/tests/Ed.Shared.Tests/src/EditorEngineTests.cs +++ b/tests/Ed.Shared.Tests/src/EditorEngineTests.cs @@ -5,6 +5,17 @@ namespace Icod.LineEditor.Ed.Shared.Tests; using Icod.LineEditor.Ed; public sealed class EditorEngineTests { + [Fact] + public void InjectableRegexProviderUsesExpressionsAssembly() { + var constructor = Assert.Single( + typeof( EditorEngine ).GetConstructors().Where( candidate => candidate.GetParameters().Length == 4 ) + ); + Assert.Equal( + "Icod.Expressions", + constructor.GetParameters()[3].ParameterType.Assembly.GetName().Name + ); + } + [Fact] public async Task ExecutesMutationAddressMarkCutAndUndoCommands() { var engine = CreateEngine(); From a874f7c6ce713496e10f9f089495ae3d980f9323 Mon Sep 17 00:00:00 2001 From: Timothy Bruce Date: Fri, 23 Oct 2026 23:21:31 -0400 Subject: [PATCH 2/3] Migrate ed and red GNU regex to Icod.Expressions prerelease --- Directory.Build.props | 7 ++++--- .../Icod.LineEditor.Ed.Shared.csproj | 1 + Icod.LineEditor.Ed.Shared/README.md | 19 ++++++++----------- Icod.LineEditor.Ed.Shared/src/EditorEngine.cs | 10 ++++++---- README.md | 6 ++++-- ed/Icod.LineEditor.Ed.csproj | 1 + ed/README.md | 2 +- ed/src/Command.cs | 4 +++- packaging/README.md | 17 +++++++++-------- packaging/VerifyPackageArtifact.ps1 | 1 + red/Icod.LineEditor.Red.csproj | 1 + red/src/Command.cs | 4 +++- .../Icod.LineEditor.Ed.Shared.Tests.csproj | 1 + .../Ed.Shared.Tests/src/EditorEngineTests.cs | 8 +++++--- .../src/SecurityAndCompatibilityTests.cs | 4 +++- 15 files changed, 51 insertions(+), 35 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 2ee8f3d..649bcfd 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,9 +1,10 @@ - 1.1.1 - $(VersionPrefix) - $(VersionPrefix) + 2.0.0 + alpha.1 + $(VersionPrefix)-$(VersionSuffix) + $(Version) $(VersionPrefix).0 $(VersionPrefix).0 false diff --git a/Icod.LineEditor.Ed.Shared/Icod.LineEditor.Ed.Shared.csproj b/Icod.LineEditor.Ed.Shared/Icod.LineEditor.Ed.Shared.csproj index 12d98b7..19816a0 100644 --- a/Icod.LineEditor.Ed.Shared/Icod.LineEditor.Ed.Shared.csproj +++ b/Icod.LineEditor.Ed.Shared/Icod.LineEditor.Ed.Shared.csproj @@ -16,6 +16,7 @@ + diff --git a/Icod.LineEditor.Ed.Shared/README.md b/Icod.LineEditor.Ed.Shared/README.md index 75e9cc0..8c77af9 100644 --- a/Icod.LineEditor.Ed.Shared/README.md +++ b/Icod.LineEditor.Ed.Shared/README.md @@ -21,19 +21,16 @@ The project deliberately has no runtime reference to `Icod.DiffUtils.Shared`. Co ## Dependency direction -The permanent repository boundary is: +The repository dependency boundary is: -```text -Published neutral foundation - Icod.CommandFramework 2.1.0 - ↓ PackageReference - Icod.LineEditor.Ed.Shared - ↓ ↓ - ed red - ProjectReference -``` +| Project | Dependencies | +|---|---| +| `Icod.LineEditor.Ed.Shared` | `Icod.CommandFramework 2.1.0`, `Icod.Expressions 0.1.0-alpha.1`, `Icod.Processes 1.2.0` | +| `ed`, `red` | The repository-local shared engine and aliased `Icod.Expressions` regex providers | + +The shared engine consumes GNU regular-expression contracts from published `Icod.Expressions 0.1.0-alpha.1`. It continues to consume record, process, temporary-file, filesystem, metadata, traversal, and transactional-replacement contracts from published `Icod.CommandFramework 2.1.0`. The Expressions package currently retains the `Icod.CommandFramework.RegularExpressions` namespace, so source files use an assembly alias to distinguish the types. -The shared engine consumes neutral command-line, record, regular-expression, process, temporary-file, filesystem, metadata, traversal, and transactional-replacement contracts from the published `Icod.CommandFramework` package. +The public `EditorEngine` provider parameter now has `Icod.Expressions` assembly identity. In-process callers injecting a provider must reference that package and update their provider type; this is a source and binary API change in the planned `2.0.0-alpha.1` prerelease. Additional API refactoring may follow before the stable 2.0 release. `ed` and `red` consume this engine through repository-local `ProjectReference` relationships. The library has no source-tree dependency on `Icod.CoreUtils.Shared`. diff --git a/Icod.LineEditor.Ed.Shared/src/EditorEngine.cs b/Icod.LineEditor.Ed.Shared/src/EditorEngine.cs index dbbd7d8..6565e75 100644 --- a/Icod.LineEditor.Ed.Shared/src/EditorEngine.cs +++ b/Icod.LineEditor.Ed.Shared/src/EditorEngine.cs @@ -1,9 +1,11 @@ +extern alias Expressions; + namespace Icod.LineEditor.Ed; using System.Globalization; using System.Text; using Icod.CommandFramework.Records; -using Icod.CommandFramework.RegularExpressions; +using Expressions::Icod.CommandFramework.RegularExpressions; /// /// Executes Ed scripts over a mutable, stable-identity line buffer using injectable regular-expression, @@ -34,7 +36,7 @@ public EditorEngine() : this( /// Initializes an engine from one immutable capability profile. /// The policy and capabilities exposed to the engine. - /// The Shared GNU regular-expression provider. + /// The Icod.Expressions GNU regular-expression provider. public EditorEngine( EditorCapabilityProfile profile, IRegularExpressionProvider regularExpressionProvider @@ -50,7 +52,7 @@ IRegularExpressionProvider regularExpressionProvider /// The immutable parser and dispatch policy. /// The filename-bearing capability. /// The process capability. - /// The Shared GNU BRE provider. + /// The Icod.Expressions GNU BRE provider. public EditorEngine( EditorSecurityPolicy securityPolicy, IEditorFileAccess fileAccess, @@ -71,7 +73,7 @@ IRegularExpressionProvider regularExpressionProvider /// Creates a restricted engine rooted at the supplied working directory. /// The captured working directory. /// The underlying file capability to constrain beneath the captured directory. - /// An optional Shared GNU BRE provider. + /// An optional Icod.Expressions GNU BRE provider. /// The configured engine. public static EditorEngine CreateRestricted( string workingDirectory, diff --git a/README.md b/README.md index 20b0354..6ad9343 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ It calls the managed command implementations directly and does not spawn the sta ## Installation and distribution -The distribution router is published as the .NET tool package `Icod.LineEditor.Tools`. Install version `1.1.1` with: +The last stable distribution router is published as the .NET tool package `Icod.LineEditor.Tools`. Install version `1.1.1` with: ```text dotnet tool install --global Icod.LineEditor.Tools --version 1.1.1 @@ -183,7 +183,9 @@ The solution defines `Debug`, `Staging`, and `Release` configurations. Release b ## Versioning -Repository versioning is centralized in the root [`Directory.Build.props`](Directory.Build.props). `VersionPrefix` is the single authoritative release-version literal and is currently `1.1.1`. `Version`, `PackageVersion`, `AssemblyVersion`, and `FileVersion` are derived from it for projects in the repository. +Repository versioning is centralized in the root [`Directory.Build.props`](Directory.Build.props). This branch prepares the unpublished `2.0.0-alpha.1` prerelease: `VersionPrefix` is `2.0.0`, `VersionSuffix` is `alpha.1`, and the package version combines them. `AssemblyVersion` and `FileVersion` remain numeric `2.0.0.0`. + +The prerelease moves the `ed`/`red` injectable regex provider from the CommandFramework assembly to `Icod.Expressions 0.1.0-alpha.1`. In-process callers of `EditorEngine` must reference `Icod.Expressions` and pass its provider type; this changes source and binary API identity. The command-line interfaces remain the same. Further API refactoring may occur before stable 2.0. `sed` will migrate in a separate change. For a tagged release, the `v` tag must agree with the generated NuGet package version. The release workflow selects packages by their actual nuspec version, so a mismatched tag cannot silently publish a differently versioned package. diff --git a/ed/Icod.LineEditor.Ed.csproj b/ed/Icod.LineEditor.Ed.csproj index 59f62cc..fc7d885 100644 --- a/ed/Icod.LineEditor.Ed.csproj +++ b/ed/Icod.LineEditor.Ed.csproj @@ -18,6 +18,7 @@ + prompt diff --git a/ed/README.md b/ed/README.md index 5864f95..09832e6 100644 --- a/ed/README.md +++ b/ed/README.md @@ -95,7 +95,7 @@ Editor-command errors can interact with `--loose-exit-status` as described above ## PLATFORM NOTES -The project targets .NET 10 with C# 13 and is tested on Windows, Linux, and macOS. Neutral command-line, regular-expression, process, record, filesystem, and transactional-replacement mechanics come from the published `Icod.CommandFramework` package. Mutable Ed-family behavior remains in `Icod.LineEditor.Ed.Shared`. +The project targets .NET 10 with C# 13 and is tested on Windows, Linux, and macOS. GNU regular-expression matching comes from `Icod.Expressions`; neutral command-line, process, record, filesystem, and transactional-replacement mechanics remain in `Icod.CommandFramework`. Mutable Ed-family behavior remains in `Icod.LineEditor.Ed.Shared`. ## AUTHORS diff --git a/ed/src/Command.cs b/ed/src/Command.cs index 2eb29df..2883752 100644 --- a/ed/src/Command.cs +++ b/ed/src/Command.cs @@ -1,3 +1,5 @@ +extern alias Expressions; + namespace Icod.LineEditor.Ed; using System.Globalization; @@ -5,7 +7,7 @@ namespace Icod.LineEditor.Ed; using Icod.CommandFramework.CommandLine; using Icod.CommandFramework.Diagnostics; using Icod.CommandFramework.Records; -using Icod.CommandFramework.RegularExpressions; +using Expressions::Icod.CommandFramework.RegularExpressions; /// /// Implements the GNU-compatible line editor over . diff --git a/packaging/README.md b/packaging/README.md index 8388cde..6a6ddc1 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -54,16 +54,17 @@ The standalone `ed`, `red`, and `sed` commands remain release artifacts through Repository versioning is centralized in the root `Directory.Build.props`: ```xml -1.1.0 +2.0.0 +alpha.1 ``` -`VersionPrefix` is the single authoritative release-version literal. The repository derives: +`VersionPrefix` and `VersionSuffix` prepare the prerelease. The repository derives: ```text -Version = 1.1.0 -PackageVersion = 1.1.0 -AssemblyVersion = 1.1.0.0 -FileVersion = 1.1.0.0 +Version = 2.0.0-alpha.1 +PackageVersion = 2.0.0-alpha.1 +AssemblyVersion = 2.0.0.0 +FileVersion = 2.0.0.0 ``` Production projects inherit these values unless a future project has an explicit reason to override them. Release tags must agree with the generated package version; `SelectReleasePackages.ps1` verifies the actual nuspec version before publication. @@ -211,9 +212,9 @@ That `README.md` is sourced from the repository root and packed at the NuGet pac Before pushing release tag `v1.1.0`: -1. confirm `Directory.Build.props` still declares `VersionPrefix` `1.1.0`; +1. confirm `Directory.Build.props` declares `VersionPrefix` `2.0.0` and `VersionSuffix` `alpha.1`; 2. confirm solution-wide pack produces only `Icod.LineEditor.Tools.1.1.0.nupkg`; -3. confirm `lineeditor --version` reports `1.1.0` from assembly informational version metadata; +3. confirm `lineeditor --version` reports `2.0.0-alpha.1` from assembly informational version metadata; 4. confirm the root README installation example and package identity are current; 5. confirm PR Staging validation is green; 6. merge to `main` and require the six-runner Release validation to pass; and diff --git a/packaging/VerifyPackageArtifact.ps1 b/packaging/VerifyPackageArtifact.ps1 index 2ff4d30..c852567 100644 --- a/packaging/VerifyPackageArtifact.ps1 +++ b/packaging/VerifyPackageArtifact.ps1 @@ -13,6 +13,7 @@ foreach($package in $packages){ $archive=[System.IO.Compression.ZipFile]::OpenRead($package.FullName) try{ if(-not [string]::IsNullOrWhiteSpace($metadata.Readme) -and $null -eq ($archive.Entries|Where-Object{$_.FullName -eq $metadata.Readme}|Select-Object -First 1)){throw "Package '$($package.Name)' declares a missing readme."} + if('Icod.LineEditor.Tools' -eq $metadata.Id -and $null -eq $archive.GetEntry('tools/net10.0/any/Icod.Expressions.dll')){throw "Package '$($package.Name)' is missing the Icod.Expressions runtime assembly."} }finally{$archive.Dispose()} } if(-not [string]::IsNullOrWhiteSpace($GitHubOutputPath)){"package_count=$($packages.Count)" >> $GitHubOutputPath;"has_packages=$((0 -lt $packages.Count).ToString().ToLowerInvariant())" >> $GitHubOutputPath} diff --git a/red/Icod.LineEditor.Red.csproj b/red/Icod.LineEditor.Red.csproj index 3da5a72..7f07c0b 100644 --- a/red/Icod.LineEditor.Red.csproj +++ b/red/Icod.LineEditor.Red.csproj @@ -18,6 +18,7 @@ + prompt diff --git a/red/src/Command.cs b/red/src/Command.cs index c163bda..66999b5 100644 --- a/red/src/Command.cs +++ b/red/src/Command.cs @@ -1,3 +1,5 @@ +extern alias Expressions; + namespace Icod.LineEditor.Red; using Icod.LineEditor.Ed; @@ -7,7 +9,7 @@ namespace Icod.LineEditor.Red; using Icod.CommandFramework.CommandLine; using Icod.CommandFramework.Diagnostics; using Icod.CommandFramework.Records; -using Icod.CommandFramework.RegularExpressions; +using Expressions::Icod.CommandFramework.RegularExpressions; /// /// Implements the GNU-compatible restricted line editor over . diff --git a/tests/Ed.Shared.Tests/Icod.LineEditor.Ed.Shared.Tests.csproj b/tests/Ed.Shared.Tests/Icod.LineEditor.Ed.Shared.Tests.csproj index 1dea93d..25d6b87 100644 --- a/tests/Ed.Shared.Tests/Icod.LineEditor.Ed.Shared.Tests.csproj +++ b/tests/Ed.Shared.Tests/Icod.LineEditor.Ed.Shared.Tests.csproj @@ -21,6 +21,7 @@ + diff --git a/tests/Ed.Shared.Tests/src/EditorEngineTests.cs b/tests/Ed.Shared.Tests/src/EditorEngineTests.cs index 55122cb..a321230 100644 --- a/tests/Ed.Shared.Tests/src/EditorEngineTests.cs +++ b/tests/Ed.Shared.Tests/src/EditorEngineTests.cs @@ -1,14 +1,16 @@ +extern alias Expressions; + namespace Icod.LineEditor.Ed.Shared.Tests; using System.Text; -using Icod.CommandFramework.RegularExpressions; +using Expressions::Icod.CommandFramework.RegularExpressions; using Icod.LineEditor.Ed; public sealed class EditorEngineTests { [Fact] public void InjectableRegexProviderUsesExpressionsAssembly() { - var constructor = Assert.Single( - typeof( EditorEngine ).GetConstructors().Where( candidate => candidate.GetParameters().Length == 4 ) + var constructor = typeof( EditorEngine ).GetConstructors().Single( + candidate => candidate.GetParameters().Length == 4 ); Assert.Equal( "Icod.Expressions", diff --git a/tests/Ed.Shared.Tests/src/SecurityAndCompatibilityTests.cs b/tests/Ed.Shared.Tests/src/SecurityAndCompatibilityTests.cs index c43e835..0626c4b 100644 --- a/tests/Ed.Shared.Tests/src/SecurityAndCompatibilityTests.cs +++ b/tests/Ed.Shared.Tests/src/SecurityAndCompatibilityTests.cs @@ -1,8 +1,10 @@ +extern alias Expressions; + namespace Icod.LineEditor.Ed.Shared.Tests; using System.Diagnostics; using System.Text; -using Icod.CommandFramework.RegularExpressions; +using Expressions::Icod.CommandFramework.RegularExpressions; using Icod.LineEditor.Ed; public sealed class SecurityAndCompatibilityTests { From aa6240baf4600c16441356f3f0d84ab164707f14 Mon Sep 17 00:00:00 2001 From: Timothy Bruce Date: Fri, 23 Oct 2026 23:23:17 -0400 Subject: [PATCH 3/3] Guard LineEditor prerelease package selection and docs --- packaging/README.md | 8 ++++---- packaging/SelectReleasePackages.ps1 | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packaging/README.md b/packaging/README.md index 6a6ddc1..3dadf7c 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -44,7 +44,7 @@ lineeditor packable as Icod.LineEditor.Tools Therefore solution-wide `dotnet pack` must produce exactly the router package for the coordinated release version: ```text -Icod.LineEditor.Tools.1.1.0.nupkg +Icod.LineEditor.Tools.2.0.0-alpha.1.nupkg ``` The standalone `ed`, `red`, and `sed` commands remain release artifacts through the six RID ZIP archives; disabling NuGet packing does not remove them from builds, tests, or executable archive publication. `Icod.LineEditor.Ed.Shared` remains a repository-local implementation library. @@ -210,12 +210,12 @@ That `README.md` is sourced from the repository root and packed at the NuGet pac ## Release checklist -Before pushing release tag `v1.1.0`: +Before pushing release tag `v2.0.0-alpha.1`: 1. confirm `Directory.Build.props` declares `VersionPrefix` `2.0.0` and `VersionSuffix` `alpha.1`; -2. confirm solution-wide pack produces only `Icod.LineEditor.Tools.1.1.0.nupkg`; +2. confirm solution-wide pack produces only `Icod.LineEditor.Tools.2.0.0-alpha.1.nupkg`; 3. confirm `lineeditor --version` reports `2.0.0-alpha.1` from assembly informational version metadata; 4. confirm the root README installation example and package identity are current; 5. confirm PR Staging validation is green; 6. merge to `main` and require the six-runner Release validation to pass; and -7. only then push tag `v1.1.0`. +7. only then push tag `v2.0.0-alpha.1`. diff --git a/packaging/SelectReleasePackages.ps1 b/packaging/SelectReleasePackages.ps1 index be718a6..b2c5343 100644 --- a/packaging/SelectReleasePackages.ps1 +++ b/packaging/SelectReleasePackages.ps1 @@ -38,7 +38,7 @@ $packages = @( ) foreach ($package in $packages) { $metadata = Get-PackageMetadata -PackagePath $package.FullName - if ($metadata.Version -ne $ExpectedVersion) { + if ($metadata.Version -ne $ExpectedVersion -or $metadata.Id -ne 'Icod.LineEditor.Tools') { continue } Copy-Item -LiteralPath $package.FullName -Destination (Join-Path $DestinationDirectory $package.Name) @@ -46,6 +46,9 @@ foreach ($package in $packages) { } $hasPackages = 0 -lt $selected.Count +if (1 -ne $selected.Count) { + throw "Expected exactly one Icod.LineEditor.Tools package for release $ExpectedVersion; selected $($selected.Count)." +} if (-not [string]::IsNullOrWhiteSpace($GitHubOutputPath)) { "has_packages=$($hasPackages.ToString().ToLowerInvariant())" >> $GitHubOutputPath "package_count=$($selected.Count)" >> $GitHubOutputPath