// ZSH-XCODE-COMPLETIONS — ENGINEERING REPORT

11 #compdef files for the Xcode CLI · xcodebuild / xcrun / swift / swift-demangle / nm / plutil / strings / dyldinfo / genstrings / instruments / xcode-select · SDK / scheme / target / configuration / arch live-queried from xcodebuild -list · bin/swift-demangle xcrun shim binary

>_EXECUTIVE SUMMARY

zsh-xcode-completions is the largest plugin in this batch by completion-file count: 11 separate #compdef files covering the Xcode command-line tools, totaling 435 lines under src/ plus a 1-line plugin entrypoint. Coverage spans the entire mac developer CLI surface — xcodebuild (the largest at 139 lines), swift (54 lines for the compiler driver), xcrun (49 lines, the developer-tool dispatcher with SDK/toolchain switches), nm (symbol table dump), plutil (plist conversion), strings, dyldinfo, genstrings (localization), instruments (profiling templates), swift-demangle, and xcode-select. Many completers shell out to xcodebuild itself for live data: schemes / targets / configurations / valid-archs are queried at completion time via xcodebuild -list + xcodebuild -showBuildSettings piped through sed / cut for parsing. SDK lists go through _retrieve_cache SDKS / _store_cache SDKS because they rarely change. An xcrun-shim binary at bin/swift-demangle works around xcrun's inability to dispatch zsh completion through its xcrun <tool> ... indirection — the shim is a one-line xcrun swift-demangle "$@" wrapper that surfaces the nested tool as a direct PATH binary so its _swift-demangle completer can fire.

435
Total Completion-File LOC
11
#compdef Files
40
zunit @test Cases
21
Structural Gates (.sh)
6
zunit Files
66
Git Commits

~ARCHITECTURE · FILE STRUCTURE

Eleven #compdef files under src/, one xcrun-shim binary under bin/, one 1-line plugin entrypoint.

Path Lines Role
src/_xcodebuild139Largest completer — 30+ flags (-scheme, -target, -configuration, -sdk, -arch, -workspace, -project, -archivePath, -derivedDataPath, sanitizer toggles, code coverage, export format/signing) + 7 build actions (analyze, archive, build, clean, install, installsrc, test); shells out to xcodebuild -list / -showsdks / -showBuildSettings at completion time
src/_swift54Swift compiler driver — -emit-assembly/-library/-object, -F framework path, -I import path, -L library path, -l library link, -module-cache-path, -O/-Onone/-Ounchecked, -sdk with SDK cache, -target-cpu, -Xcc/-Xlinker passthrough
src/_xcrun49The tool dispatcher — -f/--find, -l/--log, -r/--run, -k/--kill-cache, --sdk (cached SDK list), --toolchain (glob /Applications/Xcode*.app/Contents/Developer/Toolchains/*.xctoolchain), --show-sdk-{path,platform-path,platform-version,version}; executable completion via ls $(dirname $(xcrun -f swift))
src/_nm38-a/-A/-f/-g/-j/-l/-m/-n/-o/-p/-r/-s/-u/-U/-x; -arch with arch enum
src/_instruments33-s templates/devices; -t template selection backed by _instruments_templates cache (parses quoted output of instruments -s templates); -p attach-pid via zsh's _pids; mutex group between pid-attach and command-launch modes
src/_plutil29-help, -lint, -convert (with format enum: xml1/binary1/json), -p print, -extract, -replace, -insert, -remove
src/_strings26Symbol-table strings dump — flag set + file completion
src/_xcode-select19-p/--print-path, -r/--reset, -s/--switch backed by glob of /Applications/Xcode*.app, --install
src/_genstrings18Localization-string generator flag set + source-file completion
src/_swift-demangle15Swift name-mangling decoder — flag set + stdin/file input
src/_dyldinfo15dyld load-commands inspector
bin/swift-demangle3#!/bin/sh shim — xcrun swift-demangle "$@" — gives zsh a direct PATH binary it can run _swift-demangle against (xcrun's nested dispatch hides it from zsh's completion-system #compdef lookup)
zsh-xcode-completions.plugin.zsh1fpath=("${0:h}/src" $fpath) — only line, no setup chrome needed because every file is autoloaded by zsh's compsys when compinit runs after fpath patch
Total source~43911 completion files + 1 shim + 1 entrypoint

@COMPLETION COVERAGE

11 distinct tools. Common pattern: _arguments flag table + state machine for context-sensitive args + project-aware queries that shell out to the tool itself.

Project-aware xcodebuild completion

Instead of static enum lists, _xcodebuild queries the current directory:

  • -scheme <TAB>xcodebuild -list output, sed-extracted between "Schemes:" and end
  • -target <TAB>xcodebuild -list, sed-extracted between "Targets:" and "Build Configurations:"
  • -configuration <TAB> → same, between "Build Configurations:" and "If no build"
  • -arch <TAB>xcodebuild -showBuildSettings | grep VALID_ARCHS | cut -f 2 -d '='
  • -project <TAB> → glob *.xcodeproj via _multi_parts /
  • -workspace <TAB> → glob *.xcworkspace
  • -xcconfig <TAB> → glob *.xcconfig

Cached SDK list (cross-tool)

Both _xcodebuild and _swift share the same SDK-cache idiom: _retrieve_cache SDKS → populate _installed_sdks via xcodebuild -showsdks_store_cache SDKS. The cache key (SDKS) is shared across completers so a single SDK install/uninstall invalidates everywhere.

xcrun toolchain glob

xcrun --toolchain <TAB>toolchains=(/Applications/Xcode*.app/Contents/Developer/Toolchains/*.xctoolchain) — glob over every installed Xcode's toolchains directory. Works with side-by-side Xcode installations (beta + release).

Instruments template cache

instruments -t <TAB>_instruments_templates_call_program templates 'instruments -s templates'. Output format is one quoted template per line with a "Known Templates" header. The completer uses ${(Q)${(f)...}} to split-by-line + strip-quotes, then shift template_list to drop the header. _retrieve_cache _instruments_templates persists the result so repeated TABs don't re-spawn instruments.

xcode-select Xcode picker

xcode-select --switch <TAB>xcodes=(/Applications/Xcode*.app)_values "Available Xcodes" $xcodes. Side-by-side Xcode versions are visible by glob, no enumeration of /Applications needed.

xcrun shim for nested tools

xcrun's design (xcrun <tool> <args>) hides nested tools from zsh's completion-system #compdef lookup — swift-demangle isn't directly on PATH, so _swift-demangle never fires. The shim at bin/swift-demangle (3-line POSIX sh wrapper running xcrun swift-demangle "$@") gives users a direct PATH binary that surfaces the completer. Homebrew offers --without-shims for users who don't want the wrapper.


$FULL FLAG SURFACE

Every flag wired into the eleven _arguments tables, transcribed from src/. “→” marks a flag whose argument completes to a value list.

Tool Flags Surface
xcodebuild31Project-aware→: -scheme, -target, -configuration, -arch, -sdk, -project, -workspace, -xcconfig. Paths: -archivePath, -derivedDataPath, -resultBundlePath. YES/NO toggles: -enableAddressSanitizer, -enableThreadSanitizer, -enableUndefinedBehaviorSanitizer, -enableCodeCoverage. Switches: -n/-dry-run, -alltargets, -list, -showsdks, -showBuildSettings, -skipUnavailableActions, -usage, -version. Archive/export: -exportArchive, -exportFormat (IPA/PKG/APP), -exportInstallerIdentity, -exportProvisiningProfile, -exportSigningIdentity, -exportWithOriginalSigningIdentity, -destination, -destination-timeout. Actions: analyze / archive / build / clean / install / installsrc / test.
xcrun14-f/--find, -h/--help, -k/--kill-cache, -l/--log, -n/--no-cache, -r/--run, -v/--verbose, --sdk→, --toolchain→, --show-sdk-path, --show-sdk-platform-path, --show-sdk-platform-version, --show-sdk-version, --version; positional tool name→ via $(dirname $(xcrun -f swift)).
swift30-assert-config (Debug/Release/Replacement), -D, -emit-assembly, -emit-library, -emit-object, -F→, -framework→, -g, -gline-tables-only, -gnone, -help, -I→, -j, -L→, -l→, -module-cache-path→, -module-link-name, -module-name, -nostdimport, -O/-Onone/-Ounchecked, -o→, -sdk→ (cached), -target-cpu, -target, -v, -version, -Xcc, -Xlinker.
nm18-a, -A, -arch→ (arm64/armv7/armv7s/i386/x86_64), -f, -g, -j, -l, -m, -n, -o, -p, -P, -r, -s, -t (d/o/x), -u, -U, -x.
plutil12-convert→ (json/xml1/binary1), -insert/-replace (keypath → type-bool/-integer/-float/-string/-date/-data/-xml/-json → value), -remove, -extract→, -e, -help, -lint, -o→, -p, -r, -s.
swift-demangle11-classify, -compact, -expand, -help, -help-list-hidden, -no-sugar, -remangle-new, -simplified, -test-remangle, -tree-only, -version; positional = symbol(s).
dyldinfo9-arch→ (i386/x86_64/armv7/arm64), -dylibs, -rebase, -bind, -weak_bind, -lazy_bind, -export, -opcodes, -function_starts; positional→ Mach-O files.
genstrings8-a, -macRoman, -noPositionalParameters, -o→ (output dir), -q, -s (custom NSLocalizedString fn), -skipTable, -u; positional→ source files.
instruments8-w, -v, -t→ (cached templates), -s (templates/devices), -D→, -l, -i, -p_pids; mutex modes split the -p attach path from the positional command-launch path.
strings6- (all bytes), -a (all sections), -arch→, -n, -o, -t (d/o/x).
xcode-select6-h/--help, -p/--print-path, -r/--reset, -s/--switch→ (glob /Applications/Xcode*.app), -v/--version, --install.

#TEST COVERAGE

40 zunit @test cases across 6 files, plus 21 structural shell gates from the umbrella. The t-completions.zsh file pins every one of the 11 _* files individually.

Test file @test count What it pins
tests/t-completions.zsh20Per-completer pins — each of the 11 src/_* files exists, starts with the right #compdef line, parses cleanly under zsh -n
tests/t-contract.zsh3Entrypoint stem matches plugin-dir basename (Zinit / OMZ source-line copy-paste pin); plugin file is exactly the 1-line fpath patch
tests/t-contract2.zsh5src/ contains exactly 11 completion files with names matching the documented tool list
tests/t-contract3.zsh5bin/swift-demangle shim exists, is executable, has the xcrun swift-demangle "$@" body
tests/t-contract4.zsh5SDK cache key consistency — _xcodebuild + _swift + _xcrun all use SDKS as the cache key (so SDK install invalidates everywhere)
tests/t-syntax.zsh2zsh -n parse-cleanness on entrypoint + every src/_* file
Total406 zunit files

// STRUCTURAL GATES (21 shell scripts)

Same 21-script umbrella gate-set: 9 docs/*.html gates + 4 README + 3 man-page + 2 tests/ + 2 workflows + 1 cargo (vacuous).


?KEY DESIGN DECISIONS

Five tradeoffs unique to completing Xcode CLI tools.

11 separate #compdef files, not one mega-file

Each Xcode CLI tool is its own binary with its own flag surface; folding them into a single _xcode dispatcher would slow autoload and couple their lifecycles. Keeping 11 small #compdef files means zsh only loads the completer for the tool the user actually invokes — compinit-time cost is paid once and lazily-resolved per tool.

Live project queries, not static enums

Xcode schemes / targets / configurations / valid-archs differ per project. Hardcoding enums would be wrong the moment the user cds into a different repo. Instead, _xcodebuild shells out to xcodebuild -list / -showBuildSettings at completion time — cost is one xcodebuild spawn per TAB, but the result is project-correct.

Shim binary for xcrun nesting

xcrun's dispatch model breaks zsh's completion-system #compdef <binary> contract — nested tools aren't directly on PATH. The shim path (bin/swift-demangle = xcrun swift-demangle "$@") is the cleanest workaround: surface the tool as a PATH binary so the completer fires. Cost is one extra fork; benefit is autocomplete that Just Works.

Shared SDK cache key

Three completers (_xcodebuild, _swift, _xcrun) all need the SDK list. They share the cache key SDKS, so installing or uninstalling an SDK invalidates the cache for all three at once — no per-tool cache divergence. The cache key is plain SDKS (not prefix-keyed) because SDK lists are tiny and global.

1-line plugin entrypoint

The plugin file is literally fpath=("${0:h}/src" $fpath). No ZSH_ARGZERO self-locate because the plugin file lives at the repo root, and ${0:h} works correctly for direct sourcing. Zinit / OMZ / antibody all set $0 to the plugin file's path before sourcing — the 2-line idiom is unnecessary here. Less code, fewer pins, same outcome.