Skip to content

Commit 2735bc3

Browse files
authored
Use FileWatcher for background compilation (#1431)
* Use FileWatcher for background compilation This `swift.backgroundCompilation` setting listened for file save events from VS Code and triggered the build task. This meant that only modifications made by saving in a VS Code editor would trigger background compilation. Switch to using a `vscode.FileWatcher` so background compilation still gets kicked off even if a file is modified from outside VS Code. This is useful if you have a command plugin that modifies source files like swift-format. Issue: #1274
1 parent 767fb08 commit 2735bc3

File tree

5 files changed

+84
-48
lines changed

5 files changed

+84
-48
lines changed

package-lock.json

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,6 +1648,7 @@
16481648
"@types/glob": "^7.1.6",
16491649
"@types/lcov-parse": "^1.0.2",
16501650
"@types/lodash.throttle": "^4.1.9",
1651+
"@types/lodash.debounce": "^4.0.9",
16511652
"@types/mocha": "^10.0.10",
16521653
"@types/mock-fs": "^4.13.4",
16531654
"@types/node": "^18.19.80",
@@ -1671,6 +1672,7 @@
16711672
"eslint": "^8.57.0",
16721673
"eslint-config-prettier": "^10.1.1",
16731674
"lodash.throttle": "^4.1.1",
1675+
"lodash.debounce": "^4.0.8",
16741676
"mocha": "^10.8.2",
16751677
"mock-fs": "^5.5.0",
16761678
"node-pty": "^1.0.0",

src/BackgroundCompilation.ts

Lines changed: 49 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -13,63 +13,67 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
import * as vscode from "vscode";
16-
import * as path from "path";
17-
import { isPathInsidePath } from "./utilities/filesystem";
1816
import { getBuildAllTask } from "./tasks/SwiftTaskProvider";
1917
import configuration from "./configuration";
2018
import { FolderContext } from "./FolderContext";
21-
import { WorkspaceContext } from "./WorkspaceContext";
2219
import { TaskOperation } from "./tasks/TaskQueue";
20+
// eslint-disable-next-line @typescript-eslint/no-require-imports
21+
import debounce = require("lodash.debounce");
2322

24-
export class BackgroundCompilation {
25-
private waitingToRun = false;
23+
export class BackgroundCompilation implements vscode.Disposable {
24+
private workspaceFileWatcher?: vscode.FileSystemWatcher;
25+
private configurationEventDisposable?: vscode.Disposable;
26+
private validFileTypes = ["swift", "c", "cpp", "h", "hpp", "m", "mm"];
27+
private disposables: vscode.Disposable[] = [];
2628

27-
constructor(private folderContext: FolderContext) {}
28-
29-
/**
30-
* Start onDidSave handler which will kick off compilation tasks
31-
*
32-
* The task works out which folder the saved file is in and then
33-
* will call `runTask` on the background compilation attached to
34-
* that folder.
35-
* */
36-
static start(workspaceContext: WorkspaceContext): vscode.Disposable {
37-
const onDidSaveDocument = vscode.workspace.onDidSaveTextDocument(event => {
38-
if (configuration.backgroundCompilation === false) {
39-
return;
40-
}
41-
42-
// is document a valid type for rebuild
43-
const languages = ["swift", "c", "cpp", "objective-c", "objective-cpp"];
44-
let foundLanguage = false;
45-
languages.forEach(lang => {
46-
if (event.languageId === lang) {
47-
foundLanguage = true;
29+
constructor(private folderContext: FolderContext) {
30+
// We only want to configure the file watcher if background compilation is enabled.
31+
this.configurationEventDisposable = vscode.workspace.onDidChangeConfiguration(event => {
32+
if (event.affectsConfiguration("swift.backgroundCompilation", folderContext.folder)) {
33+
if (configuration.backgroundCompilation) {
34+
this.setupFileWatching();
35+
} else {
36+
this.stopFileWatching();
4837
}
49-
});
50-
if (foundLanguage === false) {
51-
return;
5238
}
39+
});
40+
41+
if (configuration.backgroundCompilation) {
42+
this.setupFileWatching();
43+
}
44+
}
5345

54-
// is editor document in any of the current FolderContexts
55-
const folderContext = workspaceContext.folders.find(context => {
56-
return isPathInsidePath(event.uri.fsPath, context.folder.fsPath);
57-
});
46+
private setupFileWatching() {
47+
const fileTypes = this.validFileTypes.join(",");
48+
const rootFolders = ["Sources", "Tests", "Snippets", "Plugins"].join(",");
49+
this.disposables.push(
50+
(this.workspaceFileWatcher = vscode.workspace.createFileSystemWatcher(
51+
`**/{${rootFolders}}/**/*.{${fileTypes}}`
52+
))
53+
);
5854

59-
if (!folderContext) {
60-
return;
61-
}
55+
// Throttle events since many change events can be recieved in a short time if the user
56+
// does a "Save All" or a process writes several files in quick succession.
57+
this.disposables.push(
58+
this.workspaceFileWatcher.onDidChange(
59+
debounce(
60+
() => {
61+
this.runTask();
62+
},
63+
100 /* 10 times per second */,
64+
{ trailing: true }
65+
)
66+
)
67+
);
68+
}
6269

63-
// don't run auto-build if saving Package.swift as it clashes with the resolve
64-
// that is run after the Package.swift is saved
65-
if (path.join(folderContext.folder.fsPath, "Package.swift") === event.uri.fsPath) {
66-
return;
67-
}
70+
private stopFileWatching() {
71+
this.disposables.forEach(disposable => disposable.dispose());
72+
}
6873

69-
// run background compilation task
70-
folderContext.backgroundCompilation.runTask();
71-
});
72-
return { dispose: () => onDidSaveDocument.dispose() };
74+
dispose() {
75+
this.configurationEventDisposable?.dispose();
76+
this.disposables.forEach(disposable => disposable.dispose());
7377
}
7478

7579
/**

src/FolderContext.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export class FolderContext implements vscode.Disposable {
5454
this.linuxMain?.dispose();
5555
this.packageWatcher.dispose();
5656
this.testExplorer?.dispose();
57+
this.backgroundCompilation.dispose();
5758
}
5859

5960
/**

src/WorkspaceContext.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import { isPathInsidePath } from "./utilities/filesystem";
2222
import { LanguageClientManager } from "./sourcekit-lsp/LanguageClientManager";
2323
import { TemporaryFolder } from "./utilities/tempFolder";
2424
import { TaskManager } from "./tasks/TaskManager";
25-
import { BackgroundCompilation } from "./BackgroundCompilation";
2625
import { makeDebugConfigurations } from "./debugger/launch";
2726
import configuration from "./configuration";
2827
import contextKeys from "./contextKeys";
@@ -121,7 +120,6 @@ export class WorkspaceContext implements vscode.Disposable {
121120
});
122121
}
123122
});
124-
const backgroundCompilationOnDidSave = BackgroundCompilation.start(this);
125123
const contextKeysUpdate = this.onDidChangeFolders(event => {
126124
switch (event.operation) {
127125
case FolderOperation.remove:
@@ -174,7 +172,6 @@ export class WorkspaceContext implements vscode.Disposable {
174172
swiftFileWatcher,
175173
onDidEndTask,
176174
this.commentCompletionProvider,
177-
backgroundCompilationOnDidSave,
178175
contextKeysUpdate,
179176
onChangeConfig,
180177
this.tasks,

0 commit comments

Comments
 (0)