Skip to content
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

watcher - enable event correlation for all users of new proposed API #196629

Merged
merged 1 commit into from Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -212,7 +212,7 @@ export class MainThreadFileSystemEventService implements MainThreadFileSystemEve
this._listener.add(workingCopyFileService.onDidRunWorkingCopyFileOperation(e => this._proxy.$onDidRunFileOperation(e.operation, e.files)));
}

async $watch(extensionId: string, session: number, resource: UriComponents, unvalidatedOpts: IWatchOptions): Promise<void> {
async $watch(extensionId: string, session: number, resource: UriComponents, unvalidatedOpts: IWatchOptions, correlate: boolean): Promise<void> {
const uri = URI.revive(resource);

const opts: IWatchOptions = {
Expand All @@ -234,8 +234,7 @@ export class MainThreadFileSystemEventService implements MainThreadFileSystemEve
}
}

// Correlated file watching is taken as is (for now we only opt into correlating with proposed new file system watcher API with excludes)
const correlate = Array.isArray(unvalidatedOpts?.excludes) && unvalidatedOpts.excludes.length > 0;
// Correlated file watching is taken as is
if (correlate) {
this._logService.trace(`MainThreadFileSystemEventService#$watch(): request to start watching correlated (extension: ${extensionId}, path: ${uri.toString(true)}, recursive: ${opts.recursive}, session: ${session})`);

Expand Down
12 changes: 8 additions & 4 deletions src/vs/workbench/api/common/extHost.api.impl.ts
Expand Up @@ -28,7 +28,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { Extension, IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { ExtHostFileSystem } from 'vs/workbench/api/common/extHostFileSystem';
import { ExtHostFileSystemEventService } from 'vs/workbench/api/common/extHostFileSystemEventService';
import { ExtHostFileSystemEventService, FileSystemWatcherCreateOptions } from 'vs/workbench/api/common/extHostFileSystemEventService';
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages';
import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService';
Expand Down Expand Up @@ -947,17 +947,21 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostBulkEdits.applyWorkspaceEdit(edit, extension, metadata);
},
createFileSystemWatcher: (pattern, optionsOrIgnoreCreate, ignoreChange?, ignoreDelete?): vscode.FileSystemWatcher => {
let options: vscode.FileSystemWatcherOptions | undefined = undefined;
let options: FileSystemWatcherCreateOptions | undefined = undefined;

if (typeof optionsOrIgnoreCreate === 'boolean') {
options = {
ignoreCreateEvents: Boolean(optionsOrIgnoreCreate),
ignoreChangeEvents: Boolean(ignoreChange),
ignoreDeleteEvents: Boolean(ignoreDelete)
ignoreDeleteEvents: Boolean(ignoreDelete),
correlate: false
};
} else if (optionsOrIgnoreCreate) {
checkProposedApiEnabled(extension, 'createFileSystemWatcher');
options = optionsOrIgnoreCreate;
options = {
...optionsOrIgnoreCreate,
correlate: true
};
}

return extHostFileSystemEvent.createFileSystemWatcher(extHostWorkspace, extension, pattern, options);
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/api/common/extHost.protocol.ts
Expand Up @@ -1351,7 +1351,7 @@ export interface MainThreadFileSystemShape extends IDisposable {
}

export interface MainThreadFileSystemEventServiceShape extends IDisposable {
$watch(extensionId: string, session: number, resource: UriComponents, opts: files.IWatchOptions): void;
$watch(extensionId: string, session: number, resource: UriComponents, opts: files.IWatchOptions, correlate: boolean): void;
$unwatch(session: number): void;
}

Expand Down
14 changes: 8 additions & 6 deletions src/vs/workbench/api/common/extHostFileSystemEventService.ts
Expand Up @@ -18,7 +18,9 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { Lazy } from 'vs/base/common/lazy';

interface FileSystemWatcherCreateOptions {
export interface FileSystemWatcherCreateOptions {
readonly correlate: boolean;

readonly ignoreCreateEvents?: boolean;
readonly ignoreChangeEvents?: boolean;
readonly ignoreDeleteEvents?: boolean;
Expand Down Expand Up @@ -71,9 +73,9 @@ class FileSystemWatcher implements vscode.FileSystemWatcher {
const excludeOutOfWorkspaceEvents = typeof globPattern === 'string';

// 1.84.x introduces new proposed API for a watcher to set exclude
// rules. When this is provided, we turn the file watcher into correlation
// rules. In these cases, we turn the file watcher into correlation
// mode and ignore any event that does not match the correlation ID.
const excludeUncorrelatedEvents = Array.isArray(options?.excludes) && options.excludes.length > 0;
const excludeUncorrelatedEvents = options?.correlate;

const subscription = dispatcher(events => {
if (typeof events.session === 'number' && events.session !== this.session) {
Expand Down Expand Up @@ -110,10 +112,10 @@ class FileSystemWatcher implements vscode.FileSystemWatcher {
}
});

this._disposable = Disposable.from(this.ensureWatching(mainContext, extension, globPattern, options), this._onDidCreate, this._onDidChange, this._onDidDelete, subscription);
this._disposable = Disposable.from(this.ensureWatching(mainContext, extension, globPattern, options, options?.correlate), this._onDidCreate, this._onDidChange, this._onDidDelete, subscription);
}

private ensureWatching(mainContext: IMainContext, extension: IExtensionDescription, globPattern: string | IRelativePatternDto, options?: FileSystemWatcherCreateOptions): Disposable {
private ensureWatching(mainContext: IMainContext, extension: IExtensionDescription, globPattern: string | IRelativePatternDto, options: FileSystemWatcherCreateOptions | undefined, correlate: boolean | undefined): Disposable {
const disposable = Disposable.from();

if (typeof globPattern === 'string') {
Expand All @@ -127,7 +129,7 @@ class FileSystemWatcher implements vscode.FileSystemWatcher {
recursive = true; // only watch recursively if pattern indicates the need for it
}

proxy.$watch(extension.identifier.value, this.session, globPattern.baseUri, { recursive, excludes: options?.excludes ?? [] });
proxy.$watch(extension.identifier.value, this.session, globPattern.baseUri, { recursive, excludes: options?.excludes ?? [] }, Boolean(correlate));

return Disposable.from({ dispose: () => proxy.$unwatch(this.session) });
}
Expand Down
Expand Up @@ -22,13 +22,13 @@ suite('ExtHostFileSystemEventService', () => {
drain: undefined!
};

const watcher1 = new ExtHostFileSystemEventService(protocol, new NullLogService(), undefined!).createFileSystemWatcher(undefined!, undefined!, '**/somethingInteresting', {});
const watcher1 = new ExtHostFileSystemEventService(protocol, new NullLogService(), undefined!).createFileSystemWatcher(undefined!, undefined!, '**/somethingInteresting', { correlate: false });
assert.strictEqual(watcher1.ignoreChangeEvents, false);
assert.strictEqual(watcher1.ignoreCreateEvents, false);
assert.strictEqual(watcher1.ignoreDeleteEvents, false);
watcher1.dispose();

const watcher2 = new ExtHostFileSystemEventService(protocol, new NullLogService(), undefined!).createFileSystemWatcher(undefined!, undefined!, '**/somethingBoring', { ignoreCreateEvents: true, ignoreChangeEvents: true, ignoreDeleteEvents: true });
const watcher2 = new ExtHostFileSystemEventService(protocol, new NullLogService(), undefined!).createFileSystemWatcher(undefined!, undefined!, '**/somethingBoring', { ignoreCreateEvents: true, ignoreChangeEvents: true, ignoreDeleteEvents: true, correlate: false });
assert.strictEqual(watcher2.ignoreChangeEvents, true);
assert.strictEqual(watcher2.ignoreCreateEvents, true);
assert.strictEqual(watcher2.ignoreDeleteEvents, true);
Expand Down
13 changes: 13 additions & 0 deletions src/vscode-dts/vscode.proposed.createFileSystemWatcher.d.ts
Expand Up @@ -33,6 +33,19 @@ declare module 'vscode' {

export namespace workspace {

/**
* A variant of {@link workspace.createFileSystemWatcher} that optionally allows to specify
* a set of glob patterns to exclude from watching.
*
* It provides the following advantages over the other {@link workspace.createFileSystemWatcher}
* method:
* - the configured excludes from `files.watcherExclude` setting are NOT applied
* - requests for recursive file watchers inside the opened workspace are NOT ignored
* - the watcher is ONLY notified for events from this request and not from any other watcher
*
* As such, this method is prefered in cases where you want full control over the watcher behavior
* without being impacted by settings or other watchers that are installed.
*/
export function createFileSystemWatcher(pattern: RelativePattern, options?: FileSystemWatcherOptions): FileSystemWatcher;
}
}