private HighlightJobCollection ApplyDescriptors(string text, int indexOfTextArgInSourceCode, IList <SyntaxHighlightDescriptor> descriptors) { var jobs = new HighlightJobCollection(); foreach (var descriptor in descriptors) { CancellationToken?.ThrowIfCancellationRequested(); ApplyDescriptor(text, indexOfTextArgInSourceCode, descriptor, jobs); } return(jobs); }
private void ApplyDescriptor(string text, int indexOfTextArgInSourceCode, SyntaxHighlightDescriptor descriptor, HighlightJobCollection jobs) { if (descriptor.Pattern == null) { var job = new HighlightJob(descriptor.ColorKey, indexOfTextArgInSourceCode, text.Length); jobs.TryInsert(job); return; } var matches = descriptor.Pattern.Matches(text); if (matches.Count == 0) { return; } foreach (Match match in matches) { CancellationToken?.ThrowIfCancellationRequested(); var job = new HighlightJob(descriptor.ColorKey, indexOfTextArgInSourceCode + match.Index, match.Length); var insertionPoint = jobs.GetInsertionPoint(job); var processChildDescriptors = (insertionPoint >= 0) && (descriptor.CapturedGroups != null); if (processChildDescriptors) { // because regex groups can't overlap, we do not require the added constraint provided by HighlightJobCollection. // A simple List<HighlightJob> is sufficient var childJobs = new List <HighlightJob>(); for (var i = 1; i < match.Groups.Count; ++i) { if (descriptor.CapturedGroups.TryGetValue(i, out var childDescriptors)) { childJobs.AddRange(ApplyDescriptors(match.Groups[i].Value, indexOfTextArgInSourceCode + match.Groups[i].Index, childDescriptors)); } } job.ChildJobs = childJobs; } // A job without a color key leaves its portion of text up for grabs by other jobs. // The portion of its text used by its child jobs (if any) are not available to other jobs if (!string.IsNullOrEmpty(job.ColorKey) && insertionPoint >= 0) { jobs.Insert(insertionPoint, job); } else if (processChildDescriptors) { jobs.AddJobs(job.ChildJobs); } } }