wtw.psm1
|
# wtw — Git Worktree + Workspace Manager # Module loader: dot-source public/ and private/ functions. # # IMPORTANT: Everything ABOVE the `return` in the Windows PowerShell branch must # stay parseable AND runnable by Windows PowerShell 5.1 (Desktop edition). The # rest of the module (the dot-sourced public/ + private/ files) uses PowerShell # 7+ syntax (??, ternary, &&) and would fail to even parse under 5.1, so it is # only dot-sourced once we have confirmed we are on PowerShell 7+ (Core). # # Net effect: running `wtw ...` from Windows PowerShell transparently hands off # to pwsh (PowerShell 7), or — when pwsh is not installed — explains how to get # it. From pwsh itself, the full module loads normally. $script:WtwModuleRoot = $PSScriptRoot function Get-WtwPwshExecutable { # 5.1-safe discovery of a PowerShell 7+ (pwsh) executable. # Returns the full path, or $null when pwsh is not installed. $cmd = Get-Command pwsh -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1 if ($cmd -and $cmd.Source) { return $cmd.Source } $candidates = @( (Join-Path $env:ProgramFiles 'PowerShell\7\pwsh.exe'), (Join-Path ${env:ProgramFiles(x86)} 'PowerShell\7\pwsh.exe'), (Join-Path $env:LOCALAPPDATA 'Microsoft\PowerShell\7\pwsh.exe'), (Join-Path $env:LOCALAPPDATA 'Microsoft\WindowsApps\pwsh.exe') ) foreach ($candidate in $candidates) { if ($candidate -and (Test-Path $candidate)) { return $candidate } } return $null } # Edition detection. $PSVersionTable.PSEdition is 'Core' on PowerShell 7+ (all # platforms) and 'Desktop' on Windows PowerShell 5.1. Treat anything that is not # explicitly Core as Desktop (covers ancient hosts that predate PSEdition). $wtwEdition = $PSVersionTable.PSEdition if (-not $wtwEdition) { $wtwEdition = 'Desktop' } if ($wtwEdition -ne 'Core') { # ----- Windows PowerShell (Desktop): thin pwsh hand-off shim --------------- $script:WtwPwshPath = Get-WtwPwshExecutable function Invoke-Wtw { $pwshPath = $script:WtwPwshPath if (-not $pwshPath) { Write-Host '' Write-Host ' wtw requires PowerShell 7+ (pwsh).' -ForegroundColor Red Write-Host " You're running Windows PowerShell $($PSVersionTable.PSVersion), and pwsh is not installed." -ForegroundColor Yellow Write-Host '' Write-Host ' Install PowerShell 7 with:' -ForegroundColor Cyan Write-Host ' winget install --id Microsoft.PowerShell --source winget' -ForegroundColor White Write-Host '' $answer = Read-Host ' Install it now via winget? [y/N]' if ($answer -match '^(y|yes)$') { if (Get-Command winget -ErrorAction SilentlyContinue) { & winget install --id Microsoft.PowerShell --source winget --accept-package-agreements --accept-source-agreements Write-Host '' Write-Host ' Done. Open a new terminal (or run pwsh) and re-run your wtw command.' -ForegroundColor Green } else { Write-Host ' winget is not available. Install PowerShell 7 manually: https://aka.ms/powershell' -ForegroundColor Red } } return } $modulePath = Join-Path $script:WtwModuleRoot 'wtw.psm1' # No arguments: drop the user into a pwsh session in this console # (auto-switch), with the wtw module loaded and help shown. if ($args.Count -eq 0) { Write-Host ' wtw: switching this console to PowerShell 7 (pwsh)...' -ForegroundColor DarkGray & $pwshPath -NoLogo -NoExit -Command "Import-Module '$modulePath' -DisableNameChecking; wtw" return } # Re-quote each argument so spaces and quotes survive the hand-off. $quoted = @() foreach ($a in $args) { $quoted += "'" + ([string]$a).Replace("'", "''") + "'" } $argLine = $quoted -join ' ' Write-Host ' wtw: running under PowerShell 7 (pwsh)...' -ForegroundColor DarkGray & $pwshPath -NoLogo -NoProfile -Command "Import-Module '$modulePath' -DisableNameChecking; Invoke-Wtw $argLine" } # The installed profile loader calls Register-WtwProfile right after import; # provide a no-op so Windows PowerShell sessions don't error on startup. function Register-WtwProfile { } Set-Alias -Name wtw -Value Invoke-Wtw -Scope Global -Force Export-ModuleMember -Function 'Invoke-Wtw', 'Register-WtwProfile' -Alias 'wtw' return } # ----- PowerShell 7+ (Core): load the full module ----------------------------- $dotSourceParams = @{ Filter = '*.ps1' Recurse = $true ErrorAction = 'Stop' } $public = @(Get-ChildItem -Path (Join-Path -Path $PSScriptRoot -ChildPath 'public') @dotSourceParams) $private = @() $privatePath = Join-Path -Path $PSScriptRoot -ChildPath 'private' if (Test-Path $privatePath) { $private = @(Get-ChildItem -Path $privatePath @dotSourceParams) } foreach ($import in @($private + $public)) { try { . $import.FullName } catch { throw "Unable to dot source [$($import.FullName)]" } } Export-ModuleMember -Function $public.BaseName Set-Alias -Name wtw -Value Invoke-Wtw -Scope Global -Force Export-ModuleMember -Alias wtw # Load tab completion $completionPath = Join-Path $PSScriptRoot 'completions' 'wtw.auto-completion.ps1' if (Test-Path $completionPath) { . $completionPath } |