The Search and Replace engine used in SharpDevelop had a bad architecture. The concept of IDocumentIterator (for a number of documents) and ITextIterator (for a single document) leads to problems when doing manual "Find next" over multiple documents. It leads code duplication and there are lots of hacks to circumvent all sorts of bugs.
In the most recent alpha builds of SharpDevelop 4.2 the core parts of the Search and Replace engine were rewritten. While rewriting the code I wanted to get rid of code duplication, bugs, special cases and improve performance of the search engine. In a first step I removed all the existing engine code.
Choosing a search algorithm
There are lots of debates on .NET string search algorithm on the net. Some propose to use IndexOf, because it seems faster than Regex, others suggest to implement your own FastIndexOf. I choose to implement search using the Regex classes in the BCL for several reasons:
- It is easier to maintain because it is less code. Additionally the Regex classes are well tested in contrast to a custom IndexOf.
- There are multiple search modes: Normal, Wildcards and Regex. For regex, of course, we had to use the Regex classes. Wildcards are easier to translate to regex and plain text search is fast enough (if not faster in some cases), when using compiled regex.
- Features like "Ignore case" and "Match whole words" are implemented with Regex easily. "Match whole words" is simply \bsearchTerm\b.
Using regex has helped to get rid of code duplication, bugs and special cases. I hope you agree with me and see the benefits of simplicity in contrast to micro and rare-case optimization.
SearchPanel: Single file search - Integrated into the AvalonEdit text editor
In AvalonEdit 4.2 Ctrl+F functionality has been directly built into the editor. The normal Search and Replace dialog has been moved to Ctrl+Shift+F. Incremental and Quick find were removed, because the SearchPanel is a very powerful replacement.
As you can see it offers some basic search options. You can use F3 to jump to the next match and Shift+F3 to move to the previous match.The SearchPanel will soon be integrated into ILSpy to allow full-text search in currently decompiled code.
Improving performance and usability of Find all in multiple files
One of the weaknesses of Find all in SharpDevelop was its speed on the one hand and on the other hand, it was locking up SharpDevelop so the user had to wait for Find all to complete.
During the redesign of the search engine, we also focused on making it thread-safe. This requires to create a list of files to search through before doing the actual search. This causes some neglectable delay and overhead. The only case in which this would turn out really bad, is a recursive directory search starting from C:\ using *.* as file mask. But this is certainly not a common scenario when working with an IDE.
The good news is, you can continue working while waiting for the search to complete. Please keep in mind that all changes you make to documents while Find all is active are not guaranteed to be recognized, depending on when the background thread processes the file.
Another good news for all those of you with multi-core CPUs: SharpDevelop 4.2 will process multiple files in parallel and display all results in real-time. So you can work with the first results while the remaining files are processed. This is implemented using the IObservable<T> and IObserver<T> interfaces.
These are the key features of the new search engine. I hope you like it. If you have any suggestions, please leave a comment.