Browse Source

rewrote Find Next algorithm

pull/23/head
Siegfried Pammer 15 years ago
parent
commit
0f29a06847
  1. 2
      SharpDevelop.sln
  2. 161
      src/AddIns/Misc/SearchAndReplace/Project/Engine/SearchManager.cs

2
SharpDevelop.sln

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 11.00 Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010 # Visual Studio 2010
# SharpDevelop 4.2.0.7998-alpha # SharpDevelop 4.1.0.8000
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}"
ProjectSection(SolutionItems) = postProject ProjectSection(SolutionItems) = postProject
EndProjectSection EndProjectSection

161
src/AddIns/Misc/SearchAndReplace/Project/Engine/SearchManager.cs

@ -125,13 +125,17 @@ namespace SearchAndReplace
this.fileList = fileList; this.fileList = fileList;
this.monitor = monitor; this.monitor = monitor;
this.cts = cts; this.cts = cts;
this.count = fileList.Count();
} }
public IDisposable Subscribe(IObserver<SearchResultMatch> observer) public IDisposable Subscribe(IObserver<SearchResultMatch> observer)
{ {
this.observer = observer; this.observer = observer;
var task = new System.Threading.Tasks.Task(delegate { Parallel.ForEach(fileList, new ParallelOptions { CancellationToken = monitor.CancellationToken, MaxDegreeOfParallelism = Environment.ProcessorCount }, fileName => SearchFile(fileName, strategy, monitor.CancellationToken)); }); var task = new System.Threading.Tasks.Task(
delegate {
var list = fileList.ToList();
this.count = list.Count;
Parallel.ForEach(fileList, new ParallelOptions { CancellationToken = monitor.CancellationToken, MaxDegreeOfParallelism = Environment.ProcessorCount }, fileName => SearchFile(fileName, strategy, monitor.CancellationToken));
});
task.ContinueWith(t => { if (t.Exception != null) observer.OnError(t.Exception); else observer.OnCompleted(); this.Dispose(); }); task.ContinueWith(t => { if (t.Exception != null) observer.OnError(t.Exception); else observer.OnCompleted(); this.Dispose(); });
task.Start(); task.Start();
return this; return this;
@ -139,8 +143,7 @@ namespace SearchAndReplace
public void Dispose() public void Dispose()
{ {
if (!cts.IsCancellationRequested) cts.Cancel();
cts.Cancel();
monitor.Dispose(); monitor.Dispose();
} }
@ -150,7 +153,7 @@ namespace SearchAndReplace
if (buffer == null) if (buffer == null)
return; return;
if (!MimeTypeDetection.FindMimeType(buffer).StartsWith("text/")) if (!MimeTypeDetection.FindMimeType(buffer).StartsWith("text/", StringComparison.Ordinal))
return; return;
var source = DocumentUtilitites.GetTextSource(buffer); var source = DocumentUtilitites.GetTextSource(buffer);
TextDocument document = null; TextDocument document = null;
@ -191,6 +194,8 @@ namespace SearchAndReplace
if (string.IsNullOrEmpty(pattern)) if (string.IsNullOrEmpty(pattern))
return null; return null;
var files = GenerateFileList(target, baseDirectory, filter, searchSubdirs).ToArray(); var files = GenerateFileList(target, baseDirectory, filter, searchSubdirs).ToArray();
if (files.Length == 0)
return null;
if (currentSearchRegion == null || !currentSearchRegion.IsSameState(files, pattern, ignoreCase, matchWholeWords, mode, if (currentSearchRegion == null || !currentSearchRegion.IsSameState(files, pattern, ignoreCase, matchWholeWords, mode,
target, baseDirectory, filter, searchSubdirs)) target, baseDirectory, filter, searchSubdirs))
currentSearchRegion = SearchRegion.CreateSearchRegion(files, pattern, ignoreCase, matchWholeWords, mode, currentSearchRegion = SearchRegion.CreateSearchRegion(files, pattern, ignoreCase, matchWholeWords, mode,
@ -209,81 +214,97 @@ namespace SearchAndReplace
AnchorSegment selection; AnchorSegment selection;
PermanentAnchor searchStart; PermanentAnchor searchStart;
ISearchStrategy strategy; ISearchStrategy strategy;
IEnumerator<SearchResultMatch> enumerator; bool reachedEnd;
ParseableFileContentFinder finder = new ParseableFileContentFinder();
public SearchResultMatch FindNext() public SearchResultMatch FindNext()
{ {
if (enumerator == null) // Setup search inside current or first file.
enumerator = RunSearch(); ParseableFileContentFinder finder = new ParseableFileContentFinder();
if (enumerator.MoveNext()) int index = GetCurrentFileIndex();
return enumerator.Current; int startIndex = index;
int i = 0;
int searchOffset = 0;
return null; FileName file = files[index];
} ITextBuffer buffer = finder.Create(file);
SearchResultMatch result = null;
IEnumerator<SearchResultMatch> RunSearch() TextDocument document = null;
{
int startIndex = files.FindIndex(file => file.Equals(searchStart.FileName));
int endIndex = files.Length - 1;
int index = startIndex;
bool processSecondPart = false;
while (index <= endIndex) { // always use the caret position except if there is no editor open,
FileName file = files[index]; // or we are in the first file and have passed the end of the file (reachedEnd == true).
ITextBuffer buffer = finder.Create(file); var editor = GetActiveTextEditor();
if (editor != null)
if (buffer == null) { searchOffset = editor.Caret.Offset;
processSecondPart = false;
index++; // if the file could be opened, search in it.
continue; if (buffer != null) {
document = new TextDocument(DocumentUtilitites.GetTextSource(buffer));
int length;
// if (target == SearchTarget.CurrentSelection) selection will be not null
// hence use the selection as search region.
if (selection != null) {
searchOffset = Math.Max(selection.Offset, searchOffset);
length = selection.EndOffset - searchOffset;
} else {
length = buffer.TextLength - searchOffset;
} }
var document = new TextDocument(DocumentUtilitites.GetTextSource(buffer)); // try to find a result
ICSharpCode.AvalonEdit.Search.ISearchResult result; if (length > 0 && (searchOffset + length) <= buffer.TextLength)
var editor = GetActiveTextEditor(); result = Find(buffer, file, document, searchOffset, length);
int searchOffset = 0;
if (!processSecondPart && file.Equals(searchStart.FileName)) // we already passed the end of the file before and have found the first match again, so just stop.
searchOffset = searchStart.Offset; if (reachedEnd) {
if (editor != null && files.Equals(editor.FileName)) if (file.Equals(searchStart.FileName) && result != null && document.GetOffset(result.StartLocation.ToTextLocation()) >= searchStart.Offset)
searchOffset = editor.Caret.Offset; return null;
} else
reachedEnd = file.Equals(searchStart.FileName) && result == null;
}
// try the other files until we find something, or have processed all of them
while ((buffer == null || result == null) && i < files.Length) {
index = (index + 1) % files.Length;
do { file = files[index];
int length; buffer = finder.Create(file);
if (selection != null && file.Equals(searchStart.FileName)) {
searchOffset = Math.Max(selection.Offset, searchOffset);
length = selection.EndOffset - searchOffset;
} else {
length = buffer.TextLength - searchOffset;
}
if (length > 0 && (searchOffset + length) <= buffer.TextLength)
result = strategy.FindNext(DocumentUtilitites.GetTextSource(buffer), searchOffset, length);
else
result = null;
if (result != null)
searchOffset = result.EndOffset;
if (processSecondPart && file.Equals(searchStart.FileName) && searchOffset >= searchStart.Offset) {
yield break;
}
if (result != null) {
var start = document.GetLocation(result.Offset).ToLocation();
var end = document.GetLocation(result.EndOffset).ToLocation();
yield return new SearchResultMatch(file, start, end, null);
}
} while (result != null);
index++; if (buffer == null)
if (!processSecondPart && index > endIndex) { continue;
processSecondPart = true;
index = 0; document = new TextDocument(DocumentUtilitites.GetTextSource(buffer));
endIndex = startIndex; searchOffset = 0;
} int length = buffer.TextLength - searchOffset;
// try to find a result
result = Find(buffer, file, document, searchOffset, length);
// if we have not found anything and are at the start of the file, we started with, just stop
if (result != null && reachedEnd && file.Equals(searchStart.FileName)
&& document.GetOffset(result.StartLocation.ToTextLocation()) >= searchStart.Offset)
return null;
i++;
} }
return result;
}
SearchResultMatch Find(ITextBuffer buffer, FileName file, TextDocument document, int searchOffset, int length)
{
var result = strategy.FindNext(DocumentUtilitites.GetTextSource(buffer), searchOffset, length);
if (result != null) {
var start = document.GetLocation(result.Offset).ToLocation();
var end = document.GetLocation(result.EndOffset).ToLocation();
return new SearchResultMatch(file, start, end, null);
}
return null;
}
int GetCurrentFileIndex()
{
var editor = GetActiveTextEditor();
if (editor == null)
return 0;
return files.FindIndex(file => editor.FileName.Equals(file));
} }
public static SearchRegion CreateSearchRegion(FileName[] files, string pattern, bool ignoreCase, bool matchWholeWords, SearchMode mode, SearchTarget target, string baseDirectory, string filter, bool searchSubdirs) public static SearchRegion CreateSearchRegion(FileName[] files, string pattern, bool ignoreCase, bool matchWholeWords, SearchMode mode, SearchTarget target, string baseDirectory, string filter, bool searchSubdirs)
@ -404,7 +425,7 @@ namespace SearchAndReplace
void IObserver<SearchResultMatch>.OnNext(SearchResultMatch value) void IObserver<SearchResultMatch>.OnNext(SearchResultMatch value)
{ {
Interlocked.Increment(ref count); Interlocked.Increment(ref count);
WorkbenchSingleton.SafeThreadCall((Action)delegate { MarkResult(value, false); }); WorkbenchSingleton.SafeThreadAsyncCall((Action)delegate { MarkResult(value, false); });
} }
void IObserver<SearchResultMatch>.OnError(Exception error) void IObserver<SearchResultMatch>.OnError(Exception error)

Loading…
Cancel
Save