Skip to content

Commit 060daf4

Browse files
Set Swift environment variables in the integrated terminal (#944)
1 parent 34b016a commit 060daf4

File tree

6 files changed

+128
-2
lines changed

6 files changed

+128
-2
lines changed

assets/icon-font.woff

1.41 KB
Binary file not shown.

package.json

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@
3030
],
3131
"main": "./dist/extension.js",
3232
"contributes": {
33+
"icons": {
34+
"swift-icon": {
35+
"description": "The official icon for the Swift programming language",
36+
"default": {
37+
"fontPath": "assets/icon-font.woff",
38+
"fontCharacter": "\\E001"
39+
}
40+
}
41+
},
42+
"terminal": {
43+
"profiles": [
44+
{
45+
"title": "Swift",
46+
"id": "swift.terminalProfile"
47+
}
48+
]
49+
},
3350
"languages": [
3451
{
3552
"id": "swift",
@@ -320,6 +337,12 @@
320337
"description": "Controls whether or not the extension will warn about being unable to create symlinks. (Windows only)",
321338
"scope": "application",
322339
"order": 14
340+
},
341+
"swift.enableTerminalEnvironment": {
342+
"type": "boolean",
343+
"default": true,
344+
"description": "Controls whether or not the extension will contribute Swift environment variables to the integrated terminal.",
345+
"order": 15
323346
}
324347
}
325348
},
@@ -1207,4 +1230,4 @@
12071230
"vscode-languageclient": "^9.0.1",
12081231
"xml2js": "^0.6.2"
12091232
}
1210-
}
1233+
}

src/configuration.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,12 @@ const configuration = {
283283
.getConfiguration("swift")
284284
.update("warnAboutSymlinkCreation", value, vscode.ConfigurationTarget.Global);
285285
},
286+
/** Whether or not the extension will contribute Swift environment variables to the integrated terminal */
287+
get enableTerminalEnvironment(): boolean {
288+
return vscode.workspace
289+
.getConfiguration("swift")
290+
.get<boolean>("enableTerminalEnvironment", true);
291+
},
286292
};
287293

288294
export default configuration;

src/extension.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { SwiftToolchain } from "./toolchain/toolchain";
3535
import { SwiftOutputChannel } from "./ui/SwiftOutputChannel";
3636
import { showReloadExtensionNotification } from "./ui/ReloadExtension";
3737
import { checkAndWarnAboutWindowsSymlinks } from "./ui/win32";
38+
import { SwiftEnvironmentVariablesManager, SwiftTerminalProfileProvider } from "./terminal";
3839

3940
/**
4041
* External API as exposed by the extension. Can be queried by other extensions
@@ -54,6 +55,14 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api |
5455

5556
checkAndWarnAboutWindowsSymlinks(outputChannel);
5657

58+
context.subscriptions.push(new SwiftEnvironmentVariablesManager(context));
59+
context.subscriptions.push(
60+
vscode.window.registerTerminalProfileProvider(
61+
"swift.terminalProfile",
62+
new SwiftTerminalProfileProvider()
63+
)
64+
);
65+
5766
const toolchain: SwiftToolchain | undefined = await SwiftToolchain.create()
5867
.then(toolchain => {
5968
toolchain.logDiagnostics(outputChannel);
@@ -96,6 +105,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api |
96105
showToolchainError();
97106
return;
98107
}
108+
99109
const workspaceContext = await WorkspaceContext.create(outputChannel, toolchain);
100110
context.subscriptions.push(...commands.register(workspaceContext));
101111

src/terminal.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the VS Code Swift open source project
4+
//
5+
// Copyright (c) 2024 the VS Code Swift project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of VS Code Swift project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import * as vscode from "vscode";
16+
import configuration from "./configuration";
17+
18+
/** The separator to use between paths in the PATH environment variable */
19+
const pathSeparator: string = process.platform === "win32" ? ";" : ":";
20+
21+
/**
22+
* Configures Swift environment variables for VS Code. Will automatically update
23+
* whenever the configuration changes.
24+
*/
25+
export class SwiftEnvironmentVariablesManager implements vscode.Disposable {
26+
private subscriptions: vscode.Disposable[] = [];
27+
28+
constructor(private context: vscode.ExtensionContext) {
29+
this.update();
30+
this.subscriptions.push(
31+
vscode.workspace.onDidChangeConfiguration(event => {
32+
if (
33+
event.affectsConfiguration("swift.enableTerminalEnvironment") ||
34+
event.affectsConfiguration("swift.path") ||
35+
event.affectsConfiguration("swift.swiftEnvironmentVariables")
36+
) {
37+
this.update();
38+
}
39+
})
40+
);
41+
}
42+
43+
dispose() {
44+
this.context.environmentVariableCollection.clear();
45+
for (const disposable of this.subscriptions) {
46+
disposable.dispose();
47+
}
48+
}
49+
50+
private update() {
51+
const environment = this.context.environmentVariableCollection;
52+
environment.clear();
53+
54+
if (!configuration.enableTerminalEnvironment) {
55+
return;
56+
}
57+
58+
const pathEnv = process.env["PATH"] ?? "";
59+
if (!pathEnv.includes(configuration.path)) {
60+
environment.prepend("PATH", configuration.path + pathSeparator);
61+
}
62+
for (const variable in configuration.swiftEnvironmentVariables) {
63+
environment.replace(variable, configuration.swiftEnvironmentVariables[variable]);
64+
}
65+
}
66+
}
67+
68+
/**
69+
* A {@link vscode.TerminalProfileProvider} used to create a terminal with the appropriate Swift
70+
* environment variables applied.
71+
*/
72+
export class SwiftTerminalProfileProvider implements vscode.TerminalProfileProvider {
73+
provideTerminalProfile(): vscode.ProviderResult<vscode.TerminalProfile> {
74+
const env: vscode.TerminalOptions["env"] = {
75+
...configuration.swiftEnvironmentVariables,
76+
};
77+
const pathEnv = process.env["PATH"] ?? "";
78+
if (!pathEnv.includes(configuration.path)) {
79+
env["PATH"] = configuration.path + pathSeparator + pathEnv;
80+
}
81+
return new vscode.TerminalProfile({
82+
name: "Swift Terminal",
83+
iconPath: new vscode.ThemeIcon("swift-icon"),
84+
env,
85+
});
86+
}
87+
}

src/ui/ToolchainSelection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ async function getQuickPickItems(
197197
if (process.platform === "linux") {
198198
actionItems.push({
199199
type: "action",
200-
label: "$(cloud-download) Install Swiftly for toolchain management...",
200+
label: "$(swift-icon) Install Swiftly for toolchain management...",
201201
detail: "Install https://swiftlang.github.io/swiftly to manage your toolchains on Linux",
202202
run: installSwiftly,
203203
});

0 commit comments

Comments
 (0)