void HideIndeterminateProgress(Thread indeterminateProgressThread) { try { indeterminateProgressThread.Interrupt( ); indeterminateProgressThread.Join(333); indeterminateProgressThread.Abort( ); } catch (Exception exc) { _ = exc; if (Debugger.IsAttached) { Debugger.Break( ); } // ignore } UITaskHelper.BeginInvoke(this, CancellationToken.None, () => { ucMatches.ShowIndeterminateProgress(false); }); }
void ShowTextInfoThreadProc(ICancellable cnc) { UITaskHelper.BeginInvoke(this, () => { var td = ucText.GetTextData(GetEolOption( )); if (cnc.IsCancellationRequested) { return; } lblTextInfo.Visibility = lblTextInfo.Visibility == Visibility.Visible || td.Text.Length != 0 ? Visibility.Visible : Visibility.Collapsed; if (lblTextInfo.Visibility == Visibility.Visible) { int text_elements = td.LengthInTextElements; string s = $"(Length: {td.Text.Length:#,##0}"; if (text_elements != td.Text.Length) { s += $", Text Elements: {text_elements:#,##0}"; } if (ucTextHadFocus) { s += $", Index: {td.SelectionStart:#,##0}"; } s += ")"; lblTextInfo.Text = s; } }); }
void RecolouringThreadProc(ICancellable cnc) { RegexMatches matches; string eol; bool show_captures; lock (this) { matches = LastMatches; eol = LastEol; show_captures = LastShowCaptures; } TextData td = null; Rect clip_rect = Rect.Empty; int top_index = 0; int bottom_index = 0; 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 (cnc.IsCancellationRequested) { return; } 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') } }); 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); // (NOTE. Overlaps are possible in this example: (?=(..)) var segments_and_styles = new List <(Segment segment, StyleInfo styleInfo)>( ); var segments_to_uncolour = new List <Segment>( ); segments_to_uncolour.Add(new Segment(top_index, bottom_index - top_index + 1)); if (matches != null && matches.Count > 0) { int i = -1; foreach (var match in matches.Matches) { ++i; if (cnc.IsCancellationRequested) { break; } Debug.Assert(match.Success); // TODO: consider these conditions for bi-directional text if (match.TextIndex + match.TextLength < top_index) { continue; } if (match.TextIndex > bottom_index) { continue; // (do not break; the order of indices is unspecified) } var highlight_index = unchecked (i % HighlightStyleInfos.Length); Segment.Except(segments_to_uncolour, match.TextIndex, match.TextLength); segments_and_styles.Add((new Segment(match.TextIndex, match.TextLength), HighlightStyleInfos[highlight_index])); } } if (cnc.IsCancellationRequested) { return; } List <(Segment segment, StyleInfo styleInfo)> segments_to_uncolour_with_style = segments_to_uncolour .Select(s => (s, NormalStyleInfo)) .ToList( ); if (cnc.IsCancellationRequested) { return; } int center_index = (top_index + bottom_index) / 2; var all_segments_and_styles = segments_and_styles.Concat(segments_to_uncolour_with_style) .OrderBy(s => Math.Abs(center_index - (s.segment.Index + s.segment.Length / 2))) .ToList( ); if (cnc.IsCancellationRequested) { return; } RtbUtilities.ApplyStyle(cnc, ChangeEventHelper, pbProgress, td, all_segments_and_styles); if (cnc.IsCancellationRequested) { return; } UITaskHelper.BeginInvoke(pbProgress, () => { pbProgress.Visibility = Visibility.Hidden; }); }
bool CollectSpaces(ICancellable cnc, TextData td, Rect clipRect, int topIndex) { if (cnc.IsCancellationRequested) { return(false); } var rtb = Rtb; List <Rect> positions_spaces = new List <Rect>( ); List <Rect> positions_tabs = new List <Rect>( ); List <int> indices = new List <int>( ); for (var i = td.Text.IndexOfAny(SpacesAndTabs, topIndex); i >= 0; i = td.Text.IndexOfAny(SpacesAndTabs, i + 1)) { if (cnc.IsCancellationRequested) { return(false); } indices.Add(i); } var intermediate_results1 = new List <(int index, Rect left, Rect right)>( ); var intermediate_results2 = new List <(int index, Rect left, Rect right)>( ); int current_i = 0; void do_things( ) { Debug.Assert(!intermediate_results1.Any( )); var end_time = Environment.TickCount + 22; do { if (current_i >= indices.Count) { break; } if (cnc.IsCancellationRequested) { return; } var index = indices[current_i]; var tps = td.TextPointers.GetTextPointers(index, index + 1); var left = tps.Item1; var right = tps.Item2; var left_rect = left.GetCharacterRect(LogicalDirection.Forward); var right_rect = right.GetCharacterRect(LogicalDirection.Backward); intermediate_results1.Add((index, left_rect, right_rect)); if (left_rect.Top > clipRect.Bottom) { break; } ++current_i; } while(Environment.TickCount < end_time); } if (cnc.IsCancellationRequested) { return(false); } var d = UITaskHelper.BeginInvoke(rtb, do_things); for (; ;) { d.Wait( ); if (cnc.IsCancellationRequested) { return(false); } (intermediate_results1, intermediate_results2) = (intermediate_results2, intermediate_results1); if (!intermediate_results2.Any( )) { break; } d = UITaskHelper.BeginInvoke(rtb, do_things); bool should_break = false; Debug.Assert(!Rtb.Dispatcher.CheckAccess( )); foreach (var(index, left_rect, right_rect) in intermediate_results2) { if (cnc.IsCancellationRequested) { return(false); } if (right_rect.Bottom < clipRect.Top) { continue; } if (left_rect.Top > clipRect.Bottom) { should_break = true; break; } switch (td.Text[index]) { case '\t': positions_tabs.Add(Rect.Offset(left_rect, rtb.HorizontalOffset, rtb.VerticalOffset)); break; default: // (space) var r = new Rect(left_rect.TopLeft, right_rect.BottomRight); r.Offset(rtb.HorizontalOffset, rtb.VerticalOffset); positions_spaces.Add(r); break; } } if (should_break) { break; } intermediate_results2.Clear( ); } if (cnc.IsCancellationRequested) { return(false); } lock (this) { PositionsSpaces = positions_spaces; PositionsTabs = positions_tabs; } DelayedInvalidateVisual( ); return(true); }
void FindMatchesThreadProc(ICancellable cnc) { string eol = null; string pattern = null; string text = null; bool first_only = false; IRegexEngine engine = null; UITaskHelper.Invoke(this, () => { eol = GetEolOption( ); pattern = ucPattern.GetBaseTextData(eol).Text; if (cnc.IsCancellationRequested) { return; } text = ucText.GetBaseTextData(eol).Text; if (cnc.IsCancellationRequested) { return; } first_only = cbShowFirstOnly.IsChecked == true; engine = CurrentRegexEngine; }); if (cnc.IsCancellationRequested) { return; } if (string.IsNullOrEmpty(pattern)) { UITaskHelper.BeginInvoke(this, () => { ucText.SetMatches(RegexMatches.Empty, cbShowCaptures.IsChecked == true, GetEolOption( )); ucMatches.ShowNoPattern( ); lblMatches.Text = "Matches"; pnlShowAll.Visibility = Visibility.Collapsed; pnlShowFirst.Visibility = Visibility.Collapsed; }); } else { IMatcher parsed_pattern = null; RegexMatches matches = null; bool is_good = false; try { UITaskHelper.BeginInvoke(this, CancellationToken.None, () => ucMatches.ShowMatchingInProgress(true)); parsed_pattern = engine.ParsePattern(pattern); var indeterminate_progress_thread = new Thread(IndeterminateProgressThreadProc) { IsBackground = true }; try { indeterminate_progress_thread.Start( ); matches = parsed_pattern.Matches(text, cnc); } finally { HideIndeterminateProgress(indeterminate_progress_thread); } is_good = true; } catch (Exception exc) { if (cnc.IsCancellationRequested) { return; } UITaskHelper.BeginInvoke(this, CancellationToken.None, () => { ucText.SetMatches(RegexMatches.Empty, cbShowCaptures.IsChecked == true, GetEolOption( )); ucMatches.ShowError(exc, engine.Capabilities.HasFlag(RegexEngineCapabilityEnum.ScrollErrorsToEnd)); lblMatches.Text = "Error"; pnlShowAll.Visibility = Visibility.Collapsed; pnlShowFirst.Visibility = Visibility.Collapsed; }); Debug.Assert(!is_good); } finally { UITaskHelper.BeginInvoke(this, CancellationToken.None, () => ucMatches.ShowMatchingInProgress(false)); } if (cnc.IsCancellationRequested) { return; } if (is_good) { int count = matches.Count; var matches_to_show = first_only ? new RegexMatches(Math.Min(1, count), matches.Matches.Take(1)) : matches; if (cnc.IsCancellationRequested) { return; } UITaskHelper.BeginInvoke(this, () => { ucText.SetMatches(matches_to_show, cbShowCaptures.IsChecked == true, GetEolOption( )); ucMatches.SetMatches(text, matches_to_show, first_only, cbShowSucceededGroupsOnly.IsChecked == true, cbShowCaptures.IsChecked == true); lblMatches.Text = count == 0 ? "Matches" : count == 1 ? "1 match" : $"{count:#,##0} matches"; pnlShowAll.Visibility = first_only && count > 1 ? Visibility.Visible : Visibility.Collapsed; pnlShowFirst.Visibility = !first_only && count > 1 ? Visibility.Visible : Visibility.Collapsed; }); } } }