|
|
@ -86,7 +86,6 @@ namespace SearchAndReplace |
|
|
|
|
|
|
|
|
|
|
|
class SearchRun : IObservable<SearchedFile>, IDisposable |
|
|
|
class SearchRun : IObservable<SearchedFile>, IDisposable |
|
|
|
{ |
|
|
|
{ |
|
|
|
IObserver<SearchedFile> observer; |
|
|
|
|
|
|
|
ISearchStrategy strategy; |
|
|
|
ISearchStrategy strategy; |
|
|
|
ParseableFileContentFinder fileFinder; |
|
|
|
ParseableFileContentFinder fileFinder; |
|
|
|
IEnumerable<FileName> fileList; |
|
|
|
IEnumerable<FileName> fileList; |
|
|
@ -110,15 +109,23 @@ namespace SearchAndReplace |
|
|
|
|
|
|
|
|
|
|
|
public IDisposable Subscribe(IObserver<SearchedFile> observer) |
|
|
|
public IDisposable Subscribe(IObserver<SearchedFile> observer) |
|
|
|
{ |
|
|
|
{ |
|
|
|
this.observer = observer; |
|
|
|
|
|
|
|
if (UseParallel) { |
|
|
|
if (UseParallel) { |
|
|
|
|
|
|
|
LoggingService.Debug("Parallel FindAll starting"); |
|
|
|
var task = new System.Threading.Tasks.Task( |
|
|
|
var task = new System.Threading.Tasks.Task( |
|
|
|
delegate { |
|
|
|
delegate { |
|
|
|
var list = fileList.ToList(); |
|
|
|
var list = fileList.ToList(); |
|
|
|
ThrowIfCancellationRequested(); |
|
|
|
ThrowIfCancellationRequested(); |
|
|
|
SearchParallel(list, observer, fileName => SearchFile(fileName, strategy)); |
|
|
|
SearchParallel(list, observer); |
|
|
|
|
|
|
|
}, TaskCreationOptions.LongRunning); |
|
|
|
|
|
|
|
task.ContinueWith( |
|
|
|
|
|
|
|
t => { |
|
|
|
|
|
|
|
LoggingService.Debug("Parallel FindAll finished " + (t.IsFaulted ? "with error" : "successfully")); |
|
|
|
|
|
|
|
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(); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
var list = fileList.ToList(); |
|
|
|
var list = fileList.ToList(); |
|
|
@ -131,7 +138,7 @@ namespace SearchAndReplace |
|
|
|
return this; |
|
|
|
return this; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void SearchParallel(List<FileName> files, IObserver<SearchedFile> observer, Func<FileName, SearchedFile> searchInFile) |
|
|
|
void SearchParallel(List<FileName> files, IObserver<SearchedFile> observer) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int taskCount = 2 * Environment.ProcessorCount; |
|
|
|
int taskCount = 2 * Environment.ProcessorCount; |
|
|
|
Queue<Task<SearchedFile>> queue = new Queue<Task<SearchedFile>>(taskCount); |
|
|
|
Queue<Task<SearchedFile>> queue = new Queue<Task<SearchedFile>>(taskCount); |
|
|
@ -142,7 +149,7 @@ namespace SearchAndReplace |
|
|
|
} |
|
|
|
} |
|
|
|
if (exceptions.Count == 0) { |
|
|
|
if (exceptions.Count == 0) { |
|
|
|
FileName file = files[i]; |
|
|
|
FileName file = files[i]; |
|
|
|
queue.Enqueue(System.Threading.Tasks.Task.Factory.StartNew(() => searchInFile(file))); |
|
|
|
queue.Enqueue(System.Threading.Tasks.Task.Factory.StartNew(() => SearchFile(file))); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
while (queue.Count > 0) { |
|
|
|
while (queue.Count > 0) { |
|
|
@ -161,7 +168,7 @@ namespace SearchAndReplace |
|
|
|
exceptions.AddRange(ex.InnerExceptions); |
|
|
|
exceptions.AddRange(ex.InnerExceptions); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
if (exceptions.Count == 0 && result.Count > 0) |
|
|
|
if (exceptions.Count == 0 && result != null) |
|
|
|
observer.OnNext(result); |
|
|
|
observer.OnNext(result); |
|
|
|
monitor.Progress += 1.0 / files.Count; |
|
|
|
monitor.Progress += 1.0 / files.Count; |
|
|
|
} |
|
|
|
} |
|
|
@ -178,15 +185,16 @@ namespace SearchAndReplace |
|
|
|
monitor.Dispose(); |
|
|
|
monitor.Dispose(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
SearchedFile SearchFile(FileName fileName, ISearchStrategy strategy) |
|
|
|
SearchedFile SearchFile(FileName fileName) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ITextBuffer buffer = fileFinder.Create(fileName); |
|
|
|
ITextBuffer buffer = fileFinder.Create(fileName); |
|
|
|
List<SearchResultMatch> results = new List<SearchResultMatch>(); |
|
|
|
|
|
|
|
if (buffer == null) |
|
|
|
if (buffer == null) |
|
|
|
return SearchedFile.Empty(fileName); |
|
|
|
return null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfCancellationRequested(); |
|
|
|
|
|
|
|
|
|
|
|
if (!MimeTypeDetection.FindMimeType(buffer).StartsWith("text/", StringComparison.Ordinal)) |
|
|
|
if (!MimeTypeDetection.FindMimeType(buffer).StartsWith("text/", StringComparison.Ordinal)) |
|
|
|
return SearchedFile.Empty(fileName); |
|
|
|
return null; |
|
|
|
var source = DocumentUtilitites.GetTextSource(buffer); |
|
|
|
var source = DocumentUtilitites.GetTextSource(buffer); |
|
|
|
TextDocument document = null; |
|
|
|
TextDocument document = null; |
|
|
|
DocumentHighlighter highlighter = null; |
|
|
|
DocumentHighlighter highlighter = null; |
|
|
@ -196,7 +204,8 @@ namespace SearchAndReplace |
|
|
|
offset = Selection.Offset; |
|
|
|
offset = Selection.Offset; |
|
|
|
length = Selection.Length; |
|
|
|
length = Selection.Length; |
|
|
|
} |
|
|
|
} |
|
|
|
foreach(var result in strategy.FindAll(source, offset, length)) { |
|
|
|
List<SearchResultMatch> results = new List<SearchResultMatch>(); |
|
|
|
|
|
|
|
foreach (var result in strategy.FindAll(source, offset, length)) { |
|
|
|
ThrowIfCancellationRequested(); |
|
|
|
ThrowIfCancellationRequested(); |
|
|
|
if (document == null) { |
|
|
|
if (document == null) { |
|
|
|
document = new TextDocument(source); |
|
|
|
document = new TextDocument(source); |
|
|
@ -211,7 +220,10 @@ namespace SearchAndReplace |
|
|
|
var builder = SearchResultsPad.CreateInlineBuilder(start, end, document, highlighter); |
|
|
|
var builder = SearchResultsPad.CreateInlineBuilder(start, end, document, highlighter); |
|
|
|
results.Add(new SearchResultMatch(fileName, start, end, result.Offset, result.Length, builder)); |
|
|
|
results.Add(new SearchResultMatch(fileName, start, end, result.Offset, result.Length, builder)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (results.Count > 0) |
|
|
|
return new SearchedFile(fileName, results); |
|
|
|
return new SearchedFile(fileName, results); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -390,7 +402,11 @@ namespace SearchAndReplace |
|
|
|
int count = 0; |
|
|
|
int count = 0; |
|
|
|
results.ObserveOnUIThread() |
|
|
|
results.ObserveOnUIThread() |
|
|
|
.Subscribe( |
|
|
|
.Subscribe( |
|
|
|
match => { count++; match.ForEach(m => MarkResult(m, false)); }, |
|
|
|
searchedFile => { |
|
|
|
|
|
|
|
count++; |
|
|
|
|
|
|
|
foreach (var m in searchedFile.Matches) |
|
|
|
|
|
|
|
MarkResult(m, false); |
|
|
|
|
|
|
|
}, |
|
|
|
error => MessageService.ShowException(error), |
|
|
|
error => MessageService.ShowException(error), |
|
|
|
() => ShowMarkDoneMessage(count) |
|
|
|
() => ShowMarkDoneMessage(count) |
|
|
|
); |
|
|
|
); |
|
|
@ -401,9 +417,9 @@ namespace SearchAndReplace |
|
|
|
int count = 0; |
|
|
|
int count = 0; |
|
|
|
results.ObserveOnUIThread() |
|
|
|
results.ObserveOnUIThread() |
|
|
|
.Subscribe( |
|
|
|
.Subscribe( |
|
|
|
matches => { |
|
|
|
searchedFile => { |
|
|
|
int difference = 0; |
|
|
|
int difference = 0; |
|
|
|
foreach (var match in matches) { |
|
|
|
foreach (var match in searchedFile.Matches) { |
|
|
|
ITextEditor textArea = OpenTextArea(match.FileName, false); |
|
|
|
ITextEditor textArea = OpenTextArea(match.FileName, false); |
|
|
|
if (textArea != null) { |
|
|
|
if (textArea != null) { |
|
|
|
string newString = match.TransformReplacePattern(replacement); |
|
|
|
string newString = match.TransformReplacePattern(replacement); |
|
|
|