src/vs/platform/files/common/watcher.ts

508 LOC · 380 covered · 128 uncovered · 51 ranges · 75 concepts · 12 introducers · 42 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filesrc/vs/platform/files/common/files.ts · 1658 LOCcommon/files.tscolorThemeData.ts ×16 · 64 introduced LOCcolorThemeData.ts ×16tokenClassificationRegistry.ts ×1 · 3 introduced LOCtokenClassificationRegis…tokenClassificationRegistry.ts ×2 · 7 introduced LOCtokenClassificationRegis…tokenStyleResolving.test|title=Themes - TokenStyleResolving language|occurrence=1 · 0 introduced LOCtokenStyleResolving.test…colorThemeData.ts ×1 · 2 introduced LOCcolorThemeData.ts ×1colorThemeData.ts ×12 · 57 introduced LOCcolorThemeData.ts ×12tokenClassificationRegistry.ts ×2 · 6 introduced LOCtokenClassificationRegis…colorThemeData.ts ×5 · 21 introduced LOCcolorThemeData.ts ×5colorThemeData.ts ×1 · 6 introduced LOCcolorThemeData.ts ×1colorThemeData.ts ×33 · 242 introduced LOCcolorThemeData.ts ×33colorThemeData.ts ×2 · 5 introduced LOCcolorThemeData.ts ×2tokenStyleResolving.test|title=Themes - TokenStyleResolving resolveScopes - match most specific|occurrence=1 · 0 introduced LOCtokenStyleResolving.test…colorThemeData.ts ×5 · 33 introduced LOCcolorThemeData.ts ×5colorThemeData.ts ×1 · 4 introduced LOCcolorThemeData.ts ×1tokenClassificationRegistry.ts ×1 · 16 introduced LOCtokenClassificationRegis…colorThemeData.ts ×1 · 1 introduced LOCcolorThemeData.ts ×1colorThemeData.ts ×13 · 114 introduced LOCcolorThemeData.ts ×13colorThemeData.ts ×1 · 1 introduced LOCcolorThemeData.ts ×1colorThemeData.ts ×4 · 15 introduced LOCcolorThemeData.ts ×4colorThemeData.ts ×57 · 483 introduced LOCcolorThemeData.ts ×57agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: cache hit returns immediately without re-downloading|occurrence=1 · 0 introduced LOCagentSdkDownloader.test|…diskFileSystemProvider.ts ×11 · 79 introduced LOCdiskFileSystemProvider.t…agentSdkDownloader.ts ×3 · 28 introduced LOCagentSdkDownloader.ts ×3diskFileSystemProvider.ts ×20 · 260 introduced LOCdiskFileSystemProvider.t…agentSdkDownloader.ts ×1 · 2 introduced LOCagentSdkDownloader.ts ×1agentSdkDownloader.ts ×1 · 2 introduced LOCagentSdkDownloader.ts ×1agentSdkDownloader.ts ×2 · 20 introduced LOCagentSdkDownloader.ts ×2stateService.ts ×2 · 7 introduced LOCstateService.ts ×2stateService.ts ×1 · 2 introduced LOCstateService.ts ×1stateService.ts ×2 · 14 introduced LOCstateService.ts ×2stateService.ts ×1 · 2 introduced LOCstateService.ts ×1diskFileSystemProvider.ts ×9 · 73 introduced LOCdiskFileSystemProvider.t…agentSdkDownloader.ts ×1 · 6 introduced LOCagentSdkDownloader.ts ×1agentSdkDownloader.ts ×2 · 8 introduced LOCagentSdkDownloader.ts ×2agentSdkDownloader.ts ×1 · 5 introduced LOCagentSdkDownloader.ts ×1agentSdkDownloader.ts ×2 · 8 introduced LOCagentSdkDownloader.ts ×2agentSdkDownloader.ts ×5 · 10 introduced LOCagentSdkDownloader.ts ×5agentSdkDownloader.ts ×1 · 3 introduced LOCagentSdkDownloader.ts ×1agentSdkDownloader.ts ×3 · 5 introduced LOCagentSdkDownloader.ts ×3agentSdkDownloader.test|title=AgentSdkDownloader isAvailable: true when product config populated and host has a target|occurrence=1 · 0 introduced LOCagentSdkDownloader.test|…agentSdkDownloader.ts ×1 · 2 introduced LOCagentSdkDownloader.ts ×1agentSdkDownloader.ts ×2 · 3 introduced LOCagentSdkDownloader.ts ×2agentSdkDownloader.ts ×1 · 8 introduced LOCagentSdkDownloader.ts ×1diskFileSystemProvider.ts ×28 · 135 introduced LOCdiskFileSystemProvider.t…diskFileSystemProvider.ts ×3 · 12 introduced LOCdiskFileSystemProvider.t…io.ts ×12 · 175 introduced LOCio.ts ×12agentSdkDownloader.ts ×1 · 2 introduced LOCagentSdkDownloader.ts ×1agentSdkDownloader.ts ×1 · 2 introduced LOCagentSdkDownloader.ts ×1agentSdkDownloader.ts ×1 · 2 introduced LOCagentSdkDownloader.ts ×1agentSdkDownloader.ts ×2 · 5 introduced LOCagentSdkDownloader.ts ×2diskFileSystemProvider.ts ×17 · 105 introduced LOCdiskFileSystemProvider.t…diskFileSystemProvider.ts ×1 · 21 introduced LOCdiskFileSystemProvider.t…stateService.ts ×1 · 2 introduced LOCstateService.ts ×1stateService.ts ×16 · 141 introduced LOCstateService.ts ×16diskFileSystemProvider.ts ×2 · 3 introduced LOCdiskFileSystemProvider.t…diskFileSystemProvider.ts ×10 · 34 introduced LOCdiskFileSystemProvider.t…diskFileSystemProvider.ts ×15 · 104 introduced LOCdiskFileSystemProvider.t…diskFileSystemProvider.ts ×21 · 577 introduced LOCdiskFileSystemProvider.t…watcher.ts ×2 · 6 introduced LOCwatcher.ts ×2watcher.ts ×1 · 5 introduced LOCwatcher.ts ×1delete|occurrence=1 · 0 introduced LOCdelete|occurrence=1watcher.test|title=Watcher Events Normalizer event coalescer: ignore UPDATE when CREATE received|occurrence=1 · 0 introduced LOCwatcher.test|title=Watch…watcher.ts ×1 · 2 introduced LOCwatcher.ts ×1watcher.ts ×1 · 3 introduced LOCwatcher.ts ×1watcher.ts ×1 · 3 introduced LOCwatcher.ts ×1watcher.ts ×1 · 3 introduced LOCwatcher.ts ×1watcher.ts ×3 · 10 introduced LOCwatcher.ts ×3watcher.test|title=Watcher Events Normalizer event coalescer: track case renames|occurrence=1 · 0 introduced LOCwatcher.test|title=Watch…watcher.test|title=Watcher parseWatcherPatterns - posix (case insensitive)|occurrence=1 · 0 introduced LOCwatcher.test|title=Watch…watcher.test|title=Watcher parseWatcherPatterns - posix|occurrence=1 · 0 introduced LOCwatcher.test|title=Watch…watcher.ts ×3 · 8 introduced LOCwatcher.ts ×3watcher.ts ×2 · 21 introduced LOCwatcher.ts ×2watcher.ts ×11 · 60 introduced LOCwatcher.ts ×11watcher.ts ×1 · 13 introduced LOCwatcher.ts ×1watcher.ts ×24 · 249 introduced LOCwatcher.ts ×24agentSdkDownloader.test|title=AgentSdkDownloader isAvailable: false when no env override and no product config|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader isAvailable: false when no env override and no product config|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader isAvailable: true when env override set|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader isAvailable: true when env override set|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader isAvailable: true when product config populated and host has a target|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader isAvailable: true when product config populated and host has a target|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: cache dir includes sdkTarget so Universal launches stay separate|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: cache dir includes sdkTarget so Universal launches stay separate|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: cache hit returns immediately without re-downloading|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: cache hit returns immediately without re-downloading|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: cache miss → downloads, extracts, writes sentinel|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: cache miss → downloads, extracts, writes sentinel|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: cancel before download completes cleans up scratch dir|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: cancel before download completes cleans up scratch dir|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: concurrent calls in same process share one download|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: concurrent calls in same process share one download|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: dev override returns the path unchanged|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: dev override returns the path unchanged|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: missing product config and no env override throws actionable error|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: missing product config and no env override throws actionable error|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: rename-loser path returns existing cache when winner already published|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: rename-loser path returns existing cache when winner already published|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: reports monotonic download progress ending at totalBytes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: reports monotonic download progress ending at totalBytes|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: substitutes {sdkTarget} into urlTemplate|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: substitutes {sdkTarget} into urlTemplate|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: urlTemplate with unknown placeholder throws config error|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=AgentSdkDownloader loadSdkRoot: urlTemplate with unknown placeholder throws config error|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=resolveSdkTarget appends -musl on musl Linux iff the package has separate musl SKUs|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=resolveSdkTarget appends -musl on musl Linux iff the package has separate musl SKUs|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=resolveSdkTarget returns <platform>-<arch> for supported (platform, arch)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=resolveSdkTarget returns <platform>-<arch> for supported (platform, arch)|occurrence=1agentSdkDownloader.test|…agentSdkDownloader.test|title=resolveSdkTarget returns undefined for unsupported (platform, arch)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/agentSdkDownloader.test|title=resolveSdkTarget returns undefined for unsupported (platform, arch)|occurrence=1agentSdkDownloader.test|…checksumService.test|title=Checksum Service checksum|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/checksum/test/node/checksumService.test|title=Checksum Service checksum|occurrence=1checksumService.test|tit…watcher.test|title=Watcher Events Normalizer delete only reported for top level folder (0)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/files/test/common/watcher.test|title=Watcher Events Normalizer delete only reported for top level folder (0)|occurrence=1watcher.test|title=Watch…watcher.test|title=Watcher Events Normalizer event coalescer: apply DELETE|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/files/test/common/watcher.test|title=Watcher Events Normalizer event coalescer: apply DELETE|occurrence=1watcher.test|title=Watch…watcher.test|title=Watcher Events Normalizer event coalescer: flatten DELETE followed by CREATE into CHANGE|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/files/test/common/watcher.test|title=Watcher Events Normalizer event coalescer: flatten DELETE followed by CREATE into CHANGE|occurrence=1watcher.test|title=Watch…watcher.test|title=Watcher Events Normalizer event coalescer: ignore CREATE followed by DELETE|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/files/test/common/watcher.test|title=Watcher Events Normalizer event coalescer: ignore CREATE followed by DELETE|occurrence=1watcher.test|title=Watch…watcher.test|title=Watcher Events Normalizer event coalescer: ignore UPDATE when CREATE received|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/files/test/common/watcher.test|title=Watcher Events Normalizer event coalescer: ignore UPDATE when CREATE received|occurrence=1watcher.test|title=Watch…watcher.test|title=Watcher Events Normalizer event coalescer: track case renames|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/files/test/common/watcher.test|title=Watcher Events Normalizer event coalescer: track case renames|occurrence=1watcher.test|title=Watch…watcher.test|title=Watcher Events Normalizer event type filter|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/files/test/common/watcher.test|title=Watcher Events Normalizer event type filter|occurrence=1watcher.test|title=Watch…delete|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/files/test/common/watcher.test|title=Watcher Events Normalizer simple add/update/delete|occurrence=1delete|occurrence=1watcher.test|title=Watcher parseWatcherPatterns - posix (case insensitive)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/files/test/common/watcher.test|title=Watcher parseWatcherPatterns - posix (case insensitive)|occurrence=1watcher.test|title=Watch…watcher.test|title=Watcher parseWatcherPatterns - posix|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/files/test/common/watcher.test|title=Watcher parseWatcherPatterns - posix|occurrence=1watcher.test|title=Watch…state.test|title=StateService Basics (delayed strategy)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/state/test/node/state.test|title=StateService Basics (delayed strategy)|occurrence=1state.test|title=StateSe…state.test|title=StateService Basics (immediate strategy)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/state/test/node/state.test|title=StateService Basics (immediate strategy)|occurrence=1state.test|title=StateSe…state.test|title=StateService Closed before init|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/state/test/node/state.test|title=StateService Closed before init|occurrence=1state.test|title=StateSe…state.test|title=StateService Multiple ops (Immediate Strategy)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/state/test/node/state.test|title=StateService Multiple ops (Immediate Strategy)|occurrence=1state.test|title=StateSe…state.test|title=StateService Multiple ops are buffered and applied|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/state/test/node/state.test|title=StateService Multiple ops are buffered and applied|occurrence=1state.test|title=StateSe…state.test|title=StateService Used after close|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/state/test/node/state.test|title=StateService Used after close|occurrence=1state.test|title=StateSe…state.test|title=StateService Used before init|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/state/test/node/state.test|title=StateService Used before init|occurrence=1state.test|title=StateSe…tokenStyleResolving.test|title=Themes - TokenStyleResolving color defaults|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/services/themes/test/node/tokenStyleResolving.test|title=Themes - TokenStyleResolving color defaults|occurrence=1tokenStyleResolving.test…tokenStyleResolving.test|title=Themes - TokenStyleResolving language - scope resolving|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/services/themes/test/node/tokenStyleResolving.test|title=Themes - TokenStyleResolving language - scope resolving|occurrence=1tokenStyleResolving.test…tokenStyleResolving.test|title=Themes - TokenStyleResolving language|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/services/themes/test/node/tokenStyleResolving.test|title=Themes - TokenStyleResolving language|occurrence=1tokenStyleResolving.test…tokenStyleResolving.test|title=Themes - TokenStyleResolving resolveScopes - match most specific|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/services/themes/test/node/tokenStyleResolving.test|title=Themes - TokenStyleResolving resolveScopes - match most specific|occurrence=1tokenStyleResolving.test…tokenStyleResolving.test|title=Themes - TokenStyleResolving resolveScopes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/services/themes/test/node/tokenStyleResolving.test|title=Themes - TokenStyleResolving resolveScopes|occurrence=1tokenStyleResolving.test…tokenStyleResolving.test|title=Themes - TokenStyleResolving rule matching|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/services/themes/test/node/tokenStyleResolving.test|title=Themes - TokenStyleResolving rule matching|occurrence=1tokenStyleResolving.test…tokenStyleResolving.test|title=Themes - TokenStyleResolving super type|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/services/themes/test/node/tokenStyleResolving.test|title=Themes - TokenStyleResolving super type|occurrence=1tokenStyleResolving.test…Focused file · src/vs/platform/files/common/watcher.ts · 508 LOCcommon/watcher.ts

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- watcher.ts ×24
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 { Event } from '../../../base/common/event.js';
7 > import { GLOBSTAR, IRelativePattern, parse, ParsedPattern } from '../../../base/common/glob.js';
8 > import { Disposable, DisposableStore, IDisposable, MutableDisposable } from '../../../base/common/lifecycle.js';
9 > import { isAbsolute } from '../../../base/common/path.js';
10 > import { isLinux } from '../../../base/common/platform.js';
11 > import { URI } from '../../../base/common/uri.js';
12 > import { FileChangeFilter, FileChangeType, IFileChange, isParent } from './files.js';
13 >
14 > interface IWatchRequest {
15 >
16 > /**
17 > * The path to watch.
18 > */
19 > readonly path: string;
20 >
21 > /**
22 > * Whether to watch recursively or not.
23 > */
24 > readonly recursive: boolean;
25 >
26 > /**
27 > * A set of glob patterns or paths to exclude from watching.
28 > */
29 > readonly excludes: string[];
30 >
31 > /**
32 > * An optional set of glob patterns or paths to include for
33 > * watching. If not provided, all paths are considered for
34 > * events.
35 > */
36 > readonly includes?: Array<string | IRelativePattern>;
37 >
38 > /**
39 > * If provided, file change events from the watcher that
40 > * are a result of this watch request will carry the same
41 > * id.
42 > */
43 > readonly correlationId?: number;
44 >
45 > /**
46 > * If provided, allows to filter the events that the watcher should consider
47 > * for emitting. If not provided, all events are emitted.
48 > *
49 > * For example, to emit added and updated events, set to:
50 > * `FileChangeFilter.ADDED | FileChangeFilter.UPDATED`.
51 > */
52 > readonly filter?: FileChangeFilter;
53 > }
54 >
55 > export interface IWatchRequestWithCorrelation extends IWatchRequest {
56 > readonly correlationId: number;
57 > }
58 >
59 > export function isWatchRequestWithCorrelation(request: IWatchRequest): request is IWatchRequestWithCorrelation {
60 return typeof request.correlationId === 'number';
61 }
63 > export interface INonRecursiveWatchRequest extends IWatchRequest {
64 >
65 > /**
66 > * The watcher will be non-recursive.
67 > */
68 > readonly recursive: false;
69 > }
70 >
71 > export interface IRecursiveWatchRequest extends IWatchRequest {
72 >
73 > /**
74 > * The watcher will be recursive.
75 > */
76 > readonly recursive: true;
77 >
78 > /**
79 > * @deprecated this only exists for WSL1 support and should never
80 > * be used in any other case.
81 > */
82 > pollingInterval?: number;
83 > }
84 >
85 > export function isRecursiveWatchRequest(request: IWatchRequest): request is IRecursiveWatchRequest {
86 return request.recursive === true;
87 }
89 > export type IUniversalWatchRequest = IRecursiveWatchRequest | INonRecursiveWatchRequest;
90 >
91 > export interface IWatcherErrorEvent {
92 > readonly error: string;
93 > readonly request?: IUniversalWatchRequest;
94 > }
95 >
96 > export interface IWatcher {
97 >
98 > /**
99 > * A normalized file change event from the raw events
100 > * the watcher emits.
101 > */
102 > readonly onDidChangeFile: Event<IFileChange[]>;
103 >
104 > /**
105 > * An event to indicate a message that should get logged.
106 > */
107 > readonly onDidLogMessage: Event<ILogMessage>;
108 >
109 > /**
110 > * An event to indicate an error occurred from the watcher
111 > * that is unrecoverable. Listeners should restart the
112 > * watcher if possible.
113 > */
114 > readonly onDidError: Event<IWatcherErrorEvent>;
115 >
116 > /**
117 > * Configures the watcher to watch according to the
118 > * requests. Any existing watched path that is not
119 > * in the array, will be removed from watching and
120 > * any new path will be added to watching.
121 > */
122 > watch(requests: IWatchRequest[]): Promise<void>;
123 >
124 > /**
125 > * Enable verbose logging in the watcher.
126 > */
127 > setVerboseLogging(enabled: boolean): Promise<void>;
128 >
129 > /**
130 > * Stop all watchers.
131 > */
132 > stop(): Promise<void>;
133 > }
134 >
135 > export interface IRecursiveWatcher extends IWatcher {
136 > watch(requests: IRecursiveWatchRequest[]): Promise<void>;
137 > }
138 >
139 > export interface IRecursiveWatcherWithSubscribe extends IRecursiveWatcher {
140 >
141 > /**
142 > * Subscribe to file events for the given path. The callback is called
143 > * whenever a file event occurs for the path. If the watcher failed,
144 > * the error parameter is set to `true`.
145 > *
146 > * @returns an `IDisposable` to stop listening to events or `undefined`
147 > * if no events can be watched for the path given the current set of
148 > * recursive watch requests.
149 > */
150 > subscribe(path: string, callback: (error: true | null, change?: IFileChange) => void): IDisposable | undefined;
151 > }
152 >
153 > export interface IRecursiveWatcherOptions {
154 >
155 > /**
156 > * If `true`, will enable polling for all watchers, otherwise
157 > * will enable it for paths included in the string array.
158 > *
159 > * @deprecated this only exists for WSL1 support and should never
160 > * be used in any other case.
161 > */
162 > readonly usePolling: boolean | string[];
163 >
164 > /**
165 > * If polling is enabled (via `usePolling`), defines the duration
166 > * in which the watcher will poll for changes.
167 > *
168 > * @deprecated this only exists for WSL1 support and should never
169 > * be used in any other case.
170 > */
171 > readonly pollingInterval?: number;
172 > }
173 >
174 > export interface INonRecursiveWatcher extends IWatcher {
175 > watch(requests: INonRecursiveWatchRequest[]): Promise<void>;
176 > }
177 >
178 > export interface IUniversalWatcher extends IWatcher {
179 > watch(requests: IUniversalWatchRequest[]): Promise<void>;
180 > }
181 >
182 > export abstract class AbstractWatcherClient extends Disposable {
183 >
184 > private static readonly MAX_RESTARTS = 5;
185 >
186 > private watcher: IWatcher | undefined;
187 > private readonly watcherDisposables = this._register(new MutableDisposable());
188 >
189 > private requests: IWatchRequest[] | undefined = undefined;
190 >
191 > private restartCounter = 0;
192 >
193 > constructor(
194 private readonly onFileChanges: (changes: IFileChange[]) => void,
195 private readonly onLogMessage: (msg: ILogMessage) => void,
196 private verboseLogging: boolean,
197 private options: {
198 readonly type: string;
199 readonly restartOnError: boolean;
200 }
201 ) {
202 super();
203 }
205 > protected abstract createWatcher(disposables: DisposableStore): IWatcher;
206 >
207 > protected init(): void {
208
209 // Associate disposables to the watcher
210 const disposables = new DisposableStore();
211 this.watcherDisposables.value = disposables;
212
213 // Ask implementors to create the watcher
214 this.watcher = this.createWatcher(disposables);
215 this.watcher.setVerboseLogging(this.verboseLogging);
216
217 // Wire in event handlers
218 disposables.add(this.watcher.onDidChangeFile(changes => this.onFileChanges(changes)));
219 disposables.add(this.watcher.onDidLogMessage(msg => this.onLogMessage(msg)));
220 disposables.add(this.watcher.onDidError(e => this.onError(e.error, e.request)));
221 }
223 > protected onError(error: string, failedRequest?: IUniversalWatchRequest): void {
224
225 // Restart on error (up to N times, if possible)
226 if (this.canRestart(error, failedRequest)) {
227 if (this.restartCounter < AbstractWatcherClient.MAX_RESTARTS && this.requests) {
228 this.error(`restarting watcher after unexpected error: ${error}`);
229 this.restart(this.requests);
230 } else {
231 this.error(`gave up attempting to restart watcher after unexpected error: ${error}`);
232 }
233 }
234
235 // Do not attempt to restart otherwise, report the error
236 else {
237 this.error(error);
238 }
239 }
241 > private canRestart(error: string, failedRequest?: IUniversalWatchRequest): boolean {
242 if (!this.options.restartOnError) {
243 return false; // disabled by options
244 }
245
246 if (failedRequest) {
247 // do not treat a failing request as a reason to restart the entire
248 // watcher. it is possible that from a large amount of watch requests
249 // some fail and we would constantly restart all requests only because
250 // of that. rather, continue the watcher and leave the failed request
251 return false;
252 }
253
254 if (
255 error.indexOf('No space left on device') !== -1 ||
256 error.indexOf('EMFILE') !== -1
257 ) {
258 // do not restart when the error indicates that the system is running
259 // out of handles for file watching. this is not recoverable anyway
260 // and needs changes to the system before continuing
261 return false;
262 }
263
264 return true;
265 }
267 > private restart(requests: IUniversalWatchRequest[]): void {
268 this.restartCounter++;
269
270 this.init();
271 this.watch(requests);
272 }
274 > async watch(requests: IUniversalWatchRequest[]): Promise<void> {
275 this.requests = requests;
276
277 await this.watcher?.watch(requests);
278 }
280 > async setVerboseLogging(verboseLogging: boolean): Promise<void> {
281 this.verboseLogging = verboseLogging;
282
283 await this.watcher?.setVerboseLogging(verboseLogging);
284 }
286 > private error(message: string) {
287 this.onLogMessage({ type: 'error', message: `[File Watcher (${this.options.type})] ${message}` });
288 }
290 > protected trace(message: string) {
291 this.onLogMessage({ type: 'trace', message: `[File Watcher (${this.options.type})] ${message}` });
292 }
294 > override dispose(): void {
295
296 // Render the watcher invalid from here
297 this.watcher = undefined;
298
299 return super.dispose();
300 }
301 > } watcher.ts ×24
302 >
303 > export abstract class AbstractNonRecursiveWatcherClient extends AbstractWatcherClient {
304 >
305 > constructor(
306 onFileChanges: (changes: IFileChange[]) => void,
307 onLogMessage: (msg: ILogMessage) => void,
308 verboseLogging: boolean
309 ) {
310 super(onFileChanges, onLogMessage, verboseLogging, { type: 'node.js', restartOnError: false });
311 }
313 > protected abstract override createWatcher(disposables: DisposableStore): INonRecursiveWatcher;
314 > }
315 >
316 > export abstract class AbstractUniversalWatcherClient extends AbstractWatcherClient {
317 >
318 > constructor(
319 onFileChanges: (changes: IFileChange[]) => void,
320 onLogMessage: (msg: ILogMessage) => void,
321 verboseLogging: boolean
322 ) {
323 super(onFileChanges, onLogMessage, verboseLogging, { type: 'universal', restartOnError: true });
324 }
326 > protected abstract override createWatcher(disposables: DisposableStore): IUniversalWatcher;
327 > }
328 >
329 > export interface ILogMessage {
330 > readonly type: 'trace' | 'warn' | 'error' | 'info' | 'debug';
331 > readonly message: string;
332 > }
333 >
334 > export function reviveFileChanges(changes: IFileChange[]): IFileChange[] {
335 > return changes.map(change => ({ watcher.ts ×11
336 > type: change.type,
337 > resource: URI.revive(change.resource),
338 > cId: change.cId
339 > }));
340 > }
342 > export function coalesceEvents(changes: IFileChange[]): IFileChange[] {
344 > // Build deltas
345 > const coalescer = new EventCoalescer();
346 > for (const event of changes) {
347 > coalescer.processEvent(event);
348 > }
349 >
350 > return coalescer.coalesce();
351 > }
353 > export function normalizeWatcherPattern(path: string, pattern: string | IRelativePattern): string | IRelativePattern {
355 > // Patterns are always matched on the full absolute path
356 > // of the event. As such, if the pattern is not absolute
357 > // and is a string and does not start with a leading
358 > // `**`, we have to convert it to a relative pattern with
359 > // the given `base`
360 >
361 > if (typeof pattern === 'string' && !pattern.startsWith(GLOBSTAR) && !isAbsolute(pattern)) {
362 > return { base: path, pattern };
363 > }
364 >
365 > return pattern;
366 > }
368 > export function parseWatcherPatterns(path: string, patterns: Array<string | IRelativePattern>, ignoreCase: boolean): ParsedPattern[] {
369 > const parsedPatterns: ParsedPattern[] = []; watcher.ts ×2
370 >
371 > for (const pattern of patterns) {
372 > parsedPatterns.push(parse(normalizeWatcherPattern(path, pattern), { ignoreCase }));
373 > }
374 >
375 > return parsedPatterns;
376 > }
378 > class EventCoalescer { watcher.ts ×11
379 >
380 > private readonly coalesced = new Set<IFileChange>();
381 > private readonly mapPathToChange = new Map<string, IFileChange>();
383 > private toKey(event: IFileChange): string {
384 > if (isLinux) { watcher.ts ×11
385 > return event.resource.fsPath;
386 > }
387
388 return event.resource.fsPath.toLowerCase(); // normalise to file system case sensitivity
389 > } watcher.ts ×11
391 > processEvent(event: IFileChange): void {
392 > const existingEvent = this.mapPathToChange.get(this.toKey(event)); watcher.ts ×11
393 >
394 > let keepEvent = false;
395 >
396 > // Event path already exists
397 > if (existingEvent) {
398 > const currentChangeType = existingEvent.type; watcher.ts ×3
399 > const newChangeType = event.type;
400 >
401 > // macOS/Windows: track renames to different case
402 > // by keeping both CREATE and DELETE events
403 > if (existingEvent.resource.fsPath !== event.resource.fsPath && (event.type === FileChangeType.DELETED || event.type === FileChangeType.ADDED)) {
404 keepEvent = true;
405 }
407 > // Ignore CREATE followed by DELETE in one go
408 > else if (currentChangeType === FileChangeType.ADDED && newChangeType === FileChangeType.DELETED) {
409 > this.mapPathToChange.delete(this.toKey(event)); watcher.ts ×1
410 > this.coalesced.delete(existingEvent);
411 > }
413 > // Flatten DELETE followed by CREATE into CHANGE
414 > else if (currentChangeType === FileChangeType.DELETED && newChangeType === FileChangeType.ADDED) {
415 > existingEvent.type = FileChangeType.UPDATED; watcher.ts ×1
416 > }
418 > // Do nothing. Keep the created event
419 > else if (currentChangeType === FileChangeType.ADDED && newChangeType === FileChangeType.UPDATED) { }
421 > // Otherwise apply change type
422 > else {
423 > existingEvent.type = newChangeType;
424 > }
425 > } watcher.ts ×3
427 > // Otherwise keep
428 > else {
429 > keepEvent = true;
430 > }
431 >
432 > if (keepEvent) {
433 > this.coalesced.add(event);
434 > this.mapPathToChange.set(this.toKey(event), event);
435 > }
436 > }
438 > coalesce(): IFileChange[] {
439 > const addOrChangeEvents: IFileChange[] = []; watcher.ts ×11
440 > const deletedPaths: string[] = [];
441 >
442 > // This algorithm will remove all DELETE events up to the root folder
443 > // that got deleted if any. This ensures that we are not producing
444 > // DELETE events for each file inside a folder that gets deleted.
445 > //
446 > // 1.) split ADD/CHANGE and DELETED events
447 > // 2.) sort short deleted paths to the top
448 > // 3.) for each DELETE, check if there is a deleted parent and ignore the event in that case
449 > return Array.from(this.coalesced).filter(e => {
450 > if (e.type !== FileChangeType.DELETED) {
451 > addOrChangeEvents.push(e);
452 >
453 > return false; // remove ADD / CHANGE
454 > }
456 > return true; // keep DELETE
457 > }).sort((e1, e2) => { watcher.ts ×11
458 > return e1.resource.fsPath.length - e2.resource.fsPath.length; // shortest path first watcher.ts ×2
459 > }).filter(e => { watcher.ts ×11
460 > if (deletedPaths.some(deletedPath => isParent(e.resource.fsPath, deletedPath, !isLinux /* ignorecase */))) { watcher.ts ×3
461 > return false; // DELETE is ignored if parent is deleted already watcher.ts ×2
462 > }
464 > // otherwise mark as deleted
465 > deletedPaths.push(e.resource.fsPath);
466 >
467 > return true;
468 > }).concat(addOrChangeEvents); watcher.ts ×11
469 > }
470 > } watcher.ts ×24
471 >
472 > export function isFiltered(event: IFileChange, filter: FileChangeFilter | undefined): boolean {
473 > if (typeof filter === 'number') { watcher.ts ×1
474 > switch (event.type) {
475 > case FileChangeType.ADDED:
476 > return (filter & FileChangeFilter.ADDED) === 0;
477 > case FileChangeType.DELETED:
478 > return (filter & FileChangeFilter.DELETED) === 0;
479 > case FileChangeType.UPDATED:
480 > return (filter & FileChangeFilter.UPDATED) === 0;
481 > }
482 > }
483 >
484 > return false;
485 > }
487 > export function requestFilterToString(filter: FileChangeFilter | undefined): string {
488 if (typeof filter === 'number') {
489 const filters = [];
490 if (filter & FileChangeFilter.ADDED) {
491 filters.push('Added');
492 }
493 if (filter & FileChangeFilter.DELETED) {
494 filters.push('Deleted');
495 }
496 if (filter & FileChangeFilter.UPDATED) {
497 filters.push('Updated');
498 }
499
500 if (filters.length === 0) {
501 return '<all>';
502 }
503
504 return `[${filters.join(', ')}]`;
505 }
506
507 return '<none>';
508 }