Thursday, February 17, 2011

Fastest way to insert replacement characters in Visual Studio

I'm just starting to pick up ASP.Net MVC and find myself writing a lot of <%= %> in the views. Intellisense does supply the closing %>, but I find that typing the introductory <%= to be burdensome (they are tough for me to type :-)).

I've dabbled around a bit with Rails and the NetBeans IDE where I was able to type:

r<tab>  - which would expand to <%  %>

and

re<tab>  - which would expand to <%= %>

Can something similar be done in the Visual Studio 2008 IDE?

From stackoverflow
  • I believe Code Snippets would fit the bill.

  • I've found it straight forward to write a macro and then bind it to a keyboard command.

    I use Tools->Macros->Macro Explorer to see what's there and you can create a new module and add in a macro to inject your code. Then you bind it to a key with Tools->Customize->Keyboard...

    Since it's not too different from what you're doing, here is a macro to inject a source command with the date and username - VBScript - I didn't look to hard for other alternatives.

    Imports System
    Imports EnvDTE
    Imports EnvDTE80
    Imports EnvDTE90
    Imports System.Diagnostics
    
    Public Module Module1
    
        Private Function GetUserName() As String
            GetUserName = System.Environment.UserName
        End Function
    
        Sub InjectChangeComment()
            ActiveDocument().Selection().Text = "// " + System.DateTime.Now.ToString("MM-dd-yy") + " " + GetUserName() + vbTab + vbTab + vbTab
        End Sub
    
    End Module
    
  • Based on a comment, I double-checked the snippets answer below and it unfortunately doesn't run in HTML view. The other way to do this is via a recorded macro:

    • In your web project, start recording: CTRL+SHIFT+R
    • Type <%= %> then return the caret to between the spaces after the "="
    • Stop recording: CTRL+SHIFT+R
    • Insert the macro via CTRL+SHIFT+P

    That could be enough, but it would be better to have it across all projects, plus we'd like a better keystroke than CTRL+SHIFT+P:

    • Save the Macro: Tools->Macros->Save Temporary Macro, giving it a name
    • Bind it to a keystroke combination:
      • Tools->Options, and choose the Keyboard node
      • Search for the name you chose
      • Enter a key combination (e.g. ALT+A) and click OK

    Now you can press the key shortcut (e.g. ALT+A) in HTML view, it will insert <%= %>, and position the caret in the tags, ready for input.


    [Old Answer: doesn't work in HTML view, unfortunately.]

    For a Code Snippet, create an XML snippet file (e.g. "asp.snippet") with the name, shortcut and expansion, then use Tools -> Code Snippet Manager to add the folder where your snippet is stored.

    Here's the XML for snippet that (via "asp[tab][tab]"), expands "<%= [code] %>"

    <?xml version="1.0" encoding="utf-8"?>
    <CodeSnippet Format="1.0.0"  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
      <Header>
        <Title>ASP Server Tags</Title>
        <Author>Chris Bowen</Author>
        <Shortcut>asp</Shortcut>
        <Description>ASP.NET server escape characters, including equals</Description>
        <SnippetTypes>
          <SnippetType>SurroundsWith</SnippetType>
          <SnippetType>Expansion</SnippetType>
        </SnippetTypes>
      </Header>
      <Snippet>
        <Declarations>
          <Literal>
            <ID>code</ID>
            <Default>Code</Default>
          </Literal>
        </Declarations>
        <Code Language="csharp">
          <![CDATA[<%= $code$ $selected$%>$end$]]>
        </Code>
      </Snippet>
    </CodeSnippet>
    

    More details are here on MSDN.

    BTW, VS has a snippet to create snippets. Just open a new XML file, then right click and choose Insert Snippet -> "Snippet".

    Decker : Thanks Chris. I found that I couldn't get it to install as an XML snippet unless I changed the Language to "XML"? And even after that, I'm not getting any snippets to show while editing an .ASPX page? It is offered if I edit an XML file. But asp doesn't invoke it; the menu can though.
    Chris Bowen : Sorry about that, Decker. I've updated the answer with the macro-based approach. Still pretty easy, and should be what you're looking for.
    Decker : Thanks! That did it. Thank you Chris!
  • This macro function should do it:

    The main code will do one of two things, if nothing is selected it will just insert the <%= %> code construct, if you have something currently selected in the editor, it will wrap that code with the construct E.G. <%= selected code here %>

    Public Sub WrapMVC()
        Try
            DTE.UndoContext.Open("Wrap MVC")
            Dim OutText As String = ""
            Dim OutFormat As String = "<%={0} %>"
            DTE.ActiveDocument.Selection.Text = String.Format(OutFormat, ActiveWindowSelection)
        Finally
            DTE.UndoContext.Close()
        End Try
    End Sub
    

    Helper Routines:

    Friend Function ActiveWindowSelection() As String
        If DTE.ActiveWindow.ObjectKind = EnvDTE.Constants.vsWindowKindOutput Then
            Return OutputWindowSelection()
        End If
        If DTE.ActiveWindow.ObjectKind = "{57312C73-6202-49E9-B1E1-40EA1A6DC1F6}" Then
            Return HTMLEditorSelection()
        End If
        Return SelectionText(DTE.ActiveWindow.Selection)
    End Function
    
    Private Function HTMLEditorSelection() As String
        Dim hw As EnvDTE.HTMLWindow = ActiveDocument.ActiveWindow.Object
        Dim tw As TextWindow = hw.CurrentTabObject
        Return SelectionText(tw.Selection)
    End Function
    
    Private Function OutputWindowSelection() As String
        Dim w As Window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput)
        Dim ow As OutputWindow = w.Object
        Dim owp As OutputWindowPane = ow.OutputWindowPanes.Item(ow.ActivePane.Name)
        Return SelectionText(owp.TextDocument.Selection)
    End Function
    
    Private Function SelectionText(ByVal sel As EnvDTE.TextSelection) As String
        If sel Is Nothing Then
            Return ""
        End If
        If sel.Text.Length <= 2 Then
            SelectWord(sel)
        End If
        If sel.Text.Length <= 2 Then
            Return ""
        End If
        Return sel.Text
    End Function
    
    Private Sub SelectWord(ByVal sel As EnvDTE.TextSelection)
        Dim leftPos As Integer
        Dim line As Integer
        Dim pt As EnvDTE.EditPoint = sel.ActivePoint.CreateEditPoint()
    
        sel.WordLeft(True, 1)
        line = sel.TextRanges.Item(1).StartPoint.Line
        leftPos = sel.TextRanges.Item(1).StartPoint.LineCharOffset
        pt.MoveToLineAndOffset(line, leftPos)
        sel.MoveToPoint(pt)
        sel.WordRight(True, 1)
    End Sub
    
    Decker : Thank you, Brian. This works nicely too and has the advantage of dealing with selected text.
  • Code Snippets in the HTML view do not work. It's slated for the next version of Visual Studio. I'd look at a Macro approach for now, or see if other tools allow for snippets in the HTML editor.

  • One good tool which will allow you to do this is Resharper. You can create your own templates that will do what you require but also have surround with tags too. There are a whole host of features and is well worth it for the price.

0 comments:

Post a Comment