diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
index 19e60f5894..aeeeeafdcc 100644
--- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
+++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
@@ -752,6 +752,7 @@
+
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Commands/SearchMainMenuCommands.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Commands/SearchMainMenuCommands.cs
index 5511552e58..60ebb429d5 100644
--- a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Commands/SearchMainMenuCommands.cs
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Commands/SearchMainMenuCommands.cs
@@ -32,14 +32,10 @@ namespace SearchAndReplace
public static void SetSearchPattern()
{
// Get Highlighted value and set it to FindDialog.searchPattern
- IWorkbenchWindow window = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow;
-
- if (window != null && (window.ViewContent is ITextEditorControlProvider)) {
- TextEditorControl textarea = ((ITextEditorControlProvider)window.ViewContent).TextEditorControl;
- string selectedText = textarea.ActiveTextAreaControl.TextArea.SelectionManager.SelectedText;
- if (selectedText != null && selectedText.Length > 0) {
- SearchOptions.CurrentFindPattern = selectedText;
- }
+ TextEditorControl textArea = SearchReplaceUtilities.GetActiveTextEditor();
+ string selectedText = textArea.ActiveTextAreaControl.TextArea.SelectionManager.SelectedText;
+ if (selectedText != null && selectedText.Length > 0 && !IsMultipleLines(selectedText)) {
+ SearchOptions.CurrentFindPattern = selectedText;
}
}
@@ -48,13 +44,23 @@ namespace SearchAndReplace
SetSearchPattern();
SearchAndReplaceDialog.ShowSingleInstance(SearchAndReplaceMode.Search);
}
+
+ static bool IsMultipleLines(string text)
+ {
+ return text.IndexOf('\n') != -1;
+ }
}
public class FindNext : AbstractMenuCommand
{
public override void Run()
{
- SearchReplaceManager.FindNext();
+ if (SearchOptions.CurrentFindPattern.Length > 0) {
+ SearchReplaceManager.FindNext();
+ } else {
+ Find find = new Find();
+ find.Run();
+ }
}
}
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/Search.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/Search.cs
index 7ad01b5a94..2505d82edb 100644
--- a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/Search.cs
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/Search.cs
@@ -119,5 +119,37 @@ namespace SearchAndReplace
}
return null;
}
+
+ public SearchResult FindNext(int offset, int length)
+ {
+ if (info != null && textIterator != null && documentIterator.CurrentFileName != null) {
+ if (info.FileName != documentIterator.CurrentFileName) { // create new iterator, if document changed
+ info = documentIterator.Current;
+ textIterator = textIteratorBuilder.BuildTextIterator(info);
+ } else { // old document -> initialize iterator position to caret pos
+ textIterator.Position = info.CurrentOffset;
+ }
+
+ SearchResult result = CreateNamedSearchResult(searchStrategy.FindNext(textIterator, offset, length));
+ if (result != null) {
+ info.CurrentOffset = textIterator.Position;
+ return result;
+ }
+ }
+
+ // not found or first start -> move forward to the next document
+ if (documentIterator.MoveForward()) {
+ info = documentIterator.Current;
+ // document is valid for searching -> set iterator & fileName
+ if (info != null && info.TextBuffer != null && info.EndOffset >= 0 && info.EndOffset < info.TextBuffer.Length) {
+ textIterator = textIteratorBuilder.BuildTextIterator(info);
+ } else {
+ textIterator = null;
+ }
+
+ return FindNext(offset, length);
+ }
+ return null;
+ }
}
}
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceInFilesManager.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceInFilesManager.cs
index 6fd4816d9e..02d690e4db 100644
--- a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceInFilesManager.cs
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceInFilesManager.cs
@@ -100,6 +100,37 @@ namespace SearchAndReplace
FinishSearchInFiles(results);
}
+ public static void ReplaceAll(int offset, int length)
+ {
+ if (!InitializeSearchInFiles()) {
+ return;
+ }
+
+ List results = new List();
+
+ while (true) {
+ SearchResult result = find.FindNext(offset, length);
+ if (result == null) {
+ break;
+ }
+
+ string replacement = result.TransformReplacePattern(SearchOptions.ReplacePattern);
+ find.Replace(result.Offset,
+ result.Length,
+ replacement);
+ length -= result.Length - replacement.Length;
+
+ // HACK - Move the cursor to the correct offset - the caret gets
+ // moved before the replace range if we replace a string with a
+ // single character. The ProvidedDocInfo.Replace method assumes that
+ // the current offset is at the end of the found text which it is not.
+ find.CurrentDocumentInformation.CurrentOffset = result.Offset + replacement.Length - 1;
+ results.Add(result);
+ }
+
+ FinishSearchInFiles(results);
+ }
+
public static void FindAll()
{
if (!InitializeSearchInFiles()) {
@@ -116,6 +147,23 @@ namespace SearchAndReplace
}
FinishSearchInFiles(results);
}
+
+ public static void FindAll(int offset, int length)
+ {
+ if (!InitializeSearchInFiles()) {
+ return;
+ }
+
+ List results = new List();
+ while (true) {
+ SearchResult result = find.FindNext(offset, length);
+ if (result == null) {
+ break;
+ }
+ results.Add(result);
+ }
+ FinishSearchInFiles(results);
+ }
static void OnSearchAllFinished(SearchAllFinishedEventArgs e)
{
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceManager.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceManager.cs
index 9a084d4aab..7ebcd66562 100644
--- a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceManager.cs
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceManager.cs
@@ -63,6 +63,42 @@ namespace SearchAndReplace
FindNext();
}
+ static TextSelection textSelection;
+
+ public static void ReplaceFirstInSelection(int offset, int length)
+ {
+ SetSearchOptions();
+ FindFirstInSelection(offset, length);
+ }
+
+ public static bool ReplaceNextInSelection()
+ {
+ if (lastResult != null && WorkbenchSingleton.Workbench.ActiveWorkbenchWindow != null) {
+ ITextEditorControlProvider provider = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ViewContent as ITextEditorControlProvider;
+ if (provider != null) {
+ TextEditorControl textarea = provider.TextEditorControl;
+ SelectionManager selectionManager = textarea.ActiveTextAreaControl.TextArea.SelectionManager;
+
+ if (selectionManager.SelectionCollection.Count == 1
+ && selectionManager.SelectionCollection[0].Offset == lastResult.Offset
+ && selectionManager.SelectionCollection[0].Length == lastResult.Length
+ && lastResult.FileName == textarea.FileName)
+ {
+ string replacePattern = lastResult.TransformReplacePattern(SearchOptions.ReplacePattern);
+
+ textarea.BeginUpdate();
+ selectionManager.ClearSelection();
+ textarea.Document.Replace(lastResult.Offset, lastResult.Length, replacePattern);
+ textarea.ActiveTextAreaControl.Caret.Position = textarea.Document.OffsetToPosition(lastResult.Offset + replacePattern.Length);
+ textarea.EndUpdate();
+
+ textSelection.Length -= lastResult.Length - replacePattern.Length;
+ }
+ }
+ }
+ return FindNextInSelection();
+ }
+
public static void MarkAll()
{
SetSearchOptions();
@@ -185,15 +221,65 @@ namespace SearchAndReplace
int startPos = Math.Min(textArea.Document.TextLength, Math.Max(0, result.Offset));
int endPos = Math.Min(textArea.Document.TextLength, startPos + result.Length);
- textArea.ActiveTextAreaControl.Caret.Position = textArea.Document.OffsetToPosition(endPos);
- textArea.ActiveTextAreaControl.TextArea.SelectionManager.ClearSelection();
- textArea.ActiveTextAreaControl.TextArea.SelectionManager.SetSelection(new DefaultSelection(textArea.Document, textArea.Document.OffsetToPosition(startPos),
- textArea.Document.OffsetToPosition(endPos)));
- textArea.Refresh();
+ SearchReplaceUtilities.SelectText(textArea, startPos, endPos);
+ lastResult = result;
+ }
+ }
+ }
+ }
+
+ static bool foundAtLeastOneItem = false;
+
+ public static void FindFirstInSelection(int offset, int length)
+ {
+ foundAtLeastOneItem = false;
+ textSelection = null;
+ SetSearchOptions();
+
+ if (find == null ||
+ SearchOptions.FindPattern == null ||
+ SearchOptions.FindPattern.Length == 0) {
+ return;
+ }
+
+ if (!find.SearchStrategy.CompilePattern()) {
+ find.Reset();
+ lastResult = null;
+ return;
+ }
+
+ textSelection = new TextSelection(offset, length);
+ FindNextInSelection();
+ }
+
+ public static bool FindNextInSelection()
+ {
+ TextEditorControl textArea = null;
+ while (textArea == null) {
+ SearchResult result = find.FindNext(textSelection.Offset, textSelection.Length);
+ if (result == null) {
+ if (!foundAtLeastOneItem) {
+ ShowNotFoundMessage();
+ }
+ find.Reset();
+ lastResult = null;
+ foundAtLeastOneItem = false;
+ return false;
+ } else {
+ textArea = OpenTextArea(result.FileName);
+ if (textArea != null) {
+ foundAtLeastOneItem = true;
+ if (lastResult != null && lastResult.FileName == result.FileName &&
+ textArea.ActiveTextAreaControl.Caret.Offset != lastResult.Offset + lastResult.Length) {
+ }
+ int startPos = Math.Min(textArea.Document.TextLength, Math.Max(0, result.Offset));
+ int endPos = Math.Min(textArea.Document.TextLength, startPos + result.Length);
+ SearchReplaceUtilities.SelectText(textArea, startPos, endPos);
lastResult = result;
}
}
}
+ return true;
}
static void ShowNotFoundMessage()
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceUtilities.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceUtilities.cs
index 446f784d73..9225144ce2 100644
--- a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceUtilities.cs
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchReplaceUtilities.cs
@@ -26,6 +26,15 @@ namespace SearchAndReplace
}
}
+ public static TextEditorControl GetActiveTextEditor()
+ {
+ IWorkbenchWindow window = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow;
+ if (window != null && (window.ViewContent is ITextEditorControlProvider)) {
+ return ((ITextEditorControlProvider)window.ViewContent).TextEditorControl;
+ }
+ return null;
+ }
+
public static bool IsWholeWordAt(ITextBufferStrategy document, int offset, int length)
{
return (offset - 1 < 0 || Char.IsWhiteSpace(document.GetCharAt(offset - 1))) &&
@@ -95,5 +104,18 @@ namespace SearchAndReplace
}
return true;
}
+
+ public static void SelectText(TextEditorControl textArea, int offset, int endOffset)
+ {
+ int textLength = textArea.ActiveTextAreaControl.Document.TextLength;
+ if (textLength < endOffset) {
+ endOffset = textLength - 1;
+ }
+ textArea.ActiveTextAreaControl.Caret.Position = textArea.Document.OffsetToPosition(endOffset);
+ textArea.ActiveTextAreaControl.TextArea.SelectionManager.ClearSelection();
+ textArea.ActiveTextAreaControl.TextArea.SelectionManager.SetSelection(new DefaultSelection(textArea.Document, textArea.Document.OffsetToPosition(offset),
+ textArea.Document.OffsetToPosition(endOffset)));
+ textArea.Refresh();
+ }
}
}
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/BruteForceSearchStrategy.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/BruteForceSearchStrategy.cs
index e58f079faf..857156e65d 100644
--- a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/BruteForceSearchStrategy.cs
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/BruteForceSearchStrategy.cs
@@ -58,6 +58,22 @@ namespace SearchAndReplace
return -1;
}
+ int InternalFindNext(ITextIterator textIterator, int offset, int length)
+ {
+ while (textIterator.MoveAhead(1) && TextSelection.IsInsideRange(textIterator.Position, offset, length)) {
+ if (SearchOptions.MatchCase ? MatchCaseSensitive(textIterator.TextBuffer, textIterator.Position, searchPattern) : MatchCaseInsensitive(textIterator.TextBuffer, textIterator.Position, searchPattern)) {
+ if (!SearchOptions.MatchWholeWord || IsWholeWordAt(textIterator.TextBuffer, textIterator.Position, searchPattern.Length)) {
+ if (TextSelection.IsInsideRange(textIterator.Position + searchPattern.Length - 1, offset, length)) {
+ return textIterator.Position;
+ } else {
+ return -1;
+ }
+ }
+ }
+ }
+ return -1;
+ }
+
public bool CompilePattern()
{
searchPattern = SearchOptions.MatchCase ? SearchOptions.FindPattern : SearchOptions.FindPattern.ToUpper();
@@ -67,6 +83,17 @@ namespace SearchAndReplace
public SearchResult FindNext(ITextIterator textIterator)
{
int offset = InternalFindNext(textIterator);
+ return GetSearchResult(offset);
+ }
+
+ public SearchResult FindNext(ITextIterator textIterator, int offset, int length)
+ {
+ int foundOffset = InternalFindNext(textIterator, offset, length);
+ return GetSearchResult(foundOffset);
+ }
+
+ SearchResult GetSearchResult(int offset)
+ {
return offset >= 0 ? new SearchResult(offset, searchPattern.Length) : null;
}
}
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/ISearchStrategy.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/ISearchStrategy.cs
index 1f84f7bf45..6f2d4e061c 100644
--- a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/ISearchStrategy.cs
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/ISearchStrategy.cs
@@ -31,5 +31,10 @@ namespace SearchAndReplace
/// compiled pattern in the text using the textIterator and options.
///
SearchResult FindNext(ITextIterator textIterator);
+
+ ///
+ /// Find only in the specified range.
+ ///
+ SearchResult FindNext(ITextIterator textIterator, int offset, int length);
}
}
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/RegExSearchStrategy.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/RegExSearchStrategy.cs
index a6d09517b0..657787fce2 100644
--- a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/RegExSearchStrategy.cs
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/RegExSearchStrategy.cs
@@ -53,6 +53,31 @@ namespace SearchAndReplace
return null;
}
+ public SearchResult FindNext(ITextIterator textIterator, int offset, int length)
+ {
+ string document = textIterator.TextBuffer.GetText(0, textIterator.TextBuffer.Length);
+
+ while (textIterator.MoveAhead(1) && TextSelection.IsInsideRange(textIterator.Position, offset, length)) {
+ Match m = regex.Match(document, textIterator.Position);
+ if (m == null || m.Index <= 0 || m.Length <= 0) {
+
+ } else {
+ int delta = m.Index - textIterator.Position;
+ if (delta <= 0 || textIterator.MoveAhead(delta)) {
+ if (TextSelection.IsInsideRange(m.Index + m.Length - 1, offset, length)) {
+ return new RegexSearchResult(m);
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+ }
+
+ return null;
+ }
+
private class RegexSearchResult : SearchResult
{
Match m;
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/WildcardSearchStrategy.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/WildcardSearchStrategy.cs
index 5f606ff318..18d9e383d1 100644
--- a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/WildcardSearchStrategy.cs
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/SearchStrategy/WildcardSearchStrategy.cs
@@ -144,6 +144,22 @@ namespace SearchAndReplace
return -1;
}
+ int InternalFindNext(ITextIterator textIterator, int offset, int length)
+ {
+ while (textIterator.MoveAhead(1) && TextSelection.IsInsideRange(textIterator.Position, offset, length)) {
+ if (Match(textIterator.TextBuffer, textIterator.Position, !SearchOptions.MatchCase, 0)) {
+ if (!SearchOptions.MatchWholeWord || SearchReplaceUtilities.IsWholeWordAt(textIterator.TextBuffer, textIterator.Position, curMatchEndOffset - textIterator.Position)) {
+ if (TextSelection.IsInsideRange(curMatchEndOffset - 1, offset, length)) {
+ return textIterator.Position;
+ } else {
+ return -1;
+ }
+ }
+ }
+ }
+ return -1;
+ }
+
public bool CompilePattern()
{
CompilePattern(SearchOptions.FindPattern, !SearchOptions.MatchCase);
@@ -153,6 +169,17 @@ namespace SearchAndReplace
public SearchResult FindNext(ITextIterator textIterator)
{
int offset = InternalFindNext(textIterator);
+ return GetSearchResult(offset);
+ }
+
+ public SearchResult FindNext(ITextIterator textIterator, int offset, int length)
+ {
+ int foundOffset = InternalFindNext(textIterator, offset, length);
+ return GetSearchResult(foundOffset);
+ }
+
+ SearchResult GetSearchResult(int offset)
+ {
return offset >= 0 ? new SearchResult(offset, curMatchEndOffset - offset) : null;
}
}
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/TextSelection.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/TextSelection.cs
new file mode 100644
index 0000000000..9d570f389b
--- /dev/null
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Engine/TextSelection.cs
@@ -0,0 +1,49 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace SearchAndReplace
+{
+ public class TextSelection
+ {
+ int offset;
+ int length;
+
+ public TextSelection(int offset, int length)
+ {
+ this.offset = offset;
+ this.length = length;
+ }
+
+ public int Length {
+ get {
+ return length;
+ }
+ set {
+ length = value;
+ }
+ }
+
+ public int Offset {
+ get {
+ return offset;
+ }
+ set {
+ offset = value;
+ }
+ }
+
+ ///
+ /// Checks whether a position is in a specified range.
+ ///
+ public static bool IsInsideRange(int position, int offset, int length)
+ {
+ return position >= offset && position < offset + length;
+ }
+ }
+}
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Gui/SearchAndReplaceDialog.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Gui/SearchAndReplaceDialog.cs
index 374184669d..5d478636dc 100644
--- a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Gui/SearchAndReplaceDialog.cs
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Gui/SearchAndReplaceDialog.cs
@@ -11,6 +11,7 @@ using System.Windows.Forms;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui;
+using ICSharpCode.TextEditor.Document;
namespace SearchAndReplace
{
@@ -21,8 +22,8 @@ namespace SearchAndReplace
public class SearchAndReplaceDialog : Form
{
- public static string SearchPattern = "";
- public static string ReplacePattern = "";
+ public static string SearchPattern = String.Empty;
+ public static string ReplacePattern = String.Empty;
static SearchAndReplaceDialog Instance;
@@ -45,7 +46,7 @@ namespace SearchAndReplace
ToolStripButton replaceButton = new ToolStripButton();
SearchAndReplacePanel searchAndReplacePanel;
-
+
public SearchAndReplaceDialog(SearchAndReplaceMode searchAndReplaceMode)
{
this.Owner = WorkbenchSingleton.MainForm;
@@ -96,7 +97,6 @@ namespace SearchAndReplace
}
}
-
void SearchButtonClick(object sender, EventArgs e)
{
if (!searchButton.Checked) {
@@ -126,6 +126,5 @@ namespace SearchAndReplace
this.ClientSize = new Size(430, 385);
}
}
-
}
}
diff --git a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Gui/SearchAndReplacePanel.cs b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Gui/SearchAndReplacePanel.cs
index fb44eb18a9..f157c219a8 100644
--- a/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Gui/SearchAndReplacePanel.cs
+++ b/src/Main/Base/Project/Src/TextEditor/SearchAndReplace/Gui/SearchAndReplacePanel.cs
@@ -24,6 +24,10 @@ namespace SearchAndReplace
public class SearchAndReplacePanel : BaseSharpDevelopUserControl
{
SearchAndReplaceMode searchAndReplaceMode;
+ ISelection selection;
+ TextEditorControl textEditor;
+ bool ignoreSelectionChanges;
+ bool findFirst;
public SearchAndReplaceMode SearchAndReplaceMode {
get {
@@ -36,12 +40,12 @@ namespace SearchAndReplace
switch (searchAndReplaceMode) {
case SearchAndReplaceMode.Search:
SetupFromXmlStream(this.GetType().Assembly.GetManifestResourceStream("Resources.FindPanel.xfrm"));
- Get