src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts/ChokidarWatcherService/watch
class ChokidarWatcherService:	private watch(basePath: string, requests: IWatcherRequest[]): IWatcher {
		const pollingInterval = this.pollingInterval || 5000;
		let usePolling = this.usePolling; // boolean or a list of path patterns
		if (Array.isArray(usePolling)) {
			// switch to polling if one of the paths matches with a watched path
			usePolling = usePolling.some(pattern => requests.some(request => match(pattern, request.path)));
		}

		const watcherOpts: chokidar.WatchOptions = {
			ignoreInitial: true,
			ignorePermissionErrors: true,
			followSymlinks: true, // this is the default of chokidar and supports file events through symlinks
			interval: pollingInterval, // while not used in normal cases, if any error causes chokidar to fallback to polling, increase its intervals
			binaryInterval: pollingInterval,
			usePolling,
			disableGlobbing: true // fix https://github.com/microsoft/vscode/issues/4586
		};

		const excludes: string[] = [];

		const isSingleFolder = requests.length === 1;
		if (isSingleFolder) {
			excludes.push(...requests[0].excludes); // if there's only one request, use the built-in ignore-filterering
		}

		if ((isMacintosh || isLinux) && (basePath.length === 0 || basePath === '/')) {
			excludes.push('/dev/**');
			if (isLinux) {
				excludes.push('/proc/**', '/sys/**');
			}
		}

		excludes.push('**/*.asar'); // Ensure we never recurse into ASAR archives

		watcherOpts.ignored = excludes;

		// Chokidar fails when the basePath does not match case-identical to the path on disk
		// so we have to find the real casing of the path and do some path massaging to fix this
		// see https://github.com/paulmillr/chokidar/issues/418
		const realBasePath = isMacintosh ? (realcaseSync(basePath) || basePath) : basePath;
		const realBasePathLength = realBasePath.length;
		const realBasePathDiffers = (basePath !== realBasePath);

		if (realBasePathDiffers) {
			this.warn(`Watcher basePath does not match version on disk and was corrected (original: ${basePath}, real: ${realBasePath})`);
		}

		this.debug(`Start watching: ${realBasePath}, excludes: ${excludes.join(',')}, usePolling: ${usePolling ? 'true, interval ' + pollingInterval : 'false'}`);

		let chokidarWatcher: chokidar.FSWatcher | null = chokidar.watch(realBasePath, watcherOpts);
		this._watcherCount++;

		// Detect if for some reason the native watcher library fails to load
		if (isMacintosh && chokidarWatcher.options && !chokidarWatcher.options.useFsEvents) {
			this.warn('Watcher is not using native fsevents library and is falling back to unefficient polling.');
		}

		let undeliveredFileEvents: IDiskFileChange[] = [];
		let fileEventDelayer: ThrottledDelayer<undefined> | null = new ThrottledDelayer(ChokidarWatcherService.FS_EVENT_DELAY);

		const watcher: IWatcher = {
			requests,
			stop: async () => {
				try {
					if (this.verboseLogging) {
						this.log(`Stop watching: ${basePath}]`);
					}

					if (chokidarWatcher) {
						await chokidarWatcher.close();
						this._watcherCount--;
						chokidarWatcher = null;
					}

					if (fileEventDelayer) {
						fileEventDelayer.cancel();
						fileEventDelayer = null;
					}
				} catch (error) {
					this.warn('Error while stopping watcher: ' + error.toString());
				}
			}
		};

		chokidarWatcher.on('all', (type: string, path: string) => {
			if (isMacintosh) {
				// Mac: uses NFD unicode form on disk, but we want NFC
				// See also https://github.com/nodejs/node/issues/2165
				path = normalizeNFC(path);
			}

			if (path.indexOf(realBasePath) < 0) {
				return; // we really only care about absolute paths here in our basepath context here
			}

			// Make sure to convert the path back to its original basePath form if the realpath is different
			if (realBasePathDiffers) {
				path = basePath + path.substr(realBasePathLength);
			}

			let eventType: FileChangeType;
			switch (type) {
				case 'change':
					eventType = FileChangeType.UPDATED;
					break;
				case 'add':
				case 'addDir':
					eventType = FileChangeType.ADDED;
					break;
				case 'unlink':
				case 'unlinkDir':
					eventType = FileChangeType.DELETED;
					break;
				default:
					return;
			}

			// if there's more than one request we need to do
			// extra filtering due to potentially overlapping roots
			if (!isSingleFolder) {
				if (isIgnored(path, watcher.requests)) {
					return;
				}
			}

			const event = { type: eventType, path };

			// Logging
			if (this.verboseLogging) {
				this.log(`${eventType === FileChangeType.ADDED ? '[ADDED]' : eventType === FileChangeType.DELETED ? '[DELETED]' : '[CHANGED]'} ${path}`);
			}

			// Check for spam
			const now = Date.now();
			if (undeliveredFileEvents.length === 0) {
				this.spamWarningLogged = false;
				this.spamCheckStartTime = now;
			} else if (!this.spamWarningLogged && typeof this.spamCheckStartTime === 'number' && this.spamCheckStartTime + ChokidarWatcherService.EVENT_SPAM_WARNING_THRESHOLD < now) {
				this.spamWarningLogged = true;
				this.warn(`Watcher is busy catching up with ${undeliveredFileEvents.length} file changes in 60 seconds. Latest changed path is "${event.path}"`);
			}

			// Add to buffer
			undeliveredFileEvents.push(event);

			if (fileEventDelayer) {

				// Delay and send buffer
				fileEventDelayer.trigger(async () => {
					const events = undeliveredFileEvents;
					undeliveredFileEvents = [];

					// Broadcast to clients normalized
					const normalizedEvents = normalizeFileChanges(events);
					this._onDidChangeFile.fire(normalizedEvents);

					// Logging
					if (this.verboseLogging) {
						for (const e of normalizedEvents) {
							this.log(` >> normalized  ${e.type === FileChangeType.ADDED ? '[ADDED]' : e.type === FileChangeType.DELETED ? '[DELETED]' : '[CHANGED]'} ${e.path}`);
						}
					}

					return undefined;
				});
			}
		});

		chokidarWatcher.on('error', (error: NodeJS.ErrnoException) => {
			if (error) {

				// Specially handle ENOSPC errors that can happen when
				// the watcher consumes so many file descriptors that
				// we are running into a limit. We only want to warn
				// once in this case to avoid log spam.
				// See https://github.com/microsoft/vscode/issues/7950
				if (error.code === 'ENOSPC') {
					if (!this.enospcErrorLogged) {
						this.enospcErrorLogged = true;
						this.stop();
						this.error('Inotify limit reached (ENOSPC)');
					}
				} else {
					this.warn(error.toString());
				}
			}
		});
		return watcher;
	}