Skip to content

Commit 03bc90f

Browse files
committed
feat: windows installation working (after juliaup)
1 parent eedcf94 commit 03bc90f

File tree

2 files changed

+69
-33
lines changed

2 files changed

+69
-33
lines changed

src/platformUtils.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,27 @@ export function getExecutableName(baseName: string): string {
1616
return isWindows() ? `${baseName}.exe` : baseName;
1717
}
1818

19+
/**
20+
* Convert a file path to use forward slashes for Julia code
21+
* Julia accepts forward slashes on all platforms, including Windows
22+
* This avoids backslash escaping issues in shell commands
23+
*/
24+
export function toJuliaPath(path: string): string {
25+
// Replace all backslashes with forward slashes
26+
return path.replace(/\\/g, "/");
27+
}
28+
1929
/**
2030
* Escape a Julia code string for shell execution
21-
* On Windows, ShellExecution requires special handling of quotes
31+
* On Windows PowerShell, VSCode wraps the -e argument in single quotes,
32+
* so double quotes inside don't need escaping, but single quotes do.
2233
*/
2334
export function escapeJuliaCode(code: string): string {
2435
if (isWindows()) {
25-
// On Windows, we need to escape double quotes inside the Julia code
26-
// by replacing them with \"
27-
return code.replace(/"/g, '\\"');
36+
// On Windows PowerShell, VSCode wraps the -e argument in single quotes.
37+
// Inside PowerShell single quotes, we need to escape single quotes by doubling them
38+
// Double quotes are treated literally and don't need escaping
39+
return code.replace(/'/g, "''");
2840
}
2941
// On Unix-like systems, the shell handles quotes correctly
3042
return code;

src/plutoServerTask.ts

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as vscode from "vscode";
22
import { isDefined } from "./helpers.ts";
33
import { isPortAvailable, findAvailablePort } from "./portUtils.ts";
4-
import { getExecutableName, escapeJuliaCode } from "./platformUtils.ts";
4+
import { getExecutableName } from "./platformUtils.ts";
55

66
/**
77
* Parse Julia executable path to extract command and arguments
@@ -156,29 +156,34 @@ export class PlutoServerTaskManager {
156156

157157
// Julia script that runs `jh auth env` and writes output to file
158158
const jhCommand = getExecutableName("jh");
159+
// Pass the auth file path via environment variable to avoid any escaping issues
159160
const juliaScript = `
160-
try
161-
output = read(\`${jhCommand} auth env\`, String)
162-
open("${authOutputUri.fsPath}", "w") do io
163-
write(io, output)
164-
end
161+
s = string; auth_path = ENV[s(:VSCODE_PLUTO_AUTH_FILE)]
162+
try output = read(\`${jhCommand} auth env\`, String)
163+
open(io -> write(io, output), auth_path, s(:w))
165164
catch e
166-
# Command failed or not found - write empty file to signal completion
167-
open("${authOutputUri.fsPath}", "w") do io
168-
write(io, "")
169-
end
170-
end; try read(\`${jhCommand} auth refresh\`, String) catch; end
171-
`.trim();
165+
open(io -> write(io, s()), auth_path, s(:w))
166+
end
167+
try read(\`${jhCommand} auth refresh\`, String)
168+
catch e;
169+
end`
170+
.replaceAll("\n", ";")
171+
.trim();
172172

173173
// Create task to run the Julia script
174174
const authTaskDefinition: vscode.TaskDefinition = {
175175
type: "pluto-auth-setup",
176176
};
177177

178-
const authExecution = new vscode.ShellExecution(defaultJulia, [
179-
"-e",
180-
escapeJuliaCode(juliaScript),
181-
]);
178+
const authExecution = new vscode.ShellExecution(
179+
defaultJulia,
180+
["-e", juliaScript],
181+
{
182+
env: {
183+
VSCODE_PLUTO_AUTH_FILE: authOutputUri.fsPath,
184+
},
185+
}
186+
);
182187

183188
const authTask = new vscode.Task(
184189
authTaskDefinition,
@@ -262,13 +267,8 @@ end; try read(\`${jhCommand} auth refresh\`, String) catch; end
262267
const { command, args: baseArgs } = parseJuliaExecutable(executablePath);
263268

264269
// Build Julia command arguments
265-
const plutoCode = `using Pluto; Pluto.run(port=${this.actualPort}; require_secret_for_open_links=false, require_secret_for_access=false, launch_browser=false)`;
266-
const juliaArgs = [
267-
`+${juliaVersion}`,
268-
...baseArgs,
269-
"-e",
270-
escapeJuliaCode(plutoCode),
271-
];
270+
const plutoCode = `import Pkg;s = string;Pkg.activate(mkpath(joinpath(Pkg.depots1(), s(:environments), s(:vscode_pluto_notebook), string(VERSION))));using Pluto; Pluto.run(port=${this.actualPort}; require_secret_for_open_links=false, require_secret_for_access=false, launch_browser=false)`;
271+
const juliaArgs = [`+${juliaVersion}`, ...baseArgs, "-e", plutoCode];
272272

273273
console.log(
274274
`[PlutoServerTask] Resolved command: ${command} ${juliaArgs.join(" ")}`
@@ -306,12 +306,20 @@ end; try read(\`${jhCommand} auth refresh\`, String) catch; end
306306
const juliaupTask = new vscode.Task(
307307
juliaupTaskDefinition,
308308
vscode.TaskScope.Workspace,
309-
`Install Julia ${juliaVersion}`,
309+
`Pluto Server (port ${this.actualPort})`,
310310
"pluto-notebook",
311311
juliaupExecution,
312312
[]
313313
);
314314
juliaupTask.isBackground = false;
315+
juliaupTask.presentationOptions = {
316+
reveal: vscode.TaskRevealKind.Always,
317+
panel: vscode.TaskPanelKind.Shared,
318+
showReuseMessage: false,
319+
clear: false,
320+
focus: false,
321+
echo: true,
322+
};
315323

316324
const juliaupTaskExecution = await vscode.tasks.executeTask(juliaupTask);
317325
await new Promise<void>((resolve, reject) => {
@@ -358,23 +366,39 @@ end; try read(\`${jhCommand} auth refresh\`, String) catch; end
358366
};
359367

360368
// Create an envrionment for the SERVER where Pluto will run in. Let julia manage paths
361-
const setupCode = `import Pkg; Pkg.activate(mkpath(joinpath(Pkg.depots1(), "environments", "vscode-pluto-notebook", string(VERSION)))); Pkg.add("Pluto"); Pkg.instantiate(); Pkg.precompile();`;
369+
const setupCode = `import Pkg;
370+
s = string
371+
Pkg.activate(mkpath(joinpath(Pkg.depots1(), s(:environments), s(:vscode_pluto_notebook), string(VERSION))));
372+
Pkg.Registry.add();
373+
Pkg.add(s(:Pluto));
374+
Pkg.instantiate();
375+
Pkg.precompile();`
376+
.replaceAll("\n", ";")
377+
.trim();
362378
const setupExecution = new vscode.ShellExecution(command, [
363379
`+${juliaVersion}`,
364380
...baseArgs,
365381
`-e`,
366-
escapeJuliaCode(setupCode),
382+
setupCode,
367383
]);
368384

369385
const task1 = new vscode.Task(
370386
setupTaskDefinition,
371387
vscode.TaskScope.Workspace,
372-
`Instantiate Pluto`,
388+
`Pluto Server (port ${this.actualPort})`,
373389
"pluto-notebook",
374390
setupExecution,
375391
[] // No problem matchers
376392
);
377393
task1.isBackground = false;
394+
task1.presentationOptions = {
395+
reveal: vscode.TaskRevealKind.Always,
396+
panel: vscode.TaskPanelKind.Shared,
397+
showReuseMessage: false,
398+
clear: false,
399+
focus: false,
400+
echo: true,
401+
};
378402

379403
// Execute setup task and wait for it to complete
380404
const setupExecution1 = await vscode.tasks.executeTask(task1);
@@ -413,10 +437,10 @@ end; try read(\`${jhCommand} auth refresh\`, String) catch; end
413437
[] // No problem matchers
414438
);
415439

416-
// Configure task presentation
440+
// Configure task presentation - use Shared panel to reuse the same terminal as setup task
417441
task.presentationOptions = {
418442
reveal: vscode.TaskRevealKind.Always,
419-
panel: vscode.TaskPanelKind.Dedicated,
443+
panel: vscode.TaskPanelKind.Shared,
420444
showReuseMessage: false,
421445
clear: false,
422446
focus: false,

0 commit comments

Comments
 (0)