// 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 (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
62
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) + 5 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.


#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.