Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/markdown-language-features/src/client/fileWatchingManager.ts
3292 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as vscode from 'vscode';
7
import { Utils } from 'vscode-uri';
8
import { disposeAll, IDisposable } from '../util/dispose';
9
import { ResourceMap } from '../util/resourceMap';
10
import { Schemes } from '../util/schemes';
11
12
type DirWatcherEntry = {
13
readonly uri: vscode.Uri;
14
readonly disposables: readonly IDisposable[];
15
};
16
17
18
export class FileWatcherManager {
19
20
private readonly _fileWatchers = new Map<number, {
21
readonly watcher: vscode.FileSystemWatcher;
22
readonly dirWatchers: DirWatcherEntry[];
23
}>();
24
25
private readonly _dirWatchers = new ResourceMap<{
26
readonly watcher: vscode.FileSystemWatcher;
27
refCount: number;
28
}>();
29
30
create(id: number, uri: vscode.Uri, watchParentDirs: boolean, listeners: { create?: () => void; change?: () => void; delete?: () => void }): void {
31
// Non-writable file systems do not support file watching
32
if (!vscode.workspace.fs.isWritableFileSystem(uri.scheme)) {
33
return;
34
}
35
36
const watcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(uri, '*'), !listeners.create, !listeners.change, !listeners.delete);
37
const parentDirWatchers: DirWatcherEntry[] = [];
38
this._fileWatchers.set(id, { watcher, dirWatchers: parentDirWatchers });
39
40
if (listeners.create) { watcher.onDidCreate(listeners.create); }
41
if (listeners.change) { watcher.onDidChange(listeners.change); }
42
if (listeners.delete) { watcher.onDidDelete(listeners.delete); }
43
44
if (watchParentDirs && uri.scheme !== Schemes.untitled) {
45
// We need to watch the parent directories too for when these are deleted / created
46
for (let dirUri = Utils.dirname(uri); dirUri.path.length > 1; dirUri = Utils.dirname(dirUri)) {
47
const disposables: IDisposable[] = [];
48
49
let parentDirWatcher = this._dirWatchers.get(dirUri);
50
if (!parentDirWatcher) {
51
const glob = new vscode.RelativePattern(Utils.dirname(dirUri), Utils.basename(dirUri));
52
const parentWatcher = vscode.workspace.createFileSystemWatcher(glob, !listeners.create, true, !listeners.delete);
53
parentDirWatcher = { refCount: 0, watcher: parentWatcher };
54
this._dirWatchers.set(dirUri, parentDirWatcher);
55
}
56
parentDirWatcher.refCount++;
57
58
if (listeners.create) {
59
disposables.push(parentDirWatcher.watcher.onDidCreate(async () => {
60
// Just because the parent dir was created doesn't mean our file was created
61
try {
62
const stat = await vscode.workspace.fs.stat(uri);
63
if (stat.type === vscode.FileType.File) {
64
listeners.create!();
65
}
66
} catch {
67
// Noop
68
}
69
}));
70
}
71
72
if (listeners.delete) {
73
// When the parent dir is deleted, consider our file deleted too
74
// TODO: this fires if the file previously did not exist and then the parent is deleted
75
disposables.push(parentDirWatcher.watcher.onDidDelete(listeners.delete));
76
}
77
78
parentDirWatchers.push({ uri: dirUri, disposables });
79
}
80
}
81
}
82
83
delete(id: number): void {
84
const entry = this._fileWatchers.get(id);
85
if (entry) {
86
for (const dirWatcher of entry.dirWatchers) {
87
disposeAll(dirWatcher.disposables);
88
89
const dirWatcherEntry = this._dirWatchers.get(dirWatcher.uri);
90
if (dirWatcherEntry) {
91
if (--dirWatcherEntry.refCount <= 0) {
92
dirWatcherEntry.watcher.dispose();
93
this._dirWatchers.delete(dirWatcher.uri);
94
}
95
}
96
}
97
98
entry.watcher.dispose();
99
}
100
101
this._fileWatchers.delete(id);
102
}
103
}
104
105