static void UpdateWatchers(CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                return;
            }
            lock (watchers) {
                if (token.IsCancellationRequested)
                {
                    return;
                }
                newWatchers.Clear();
                foreach (var node in tree.Normalize(maxWatchers))
                {
                    if (token.IsCancellationRequested)
                    {
                        return;
                    }
                    var dir = node.GetPath().ToString();
                    if (Directory.Exists(dir))
                    {
                        newWatchers.Add(dir);
                    }
                }
                if (newWatchers.Count == 0 && watchers.Count == 0)
                {
                    // Unchanged.
                    return;
                }
                toRemove.Clear();
                foreach (var kvp in watchers)
                {
                    var directory = kvp.Key;
                    if (!newWatchers.Contains(directory))
                    {
                        toRemove.Add(directory);
                    }
                }

                // After this point, the watcher update is real and a destructive operation, so do not use the token.
                if (token.IsCancellationRequested)
                {
                    return;
                }

                // First remove the watchers, so we don't spin too many threads.
                foreach (var directory in toRemove)
                {
                    RemoveWatcher_NoLock(directory);
                }

                // Add the new ones.
                foreach (var path in newWatchers)
                {
                    // Don't modify a watcher that already exists.
                    if (watchers.ContainsKey(path))
                    {
                        continue;
                    }
                    var watcher = new FileWatcherWrapper(path);
                    watchers.Add(path, watcher);
                    try {
                        watcher.EnableRaisingEvents = true;
                    } catch (UnauthorizedAccessException e) {
                        LoggingService.LogWarning("Access to " + path + " denied. Stopping file watcher.", e);
                        watcher.Dispose();
                        watchers.Remove(path);
                    }
                }
            }
        }
        static void UpdateWatchers(
            List <WorkspaceItem> currentWorkspaceItems,
            Dictionary <object, List <FilePath> > currentMonitoredDirectories,
            CancellationToken token)
        {
            List <FileWatcherWrapper> newWatchers = null;

            HashSet <FilePath> watchedDirectories = GetWatchedDirectories();

            if (token.IsCancellationRequested)
            {
                return;
            }

            foreach (FilePath directory in GetRootDirectories(currentWorkspaceItems, currentMonitoredDirectories))
            {
                if (!watchedDirectories.Remove(directory))
                {
                    if (Directory.Exists(directory))
                    {
                        if (newWatchers == null)
                        {
                            newWatchers = new List <FileWatcherWrapper> ();
                        }
                        var watcher = new FileWatcherWrapper(directory);
                        newWatchers.Add(watcher);
                    }
                }
            }

            if (newWatchers == null && !watchedDirectories.Any())
            {
                // Unchanged.
                return;
            }

            lock (watchers) {
                if (token.IsCancellationRequested)
                {
                    if (newWatchers != null)
                    {
                        foreach (FileWatcherWrapper watcher in newWatchers)
                        {
                            watcher.Dispose();
                        }
                    }
                    return;
                }

                // Remove file watchers no longer needed.
                foreach (FilePath directory in watchedDirectories)
                {
                    Remove(directory);
                }

                if (newWatchers != null)
                {
                    foreach (FileWatcherWrapper watcher in newWatchers)
                    {
                        watchers.Add(watcher.Path, watcher);
                        watcher.EnableRaisingEvents = true;
                    }
                }
            }
        }
        static void UpdateWatchers(CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                return;
            }

            lock (watchers) {
                if (token.IsCancellationRequested)
                {
                    return;
                }

                var newPathsToWatch = tree.Normalize(maxWatchers).Select(node => (FilePath)node.FullPath);
                var newWatchers     = new HashSet <FilePath> (newPathsToWatch.Where(dir => Directory.Exists(dir)));
                if (newWatchers.Count == 0 && watchers.Count == 0)
                {
                    // Unchanged.
                    return;
                }

                List <FilePath> toRemove;
                if (newWatchers.Count == 0)
                {
                    toRemove = watchers.Keys.ToList();
                }
                else
                {
                    toRemove = new List <FilePath> ();
                    foreach (var kvp in watchers)
                    {
                        var directory = kvp.Key;
                        if (!newWatchers.Contains(directory))
                        {
                            toRemove.Add(directory);
                        }
                    }
                }

                // After this point, the watcher update is real and a destructive operation, so do not use the token.
                if (token.IsCancellationRequested)
                {
                    return;
                }

                // First remove the watchers, so we don't spin too many threads.
                foreach (var directory in toRemove)
                {
                    RemoveWatcher_NoLock(directory);
                }

                // Add the new ones.
                if (newWatchers.Count == 0)
                {
                    return;
                }

                foreach (var path in newWatchers)
                {
                    // Don't modify a watcher that already exists.
                    if (watchers.ContainsKey(path))
                    {
                        continue;
                    }

                    var watcher = new FileWatcherWrapper(path);
                    watchers.Add(path, watcher);
                    watcher.EnableRaisingEvents = true;
                }
            }
        }