feat(gpui): open a folder in a chosen shell from the Explorer menu - #145
Merged
Merged
Conversation
Right-clicking a folder has always opened the configured default shell — usually PowerShell — with no way to ask for a WSL distribution instead. - `--shell <id>` takes the same ids the `shell` setting uses (`pwsh`, `cmd`, `wsl:Ubuntu`, or an imported profile's settings id) and applies to the first tab this process creates. It carries an id rather than a path so every launch re-resolves the executable. - The id travels both startup paths: the cold start (`run_shell` → `WorkspaceStartup::NewTerminal`), and the resident hand-off, which is the common case on Windows. `tab.new`/`window.create` gained an optional `shell` field, so clicking the menu while Pebrel is already running adds a tab to the existing window instead of starting a second process. - An explicit request never silently degrades. An unresolvable id fails (`invalid_shell`, or a startup error before any window opens), and a `wsl:<distro>` id that the registry no longer lists still launches `wsl.exe -d <distro>`, leaving the complaint to the distribution itself. The `shell` setting keeps its documented fallback to the platform default. - The winit shell rejects a shell request instead of ignoring it, so the caller falls back to a cold GPUI start and still gets the requested shell. The resolution lives in a new `workspace::shell_launch` module: `main.rs` has to validate `--shell` before it opens a window, and none of it needs `NebulaWorkspace` state — `workspace.rs` is also at its line budget, which this keeps from growing (`architecture/file-budgets.txt`). The installer registers one context-menu entry per registered WSL distribution (`PebrelWsl<n>`, skipping `docker-desktop*`) and the uninstaller reclaims them by key prefix plus the command line it wrote. `--shell` is passed before `--working-directory`: a drive-root `%V` ends in `\"`, which would swallow the rest of the line if the directory came first. Both the string and the order are pinned by installer assertions. Docs (runtime API schema + control API) and shell completions are updated.
Contributor
Author
|
The CI runs here (and on #142, #143, #144) are sitting in Two of those checks would cover things I could not verify locally, which is why I would rather not merge without them:
|
This was referenced Sep 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Result / 用户结果
Right-clicking a folder in Explorer can now open it in a chosen shell. The
installer registers one context-menu entry per registered WSL distribution —
"Open in Pebrel (Ubuntu)" next to the existing "Open in Pebrel" — and the
distribution's own prompt lands in that folder (
/mnt/<drive>/…).Previously the menu only ever opened the configured default shell, usually
PowerShell, with no way to ask for anything else.
Design / 设计边界
cli.rstakes the option;workspace/shell_launch.rs(new)owns id → launch resolution; the startup paths carry the id; the installer owns
the menu entries.
main.rshas to validate--shellbefore it opens awindow, and none of the resolution needs
NebulaWorkspacestate. It also keepsworkspace.rsfrom growing — that file is at its budget inarchitecture/file-budgets.txt, and this change makes it marginally smaller.--shell <id>uses the same ids as theshellsetting (pwsh,cmd,wsl:Ubuntu, or an imported profile's settings id) and applies to the firsttab this process creates. An id, not a path: every launch re-resolves the
executable. It conflicts with
-e, which the GPUI path does not consume anywayand which would bypass the shell integration (
DetectedShell::shell()).run_shell→WorkspaceStartup::NewTerminal) and the resident hand-off(
tab.new/window.creategained an optionalshellfield). Without thelatter, clicking the menu while Pebrel is already running would silently open
the default shell in a second process.
unresolvable id fails (
invalid_shellover IPC, a startup error before anywindow for the CLI), and a
wsl:<distro>the registry no longer lists stilllaunches
wsl.exe -d <distro>so the distribution reports the problem itself.The
shellsetting keeps its documented fallback to the platform default, andthe winit shell rejects a shell request rather than ignoring it.
WindowParamsis
deny_unknown_fields: an upgraded client asking an older resident for ashell gets
invalid_paramsand falls back to a cold start — worth a releasenote ("restart the resident instance after upgrading").
PebrelWsl<n>,docker-desktop*skipped,mirroring
shell_detect::find_wsl_distros), reclaimed on uninstall by keyprefix plus the command line it wrote.
--shellis passed before--working-directory: a drive-root%Vends in\", which would swallow therest of the line if the directory came first.
Evidence / 验证依据
cargo test -p nebula --bin pebrelforcli::tests(24),runtime_api::(62),gpui_shell::workspace(98),shell_launch(1),residency(1) → all pass.python scripts/check_architecture.py --base main→ exit 0 (it failed withworkspace.rs: 4460 lines > 4363before the module extraction above — that iswhat prompted it).
scripts/tests/installer.tests.ps1→ the text assertions covering this changepass, including the argument-order regression (
--shellbefore--working-directory). The script's final step compiles the packaging payloadand needs a full release build tree (
pebrel-hook.exe,conpty.dll,OpenConsole.exe); it fails on a working tree without one, onmainas well.Inno Setup is not installed on this machine, so the Pascal was not compiled
here — it is limited to
RegGetSubkeyNames/RegQueryStringValue/RegWriteStringValue/RegDeleteKeyIncludingSubkeysand needs CI to confirm.shell_flag_parses_ahead_of_the_working_directory)and the IPC field (
tab_and_window_requests_take_an_optional_shell, includingthe no-shell form that older clients send), plus
wsl_launch_argsfor the idsemantics (
wsl:Team Linux, barewsl,wsl:with no name, non-WSL ids).(this machine can only run the Windows generator) and diffed character-for-character
against the generated Windows output; the byte comparison test runs on Linux.
The end-to-end menu click was exercised on the author's machine (cold start and
resident hand-off); no CI coverage exists for Explorer integration.
Required Review / 必须确认
CONTRIBUTING.md,docs/architecture.md, anddocs/project-constraints.md.python3 scripts/check_architecture.py --base mainpasses; budgets were not inflated to fit the change.