rust-switcher 1.0.13

Windows keyboard layout switcher and text conversion utility
Documentation
param(
    [switch]$KeepOpen,
    [switch]$NoWait
)

$ErrorActionPreference = "Stop"

function XmlEscape([string]$Value) {
    return [System.Security.SecurityElement]::Escape($Value)
}

$root = Resolve-Path (Join-Path $PSScriptRoot "..\..")
$sandboxExe = Join-Path $env:WINDIR "System32\WindowsSandbox.exe"
if (-not (Test-Path $sandboxExe)) {
    throw "Windows Sandbox is not available at $sandboxExe. Enable the Windows Sandbox optional feature first."
}

Push-Location $root
try {
    $env:CARGO_TARGET_DIR = ".target"
    & cargo +nightly build --bin rust-switcher-debug --features debug-tracing,debug-binary
    if ($LASTEXITCODE -ne 0) {
        throw "cargo build failed with exit code $LASTEXITCODE"
    }

    $exe = Join-Path $root ".target\debug\rust-switcher-debug.exe"
    if (-not (Test-Path $exe)) {
        throw "Built executable was not found at $exe"
    }

    $stamp = Get-Date -Format "yyyyMMdd-HHmmss"
    $bundle = Join-Path ([System.IO.Path]::GetTempPath()) "rust-switcher-e2e-$stamp"
    New-Item -ItemType Directory -Path $bundle -Force | Out-Null

    Copy-Item -LiteralPath $exe -Destination (Join-Path $bundle "rust-switcher-debug.exe") -Force
    Copy-Item -LiteralPath (Join-Path $PSScriptRoot "sandbox-runner.ps1") -Destination $bundle -Force

    $leaf = Split-Path $bundle -Leaf
    $guestRoot = "C:\Users\WDAGUtilityAccount\Desktop\$leaf"
    $keepOpenArg = if ($KeepOpen) { " -KeepOpen" } else { "" }
    $command = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"$guestRoot\sandbox-runner.ps1`" -SharedRoot `"$guestRoot`"$keepOpenArg"

    $wsb = Join-Path $bundle "rust-switcher-e2e.wsb"
    $hostFolder = XmlEscape $bundle
    $logonCommand = XmlEscape $command

    @"
<Configuration>
  <MappedFolders>
    <MappedFolder>
      <HostFolder>$hostFolder</HostFolder>
      <ReadOnly>false</ReadOnly>
    </MappedFolder>
  </MappedFolders>
  <ClipboardRedirection>Disable</ClipboardRedirection>
  <PrinterRedirection>Disable</PrinterRedirection>
  <Networking>Disable</Networking>
  <LogonCommand>
    <Command>$logonCommand</Command>
  </LogonCommand>
</Configuration>
"@ | Set-Content -LiteralPath $wsb -Encoding UTF8

    Write-Host "Launching Windows Sandbox..."
    Write-Host "Bundle: $bundle"

    $proc = Start-Process -FilePath $sandboxExe -ArgumentList "`"$wsb`"" -PassThru
    if ($NoWait) {
        Write-Host "Sandbox started. Result will be written to $bundle\result.json"
        return
    }

    $proc.WaitForExit()

    $resultPath = Join-Path $bundle "result.json"
    if (-not (Test-Path $resultPath)) {
        throw "Sandbox exited without writing $resultPath. Check $bundle\e2e.log"
    }

    $result = Get-Content -LiteralPath $resultPath -Raw | ConvertFrom-Json
    $result | ConvertTo-Json -Depth 8

    if ($result.status -ne "passed") {
        throw "Interactive E2E failed: $($result.error)"
    }
} finally {
    Pop-Location
}