workspace: Add configurable window title formatting (#54379)

## Summary
- Add `window_title_format` and `window_title_separator` settings for
customizing the window title
- Expose `${projectName}`, `${fileName}`, `${filePath}`,
`${relativePath}`, `${fileStem}`, `${remoteName}`, `${remoteHost}`,
`${appName}`, and `${separator}` as the native Zed window-title
variables
- Keep the collab `↗/↙` indicator hard-appended
- Translate VS Code `window.title` / `window.titleSeparator` aliases
into Zed's canonical variables during settings import, including
`${appName}` passthrough support and mapping VS Code's
`${activeEditorMedium}` onto Zed's `${relativePath}`
- Gate path-, remote-, and release-channel-derived lookups on whether
the active template references the corresponding variable, so the
default template avoids the extra work and still uses the existing
`last_window_title` cache to skip redundant platform updates

An alternative approach is at #49638. I went with `${variable}` names
over `$ZED_*`, canonical Zed variable names with VS Code aliases handled
at import time, kept `${separator}` as the only structural token, and
left `${dirty}` out of scope.

## Implementation reasoning and notes

### Variables considered but not included
- **collab/shared indicator variable**: kept hard-appended instead.
Folding it into the template would need whitespace/separator logic the
other variables don't need, and I'd rather not bake those semantics in
without a concrete need for it.
- **dirty variable**: The glyph choice and interaction with OS-level
edited indicators (like macOS's titlebar dot via `set_window_edited`)
felt like a separate design call I wasn't confident making here.

A separator-style config for each of collab/shared/dirty would solve the
above, but I didn't want to add too many additional settings initially.

### Performance
`update_window_title` is on a hot path, so two short-circuits apply:
- Path-, remote-, and release-channel-derived lookups (`absolute_path`,
relative-path string, `file_stem`, `remote_connection_options`,
`ReleaseChannel::try_global`) are gated on `template.contains(...)` via
`WindowTitleNeeds::from_template`, so the default template avoids the
extra work.
- The existing `last_window_title` cache still skips the platform call
when the rendered title is unchanged.

## Screenshots

Settings Editor entries for `window_title_format` and
`window_title_separator`:
<img width="774" height="324" alt="Settings Editor screenshot"
src="https://github.com/user-attachments/assets/b3378ec7-5649-4de3-9de6-164a42bce3fd"
/>

Customized Zed window titles in AltTab app switcher (remote, local,
empty):
<img width="774" height="324" alt="AltTab app switcher screenshot"
src="https://github.com/user-attachments/assets/a189945e-fc68-41b9-aab9-6dc04d5ef4ab"
/>

## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Closes #14534

Release Notes:

- Added configurable window title formatting with `window_title_format`
/ `window_title_separator`, including `${appName}` / `${remoteName}` /
`${remoteHost}` variables and VS Code `window.title` import support

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
Jake NelsonandKirill Bulatov authored and GitHub committed 2026-09-04 13:48:58 +00:00
1 parent f659fcc000
commit 1aab982b0a
11 files changed
+1008 -32

No files matched your search

+44
View File
@@ -5273,6 +5273,50 @@ Run the {#action theme_selector::Toggle} action in the command palette to see a
- `show_menus`: Whether to show the menus in the titlebar
- `button_layout`: The layout of window control buttons in the title bar (Linux only). Can be set to `"platform_default"` to follow the system setting, `"standard"` to use Zed's built-in layout, or a custom format like `"close:minimize,maximize"`
## Window Title Format
- Description: Template for the window title. Use `${separator}` to insert a
separator that is omitted when adjacent variables are empty. The collaboration
indicator, when present, is appended after the rendered template. If the
template renders to nothing (for example `${branch}` outside a Git
repository), the default template is used instead.
- Setting: `window_title_format`
- Default: `"${projectName}${separator}${fileName}"`
Available variables:
| Variable | Description |
| -------------- | ----------------------------------------------------- |
| `projectName` | Name of the current project |
| `fileName` | Name of the active file (e.g. `main.rs`) |
| `filePath` | Absolute path of the active file |
| `relativePath` | Path of the active file relative to its worktree root |
| `fileStem` | File name without extension (e.g. `main`) |
| `remoteName` | Display name of the remote connection, if any |
| `remoteHost` | Host of the remote connection, if any |
| `appName` | Zed release channel name (e.g. `Zed`, `Zed Nightly`) |
| `branch` | Git branch checked out in the active repository |
| `separator` | Separator string, omitted when neighbors are empty |
```json [settings]
{
"window_title_format": "${projectName}${separator}${fileName}"
}
```
## Window Title Separator
- Description: The string substituted for `${separator}` in the window title
format. Include any surrounding whitespace in the value.
- Setting: `window_title_separator`
- Default: `" — "`
```json [settings]
{
"window_title_separator": " — "
}
```
## Window Decorations
- Description: Controls whether Zed or the window manager or compositor draws window decorations.