One keystroke to jump between an Angular component's
.ts, template, style, and spec — from inside Zed.
Open foo.component.ts, press Alt+S (Option+S on macOS), land in foo.component.html. Press again → .scss. Again → .spec.ts. Again → back to .ts. Or jump directly to a specific sibling with Alt+{T, H, C, X}.
VS Code and WebStorm both ship Angular component switcher plugins. Zed doesn't have something like this.
Zed's extension API currently can't register editor commands (zed#30873), so the marketplace can't host this functionality directly. The workaround is clean: this CLI plugs into Zed's existing task system, which already supports keybinding-triggered commands with $ZED_FILE injected. Two small JSON snippets and you're done.
brew install danieljancar/tap/angular-switchercurl --proto '=https' --tlsv1.2 -LsSf https://github.com/danieljancar/angular-switcher/releases/latest/download/angular-switcher-installer.sh | shpowershell -ExecutionPolicy Bypass -c "irm https://github.com/danieljancar/angular-switcher/releases/latest/download/angular-switcher-installer.ps1 | iex"cargo install --locked angular-switcherDownload the archive for your platform from the latest release, verify the .sha256, and put angular-switcher somewhere on your $PATH.
Verify:
angular-switcher --versionCopy the contents of templates/tasks.json into either:
~/.config/zed/tasks.json(global), or.zed/tasks.json(per-project)
Copy templates/keymap.json into ~/.config/zed/keymap.json. If you already have a keymap, merge the bindings block.
Defaults:
| Shortcut | Action |
|---|---|
alt-s |
Cycle to next sibling |
alt-shift-s |
Cycle to previous sibling |
alt-t |
Switch to TypeScript (.ts) |
alt-h |
Switch to HTML template |
alt-c |
Switch to style (.scss/.css) |
alt-x |
Switch to spec (.spec.ts) |
In Zed keymaps,
altis the Option key on macOS and the Alt key on Linux/Windows.cmdis the Command key (macOS-only); Zed's built-in Save As iscmd-shift-s, which does not conflict with anything here.
All shortcuts are fully customizable — edit your keymap.json and pick any combo Zed accepts.
You normally don't invoke this by hand; Zed does. But for scripting or testing:
angular-switcher [OPTIONS] [<file>]
OPTIONS:
-t, --to <TARGET> Switch directly: ts | html | style | spec
-c, --cycle Cycle to next sibling (default)
-r, --reverse Cycle backwards
--print Print resolved path; do not launch Zed
--no-launch Resolve only; exit 0 on success
--config <P> Override config path
-v, --verbose Log resolution steps to stderr
Exit codes: 0 success · 1 input error · 2 no sibling found · 3 config error.
$ angular-switcher --print foo.component.ts
/abs/path/to/foo.component.htmlDrop an angular-switcher.toml at your platform's per-user config directory (Linux: ~/.config/angular-switcher/config.toml; macOS: ~/Library/Application Support/angular-switcher/config.toml; Windows: %APPDATA%\angular-switcher\config\config.toml) for the global default, or .angular-switcher.toml at your project root to override it. See templates/angular-switcher.toml for the annotated default and docs/CONFIGURATION.md for the full reference.
Common tweaks:
# Don't cycle through specs
[cycle]
order = ["ts", "html", "style"]
# Prefer .less over .scss in this project
[targets.style]
extensions = ["less", "scss", "css", "sass"]
preference = ["less", "scss", "css", "sass"]- Zed task fires with
$ZED_FILEset to the active editor path. angular-switcherstrips the recognised extension to find the component basename, identifies the current target, and computes the next sibling per config.- It invokes
zed <sibling>— the Zed CLI opens the file in the running window.
No shell, no globbing, no PATH lookups in critical paths. Just a strict path resolver and a single Command::spawn. See docs/ARCHITECTURE.md for the design and security posture.
#![forbid(unsafe_code)]- No shell invocation; the
zedCLI is spawned directly - Strict TOML schema (
deny_unknown_fields) — typos fail loud - CI runs
cargo auditandcargo denyon every PR - Reproducible builds (
Cargo.lockcommitted,--lockedeverywhere)
If you find a vulnerability, please follow the disclosure process in SECURITY.md — use GitHub's private "Report a vulnerability" form rather than filing a public issue.
- Optional Vue / React / Svelte file pair strategies
- Native Zed marketplace extension once zed#30873 ships
PRs welcome. cargo test, cargo clippy --all-targets -- -D warnings, and cargo fmt --check must pass. See docs/ARCHITECTURE.md before changing the resolver.
Two automated workflows ship releases:
.github/workflows/release-plz.yml— version bumps, changelog, crates.io publish.github/workflows/release.yml— generated by dist; cross-compiles, GitHub Release, Homebrew formula
Required repository secrets (Settings → Secrets and variables → Actions):
| Secret name | Type | Where used |
|---|---|---|
RELEASE_PLZ_TOKEN |
GitHub Personal Access Token (classic, repo + workflow scopes) on the angular-switcher repo |
release-plz.yml — needed because tags created with GITHUB_TOKEN do not trigger downstream workflows |
CARGO_REGISTRY_TOKEN |
crates.io token from https://crates.io/me/tokens (publish-new + publish-update scopes) |
release-plz.yml — cargo publish after the release PR merges |
HOMEBREW_TAP_TOKEN |
PAT with repo scope on the danieljancar/homebrew-tap repository |
release.yml (dist) — pushes the generated angular-switcher.rb Formula |
GITHUB_TOKEN is provided automatically — nothing to configure.
See docs/INSTALLATION.md#maintainer-release-pipeline for the operational flow.
MIT — see LICENSE.