Click here to Skip to main content
Click here to Skip to main content
Go to top

Standard Regular Expression Searcher Addin For VS.NET 2003

, 11 Jan 2005
Rate this:
Please Sign up or sign in to vote.
Standard Regular Expression Searcher add-in for VS.NET 2003.

Introduction

The "Search and Replace" and "Search in files" in VS.NET support Regular Expression, but the kind of Regular Expression is weak and wired. For instance, it uses some strange symbols like :z, :Lu, and doesn't support position-match like ?!>, ?=. Standard Regular Expression Searcher Add-in has the same functions with "Search and Replace" and "Search in files", and support standard Regular Expression, so by using it, you can take advantage of the power of standard Regular Expression and the convenient usability of VS.NET, and it provides some functions that VS.NET has not, for example, show the context of matched content.

Background

In The Code Project, there are a lot of articles involving how to write VS.NET add-ins, so we don't repeat it. We just use _DTE, TextDocument, TextSelection, EditPoint, and OutputWindowPane.

Using the Add-in

After installing the add-in, You can find a menu item in Tools that is named SearcherAddin, and click it, and then write Regular Expression into the text box for Search.

Sample Image

Click "Replace" button, you can write Regular Expression for replacing to the textbox for Replace.

Sample Image

In "Search Scope", if you select "Active Document" or "All of opened files", the add-in works like "Find and Replace" of VS.NET; if you select "Current project" or "Whole solution" or click Browse button, it works like "Find in files", and executes the command once and closes, and then shows the results into OutputWindowPane and double f on the corresponding line, then opens the relating file and goes to the right position.

Sample Image

If you input "Font Lines" and "Back Lines", the add-in will show the context front and back lines of the matched text in OutputWindowPane.

Sample Image

Sample Image

How to show the results to WindowPane

The "Find in Files" of VS.NET uses FindResult1 and FindResult2 Window to show searching or replacing results, but the DTE component model doesn't expose FindResult1 and FindResult2, so we used OutputWindowPane to do the same thing. We implement OutputWindowPaneWrapper to wrap OutputWindowPane, and encapsulate more functions in it.

public class OutputWindowPaneWrapper
{
    private OutputWindowPane pane;
    private DTE dte;
    ...

We named the OutputWindowPane "Regex Searcher" windowName, and uses this code to initialize it:

private void getWindowPane (string title) {
    Window winItem = this.dte.Windows.Item (Constants.vsWindowKindOutput);
    OutputWindow window = (OutputWindow) winItem.Object;

    try {
        this.pane = window.OutputWindowPanes.Item (title);
    }
    catch(System.ArgumentException) {
        this.pane = window.OutputWindowPanes.Add (title);
    }
}

In order to show OutputWindowPane, first of all, we should activate Output Window of IDE, and activate our specific pane.

public void Activate ()
{
    dte.Windows.Item(Constants.vsWindowKindOutput).Activate();
    this.pane.Activate();
}

Use State Pattern to implement different FindNext in TextWindow

In TextWindow, we use FindNext command to search next matched text, but FindNext will be fairly complicated by virtue of different position and showing different information by all kinds of results, if all of the logic is concentrated in FindNext. If we use enum type to define different states for FindNext, there will be too much switch-case in FindNext and it will be hard to understand and maintain. We chose State Pattern of GOF to tackle it, then all of it becomes clear and easy.

We defined IFindState that includes two methods: FindNext and ShowMessage.

public interface IFindState
{
    void ShowMessage();
    void FindNext(WindowSearcher windowSearcher);
}

We implemented concrete States by deriving from IFindState, it involves FirstFindState, FirstFindSucceededState, FirstFindFailedState, FirstSearchSucceededAndBackToStartPointState and FirstSearchFailedAndSecondSucceededState. In concrete State, we did three things. First, we once search in TextWindow; second, according to the result of searching, we set the new State for State Context -- WindowSearcher; third, according to the result of searching, we show the corresponding message or do another FindNext. For example:

public class FirstFindState : IFindState {
    public void ShowMessage(){
    }

    public void FindNext(WindowSearcher windowSearcher){
        windowSearcher.SetSearchStartPoint();
        if(windowSearcher.SearchInTextWindowOnce()) {
            windowSearcher.SelectMatchedText();
            windowSearcher.SetState(new FirstFindSucceededState());
        }
        else{
            windowSearcher.MoveToStartInTextWindow();
            windowSearcher.SetState(new FirstFindFailedState());
            windowSearcher.SetLatestFindStartPosToStartOfDoc();
            windowSearcher.FindNext();
        }
    }
}

public class FirstFindFailedState: IFindState {
    public void ShowMessage() {
        UIHelper.ShowInfo("Didn't find");
    }

    public void FindNext(WindowSearcher windowSearcher) {
        if(windowSearcher.SearchInTextWindowOnce()){
            windowSearcher.SelectMatchedText();
            windowSearcher.SetState(new FirstSearchFailedAndSecondSucceededState());
        }
        else{
            windowSearcher.ResetLatestFindStartPos();
            windowSearcher.SetState(new FirstFindState());
            ShowMessage();
        }
    }
}

WindowSearcher is State Context that has _state to keep State information, and realizes FindNext by different State.

public class WindowSearcher : Searcher {
    private IFindState _state;
    public void SetState(IFindState newState) {
        _state = newState;
    }

    public void FindNext() {
        setLatestFindStartPos();
        _state.FindNext(this);
    }
    ...

How to replace Text in TextWindow

The DTE component model provides three methods to replace text in TextWindow. First, TextSelection has ReplaceText function, but it doesn't support standard Regular Expression; second, EditPoint has ReplaceText function, it can replace the text between two points with expected text; third, TextSelection has Text property, it can set an expected text by replacing selected text. The third one is in line with our need and convenience.

private void tryToReplaceSelectedText(string replacePattern) {
    TextSelection objSel = getTextSelection();
    if(_matchedStartPoint == objSel.AnchorPoint.AbsoluteCharOffset 
           && _matchedEndPoint == objSel.ActivePoint.AbsoluteCharOffset){
        objSel.Text = 
          getReplaceText(_searchLatestEditPoint.GetText(getTextDocument().EndPoint), 
          replacePattern);
    }
    setLatestFindStartPos();
}

How to use Regular Expression in searching and replacing

The FCL of .NET Framework provides support for Regular Expressions, and it's pretty good. The namespace is System.Text.RegularExpressions, we just use Match(), Matchs(), Replace(), Match, MatchCollection of the Regex object to do Regular Expression searching and replacing.

public MatchInfo GetMatch() {
    Regex rg = new Regex(_pattern, GetRegexOptions());
    Match match = rg.IsMatch(_windowSource, _nextSearchStartPos);
    if(!match.Success){
        return null;
    }

    int startLine = 
        StringHandleHelp.GetLineCount(ref _windowSource, match.Index); 
    int startLineOffset = 
        StringHandleHelp.GetPosInLine(ref _windowSource, match.Index);
    int endLine = 
        StringHandleHelp.GetLineCount(ref _windowSource, 
        match.Index + match.Length - 1); 
    int endLineOffset = StringHandleHelp.GetPosInLine(ref _windowSource, 
                        match.Index + match.Length - 1);
    return new MatchInfo(startLine, endLine, match.Value, 
           startLineOffset, match.Index, match.Length, endLineOffset);
}
public string Replace(string source, string replacePattern){
    Regex rg = new Regex(_pattern, GetRegexOptions());
    return rg.Replace(source, replacePattern);
}

public string Replace(string source, string replacePattern, int startPos){
    Regex rg = new Regex(_pattern, GetRegexOptions());
    return rg.Replace(source, replacePattern, 1, startPos);
}

protected string replaceAll(string source, 
          string replacePattern, out int repeatCount)
{
    Regex rg = new Regex(_pattern, GetRegexOptions());
    repeatCount = rg.Matches(source).Count;
    return repeatCount > 0?rg.Replace(source, 
           replacePattern):string.Empty;
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

niugang

China China
No Biography provided

Comments and Discussions

 
QuestionThe copyright thing.. PinmemberAlexandru Stanciu18-Dec-05 22:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140905.1 | Last Updated 11 Jan 2005
Article Copyright 2004 by niugang
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid