public IReadOnlyList <Segment> GetUnderliningInfo( ) { if (LastMatches == null) { return(Enumerable.Empty <Segment>( ).ToList( )); } TextData td = null; if (!CheckAccess( )) { ChangeEventHelper.Invoke(CancellationToken.None, () => { td = rtb.GetTextData(LastEol); }); } else { td = rtb.GetTextData(LastEol); } return(GetUnderliningInfo(NonCancellable.Instance, td, LastMatches, LastShowCaptures)); }
void ShowMatchesThreadProc(ICancellable cnc) { lock ( MatchInfos ) { MatchInfos.Clear( ); ExternalUnderliningLoop.SendWaitAndExecute( ); } string text; RegexMatches matches; bool show_captures; bool show_succeeded_groups_only; bool show_first_only; lock (this) { text = LastText; matches = LastMatches; show_captures = LastShowCaptures; show_succeeded_groups_only = LastShowSucceededGroupsOnly; show_first_only = LastShowFirstOnly; } if (matches.Count == 0) { Dispatcher.BeginInvoke(new Action(() => { CancelInfo( ); ShowOne(rtbNoMatches); })); return; } ChangeEventHelper.Invoke(CancellationToken.None, () => { pbProgress.Maximum = matches.Count; pbProgress.Value = 0; if (secMatches.Blocks.Count > matches.Count) { // remove unneeded paragraphs var r = new TextRange(secMatches.Blocks.ElementAt(matches.Count).ElementStart, secMatches.ContentEnd); r.Text = ""; } CancelInfo( ); ShowOne(rtbMatches); }); if (cnc.IsCancellationRequested) { return; } int show_pb_time = unchecked (Environment.TickCount + 333); // (ignore overflow) Paragraph previous_para = null; int match_number = -1; bool document_has_changed = false; int left_width = EvaluateLeftWidth(matches, show_succeeded_groups_only); foreach (IMatch match in matches.Matches) { Debug.Assert(match.Success); ++match_number; if (cnc.IsCancellationRequested) { break; } var ordered_groups = match.Groups .Skip(1) // skip match .Where(g => g.Success || !show_succeeded_groups_only) //OrderBy( g => g.Success ? g.Index : match.Index ) .ToList( ); if (cnc.IsCancellationRequested) { break; } int min_index = ordered_groups.Select(g => g.Success ? g.TextIndex : match.TextIndex).Concat(new[] { match.TextIndex }).Min( ); if (show_captures) { min_index = ordered_groups.SelectMany(g => g.Captures).Select(c => c.TextIndex).Concat(new[] { min_index }).Min( ); } if (cnc.IsCancellationRequested) { break; } int left_width_for_match = left_width + (match.TextIndex - min_index); Paragraph para = null; Run run = null; MatchInfo match_info = null; RunBuilder match_run_builder = new RunBuilder(MatchValueSpecialStyleInfo); var highlight_style = HighlightStyleInfos[match_number % HighlightStyleInfos.Length]; var highlight_light_style = HighlightLightStyleInfos[match_number % HighlightStyleInfos.Length]; // show match string match_name_text = show_first_only ? "Fɪʀꜱᴛ Mᴀᴛᴄʜ" : $"Mᴀᴛᴄʜ {match_number + 1}"; ChangeEventHelper.Invoke(CancellationToken.None, () => { pbProgress.Value = match_number; if (Environment.TickCount >= show_pb_time) { pbProgress.Visibility = Visibility.Visible; } var span = new Span( ); para = new Paragraph(span); var start_run = new Run(match_name_text.PadRight(left_width_for_match, ' '), span.ContentEnd); start_run.Style(MatchNormalStyleInfo); Inline value_inline; if (match.Length == 0) { value_inline = new Run("(empty)", span.ContentEnd); // value_inline.Style(MatchNormalStyleInfo, LocationStyleInfo); } else { value_inline = match_run_builder.Build(match.Value, span.ContentEnd); value_inline.Style(MatchValueStyleInfo, highlight_style); } run = new Run($"\x200E ({match.Index}, {match.Length})", span.ContentEnd); run.Style(MatchNormalStyleInfo, LocationStyleInfo); _ = new LineBreak(span.ElementEnd); // (after span) match_info = new MatchInfo { MatchSegment = new Segment(match.TextIndex, match.TextLength), Span = span, ValueInline = value_inline, }; span.Tag = match_info; lock ( MatchInfos ) { MatchInfos.Add(match_info); //...ExternalUnderliningEvents.SendRestart( ); } // captures for match //if( showCaptures) AppendCaptures( ct, para, LEFT_WIDTH, match, match ); }); if (cnc.IsCancellationRequested) { break; } // show groups RunBuilder sibling_run_builder = new RunBuilder(null); foreach (var group in ordered_groups) { if (cnc.IsCancellationRequested) { break; } string group_name_text = $" • Gʀᴏᴜᴘ ‹{group.Name}›"; int left_width_for_group = left_width_for_match - Math.Max(0, match.TextIndex - (group.Success ? group.TextIndex : match.TextIndex)); ChangeEventHelper.Invoke(CancellationToken.None, () => { var span = new Span( ); var start_run = new Run(group_name_text.PadRight(left_width_for_group, ' '), span.ContentEnd); start_run.Style(GroupNameStyleInfo); // (NOTE. Overlaps are possible in this example: (?=(..)) Inline value_inline; Inline inl; if (!group.Success) { value_inline = new Run("(fail)", span.ContentEnd); value_inline.Style(GroupFailedStyleInfo); } else if (group.Length == 0) { value_inline = new Run("(empty)", span.ContentEnd); value_inline.Style(LocationStyleInfo); } else { string left = Utilities.SubstringFromTo(text, match.TextIndex, group.TextIndex); string middle = group.Value; string right = Utilities.SubstringFromTo(text, group.TextIndex + group.TextLength, Math.Max(match.TextIndex + match.TextLength, group.TextIndex + group.TextLength)); inl = sibling_run_builder.Build(left, span.ContentEnd); inl.Style(GroupSiblingValueStyleInfo); value_inline = match_run_builder.Build(middle, span.ContentEnd); value_inline.Style(GroupValueStyleInfo, highlight_light_style); inl = sibling_run_builder.Build(right, span.ContentEnd); inl.Style(GroupSiblingValueStyleInfo); } if (cnc.IsCancellationRequested) { return; } run = new Run($"\x200E ({group.Index}, {group.Length})", span.ContentEnd); run.Style(MatchNormalStyleInfo, LocationStyleInfo); para.Inlines.Add(span); _ = new LineBreak(span.ElementEnd); // (after span) var group_info = new GroupInfo { Parent = match_info, IsSuccess = group.Success, GroupSegment = new Segment(group.TextIndex, group.TextLength), Span = span, ValueInline = value_inline, }; span.Tag = group_info; match_info.GroupInfos.Add(group_info); // captures for group if (show_captures) { AppendCaptures(cnc, group_info, para, left_width_for_match, text, match, group, highlight_light_style, match_run_builder, sibling_run_builder); } }); } if (cnc.IsCancellationRequested) { break; } ChangeEventHelper.Invoke(CancellationToken.None, () => { if (previous_para == null) { var first_block = secMatches.Blocks.FirstBlock; if (first_block == null) { secMatches.Blocks.Add(para); } else { secMatches.Blocks.InsertBefore(first_block, para); secMatches.Blocks.Remove(first_block); } } else { if (!previous_para.ContentStart.IsInSameDocument(rtbMatches.Document.ContentStart)) { document_has_changed = true; } else { var next = previous_para.NextBlock; if (next != null) { secMatches.Blocks.Remove(next); } secMatches.Blocks.InsertAfter(previous_para, para); } } }); if (document_has_changed) { break; } previous_para = para; } if (document_has_changed) { return; } if (cnc.IsCancellationRequested) { return; } ChangeEventHelper.Invoke(CancellationToken.None, () => { pbProgress.Visibility = Visibility.Hidden; }); ExternalUnderliningLoop.SendWaitAndExecute( ); }
void HighlightingThreadProc(ICancellable cnc) { IRegexEngine regex_engine; string eol; lock (this) { regex_engine = mRegexEngine; eol = mEol; } if (regex_engine == null) { return; } TextData td = null; Rect clip_rect = Rect.Empty; int top_index = 0; int bottom_index = 0; bool is_focused = false; UITaskHelper.Invoke(rtb, () => { td = null; var start_doc = rtb.Document.ContentStart; var end_doc = rtb.Document.ContentStart; if (!start_doc.HasValidLayout || !end_doc.HasValidLayout) { return; } var td0 = rtb.GetTextData(eol); if (cnc.IsCancellationRequested) { return; } td = td0; clip_rect = new Rect(new Size(rtb.ViewportWidth, rtb.ViewportHeight)); TextPointer top_pointer = rtb.GetPositionFromPoint(new Point(0, 0), snapToText: true).GetLineStartPosition(-1, out int _); if (cnc.IsCancellationRequested) { return; } top_index = td.TextPointers.GetIndex(top_pointer, LogicalDirection.Backward); if (top_index < 0) { top_index = 0; } TextPointer bottom_pointer = rtb.GetPositionFromPoint(new Point(0, rtb.ViewportHeight), snapToText: true).GetLineStartPosition(+1, out int lines_skipped); if (cnc.IsCancellationRequested) { return; } if (bottom_pointer == null || lines_skipped == 0) { bottom_index = td.Text.Length; } else { bottom_index = td.TextPointers.GetIndex(bottom_pointer, LogicalDirection.Forward); if (cnc.IsCancellationRequested) { return; } } if (bottom_index > td.Text.Length) { bottom_index = td.Text.Length; } if (bottom_index < top_index) { bottom_index = top_index; // (including 'if bottom_index == 0') } is_focused = rtb.IsFocused; }); if (cnc.IsCancellationRequested) { return; } if (td == null) { return; } if (td.Text.Length == 0) { return; } Debug.Assert(top_index >= 0); Debug.Assert(bottom_index >= top_index); Debug.Assert(bottom_index <= td.Text.Length); Highlights highlights = null; if (is_focused) { var visible_segment = new Segment(top_index, bottom_index - top_index + 1); highlights = new Highlights( ); regex_engine.HighlightPattern(cnc, highlights, td.Text, td.SelectionStart, td.SelectionEnd, visible_segment); } if (cnc.IsCancellationRequested) { return; } lock ( Locker ) { ChangeEventHelper.Invoke(CancellationToken.None, () => { TryHighlight(ref LeftHighlightedParenthesis, highlights?.LeftPar ?? Segment.Empty, td, PatternParaHighlightStyleInfo); if (cnc.IsCancellationRequested) { return; } TryHighlight(ref RightHighlightedParenthesis, highlights?.RightPar ?? Segment.Empty, td, PatternParaHighlightStyleInfo); if (cnc.IsCancellationRequested) { return; } TryHighlight(ref LeftHighlightedBracket, highlights?.LeftBracket ?? Segment.Empty, td, PatternCharGroupBracketHighlightStyleInfo); if (cnc.IsCancellationRequested) { return; } TryHighlight(ref RightHighlightedBracket, highlights?.RightBracket ?? Segment.Empty, td, PatternCharGroupBracketHighlightStyleInfo); if (cnc.IsCancellationRequested) { return; } TryHighlight(ref LeftHighlightedCurlyBrace, highlights?.LeftCurlyBrace ?? Segment.Empty, td, PatternRangeCurlyBraceHighlightStyleInfo); if (cnc.IsCancellationRequested) { return; } TryHighlight(ref RightHighlightedCurlyBrace, highlights?.RightCurlyBrace ?? Segment.Empty, td, PatternRangeCurlyBraceHighlightStyleInfo); if (cnc.IsCancellationRequested) { return; } }); } }