fix: execute automation commands in AutoCAD command context

This commit is contained in:
codex
2026-08-04 09:37:24 +03:00
parent 1fa25809de
commit bc481d4378
2 changed files with 25 additions and 17 deletions
@@ -264,23 +264,30 @@ internal sealed class FirstLimitedApplyAutomationCoordinator
catch (System.Exception ex) { FailFromCallback("ContextVerification", ex, "AUTOMATION_CONTEXT_FAILED"); } catch (System.Exception ex) { FailFromCallback("ContextVerification", ex, "AUTOMATION_CONTEXT_FAILED"); }
} }
private void Queue(string command) private void Queue(string command) => _ = DispatchCommandAsync(command, false);
{
if (IsTerminal || document is null) return;
transitions.Add("CommandQueued:" + command);
document.SendStringToExecute(command + "\n", true, true, false);
}
private void QueueReadinessBarrier() private void QueueReadinessBarrier()
{ {
if (IsTerminal || document is null) return; _ = DispatchCommandAsync("PHP_REC_AUTOMATION_READY", true);
var active = AcadApplication.DocumentManager.MdiActiveDocument;
if (active is null || !string.Equals(active.Name, document.Name, StringComparison.OrdinalIgnoreCase))
{
Complete(false, "AUTOMATION_READINESS_DOCUMENT_NOT_ACTIVE");
return;
} }
transitions.Add("ReadinessBarrierQueued"); private async Task DispatchCommandAsync(string command, bool readiness)
document.SendStringToExecute("PHP_REC_AUTOMATION_READY\n", true, false, false); {
if (IsTerminal || document is null) return;
var expected = document;
transitions.Add(readiness ? "ReadinessCommandDispatchRequested" : "CommandDispatchRequested:" + command);
try
{
await AcadApplication.DocumentManager.ExecuteInCommandContextAsync(async _ =>
{
transitions.Add("CommandContextEntered:" + command);
var active = AcadApplication.DocumentManager.MdiActiveDocument;
if (active is null || !string.Equals(active.Name, expected.Name, StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException("AUTOMATION_COMMAND_DOCUMENT_NOT_ACTIVE");
transitions.Add(readiness ? "ReadinessBarrierQueued" : "CommandQueued:" + command);
await active.Editor.CommandAsync(command);
transitions.Add("CommandInvocationReturned:" + command);
}, null);
}
catch (System.Exception exception) { FailFromCallback("CommandDispatcher", exception, "AUTOMATION_COMMAND_CONTEXT_FAILED"); }
} }
private void OnCommandEnded(object sender, CommandEventArgs e) private void OnCommandEnded(object sender, CommandEventArgs e)
{ {
@@ -113,11 +113,12 @@ public sealed class FoundationTests
[Fact] public void QueueReadinessBarrier_RequiresActiveFixtureAndUsesSafeDispatch() [Fact] public void QueueReadinessBarrier_RequiresActiveFixtureAndUsesSafeDispatch()
{ {
var source = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "FirstLimitedApplyAutomation.cs")); var source = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "FirstLimitedApplyAutomation.cs"));
var barrier = source[source.IndexOf("private void QueueReadinessBarrier", StringComparison.Ordinal)..source.IndexOf("private void OnCommandEnded", StringComparison.Ordinal)]; var dispatcher = source[source.IndexOf("private async Task DispatchCommandAsync", StringComparison.Ordinal)..source.IndexOf("private void OnCommandEnded", StringComparison.Ordinal)];
Assert.Contains("MdiActiveDocument", barrier); Assert.Contains("ExecuteInCommandContextAsync", dispatcher);
Assert.Contains("AUTOMATION_READINESS_DOCUMENT_NOT_ACTIVE", barrier); Assert.Contains("MdiActiveDocument", dispatcher);
Assert.Contains("PHP_REC_AUTOMATION_READY\\n\", true, false, false", barrier); Assert.Contains("AUTOMATION_COMMAND_DOCUMENT_NOT_ACTIVE", dispatcher);
Assert.True(barrier.IndexOf("AUTOMATION_READINESS_DOCUMENT_NOT_ACTIVE", StringComparison.Ordinal) < barrier.IndexOf("SendStringToExecute", StringComparison.Ordinal)); Assert.Contains("Editor.CommandAsync", dispatcher);
Assert.DoesNotContain("SendStringToExecute", dispatcher);
} }
[Fact] public void AutomationControlledExit_QueuesNativeQuitAfterPublicCommand() [Fact] public void AutomationControlledExit_QueuesNativeQuitAfterPublicCommand()