in src/MatchMargin/MatchMarginElement.cs [625:697]
public BackgroundSearch(ITextSnapshot snapshot, string searchText, bool matchWholeWord, Action completionCallback)
{
this.Snapshot = snapshot;
ThreadPool.QueueUserWorkItem(delegate (object state)
{
//Lower our priority so that we do not compete with the rendering.
System.Threading.Thread.CurrentThread.Priority = ThreadPriority.Lowest;
System.Threading.Thread.CurrentThread.IsBackground = true;
List<SnapshotSpan> newMatches = new List<SnapshotSpan>();
int start = 0;
while (true)
{
int end = Math.Min(snapshot.Length, start + MatchMarginElement.SearchBufferSize);
string text = snapshot.GetText(start, end - start);
int offset = (start == 0) ? 0 : 1;
while (true)
{
int match = text.IndexOf(searchText, offset, StringComparison.Ordinal);
if (match == -1)
break;
if (matchWholeWord)
{
//Make sure the character preceeding the match is a word break
//(or the very start of the buffer, which is the only time match can equal 0).
if ((match == 0) || !BackgroundSearch.IsWordCharacter(text[match - 1]))
{
//Make sure the character after the match is a word break.
//If we're at the end of text, then it is only considered a word break if that is also the very end of the buffer.
if ((match + searchText.Length == text.Length)
? (end == snapshot.Length)
: !BackgroundSearch.IsWordCharacter(text[match + searchText.Length]))
{
SnapshotSpan matchSpan = new SnapshotSpan(snapshot, match + start, searchText.Length);
newMatches.Add(matchSpan);
}
}
}
else
{
//Any match is a match.
SnapshotSpan matchSpan = new SnapshotSpan(snapshot, match + start, searchText.Length);
newMatches.Add(matchSpan);
}
//Continue searching at the location of the next possible match
//(we could add one more since there needs to be one character of whitespace between matches, but
//then we'd need an if to guard against placing offset past the end of text).
offset = match + searchText.Length;
}
//Check to see if the search should be aborted because no one cares about the result any more.
if (_abort)
return;
if (end == snapshot.Length)
break; //All done.
//rollback from the end enough so that we can match something that we previously matched at the very end of the
//(along with the preceeding character so we can ensure it starts on a word break).
start = end - (searchText.Length + 1);
}
//This should be a thread safe operation since it is atomic
_matches = newMatches;
completionCallback();
});
}