From 1570138319762e50c035910003f4f208bef2350a Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 22 Oct 2011 23:31:58 +0200 Subject: [PATCH] fixing some bugs and playing around with cancellation --- .../SearchAndReplace/Project/Engine/Enums.cs | 6 ++ .../Project/Engine/SearchManager.cs | 56 +++++------ .../Project/Gui/DefaultSearchResult.cs | 16 +++- .../Project/Gui/SearchAndReplacePanel.cs | 95 +++++-------------- .../Project/SearchAndReplace.csproj | 5 + .../Search/RegexSearchStrategy.cs | 3 +- .../Src/Editor/Search/ISearchResultFactory.cs | 1 + .../Src/Editor/Search/SearchResultsPad.cs | 2 + .../Src/Services/FileUtility/FileUtility.cs | 2 +- 9 files changed, 78 insertions(+), 108 deletions(-) diff --git a/src/AddIns/Misc/SearchAndReplace/Project/Engine/Enums.cs b/src/AddIns/Misc/SearchAndReplace/Project/Engine/Enums.cs index 2f4ce555f8..cbf50eded7 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/Engine/Enums.cs +++ b/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) using System; +using System.ComponentModel; namespace SearchAndReplace { public enum SearchTarget { + [Description("${res:Dialog.NewProject.SearchReplace.LookIn.CurrentDocument}")] CurrentDocument, + [Description("${res:Dialog.NewProject.SearchReplace.LookIn.CurrentSelection}")] CurrentSelection, + [Description("${res:Dialog.NewProject.SearchReplace.LookIn.AllOpenDocuments}")] AllOpenFiles, + [Description("${res:Dialog.NewProject.SearchReplace.LookIn.WholeProject}")] WholeProject, + [Description("${res:Dialog.NewProject.SearchReplace.LookIn.WholeSolution}")] WholeSolution, Directory } diff --git a/src/AddIns/Misc/SearchAndReplace/Project/Engine/SearchManager.cs b/src/AddIns/Misc/SearchAndReplace/Project/Engine/SearchManager.cs index bb59298fae..ce0169d249 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/Engine/SearchManager.cs +++ b/src/AddIns/Misc/SearchAndReplace/Project/Engine/SearchManager.cs @@ -7,8 +7,8 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; - using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Search; using ICSharpCode.Core; @@ -74,38 +74,14 @@ namespace SearchAndReplace SearchResultsPad.Instance.BringToFront(); } - public static IObservable FindAll(string pattern, bool ignoreCase, bool matchWholeWords, SearchMode mode, - SearchTarget target, string baseDirectory = null, string filter = "*.*", bool searchSubdirs = false, bool useParallel = true, IProgressMonitor progressMonitor = null) + public static IObservable FindAll(IProgressMonitor progressMonitor, string pattern, bool ignoreCase, bool matchWholeWords, SearchMode mode, + SearchTarget target, string baseDirectory = null, string filter = "*.*", bool searchSubdirs = false, ISegment selection = null, bool useParallel = true) { 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); ParseableFileContentFinder fileFinder = new ParseableFileContentFinder(); IEnumerable fileList = GenerateFileList(target, baseDirectory, filter, searchSubdirs); - return new SearchRun(strategy, fileFinder, fileList, monitor); - } - - 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"); - } + return new SearchRun(strategy, fileFinder, fileList, progressMonitor) { UseParallel = useParallel, Target = target, Selection = selection }; } class SearchRun : IObservable, IDisposable @@ -116,15 +92,21 @@ namespace SearchAndReplace IEnumerable fileList; IProgressMonitor monitor; int count; + CancellationTokenSource cts; public bool UseParallel { get; set; } + public SearchTarget Target { get; set; } + + public ISegment Selection { get; set; } + public SearchRun(ISearchStrategy strategy, ParseableFileContentFinder fileFinder, IEnumerable fileList, IProgressMonitor monitor) { this.strategy = strategy; this.fileFinder = fileFinder; this.fileList = fileList; this.monitor = monitor; + this.cts = new CancellationTokenSource(); } public IDisposable Subscribe(IObserver observer) @@ -135,12 +117,18 @@ namespace SearchAndReplace delegate { var list = fileList.ToList(); 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)); }); task.ContinueWith(t => { if (t.Exception != null) observer.OnError(t.Exception); else observer.OnCompleted(); this.Dispose(); }); task.Start(); } 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); } } @@ -149,6 +137,7 @@ namespace SearchAndReplace public void Dispose() { + cts.Cancel(); monitor.Dispose(); } @@ -163,8 +152,15 @@ namespace SearchAndReplace var source = DocumentUtilitites.GetTextSource(buffer); TextDocument document = 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(); + cts.Token.ThrowIfCancellationRequested(); if (document == null) { document = new TextDocument(source); var highlighting = HighlightingManager.Instance.GetDefinitionByExtension(Path.GetExtension(fileName)); diff --git a/src/AddIns/Misc/SearchAndReplace/Project/Gui/DefaultSearchResult.cs b/src/AddIns/Misc/SearchAndReplace/Project/Gui/DefaultSearchResult.cs index 84ace10bea..d94aeab487 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/Gui/DefaultSearchResult.cs +++ b/src/AddIns/Misc/SearchAndReplace/Project/Gui/DefaultSearchResult.cs @@ -5,6 +5,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Threading; @@ -13,6 +14,7 @@ using ICSharpCode.Core.Presentation; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Editor.Search; using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop.Widgets.Resources; namespace SearchAndReplace { @@ -192,15 +194,19 @@ namespace SearchAndReplace collapseAll.Click += delegate { ExpandCollapseAll(false); }; toolbarItems.Add(collapseAll); - stopButton = new Button { Content = "Stop" }; - stopButton.Click += delegate { - stopButton.Visibility = Visibility.Collapsed; - if (Registration != null) Registration.Dispose(); - }; + stopButton = new Button { Content = new Image { Height = 16, Source = PresentationResourceService.GetBitmapSource("Icons.16x16.Debug.StopProcess") } }; + stopButton.Click += StopButtonClick; toolbarItems.Add(stopButton); } + stopButton.Visibility = Visibility.Visible; return toolbarItems; } + + void StopButtonClick(object sender, RoutedEventArgs e) + { + stopButton.Visibility = Visibility.Hidden; + if (Registration != null) Registration.Dispose(); + } static void ExpandCollapseAll(bool newIsExpanded) { diff --git a/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchAndReplacePanel.cs b/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchAndReplacePanel.cs index 815d278860..f82002ab3e 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchAndReplacePanel.cs +++ b/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) // 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.SharpDevelop.Editor; using System; @@ -14,32 +19,11 @@ using ICSharpCode.SharpDevelop.Gui.XmlForms; 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 { - SearchAndReplaceMode searchAndReplaceMode; - StoredSelection selection; + SearchAndReplaceMode searchAndReplaceMode; ITextEditor textEditor; - bool ignoreSelectionChanges; - bool findFirst; + ISegment selection; public SearchAndReplaceMode SearchAndReplaceMode { get { @@ -119,24 +103,30 @@ namespace SearchAndReplace void FindAllButtonClicked(object sender, EventArgs e) { 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); } void BookmarkAllButtonClicked(object sender, EventArgs e) { 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); } void ReplaceAllButtonClicked(object sender, EventArgs e) { WritebackOptions(); - using (AsynchronousWaitDialog monitor = AsynchronousWaitDialog.ShowWaitDialog("Search", true)) { - var results = SearchManager.FindAll(SearchOptions.FindPattern, !SearchOptions.MatchCase, SearchOptions.MatchWholeWord, SearchOptions.SearchStrategyType, SearchOptions.SearchTarget, SearchOptions.LookIn, SearchOptions.LookInFiletypes, SearchOptions.IncludeSubdirectories, false, monitor); - SearchManager.ReplaceAll(results, SearchOptions.ReplacePattern, monitor.CancellationToken); - } + AsynchronousWaitDialog.RunInCancellableWaitDialog( + "Searching ...", "replaceall", + 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) @@ -195,15 +185,7 @@ namespace SearchAndReplace } Get("lookIn").Text = SearchOptions.LookIn; - string[] lookInTexts = { - // 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) { + foreach (string lookInText in typeof(SearchTarget).GetFields().SelectMany(f => f.GetCustomAttributes(false).OfType()).Select(da => da.Description)) { Get("lookIn").Items.Add(StringParser.Parse(lookInText)); } Get("lookIn").Items.Add(SearchOptions.LookIn); @@ -280,11 +262,11 @@ namespace SearchAndReplace /// /// Returns the first ISelection object from the currently active text editor /// - static StoredSelection GetCurrentTextSelection() + static ISegment GetCurrentTextSelection() { ITextEditor textArea = SearchManager.GetActiveTextEditor(); if (textArea != null) { - return new StoredSelection(textArea.SelectionStart, textArea.SelectionLength); + return new TextSegment { StartOffset = textArea.SelectionStart, Length = textArea.SelectionLength }; } return null; } @@ -329,16 +311,12 @@ namespace SearchAndReplace /// changed. void TextSelectionChanged(object source, EventArgs e) { - if (!ignoreSelectionChanges) { - LoggingService.Debug("TextSelectionChanged."); - selection = GetCurrentTextSelection(); - findFirst = true; - } + LoggingService.Debug("TextSelectionChanged."); + selection = GetCurrentTextSelection(); } void InitSelectionSearch() { - findFirst = true; selection = GetCurrentTextSelection(); AddSelectionChangedHandler(SearchManager.GetActiveTextEditor()); WorkbenchSingleton.Workbench.ActiveViewContentChanged += WorkbenchActiveViewContentChanged; @@ -350,31 +328,6 @@ namespace SearchAndReplace 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; - } - } - /// /// Enables the various find, bookmark and replace buttons /// depending on whether any find string has been entered. The buttons diff --git a/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj b/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj index 14c5ff1174..7351fc863e 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj +++ b/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj @@ -126,5 +126,10 @@ + + {8035765F-D51F-4A0C-A746-2FD100E19419} + ICSharpCode.SharpDevelop.Widgets + False + \ No newline at end of file diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/RegexSearchStrategy.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/RegexSearchStrategy.cs index 0610d33c54..89d4d8a6fe 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/RegexSearchStrategy.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/RegexSearchStrategy.cs @@ -22,8 +22,9 @@ namespace ICSharpCode.AvalonEdit.Search public IEnumerable FindAll(ITextSource document, int offset, int length) { + int endOffset = offset + length; 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 }; } } diff --git a/src/Main/Base/Project/Src/Editor/Search/ISearchResultFactory.cs b/src/Main/Base/Project/Src/Editor/Search/ISearchResultFactory.cs index 9091780ab2..57c659fd76 100644 --- a/src/Main/Base/Project/Src/Editor/Search/ISearchResultFactory.cs +++ b/src/Main/Base/Project/Src/Editor/Search/ISearchResultFactory.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Threading; namespace ICSharpCode.SharpDevelop.Editor.Search { diff --git a/src/Main/Base/Project/Src/Editor/Search/SearchResultsPad.cs b/src/Main/Base/Project/Src/Editor/Search/SearchResultsPad.cs index 3c496e9784..efd7e85df7 100644 --- a/src/Main/Base/Project/Src/Editor/Search/SearchResultsPad.cs +++ b/src/Main/Base/Project/Src/Editor/Search/SearchResultsPad.cs @@ -4,9 +4,11 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Media; + using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.Core; diff --git a/src/Main/Core/Project/Src/Services/FileUtility/FileUtility.cs b/src/Main/Core/Project/Src/Services/FileUtility/FileUtility.cs index d650c304a5..7004ece1bb 100644 --- a/src/Main/Core/Project/Src/Services/FileUtility/FileUtility.cs +++ b/src/Main/Core/Project/Src/Services/FileUtility/FileUtility.cs @@ -361,7 +361,7 @@ namespace ICSharpCode.Core dir = dir.Flatten( d => { 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 Directory.EnumerateDirectories(d); } catch (UnauthorizedAccessException) {