Browse Source

fixing some bugs and playing around with cancellation

pull/23/head
Siegfried Pammer 14 years ago
parent
commit
1570138319
  1. 6
      src/AddIns/Misc/SearchAndReplace/Project/Engine/Enums.cs
  2. 56
      src/AddIns/Misc/SearchAndReplace/Project/Engine/SearchManager.cs
  3. 16
      src/AddIns/Misc/SearchAndReplace/Project/Gui/DefaultSearchResult.cs
  4. 95
      src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchAndReplacePanel.cs
  5. 5
      src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj
  6. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/RegexSearchStrategy.cs
  7. 1
      src/Main/Base/Project/Src/Editor/Search/ISearchResultFactory.cs
  8. 2
      src/Main/Base/Project/Src/Editor/Search/SearchResultsPad.cs
  9. 2
      src/Main/Core/Project/Src/Services/FileUtility/FileUtility.cs

6
src/AddIns/Misc/SearchAndReplace/Project/Engine/Enums.cs

@ -2,15 +2,21 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using System.ComponentModel;
namespace SearchAndReplace namespace SearchAndReplace
{ {
public enum SearchTarget public enum SearchTarget
{ {
[Description("${res:Dialog.NewProject.SearchReplace.LookIn.CurrentDocument}")]
CurrentDocument, CurrentDocument,
[Description("${res:Dialog.NewProject.SearchReplace.LookIn.CurrentSelection}")]
CurrentSelection, CurrentSelection,
[Description("${res:Dialog.NewProject.SearchReplace.LookIn.AllOpenDocuments}")]
AllOpenFiles, AllOpenFiles,
[Description("${res:Dialog.NewProject.SearchReplace.LookIn.WholeProject}")]
WholeProject, WholeProject,
[Description("${res:Dialog.NewProject.SearchReplace.LookIn.WholeSolution}")]
WholeSolution, WholeSolution,
Directory Directory
} }

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

@ -7,8 +7,8 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Search; using ICSharpCode.AvalonEdit.Search;
using ICSharpCode.Core; using ICSharpCode.Core;
@ -74,38 +74,14 @@ namespace SearchAndReplace
SearchResultsPad.Instance.BringToFront(); SearchResultsPad.Instance.BringToFront();
} }
public static IObservable<SearchResultMatch> FindAll(string pattern, bool ignoreCase, bool matchWholeWords, SearchMode mode, public static IObservable<SearchResultMatch> FindAll(IProgressMonitor progressMonitor, string pattern, bool ignoreCase, bool matchWholeWords, SearchMode mode,
SearchTarget target, string baseDirectory = null, string filter = "*.*", bool searchSubdirs = false, bool useParallel = true, IProgressMonitor progressMonitor = null) SearchTarget target, string baseDirectory = null, string filter = "*.*", bool searchSubdirs = false, ISegment selection = null, bool useParallel = true)
{ {
currentSearchRegion = null; currentSearchRegion = null;
CancellationToken ct = progressMonitor != null ? progressMonitor.CancellationToken : new CancellationTokenSource().Token;
var monitor = progressMonitor ?? WorkbenchSingleton.Workbench.StatusBar.CreateProgressMonitor(ct);
monitor.TaskName = "Find all occurrences of '" + pattern + "' in " + GetTargetDescription(target, baseDirectory);
monitor.Status = OperationStatus.Normal;
var strategy = SearchStrategyFactory.Create(pattern, ignoreCase, matchWholeWords, mode); var strategy = SearchStrategyFactory.Create(pattern, ignoreCase, matchWholeWords, mode);
ParseableFileContentFinder fileFinder = new ParseableFileContentFinder(); ParseableFileContentFinder fileFinder = new ParseableFileContentFinder();
IEnumerable<FileName> fileList = GenerateFileList(target, baseDirectory, filter, searchSubdirs); IEnumerable<FileName> fileList = GenerateFileList(target, baseDirectory, filter, searchSubdirs);
return new SearchRun(strategy, fileFinder, fileList, monitor); return new SearchRun(strategy, fileFinder, fileList, progressMonitor) { UseParallel = useParallel, Target = target, Selection = selection };
}
static string GetTargetDescription(SearchTarget target, string baseDirectory = null)
{
switch (target) {
case SearchTarget.CurrentDocument:
return "the current document";
case SearchTarget.CurrentSelection:
return "the current selection";
case SearchTarget.AllOpenFiles:
return "all open files";
case SearchTarget.WholeProject:
return "the whole project";
case SearchTarget.WholeSolution:
return "the whole solution";
case SearchTarget.Directory:
return "the directory '" + baseDirectory + "'";
default:
throw new Exception("Invalid value for SearchTarget");
}
} }
class SearchRun : IObservable<SearchResultMatch>, IDisposable class SearchRun : IObservable<SearchResultMatch>, IDisposable
@ -116,15 +92,21 @@ namespace SearchAndReplace
IEnumerable<FileName> fileList; IEnumerable<FileName> fileList;
IProgressMonitor monitor; IProgressMonitor monitor;
int count; int count;
CancellationTokenSource cts;
public bool UseParallel { get; set; } public bool UseParallel { get; set; }
public SearchTarget Target { get; set; }
public ISegment Selection { get; set; }
public SearchRun(ISearchStrategy strategy, ParseableFileContentFinder fileFinder, IEnumerable<FileName> fileList, IProgressMonitor monitor) public SearchRun(ISearchStrategy strategy, ParseableFileContentFinder fileFinder, IEnumerable<FileName> fileList, IProgressMonitor monitor)
{ {
this.strategy = strategy; this.strategy = strategy;
this.fileFinder = fileFinder; this.fileFinder = fileFinder;
this.fileList = fileList; this.fileList = fileList;
this.monitor = monitor; this.monitor = monitor;
this.cts = new CancellationTokenSource();
} }
public IDisposable Subscribe(IObserver<SearchResultMatch> observer) public IDisposable Subscribe(IObserver<SearchResultMatch> observer)
@ -135,12 +117,18 @@ namespace SearchAndReplace
delegate { delegate {
var list = fileList.ToList(); var list = fileList.ToList();
this.count = list.Count; this.count = list.Count;
monitor.CancellationToken.ThrowIfCancellationRequested();
cts.Token.ThrowIfCancellationRequested();
Parallel.ForEach(list, new ParallelOptions { CancellationToken = monitor.CancellationToken, MaxDegreeOfParallelism = Environment.ProcessorCount }, fileName => SearchFile(fileName, strategy, monitor.CancellationToken)); Parallel.ForEach(list, 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();
} else { } else {
foreach (var file in fileList) { var list = fileList.ToList();
this.count = list.Count;
monitor.CancellationToken.ThrowIfCancellationRequested();
cts.Token.ThrowIfCancellationRequested();
foreach (var file in list) {
SearchFile(file, strategy, monitor.CancellationToken); SearchFile(file, strategy, monitor.CancellationToken);
} }
} }
@ -149,6 +137,7 @@ namespace SearchAndReplace
public void Dispose() public void Dispose()
{ {
cts.Cancel();
monitor.Dispose(); monitor.Dispose();
} }
@ -163,8 +152,15 @@ namespace SearchAndReplace
var source = DocumentUtilitites.GetTextSource(buffer); var source = DocumentUtilitites.GetTextSource(buffer);
TextDocument document = null; TextDocument document = null;
DocumentHighlighter highlighter = null; DocumentHighlighter highlighter = null;
foreach(var result in strategy.FindAll(source, 0, source.TextLength)) { int offset = 0;
int length = source.TextLength;
if (Target == SearchTarget.CurrentSelection && Selection != null) {
offset = Selection.Offset;
length = Selection.Length;
}
foreach(var result in strategy.FindAll(source, offset, length)) {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
cts.Token.ThrowIfCancellationRequested();
if (document == null) { if (document == null) {
document = new TextDocument(source); document = new TextDocument(source);
var highlighting = HighlightingManager.Instance.GetDefinitionByExtension(Path.GetExtension(fileName)); var highlighting = HighlightingManager.Instance.GetDefinitionByExtension(Path.GetExtension(fileName));

16
src/AddIns/Misc/SearchAndReplace/Project/Gui/DefaultSearchResult.cs

@ -5,6 +5,7 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Threading; using System.Windows.Threading;
@ -13,6 +14,7 @@ using ICSharpCode.Core.Presentation;
using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor.Search; using ICSharpCode.SharpDevelop.Editor.Search;
using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Widgets.Resources;
namespace SearchAndReplace namespace SearchAndReplace
{ {
@ -192,15 +194,19 @@ namespace SearchAndReplace
collapseAll.Click += delegate { ExpandCollapseAll(false); }; collapseAll.Click += delegate { ExpandCollapseAll(false); };
toolbarItems.Add(collapseAll); toolbarItems.Add(collapseAll);
stopButton = new Button { Content = "Stop" }; stopButton = new Button { Content = new Image { Height = 16, Source = PresentationResourceService.GetBitmapSource("Icons.16x16.Debug.StopProcess") } };
stopButton.Click += delegate { stopButton.Click += StopButtonClick;
stopButton.Visibility = Visibility.Collapsed;
if (Registration != null) Registration.Dispose();
};
toolbarItems.Add(stopButton); toolbarItems.Add(stopButton);
} }
stopButton.Visibility = Visibility.Visible;
return toolbarItems; return toolbarItems;
} }
void StopButtonClick(object sender, RoutedEventArgs e)
{
stopButton.Visibility = Visibility.Hidden;
if (Registration != null) Registration.Dispose();
}
static void ExpandCollapseAll(bool newIsExpanded) static void ExpandCollapseAll(bool newIsExpanded)
{ {

95
src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchAndReplacePanel.cs

@ -1,6 +1,11 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System.ComponentModel;
using System.Linq;
using System.Threading;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Search; using ICSharpCode.AvalonEdit.Search;
using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor;
using System; using System;
@ -14,32 +19,11 @@ using ICSharpCode.SharpDevelop.Gui.XmlForms;
namespace SearchAndReplace namespace SearchAndReplace
{ {
class StoredSelection
{
public readonly int Offset, Length;
public int EndOffset {
get { return Offset + Length; }
}
public bool IsTextSelected {
get { return Length > 0; }
}
public StoredSelection(int offset, int length)
{
this.Offset = offset;
this.Length = length;
}
}
public class SearchAndReplacePanel : BaseSharpDevelopUserControl public class SearchAndReplacePanel : BaseSharpDevelopUserControl
{ {
SearchAndReplaceMode searchAndReplaceMode; SearchAndReplaceMode searchAndReplaceMode;
StoredSelection selection;
ITextEditor textEditor; ITextEditor textEditor;
bool ignoreSelectionChanges; ISegment selection;
bool findFirst;
public SearchAndReplaceMode SearchAndReplaceMode { public SearchAndReplaceMode SearchAndReplaceMode {
get { get {
@ -119,24 +103,30 @@ namespace SearchAndReplace
void FindAllButtonClicked(object sender, EventArgs e) void FindAllButtonClicked(object sender, EventArgs e)
{ {
WritebackOptions(); WritebackOptions();
var results = SearchManager.FindAll(SearchOptions.FindPattern, !SearchOptions.MatchCase, SearchOptions.MatchWholeWord, SearchOptions.SearchStrategyType, SearchOptions.SearchTarget, SearchOptions.LookIn, SearchOptions.LookInFiletypes, SearchOptions.IncludeSubdirectories); var monitor = WorkbenchSingleton.StatusBar.CreateProgressMonitor();
monitor.TaskName = "Searching ...";
var results = SearchManager.FindAll(monitor, SearchOptions.FindPattern, !SearchOptions.MatchCase, SearchOptions.MatchWholeWord, SearchOptions.SearchStrategyType, SearchOptions.SearchTarget, SearchOptions.LookIn, SearchOptions.LookInFiletypes, SearchOptions.IncludeSubdirectories, selection);
SearchManager.ShowSearchResults(SearchOptions.FindPattern, results); SearchManager.ShowSearchResults(SearchOptions.FindPattern, results);
} }
void BookmarkAllButtonClicked(object sender, EventArgs e) void BookmarkAllButtonClicked(object sender, EventArgs e)
{ {
WritebackOptions(); WritebackOptions();
var results = SearchManager.FindAll(SearchOptions.FindPattern, !SearchOptions.MatchCase, SearchOptions.MatchWholeWord, SearchOptions.SearchStrategyType, SearchOptions.SearchTarget, SearchOptions.LookIn, SearchOptions.LookInFiletypes, SearchOptions.IncludeSubdirectories); var monitor = WorkbenchSingleton.StatusBar.CreateProgressMonitor();
monitor.TaskName = "Searching ...";
var results = SearchManager.FindAll(monitor, SearchOptions.FindPattern, !SearchOptions.MatchCase, SearchOptions.MatchWholeWord, SearchOptions.SearchStrategyType, SearchOptions.SearchTarget, SearchOptions.LookIn, SearchOptions.LookInFiletypes, SearchOptions.IncludeSubdirectories);
SearchManager.MarkAll(results); SearchManager.MarkAll(results);
} }
void ReplaceAllButtonClicked(object sender, EventArgs e) void ReplaceAllButtonClicked(object sender, EventArgs e)
{ {
WritebackOptions(); WritebackOptions();
using (AsynchronousWaitDialog monitor = AsynchronousWaitDialog.ShowWaitDialog("Search", true)) { AsynchronousWaitDialog.RunInCancellableWaitDialog(
var results = SearchManager.FindAll(SearchOptions.FindPattern, !SearchOptions.MatchCase, SearchOptions.MatchWholeWord, SearchOptions.SearchStrategyType, SearchOptions.SearchTarget, SearchOptions.LookIn, SearchOptions.LookInFiletypes, SearchOptions.IncludeSubdirectories, false, monitor); "Searching ...", "replaceall",
SearchManager.ReplaceAll(results, SearchOptions.ReplacePattern, monitor.CancellationToken); monitor => {
} var results = SearchManager.FindAll(monitor, SearchOptions.FindPattern, !SearchOptions.MatchCase, SearchOptions.MatchWholeWord, SearchOptions.SearchStrategyType, SearchOptions.SearchTarget, SearchOptions.LookIn, SearchOptions.LookInFiletypes, SearchOptions.IncludeSubdirectories, selection, false);
SearchManager.ReplaceAll(results, SearchOptions.ReplacePattern, monitor.CancellationToken);
});
} }
void ReplaceButtonClicked(object sender, EventArgs e) void ReplaceButtonClicked(object sender, EventArgs e)
@ -195,15 +185,7 @@ namespace SearchAndReplace
} }
Get<ComboBox>("lookIn").Text = SearchOptions.LookIn; Get<ComboBox>("lookIn").Text = SearchOptions.LookIn;
string[] lookInTexts = { foreach (string lookInText in typeof(SearchTarget).GetFields().SelectMany(f => f.GetCustomAttributes(false).OfType<DescriptionAttribute>()).Select(da => da.Description)) {
// must be in the same order as the DocumentIteratorType enum
"${res:Dialog.NewProject.SearchReplace.LookIn.CurrentDocument}",
"${res:Dialog.NewProject.SearchReplace.LookIn.CurrentSelection}",
"${res:Dialog.NewProject.SearchReplace.LookIn.AllOpenDocuments}",
"${res:Dialog.NewProject.SearchReplace.LookIn.WholeProject}",
"${res:Dialog.NewProject.SearchReplace.LookIn.WholeSolution}"
};
foreach (string lookInText in lookInTexts) {
Get<ComboBox>("lookIn").Items.Add(StringParser.Parse(lookInText)); Get<ComboBox>("lookIn").Items.Add(StringParser.Parse(lookInText));
} }
Get<ComboBox>("lookIn").Items.Add(SearchOptions.LookIn); Get<ComboBox>("lookIn").Items.Add(SearchOptions.LookIn);
@ -280,11 +262,11 @@ namespace SearchAndReplace
/// <summary> /// <summary>
/// Returns the first ISelection object from the currently active text editor /// Returns the first ISelection object from the currently active text editor
/// </summary> /// </summary>
static StoredSelection GetCurrentTextSelection() static ISegment GetCurrentTextSelection()
{ {
ITextEditor textArea = SearchManager.GetActiveTextEditor(); ITextEditor textArea = SearchManager.GetActiveTextEditor();
if (textArea != null) { if (textArea != null) {
return new StoredSelection(textArea.SelectionStart, textArea.SelectionLength); return new TextSegment { StartOffset = textArea.SelectionStart, Length = textArea.SelectionLength };
} }
return null; return null;
} }
@ -329,16 +311,12 @@ namespace SearchAndReplace
/// changed.</remarks> /// changed.</remarks>
void TextSelectionChanged(object source, EventArgs e) void TextSelectionChanged(object source, EventArgs e)
{ {
if (!ignoreSelectionChanges) { LoggingService.Debug("TextSelectionChanged.");
LoggingService.Debug("TextSelectionChanged."); selection = GetCurrentTextSelection();
selection = GetCurrentTextSelection();
findFirst = true;
}
} }
void InitSelectionSearch() void InitSelectionSearch()
{ {
findFirst = true;
selection = GetCurrentTextSelection(); selection = GetCurrentTextSelection();
AddSelectionChangedHandler(SearchManager.GetActiveTextEditor()); AddSelectionChangedHandler(SearchManager.GetActiveTextEditor());
WorkbenchSingleton.Workbench.ActiveViewContentChanged += WorkbenchActiveViewContentChanged; WorkbenchSingleton.Workbench.ActiveViewContentChanged += WorkbenchActiveViewContentChanged;
@ -350,31 +328,6 @@ namespace SearchAndReplace
RemoveActiveWindowChangedHandler(); RemoveActiveWindowChangedHandler();
} }
void ReplaceInSelection()
{
int startOffset = Math.Min(selection.Offset, selection.EndOffset);
int endOffset = Math.Max(selection.Offset, selection.EndOffset);
if (findFirst) {
textEditor.Caret.Offset = startOffset;
}
try {
ignoreSelectionChanges = true;
if (findFirst) {
findFirst = false;
// SearchReplaceManager.ReplaceFirstInSelection(startOffset, endOffset - startOffset, null);
} else {
// findFirst = !SearchReplaceManager.ReplaceNextInSelection(null);
if (findFirst) {
textEditor.Select(startOffset, endOffset - startOffset);
}
}
} finally {
ignoreSelectionChanges = false;
}
}
/// <summary> /// <summary>
/// Enables the various find, bookmark and replace buttons /// Enables the various find, bookmark and replace buttons
/// depending on whether any find string has been entered. The buttons /// depending on whether any find string has been entered. The buttons

5
src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj

@ -126,5 +126,10 @@
</ProjectReference> </ProjectReference>
<Page Include="Gui\ResultsTreeView.xaml"> <Page Include="Gui\ResultsTreeView.xaml">
</Page> </Page>
<ProjectReference Include="..\..\..\..\Main\ICSharpCode.SharpDevelop.Widgets\Project\ICSharpCode.SharpDevelop.Widgets.csproj">
<Project>{8035765F-D51F-4A0C-A746-2FD100E19419}</Project>
<Name>ICSharpCode.SharpDevelop.Widgets</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup> </ItemGroup>
</Project> </Project>

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/RegexSearchStrategy.cs

@ -22,8 +22,9 @@ namespace ICSharpCode.AvalonEdit.Search
public IEnumerable<ISearchResult> FindAll(ITextSource document, int offset, int length) public IEnumerable<ISearchResult> FindAll(ITextSource document, int offset, int length)
{ {
int endOffset = offset + length;
foreach (Match result in searchPattern.Matches(document.Text)) { foreach (Match result in searchPattern.Matches(document.Text)) {
if (offset <= result.Index && (offset + length) >= (result.Index + result.Length)) if (offset <= result.Index && endOffset >= (result.Length + result.Index))
yield return new SearchResult { StartOffset = result.Index, Length = result.Length, Data = result }; yield return new SearchResult { StartOffset = result.Index, Length = result.Length, Data = result };
} }
} }

1
src/Main/Base/Project/Src/Editor/Search/ISearchResultFactory.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
namespace ICSharpCode.SharpDevelop.Editor.Search namespace ICSharpCode.SharpDevelop.Editor.Search
{ {

2
src/Main/Base/Project/Src/Editor/Search/SearchResultsPad.cs

@ -4,9 +4,11 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Core; using ICSharpCode.Core;

2
src/Main/Core/Project/Src/Services/FileUtility/FileUtility.cs

@ -361,7 +361,7 @@ namespace ICSharpCode.Core
dir = dir.Flatten( dir = dir.Flatten(
d => { d => {
try { try {
if (ignoreHidden && (File.GetAttributes(d) & FileAttributes.Hidden) == FileAttributes.Hidden) if (Directory.GetDirectoryRoot(d) != d && ignoreHidden && (File.GetAttributes(d) & FileAttributes.Hidden) == FileAttributes.Hidden)
return empty; return empty;
return Directory.EnumerateDirectories(d); return Directory.EnumerateDirectories(d);
} catch (UnauthorizedAccessException) { } catch (UnauthorizedAccessException) {

Loading…
Cancel
Save