Skip to content

Commit 9b7b435

Browse files
use server info
1 parent 5be3c63 commit 9b7b435

5 files changed

Lines changed: 96 additions & 12 deletions

File tree

lsp/src/codeLens.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ type CodeLensPosition = {
1919

2020
type RunMainArgs = {
2121
uri?: string;
22+
cwd?: string;
2223
};
2324

2425
type RunTestArgs = {
2526
uri?: string;
27+
cwd?: string;
2628
position?: CodeLensPosition;
2729
testName?: string;
2830
className?: string;
@@ -45,10 +47,6 @@ function scopeForUri(uri: vscode.Uri): vscode.WorkspaceFolder | vscode.TaskScope
4547
return vscode.workspace.getWorkspaceFolder(uri) ?? vscode.TaskScope.Workspace;
4648
}
4749

48-
function cwdForUri(uri: vscode.Uri): string | undefined {
49-
return vscode.workspace.getWorkspaceFolder(uri)?.uri.fsPath;
50-
}
51-
5250
function moduleNameFromPath(uri: vscode.Uri): string | undefined {
5351
const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri);
5452
if (!workspaceFolder) {
@@ -85,6 +83,7 @@ async function runAtCursor(
8583

8684
async function executeProcessTask(
8785
uri: vscode.Uri,
86+
cwd: string | undefined,
8887
definition: vscode.TaskDefinition,
8988
label: string,
9089
command: string,
@@ -98,7 +97,7 @@ async function executeProcessTask(
9897
label,
9998
TASK_SOURCE,
10099
new vscode.ProcessExecution(command, args, {
101-
cwd: cwdForUri(uri),
100+
cwd,
102101
}),
103102
);
104103
task.presentationOptions = {
@@ -128,6 +127,7 @@ async function runMainFile(
128127
}
129128
await executeProcessTask(
130129
uri,
130+
args.cwd,
131131
{type: TASK_SOURCE, action: 'runMain'},
132132
'Pyrefly: Run File',
133133
interpreter,
@@ -143,6 +143,7 @@ async function runTestAtLocation(
143143
return;
144144
}
145145
const uri = vscode.Uri.parse(args.uri);
146+
const cwd = args.cwd;
146147
const className = args.className;
147148
const testName = args.testName;
148149

@@ -175,6 +176,7 @@ async function runTestAtLocation(
175176
}
176177
await executeProcessTask(
177178
uri,
179+
cwd,
178180
{type: TASK_SOURCE, action: 'runUnittest'},
179181
'Pyrefly: Run Test',
180182
interpreter,
@@ -192,6 +194,7 @@ async function runTestAtLocation(
192194
}
193195
await executeProcessTask(
194196
uri,
197+
cwd,
195198
{type: TASK_SOURCE, action: 'runPytest'},
196199
'Pyrefly: Run Test',
197200
interpreter,

pyrefly/lib/lsp/non_wasm/server.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,6 +2405,24 @@ impl Server {
24052405
telemetry.set_file_stats(TelemetryFileStats { uri, config_root });
24062406
}
24072407

2408+
fn runnable_code_lens_cwd(&self, path: &std::path::Path) -> Option<String> {
2409+
let config = self.state.config_finder().python_file(
2410+
ModuleNameWithKind::guaranteed(ModuleName::unknown()),
2411+
&ModulePath::filesystem(path.to_path_buf()),
2412+
);
2413+
let cwd = config
2414+
.source
2415+
.root()
2416+
.map(std::path::Path::to_path_buf)
2417+
.or_else(|| {
2418+
self.workspaces
2419+
.get_with(path.to_path_buf(), |(workspace_root, _)| {
2420+
workspace_root.cloned()
2421+
})
2422+
})?;
2423+
Some(cwd.to_string_lossy().into_owned())
2424+
}
2425+
24082426
fn send_response(&self, x: Response) {
24092427
self.connection.send(Message::Response(x))
24102428
}
@@ -4681,14 +4699,15 @@ impl Server {
46814699
let path = self.path_for_uri(uri)?;
46824700
let runnable_code_lens = self
46834701
.workspaces
4684-
.get_with(path, |(_, workspace)| workspace.runnable_code_lens);
4702+
.get_with(path.clone(), |(_, workspace)| workspace.runnable_code_lens);
46854703
if !runnable_code_lens {
46864704
return Some(Vec::new());
46874705
}
46884706
let maybe_cell_idx = self.maybe_get_cell_index(uri);
46894707
let handle = self.make_handle_if_enabled(uri, Some(CodeLensRequest::METHOD))?;
46904708
let info = transaction.get_module_info(&handle)?;
46914709
let entries = transaction.code_lens_entries(&handle)?;
4710+
let cwd = self.runnable_code_lens_cwd(&path);
46924711

46934712
let mut lenses = Vec::new();
46944713
for entry in entries {
@@ -4697,14 +4716,20 @@ impl Server {
46974716
}
46984717
let range = info.to_lsp_range(entry.range);
46994718
let (title, command, arguments) = match entry.kind {
4700-
CodeLensKind::Run => (
4701-
"Run",
4702-
"pyrefly.runMain",
4703-
Some(vec![serde_json::json!({ "uri": uri.to_string() })]),
4704-
),
4719+
CodeLensKind::Run => {
4720+
let mut args = serde_json::Map::new();
4721+
args.insert("uri".to_owned(), serde_json::json!(uri.to_string()));
4722+
if let Some(cwd) = &cwd {
4723+
args.insert("cwd".to_owned(), serde_json::json!(cwd));
4724+
}
4725+
("Run", "pyrefly.runMain", Some(vec![Value::Object(args)]))
4726+
}
47054727
CodeLensKind::Test => {
47064728
let mut args = serde_json::Map::new();
47074729
args.insert("uri".to_owned(), serde_json::json!(uri.to_string()));
4730+
if let Some(cwd) = &cwd {
4731+
args.insert("cwd".to_owned(), serde_json::json!(cwd));
4732+
}
47084733
args.insert(
47094734
"position".to_owned(),
47104735
serde_json::json!({

pyrefly/lib/test/lsp/lsp_interaction/code_lens.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ fn test_code_lens_for_tests_and_main() {
6565
has_run |= lens.range.start.line == 17;
6666
}
6767
if command.command == "pyrefly.runTest" && command.title == "Test" {
68-
let args = command.arguments.unwrap_or_default();
68+
let args = command.arguments.clone().unwrap_or_default();
6969
let Some(Value::Object(obj)) = args.get(0) else {
7070
continue;
7171
};
@@ -91,6 +91,56 @@ fn test_code_lens_for_tests_and_main() {
9191
interaction.shutdown().unwrap();
9292
}
9393

94+
#[test]
95+
fn test_code_lens_uses_config_root_for_cwd() {
96+
let root = get_test_files_root();
97+
let mut interaction = LspInteraction::new();
98+
let test_root = root.path().join("code_lens");
99+
interaction.set_root(test_root.clone());
100+
interaction
101+
.initialize(InitializeSettings {
102+
configuration: Some(Some(runnable_code_lens_config())),
103+
..Default::default()
104+
})
105+
.unwrap();
106+
107+
interaction
108+
.client
109+
.did_open("nested_project/main_and_tests.py");
110+
111+
let path = test_root.join("nested_project/main_and_tests.py");
112+
let uri = Url::from_file_path(&path).unwrap();
113+
let expected_cwd = test_root
114+
.join("nested_project")
115+
.to_string_lossy()
116+
.into_owned();
117+
118+
interaction
119+
.client
120+
.send_request::<CodeLensRequest>(json!({
121+
"textDocument": {
122+
"uri": uri.to_string()
123+
},
124+
}))
125+
.expect_response_with(|response: Option<Vec<CodeLens>>| {
126+
let Some(lenses) = response else {
127+
return false;
128+
};
129+
let mut saw_lens = false;
130+
lenses.into_iter().all(|lens| {
131+
saw_lens = true;
132+
lens.command
133+
.and_then(|command| command.arguments)
134+
.and_then(|args| args.into_iter().next())
135+
.and_then(|arg| arg.get("cwd").and_then(Value::as_str).map(str::to_owned))
136+
.is_some_and(|cwd| cwd == expected_cwd)
137+
}) && saw_lens
138+
})
139+
.unwrap();
140+
141+
interaction.shutdown().unwrap();
142+
}
143+
94144
#[test]
95145
fn test_code_lens_ignores_stub_files() {
96146
let root = get_test_files_root();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
def test_nested():
2+
pass
3+
4+
if __name__ == "__main__":
5+
test_nested()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[tool.pyrefly]

0 commit comments

Comments
 (0)