private void RefreshExcludePatterns()
        {
            TextLines excludeFromScans = new TextLines(this.options.ExcludeFromCommentScans);

            List <Regex> currentPatterns = new List <Regex>();

            foreach (string pattern in excludeFromScans.Lines.Where(line => !string.IsNullOrEmpty(line)).Distinct())
            {
                if (!this.excludePatternsCache.TryGetValue(pattern, out Regex regex))
                {
                    try
                    {
                        regex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant);
                        this.excludePatternsCache.Add(pattern, regex);
                    }
                    catch (ArgumentException ex)
                    {
                        // The pattern isn't a valid regular expression.
                        MainPackage.LogException(ex);
                    }
                }

                if (regex != null)
                {
                    currentPatterns.Add(regex);
                }
            }

            lock (this.backgroundExcludePatterns)
            {
                this.backgroundExcludePatterns.Clear();
                this.backgroundExcludePatterns.AddRange(currentPatterns);
            }
        }
        public void UpdateTasks(bool updateAll)
        {
            IEnumerable <FileItem> items;

            lock (this.changedItems)
            {
                items = this.changedItems.ToList();
            }

            if (updateAll)
            {
                // We have to include any changedItems to make sure we remove existing tasks
                // from files that no longer exist in this.files.
                items = items.Concat(this.files.Select(pair => pair.Value)).Distinct();
            }

            if (items.Any())
            {
                List <Regex> localExcludePatterns;
                lock (this.backgroundExcludePatterns)
                {
                    localExcludePatterns = new List <Regex>(this.backgroundExcludePatterns);
                }

                // Try to use a fourth of the processors, but stay in the 1 to 8 range.
                const int MinParallelism       = 1;
                const int MaxParallelism       = 8;
                const int ProcessorScaleFactor = 4;
                int       maxParallelism       = Math.Max(MinParallelism, Math.Min(Environment.ProcessorCount / ProcessorScaleFactor, MaxParallelism));
                try
                {
                    RefreshAction generalAction = updateAll ? RefreshAction.Always : RefreshAction.IfNeeded;
                    Parallel.ForEach(
                        items.ToArray(),                         // Copy before iterating through it.
                        new ParallelOptions()
                    {
                        MaxDegreeOfParallelism = maxParallelism
                    },
                        item =>
                    {
                        RefreshAction itemAction;
                        if (localExcludePatterns.Any(pattern => pattern.IsMatch(item.FileName)))
                        {
                            itemAction = RefreshAction.Remove;
                        }
                        else
                        {
                            itemAction = generalAction;
                        }

                        this.RefreshItem(item, itemAction);
                    });
                }
                catch (Exception ex)
                {
                    MainPackage.LogException(ex);
                    if (!(ex is AggregateException))
                    {
                        throw;
                    }
                }
            }
        }