Tools/carapace.ps1
|
# Companion for carapace — registers native argument completers for ~519 commands. # Invoke-Expression is required by carapace's init pattern — no alternative exists. [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingInvokeExpression', '')] param() # carapace's init emits Register-ArgumentCompleter calls only — it never binds Tab # and never overrides TabExpansion. That is why it composes with PSFzf rather than # fighting it: PSFzf owns the Tab key (Tools/PSFzf.ps1) and routes through # TabExpansion2, which consults these completers. Registration order is irrelevant, # so no dependsOn is declared. # # Argument completers are registered session-wide by the engine regardless of the # scope Invoke-Expression runs in, so dot-sourcing from Register-DFTool is safe. # # Known deviation: carapace's generated init prepends $XDG_CONFIG_HOME/carapace/bin # to PATH itself (the bridge-shim directory) instead of going through Add-DFToPath. # That line is emitted by carapace, not DotForge, and cannot be rerouted. # # CARAPACE_BRIDGES is deliberately left unset. Bridging (zsh/fish/bash/inshellisense) # shells out per completion, and of those only bash is present on this machine. Enable-DFCarapaceInshellisenseBridge | Out-Null # Deploy bundled specs (e.g. scoop, which carapace ships no completer for) into # carapace's spec directory. carapace auto-loads *.yaml from there — see # `carapace --help` ("Specs are loaded from ..."). We overwrite DotForge-shipped # specs (matched by filename) so fixes propagate; users wanting a custom scoop # spec can place it elsewhere or edit the deployed copy, which is refreshed only # when the bundled content changes. $_bundledSpecs = Join-Path $PSScriptRoot 'carapace' 'specs' if (Test-Path $_bundledSpecs) { $_specDir = Join-Path ($Env:XDG_CONFIG_HOME ?? (Join-Path $HOME '.config')) 'carapace' 'specs' New-DFDirectory $_specDir | Out-Null Get-ChildItem $_bundledSpecs -Filter '*.yaml' | ForEach-Object { $_dest = Join-Path $_specDir $_.Name $_new = Get-Content $_.FullName -Raw if (-not (Test-Path $_dest) -or (Get-Content $_dest -Raw) -ne $_new) { Set-Content -Path $_dest -Value $_new -Encoding UTF8 } } } # carapace appends a trailing space to each CompletionText (its "token complete" # convention). PSFzf's FixCompletionResult quotes any completion containing a # space, so a fuzzy-picked `docker build` would land as `docker "build "`. When # PSFzf will own Tab (Native mode + PSFzf available), trim the trailing space so # the picker inserts a clean, unquoted value — PSFzf re-adds a single trailing # space itself. The replacement targets carapace's generated constructor call # and no-ops (leaving the space intact, which MenuComplete needs for subcommand # chaining) if carapace ever changes that codegen. Catalogued in # docs/external-dependencies.md. $_carapaceInit = carapace _carapace powershell | Out-String if (((Get-DFCompletionMode) -eq 'Native') -and (Get-Module -ListAvailable -Name PSFzf)) { $_carapaceInit = $_carapaceInit.Replace( '[CompletionResult]::new($_.CompletionText,', '[CompletionResult]::new(([string]$_.CompletionText).TrimEnd(),') } Invoke-Expression $_carapaceInit |