Finding text in a large document stutters on first characters
If the finding matches too many occurrences, the control causes a stutter making sure that all occurrences are evaluated before accepting more text input and cancelling the find on the short text.
Example of large document: https://raw.githubusercontent.com/dotnet/roslyn/main/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs
Typing "test" will cause a stutter upon typing "t", and then as the results diminish, the other letters will appear normally without any visible stutter.
We could review the sewch performance to see if we can improve it. I guess other editors such as VSCode/Sublime can do it without issues.
If the performance cannot be easily improved an option could be restricting starting the search for two or more chars (giving probably some UI clue about it)
If the performance cannot be easily improved an option could be restricting starting the search for two or more chars ...
Another solution would be to throttle/debounce the input, i.e. wait for a few milliseconds before executing the search to see if more characters are entered.
I did some quick profiling using @Rekkonnect's example. When I search for "t" I get more than 50,000 results. It seems most time is spent here:
https://github.com/AvaloniaUI/AvaloniaEdit/blob/master/src/AvaloniaEdit/Search/SearchPanel.cs#L460
TextSegmentCollection.Add is slow. Each result is inserted as a class TextSegment in binary (red-black) tree. Lots of memory allocations, lots of overhead for insertion.
SearchResultBackgroundRenderer can also be optimized here:
https://github.com/AvaloniaUI/AvaloniaEdit/blob/master/src/AvaloniaEdit/Search/SearchResultBackgroundRenderer.cs#L68-L80
Instead of creating n BackgroundGeometryBuilders and adding n geometries, we can use a single BackgroundGeometryBuilder and add everything as a single geometry. E.g.
var overlappingSegments = CurrentResults.FindOverlappingSegments(viewStart, viewEnd - viewStart);
if (overlappingSegments.Count == 0)
return;
var geoBuilder = new BackgroundGeometryBuilder
{
AlignToWholePixels = true,
CornerRadius = 0
};
foreach (var result in overlappingSegments)
geoBuilder.AddSegment(textView, result);
var geometry = geoBuilder.CreateGeometry();
if (geometry != null)
drawingContext.DrawGeometry(_markerBrush, null, geometry);