Skip to content

Use FileWatcher for background compilation #1431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 17, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1600,6 +1600,7 @@
"@types/glob": "^7.1.6",
"@types/lcov-parse": "^1.0.2",
"@types/lodash.throttle": "^4.1.9",
"@types/lodash.debounce": "^4.0.9",
"@types/mocha": "^10.0.10",
"@types/mock-fs": "^4.13.4",
"@types/node": "^18.19.80",
@@ -1623,6 +1624,7 @@
"eslint": "^8.57.0",
"eslint-config-prettier": "^10.1.1",
"lodash.throttle": "^4.1.1",
"lodash.debounce": "^4.0.8",
"mocha": "^10.8.2",
"mock-fs": "^5.5.0",
"node-pty": "^1.0.0",
94 changes: 49 additions & 45 deletions src/BackgroundCompilation.ts
Original file line number Diff line number Diff line change
@@ -13,63 +13,67 @@
//===----------------------------------------------------------------------===//

import * as vscode from "vscode";
import * as path from "path";
import { isPathInsidePath } from "./utilities/filesystem";
import { getBuildAllTask } from "./tasks/SwiftTaskProvider";
import configuration from "./configuration";
import { FolderContext } from "./FolderContext";
import { WorkspaceContext } from "./WorkspaceContext";
import { TaskOperation } from "./tasks/TaskQueue";
// eslint-disable-next-line @typescript-eslint/no-require-imports
import debounce = require("lodash.debounce");

export class BackgroundCompilation {
private waitingToRun = false;
export class BackgroundCompilation implements vscode.Disposable {
private workspaceFileWatcher?: vscode.FileSystemWatcher;
private configurationEventDisposable?: vscode.Disposable;
private validFileTypes = ["swift", "c", "cpp", "h", "hpp", "m", "mm"];
private disposables: vscode.Disposable[] = [];

constructor(private folderContext: FolderContext) {}

/**
* Start onDidSave handler which will kick off compilation tasks
*
* The task works out which folder the saved file is in and then
* will call `runTask` on the background compilation attached to
* that folder.
* */
static start(workspaceContext: WorkspaceContext): vscode.Disposable {
const onDidSaveDocument = vscode.workspace.onDidSaveTextDocument(event => {
if (configuration.backgroundCompilation === false) {
return;
}

// is document a valid type for rebuild
const languages = ["swift", "c", "cpp", "objective-c", "objective-cpp"];
let foundLanguage = false;
languages.forEach(lang => {
if (event.languageId === lang) {
foundLanguage = true;
constructor(private folderContext: FolderContext) {
// We only want to configure the file watcher if background compilation is enabled.
this.configurationEventDisposable = vscode.workspace.onDidChangeConfiguration(event => {
if (event.affectsConfiguration("swift.backgroundCompilation", folderContext.folder)) {
if (configuration.backgroundCompilation) {
this.setupFileWatching();
} else {
this.stopFileWatching();
}
});
if (foundLanguage === false) {
return;
}
});

if (configuration.backgroundCompilation) {
this.setupFileWatching();
}
}

// is editor document in any of the current FolderContexts
const folderContext = workspaceContext.folders.find(context => {
return isPathInsidePath(event.uri.fsPath, context.folder.fsPath);
});
private setupFileWatching() {
const fileTypes = this.validFileTypes.join(",");
const rootFolders = ["Sources", "Tests", "Snippets", "Plugins"].join(",");
this.disposables.push(
(this.workspaceFileWatcher = vscode.workspace.createFileSystemWatcher(
`**/{${rootFolders}}/**/*.{${fileTypes}}`
))
);

if (!folderContext) {
return;
}
// Throttle events since many change events can be recieved in a short time if the user
// does a "Save All" or a process writes several files in quick succession.
this.disposables.push(
this.workspaceFileWatcher.onDidChange(
debounce(
() => {
this.runTask();
},
100 /* 10 times per second */,
{ trailing: true }
)
)
);
}

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

// run background compilation task
folderContext.backgroundCompilation.runTask();
});
return { dispose: () => onDidSaveDocument.dispose() };
dispose() {
this.configurationEventDisposable?.dispose();
this.disposables.forEach(disposable => disposable.dispose());
}

/**
1 change: 1 addition & 0 deletions src/FolderContext.ts
Original file line number Diff line number Diff line change
@@ -54,6 +54,7 @@ export class FolderContext implements vscode.Disposable {
this.linuxMain?.dispose();
this.packageWatcher.dispose();
this.testExplorer?.dispose();
this.backgroundCompilation.dispose();
}

/**
3 changes: 0 additions & 3 deletions src/WorkspaceContext.ts
Original file line number Diff line number Diff line change
@@ -22,7 +22,6 @@ import { isPathInsidePath } from "./utilities/filesystem";
import { LanguageClientManager } from "./sourcekit-lsp/LanguageClientManager";
import { TemporaryFolder } from "./utilities/tempFolder";
import { TaskManager } from "./tasks/TaskManager";
import { BackgroundCompilation } from "./BackgroundCompilation";
import { makeDebugConfigurations } from "./debugger/launch";
import configuration from "./configuration";
import contextKeys from "./contextKeys";
@@ -121,7 +120,6 @@ export class WorkspaceContext implements vscode.Disposable {
});
}
});
const backgroundCompilationOnDidSave = BackgroundCompilation.start(this);
const contextKeysUpdate = this.onDidChangeFolders(event => {
switch (event.operation) {
case FolderOperation.remove:
@@ -174,7 +172,6 @@ export class WorkspaceContext implements vscode.Disposable {
swiftFileWatcher,
onDidEndTask,
this.commentCompletionProvider,
backgroundCompilationOnDidSave,
contextKeysUpdate,
onChangeConfig,
this.tasks,