Skip to content

Commit 6663693

Browse files
committed
feat: Pop a notification prompting the user to add a Cargo.toml of unlinked file to the linkedProjects
1 parent 8330f8e commit 6663693

File tree

6 files changed

+78
-14
lines changed

6 files changed

+78
-14
lines changed

crates/ide-diagnostics/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ use ide_db::{
7474
};
7575
use syntax::{algo::find_node_at_range, ast::AstNode, SyntaxNodePtr, TextRange};
7676

77+
// FIXME: Make this an enum
7778
#[derive(Copy, Clone, Debug, PartialEq)]
7879
pub struct DiagnosticCode(pub &'static str);
7980

crates/rust-analyzer/src/global_state.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ impl GlobalState {
331331
}
332332

333333
pub(crate) fn send_notification<N: lsp_types::notification::Notification>(
334-
&mut self,
334+
&self,
335335
params: N::Params,
336336
) {
337337
let not = lsp_server::Notification::new(N::METHOD.to_string(), params);
@@ -372,7 +372,7 @@ impl GlobalState {
372372
self.req_queue.incoming.is_completed(&request.id)
373373
}
374374

375-
fn send(&mut self, message: lsp_server::Message) {
375+
fn send(&self, message: lsp_server::Message) {
376376
self.sender.send(message).unwrap()
377377
}
378378
}

crates/rust-analyzer/src/reload.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ impl GlobalState {
112112
&& self.config.notifications().cargo_toml_not_found
113113
{
114114
status.health = lsp_ext::Health::Warning;
115-
message.push_str("Failed to discover workspace.\n\n");
115+
message.push_str("Failed to discover workspace.\n");
116+
message.push_str("Consider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/manual.html#rust-analyzer.linkedProjects) setting.\n\n");
116117
}
117118

118119
for ws in self.workspaces.iter() {

editors/code/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,11 @@
444444
"type": "string"
445445
}
446446
},
447+
"rust-analyzer.showUnlinkedFileNotification": {
448+
"markdownDescription": "Whether to show a notification for unlinked files asking the user to add the corresponding Cargo.toml to the linked projects setting.",
449+
"default": true,
450+
"type": "boolean"
451+
},
447452
"$generated-start": {},
448453
"rust-analyzer.assist.emitMustUse": {
449454
"markdownDescription": "Whether to insert #[must_use] when generating `as_` methods\nfor enum variants.",

editors/code/src/client.ts

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as diagnostics from "./diagnostics";
88
import { WorkspaceEdit } from "vscode";
99
import { Config, prepareVSCodeConfig } from "./config";
1010
import { randomUUID } from "crypto";
11+
import { sep as pathSeparator } from "path";
1112

1213
export interface Env {
1314
[name: string]: string;
@@ -69,7 +70,8 @@ export async function createClient(
6970
outputChannel: vscode.OutputChannel,
7071
initializationOptions: vscode.WorkspaceConfiguration,
7172
serverOptions: lc.ServerOptions,
72-
config: Config
73+
config: Config,
74+
unlinkedFiles: vscode.Uri[]
7375
): Promise<lc.LanguageClient> {
7476
const clientOptions: lc.LanguageClientOptions = {
7577
documentSelector: [{ scheme: "file", language: "rust" }],
@@ -119,6 +121,65 @@ export async function createClient(
119121
const preview = config.previewRustcOutput;
120122
const errorCode = config.useRustcErrorCode;
121123
diagnosticList.forEach((diag, idx) => {
124+
let value =
125+
typeof diag.code === "string" || typeof diag.code === "number"
126+
? diag.code
127+
: diag.code?.value;
128+
if (value === "unlinked-file" && !unlinkedFiles.includes(uri)) {
129+
let config = vscode.workspace.getConfiguration("rust-analyzer");
130+
if (config.get("showUnlinkedFileNotification")) {
131+
unlinkedFiles.push(uri);
132+
let folder = vscode.workspace.getWorkspaceFolder(uri)?.uri.fsPath;
133+
if (folder) {
134+
let parent_backslash = uri.fsPath.lastIndexOf(
135+
pathSeparator + "src"
136+
);
137+
let parent = uri.fsPath.substring(0, parent_backslash);
138+
139+
if (parent.startsWith(folder)) {
140+
let path = vscode.Uri.file(
141+
parent + pathSeparator + "Cargo.toml"
142+
);
143+
void vscode.workspace.fs.stat(path).then(() => {
144+
vscode.window
145+
.showInformationMessage(
146+
`This rust file does not belong to a loaded cargo project. It looks like it might belong to the workspace at ${path}, do you want to add it to the linked Projects?`,
147+
"Yes",
148+
"No",
149+
"Don't show this again"
150+
)
151+
.then((choice) => {
152+
switch (choice) {
153+
case "Yes":
154+
break;
155+
case "No":
156+
config.update(
157+
"linkedProjects",
158+
config
159+
.get<any[]>("linkedProjects")
160+
?.concat(
161+
path.fsPath.substring(
162+
folder!.length
163+
)
164+
),
165+
false
166+
);
167+
break;
168+
case "Don't show this again":
169+
config.update(
170+
"showUnlinkedFileNotification",
171+
false,
172+
false
173+
);
174+
break;
175+
}
176+
});
177+
});
178+
}
179+
}
180+
}
181+
}
182+
122183
// Abuse the fact that VSCode leaks the LSP diagnostics data field through the
123184
// Diagnostic class, if they ever break this we are out of luck and have to go
124185
// back to the worst diagnostics experience ever:)
@@ -138,22 +199,15 @@ export async function createClient(
138199
.substring(0, index)
139200
.replace(/^ -->[^\n]+\n/m, "");
140201
}
141-
let value;
142-
if (errorCode) {
143-
if (typeof diag.code === "string" || typeof diag.code === "number") {
144-
value = diag.code;
145-
} else {
146-
value = diag.code?.value;
147-
}
148-
}
149202
diag.code = {
150203
target: vscode.Uri.from({
151204
scheme: diagnostics.URI_SCHEME,
152205
path: `/diagnostic message [${idx.toString()}]`,
153206
fragment: uri.toString(),
154207
query: idx.toString(),
155208
}),
156-
value: value ?? "Click for full compiler diagnostic",
209+
value:
210+
errorCode && value ? value : "Click for full compiler diagnostic",
157211
};
158212
}
159213
});

editors/code/src/ctx.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export class Ctx {
8282
private state: PersistentState;
8383
private commandFactories: Record<string, CommandFactory>;
8484
private commandDisposables: Disposable[];
85+
private unlinkedFiles: vscode.Uri[];
8586

8687
get client() {
8788
return this._client;
@@ -99,6 +100,7 @@ export class Ctx {
99100
this.clientSubscriptions = [];
100101
this.commandDisposables = [];
101102
this.commandFactories = commandFactories;
103+
this.unlinkedFiles = [];
102104

103105
this.state = new PersistentState(extCtx.globalState);
104106
this.config = new Config(extCtx);
@@ -218,7 +220,8 @@ export class Ctx {
218220
this.outputChannel,
219221
initializationOptions,
220222
serverOptions,
221-
this.config
223+
this.config,
224+
this.unlinkedFiles
222225
);
223226
this.pushClientCleanup(
224227
this._client.onNotification(ra.serverStatus, (params) =>

0 commit comments

Comments
 (0)