Add VS Code create new project command#22103
Add VS Code create new project command#22103joshka wants to merge 2 commits intorust-lang:masterfrom
Conversation
| /** | ||
| * Entry point for the `rust-analyzer: Create New Project...` command. | ||
| * | ||
| * This function keeps the user-visible workflow in one place: resolve Cargo, gather the project | ||
| * inputs, run `cargo new`, and then apply the requested post-create workspace action. | ||
| */ |
There was a problem hiding this comment.
I intentionally steered codex to produce docs as the intent helps make the code readable IMO. Intention revealing names are good, but they don't convey tradeoffs / rationale / etc. This might be a bit noisier than most places in RA, but this is an intentional choice to improve such things.
| * inputs, run `cargo new`, and then apply the requested post-create workspace action. | ||
| */ | ||
| export function newProject(ctx: Ctx): Cmd { | ||
| return async () => { |
There was a problem hiding this comment.
I split this method up from a longer one that had each of the pieces in a single method. It was difficult to follow / understand. This feels a bit table of contents and similarly problematic - there's probably a good balance, but I feel this is closer to the right size than the opposite (all the helper methods inlined here).
| // Use the same effective environment rust-analyzer uses elsewhere so project creation sees | ||
| // toolchain wrappers, PATH overrides, and CARGO_HOME changes from configuration. | ||
| const cargoEnv = { ...process.env, ...ctx.config.serverExtraEnv }; |
There was a problem hiding this comment.
This is the part I'm least familiar with being correct choices. I think it's reasonably correct based on my understanding of what is going on here, but would value a second opinion.
| return async () => ctx.client.sendRequest(ra.reloadWorkspace); | ||
| } | ||
|
|
||
| type NewProjectKind = "bin" | "lib"; |
There was a problem hiding this comment.
This is a bunch of code to dump in an existing module. I'd tend to split additive code like this into a new separate module as it cuts down the cognitive load a bit, but went with keeping with the existing convention here rather than doing that. Ideally this code probably belongs in newProject.ts
| // variables may contain secrets such as API keys, tokens, and credentials, so failure logs | ||
| // must not dump the merged env here. | ||
| const commandLine = [logContext.cargo, ...logContext.args].join(" "); | ||
| log.error(message); |
There was a problem hiding this comment.
Not sure if there's an existing better logging approach here. The initial implementation just showed a notification, but I figure that there's a bunch of failure cases where the details of what's going on in cargo invocation is likely a bit more detailed for whatever reason. Maybe it's unlikely to hit this point. This should probably be extracted to a common function somewhere. Codex didn't find an obvious existing pattern / code to reuse for this.
| if (env?.["RUSTC_TOOLCHAIN"]) { | ||
| return Promise.resolve("cargo"); | ||
| } | ||
| if (env) { |
There was a problem hiding this comment.
I'm not sure I 100% understand this part of the change.
| if (env) { | ||
| return getPathForExecutableWithEnv("cargo", env); | ||
| } |
There was a problem hiding this comment.
The new-project command builds an effective Cargo environment from rust-analyzer configuration (server.extraEnv) before running cargo new. Resolve cargo from that same env here so the command does not discover one Cargo binary and then execute another.
Implement a rust-analyzer VS Code command for creating new Cargo projects from the editor. Add command registration, UI entry points, configuration for post-create behavior, and tests for the command flow. AI tools were used to research comparable editor behaviors and help refine the implementation plan; the resulting changes were reviewed before submission.
d7ff960 to
28f842e
Compare
|
This is a large wall of code, and I'm not even sure this feature is in scope for r-a. |
It's working, self-reviewed, tested manually and with unit tests, with a firm spec in the linked issue that I spent time iterating on prior to throwing the tooling at it, plus refactoring and improving the generated code. It exists because other extensions do this already, and it allows me to live in vscode rather than a terminal in order to create rust applications / libraries. This seems like a solidly good way to validate whether it's scope. r-a is the place where rust projects live in vscode. From that perspective creating a new rust project in vscode should live in r-a. |
| function displayProjectBasePath(parentFolder: vscode.Uri): string { | ||
| const fsPath = parentFolder.fsPath; | ||
| const home = os.homedir(); | ||
| if (fsPath === home) { |
There was a problem hiding this comment.
This won't ever be true on Windows, because the drive letter won't match. In general, I tend to be extremely suspicious of any path manipulation, because it's so easy to get it wrong.
Will handle UNC paths and normalize windows drive letters to lower-case
https://code.visualstudio.com/api/references/vscode-api#Uri
There was a problem hiding this comment.
Removed this home-relative ~ shortening for now to simplify the PR. We can re-add it later if it proves useful or necessary.
|
|
||
| // Keep local validation intentionally narrow: reject obviously invalid folder names up front, | ||
| // then let `cargo new` remain the source of truth for package-name-specific rules. | ||
| export function validateNewProjectName( |
There was a problem hiding this comment.
Is there any upside in doing this validation?
There was a problem hiding this comment.
https://doc.rust-lang.org/cargo/reference/manifest.html#the-name-field
Then why not harden the check to be like cargo itself? It seems like a pretty straightforward regex.
| const openNewWindow = "Open in New Window"; | ||
| const choices = [open, openNewWindow]; | ||
|
|
||
| const addToWorkspace = "Add to Workspace"; |
There was a problem hiding this comment.
What does "workspace" mean in this context? Is it about adding it to the cargo workspace or about the vscode workspace?
There was a problem hiding this comment.
vscode workspace. This is about running cargo new. That cannot add a crate to a workspace.
There was a problem hiding this comment.
I see. Would it be possible to change the wording?
If I used this cargo new command in a sub-folder of a cargo workspace, then the project would be automatically added to the cargo workspace.
At which point I'd be confused about why the extension is asking about a workspace. Until I figure out that it is asking about a vscode workspace.
|
As a general question, which other extensions do this? I don't have any extensions installed with a similar feature, except for the Typst one. Though I don't fully understand the Typst one. I think Typst does it, because it doesn't rely on a CLI? |
(From the issue plan details) #19338 (comment): |
Remove home-relative path shortening from the new-project prompt to avoid adding path-normalization logic for a cosmetic display detail. AI-assisted-by: OpenAI Codex









Fixes #19338.
Summary
Add a VS Code-side
rust-analyzer: Create New Project...command that creates a new Cargobinary or library package from the editor.
This adds:
rust-analyzer.newProjectcommandrust-analyzer.projectCreation.openAfterCreatesetting for post-create behaviorBehavior
The command flow is:
Binary ApplicationorLibrarycargo newThe implementation stays entirely in the VS Code extension and does not add any rust-analyzer
server/LSP changes.
Notes and tradeoffs
cargo newremain the source of truth for package-name-specific validation.server.extraEnv) both to resolveand to run Cargo. While implementing this, I found a broader extension-side inconsistency where
some tool-launch paths already pass an env through but
cargoPath(env)still resolved againstthe VS Code host process environment. This patch makes
cargoPath(env)honor the supplied env'sCARGO,PATH, andCARGO_HOMEview.variables may contain secrets (API keys, tokens, credentials), so failures log only the command,
cwd, exit status, and stdout/stderr/error details.
~/code) to make it clearthat the folder picker selects the parent directory and the project will be created underneath it.
Manual smoke tests
Tested manually for:
Open.Open in New Window.Add to Workspaceand confirm RA discovers it without window reload.Follow-up work
rust-analyzer.newProjectcurrently stillflips the
inRustProjectcontext totruebecause activation unconditionally sets that contexttoday. That is a broader context-management issue rather than part of the project-creation flow
itself, and should be handled as a follow-up so
newProjectremains available in empty windowswithout exposing unrelated Rust-project-only UI.
AI disclosure
I used Codex/AI tooling to research similar editor implementations, refine the implementation plan,
review parts of the code structure, and draft/refine portions of this change. I reviewed the
resulting code and notes before opening this PR.