15
15
import * as vscode from "vscode" ;
16
16
import * as path from "path" ;
17
17
import * as fs from "fs/promises" ;
18
- import { createSwiftTask } from "../tasks/SwiftTaskProvider" ;
19
- import { WorkspaceContext } from "../WorkspaceContext" ;
20
- import { Version } from "../utilities/version" ;
21
18
import configuration from "../configuration" ;
19
+ import { createSwiftTask } from "../tasks/SwiftTaskProvider" ;
20
+ import { TemporaryFolder } from "../utilities/tempFolder" ;
21
+ import { TaskManager } from "../tasks/TaskManager" ;
22
+ import { SwiftToolchain } from "../toolchain/toolchain" ;
22
23
23
24
/**
24
- * Run the active document through the Swift REPL
25
+ * Runs the Swift code in the supplied document.
26
+ *
27
+ * This function checks for a valid document and Swift version, then creates and executes
28
+ * a Swift task to run the script file. The task is configured to always reveal its output
29
+ * and clear previous output. The working directory is set to the script's location.
30
+ *
31
+ * @param document - The text document containing the Swift script to run. If undefined, the function returns early.
32
+ * @param tasks - The TaskManager instance used to execute and manage the Swift task.
33
+ * @param toolchain - The SwiftToolchain to use for running the script.
34
+ * @returns A promise that resolves when the script has finished running, or returns early if the user is prompted
35
+ * for which swift version to use and they exit the dialog without choosing one.
25
36
*/
26
- export async function runSwiftScript ( ctx : WorkspaceContext ) {
27
- const document = vscode . window . activeTextEditor ?. document ;
28
- if ( ! document ) {
29
- return ;
30
- }
31
-
32
- if ( ! ctx . currentFolder ) {
37
+ export async function runSwiftScript (
38
+ document : vscode . TextDocument ,
39
+ tasks : TaskManager ,
40
+ toolchain : SwiftToolchain
41
+ ) {
42
+ const targetVersion = await targetSwiftVersion ( ) ;
43
+ if ( ! targetVersion ) {
33
44
return ;
34
45
}
35
46
36
- // Swift scripts require new swift driver to work on Windows. Swift driver is available
37
- // from v5.7 of Windows Swift
38
- if (
39
- process . platform === "win32" &&
40
- ctx . currentFolder . swiftVersion . isLessThan ( new Version ( 5 , 7 , 0 ) )
41
- ) {
42
- void vscode . window . showErrorMessage (
43
- "Run Swift Script is unavailable with the legacy driver on Windows."
47
+ await withDocumentFile ( document , async filename => {
48
+ const runTask = createSwiftTask (
49
+ [ "-swift-version" , targetVersion , filename ] ,
50
+ `Run ${ filename } ` ,
51
+ {
52
+ scope : vscode . TaskScope . Global ,
53
+ cwd : vscode . Uri . file ( path . dirname ( filename ) ) ,
54
+ presentationOptions : { reveal : vscode . TaskRevealKind . Always , clear : true } ,
55
+ } ,
56
+ toolchain
44
57
) ;
45
- return ;
46
- }
47
-
48
- let target : string ;
58
+ await tasks . executeTaskAndWait ( runTask ) ;
59
+ } ) ;
60
+ }
49
61
62
+ /**
63
+ * Determines the target Swift language version to use for script execution.
64
+ * If the configuration is set to "Ask Every Run", prompts the user to select a version.
65
+ * Otherwise, returns the default version from the user's settings.
66
+ *
67
+ * @returns {Promise<string | undefined> } The selected Swift version, or undefined if no selection was made.
68
+ */
69
+ async function targetSwiftVersion ( ) {
50
70
const defaultVersion = configuration . scriptSwiftLanguageVersion ;
51
71
if ( defaultVersion === "Ask Every Run" ) {
52
72
const picked = await vscode . window . showQuickPick (
@@ -59,41 +79,36 @@ export async function runSwiftScript(ctx: WorkspaceContext) {
59
79
placeHolder : "Select a target Swift version" ,
60
80
}
61
81
) ;
62
-
63
- if ( ! picked ) {
64
- return ;
65
- }
66
- target = picked . value ;
82
+ return picked ?. value ;
67
83
} else {
68
- target = defaultVersion ;
84
+ return defaultVersion ;
69
85
}
86
+ }
70
87
71
- let filename = document . fileName ;
72
- let isTempFile = false ;
88
+ /**
89
+ * Executes a callback with the filename of the given `vscode.TextDocument`.
90
+ * If the document is untitled (not yet saved to disk), it creates a temporary file,
91
+ * writes the document's content to it, and passes its filename to the callback.
92
+ * Otherwise, it ensures the document is saved and passes its actual filename.
93
+ *
94
+ * The temporary file is automatically deleted when the callback completes.
95
+ *
96
+ * @param document - The VSCode text document to operate on.
97
+ * @param callback - An async function that receives the filename of the document or temporary file.
98
+ * @returns A promise that resolves when the callback has completed.
99
+ */
100
+ async function withDocumentFile (
101
+ document : vscode . TextDocument ,
102
+ callback : ( filename : string ) => Promise < void >
103
+ ) {
73
104
if ( document . isUntitled ) {
74
- // if document hasn't been saved, save it to a temporary file
75
- isTempFile = true ;
76
- filename = ctx . tempFolder . filename ( document . fileName , "swift" ) ;
77
- const text = document . getText ( ) ;
78
- await fs . writeFile ( filename , text ) ;
105
+ const tmpFolder = await TemporaryFolder . create ( ) ;
106
+ await tmpFolder . withTemporaryFile ( "swift" , async filename => {
107
+ await fs . writeFile ( filename , document . getText ( ) ) ;
108
+ await callback ( filename ) ;
109
+ } ) ;
79
110
} else {
80
- // otherwise save document
81
111
await document . save ( ) ;
82
- }
83
- const runTask = createSwiftTask (
84
- [ "-swift-version" , target , filename ] ,
85
- `Run ${ filename } ` ,
86
- {
87
- scope : vscode . TaskScope . Global ,
88
- cwd : vscode . Uri . file ( path . dirname ( filename ) ) ,
89
- presentationOptions : { reveal : vscode . TaskRevealKind . Always , clear : true } ,
90
- } ,
91
- ctx . currentFolder . toolchain
92
- ) ;
93
- await ctx . tasks . executeTaskAndWait ( runTask ) ;
94
-
95
- // delete file after running swift
96
- if ( isTempFile ) {
97
- await fs . rm ( filename ) ;
112
+ await callback ( document . fileName ) ;
98
113
}
99
114
}
0 commit comments