Skip to content

CmdPal: Enable dock pinning and per-profile icons for Windows Terminal#46372

Open
niels9001 wants to merge 5 commits intomainfrom
niels9001/cmdpal-terminal-dock-pinning
Open

CmdPal: Enable dock pinning and per-profile icons for Windows Terminal#46372
niels9001 wants to merge 5 commits intomainfrom
niels9001/cmdpal-terminal-dock-pinning

Conversation

@niels9001
Copy link
Copy Markdown
Collaborator

@niels9001 niels9001 commented Mar 21, 2026

Summary

Enables Windows Terminal profiles to be pinned to the Command Palette dock and shows per-profile icons instead of the generic Terminal app logo.

Dock Pinning

Root cause: \LaunchProfileCommand.Id\ was never set (defaulted to \string.Empty). The context menu factory checks !string.IsNullOrEmpty(itemId)\ before showing "Pin to Dock", so the option was silently hidden. Additionally, \GetCommandItem()\ was not overridden, so pinned commands could not be resolved on load.

Fix:

  • Set stable \Id\ on \LaunchProfileCommand\ (format: \ erminal/{appUserModelId}/{profileName})
  • Override \GetCommandItem(string id)\ in \WindowsTerminalCommandsProvider\ to look up profile items by ID
image

Per-Profile Icons

Root cause: All profiles showed the same Terminal application logo. The per-profile \icon\ field from Terminal settings.json was parsed into \TerminalProfile.Icon\ but never used.

Fix:

  • Add \InstallPath\ to \TerminalPackage\ (from \Package.InstalledPath)
  • Add \ResolveProfileIcon()\ helper to \TerminalHelper\ that resolves \ms-appx:///\ URIs to the Terminal package install directory (with scale variant probing), passes through file paths and glyphs, and falls back to the Terminal logo
  • Set resolved per-profile icon on both \ListItem.Icon\ and \LaunchProfileCommand\
image

Validation

  • Build clean with exit code 0
  • Dock pinning tested and working

Enable Windows Terminal profiles to be pinned to the Command Palette dock
and show per-profile icons instead of the generic Terminal app logo.

Dock pinning:
- Set stable Id on LaunchProfileCommand (terminal/{appUserModelId}/{profileName})
- Override GetCommandItem() in WindowsTerminalCommandsProvider so the dock
  can resolve pinned commands on load

Per-profile icons:
- Add InstallPath to TerminalPackage for resolving ms-appx:/// URIs
- Add ResolveProfileIcon() helper that maps ms-appx:/// paths to the
  Terminal package install directory with scale variant probing
- Set resolved per-profile icon on ListItem and LaunchProfileCommand

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@niels9001 niels9001 force-pushed the niels9001/cmdpal-terminal-dock-pinning branch from 59f6260 to c533c34 Compare March 21, 2026 15:04
@cinnamon-msft
Copy link
Copy Markdown
Collaborator

YAY

@jiripolasek jiripolasek added the Product-Command Palette Refers to the Command Palette utility label Mar 21, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Enables Windows Terminal profile commands in CmdPal to support dock pinning (via stable command IDs and provider-side rehydration) and improves UX by showing per-profile icons rather than the generic Terminal app icon.

Changes:

  • Assigns stable IDs to LaunchProfileCommand and adds GetCommandItem(string id) to rehydrate pinned profile commands.
  • Adds InstallPath to TerminalPackage and uses it to resolve profile icons (including ms-appx:/// and GUID-based built-in profile icons).
  • Updates the profiles list to use resolved per-profile icons for both list items and launch commands.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowsTerminal/WindowsTerminalCommandsProvider.cs Adds GetCommandItem implementation to resolve pinned profile commands by ID.
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowsTerminal/TerminalPackage.cs Extends package model with InstallPath needed for icon resolution.
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowsTerminal/Pages/ProfilesListPage.cs Applies resolved per-profile icons to the rendered list items and commands.
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowsTerminal/Helpers/TerminalQuery.cs Populates InstallPath from the discovered Terminal package.
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowsTerminal/Helpers/TerminalHelper.cs Adds icon resolution logic and updates GUID parsing under nullable context.
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowsTerminal/Commands/LaunchProfileCommand.cs Generates and assigns stable command IDs for profile launch commands.

michaeljolley and others added 3 commits March 24, 2026 14:37
…ges/ProfilesListPage.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…lpers/TerminalHelper.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…ndowsTerminalCommandsProvider.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 24, 2026

@michaeljolley I've opened a new pull request, #46481, to work on those changes. Once the pull request is ready, I'll request review from you.

…ove ambiguity (#46481)

## Summary of the Pull Request

`LaunchProfileCommand` had a constructor parameter `id` and backing
field `_id` that held the Terminal `AppUserModelId` used for COM
activation, which was ambiguous given the base class `Id` property (set
to a generated command identifier via `MakeId`). Renames the parameter
and field throughout to `appUserModelId`/`_appUserModelId`.

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

Addresses review feedback on #46372. Changes in
`LaunchProfileCommand.cs`:

- `_id` field → `_appUserModelId`
- Constructor parameter `id` → `appUserModelId`
- Private `Launch(string id, ...)` → `Launch(string appUserModelId,
...)`

Before, both the activation ID and the command identity used
`id`-derived names, making it easy to accidentally pass the wrong value.
The `MakeId` static method already used `appUserModelId` as its
parameter; this aligns the rest of the class with that convention.

```csharp
// Before
private readonly string _id;
internal LaunchProfileCommand(string id, ...) { this._id = id; this.Id = MakeId(id, profile); }

// After
private readonly string _appUserModelId;
internal LaunchProfileCommand(string appUserModelId, ...) { this._appUserModelId = appUserModelId; this.Id = MakeId(appUserModelId, profile); }
```

## Validation Steps Performed

- Code review: no issues flagged.
- Caller site (`ProfilesListPage.cs`) already passes
`profile.Terminal.AppUserModelId` — no functional change.

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 Send tasks to Copilot coding agent from
[Slack](https://gh.io/cca-slack-docs) and
[Teams](https://gh.io/cca-teams-docs) to turn conversations into code.
Copilot posts an update in your thread when it's finished.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: michaeljolley <1228996+michaeljolley@users.noreply.github.com>
}

private void Launch(string id, string profile)
internal static string MakeId(string appUserModelId, string profileName) => $"terminal/{appUserModelId}/{profileName}";
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how this would fit with the deep-links... I assume we'd like to end up with sth like: x-cmdpal://commands/providerId/commandId and question is if / should be a reserved char or not? In theory we can treat commandId as catch-all parameter

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jiripolasek what is your recommendation here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Product-Command Palette Refers to the Command Palette utility

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants