Monday, June 19, 2006 - Posts

Visual Studio IDE Keyboard Shortcuts Macro

I came across this macro last week and have found it to be practically invaluable in my quest to become the keyboard shortcut Ninja!

It works for 2003 and 2005 so get to it!

Kudos to Jeff Atwood @ http://www.codinghorror.com/blog for this peach.

 

Imports EnvDTE

Imports System

Imports System.Diagnostics

Imports System.Text

Imports System.Text.RegularExpressions

Imports System.Data

Imports System.IO

Imports System.Environment

 

'''

''' Keyboard Shortcut enumeration macro for VS 2005

'''

''' Jeff Atwood

''' http://www.codinghorror.com/blog/

'''

''' version 3/2/06, 3pm

'''

Public Module KeyboardShortcuts

'-- possible fields are Category, Command, Scope, PrimaryKey, Key

Private Const _defaultSortOrder As String = "Scope, PrimaryKey, Key"

Private Const _groupColumnName As String = "Scope"

Private _pageTitle As String

Private _fileName As String

Private _sb As New Text.StringBuilder

Sub List()

_pageTitle = "Visual Studio .NET " & VSNetYear() & " Keyboard Shortcuts"

_fileName = _pageTitle & ".htm"

Dim filePath As String

filePath = Path.Combine(GetFolderPath(SpecialFolder.Personal), _fileName)

If Not File.Exists(filePath) Then

GenerateDocument(filePath)

End If

Debug.WriteLine(DTE.Version)

DTE.ItemOperations.Navigate(filePath)

End Sub

Private Function VSNetYear() As String

If DTE.Version.StartsWith("8") Then

Return "2005"

End If

If DTE.Version.StartsWith("7.1") Then

Return "2003"

End If

If DTE.Version.StartsWith("7") Then

Return "2002"

End If

Return "20xx"

End Function

Private Sub GenerateDocument(ByVal filePath)

Dim dv As New DataView(KeyboardCommandTable())

dv.Sort = _defaultSortOrder

WriteLine("<html>")

WriteLine("<head>")

WriteLine("<title>" & _pageTitle & "</title>")

WriteLine("<style type=""text/css"">")

WriteLine("body {font-family: Tahoma}")

WriteLine("table {font-size: 80%}")

Write(".kbd {font-family:arial,helvetica,sans-serif;padding:5px 3px;white-space:nowrap;")

Write("color:#000;background:#eee;border-width:2px 4px 5px 3px;")

WriteLine("border-style:solid;border-color:#ccc #aaa #888 #bbb;}")

WriteLine(".i20 {margin:8px 10px;}")

WriteLine("</style>")

WriteLine("</head>")

WriteLine("<body>")

WriteLine("<h2>" & _pageTitle & "</hr></h2>")

WriteLine(ViewToHtmlTable(dv, _groupColumnName))

WriteLine("</body>")

WriteLine("</html>")

DumpToFile(filePath)

End Sub

Private Sub DumpToFile(ByVal targetFile As String)

Dim sw As StreamWriter

Try

sw = New StreamWriter(targetFile, FileMode.OpenOrCreate)

sw.Write(_sb.ToString)

sw.Close()

Finally

If Not sw Is Nothing Then

sw.Close()

End If

End Try

End Sub

Private Sub WriteLine(ByVal s As String)

Write(s)

_sb.Append(NewLine)

End Sub

Private Sub Write(ByVal s As String)

_sb.Append(s)

End Sub

Private Function KeyboardCommandTable() As DataTable

Dim dt As New DataTable

dt.Columns.Add("Category")

dt.Columns.Add("Command")

dt.Columns.Add("Scope")

dt.Columns.Add("PrimaryKey")

dt.Columns.Add("Key")

For Each cmd As EnvDTE.Command In DTE.Commands

If cmd.Bindings.Length > 0 Then

ParseBindings(cmd, dt)

End If

Next

Return dt

End Function

Private Sub ParseBindings(ByVal cmd As EnvDTE.Command, ByVal dt As DataTable)

If cmd.Name Is Nothing Then Return

If cmd.Name.Length = 0 Then Return

Debug.WriteLine(cmd.Name)

Dim dr As DataRow = dt.NewRow

Dim sa() As String = Regex.Split(cmd.Name, "\.")

dr.Item("Category") = sa(0)

If sa.Length = 1 Then

dr.Item("Command") = ""

Else

dr.Item("Command") = sa(1)

End If

For Each s As String In cmd.Bindings

ParseBinding(s, dr)

Next

dt.Rows.Add(dr)

End Sub

Private Sub ParseBinding(ByVal s As String, ByVal dr As DataRow)

Dim sa() As String = Regex.Split(s, "::")

dr.Item("Scope") = sa(0)

dr.Item("Key") = sa(1)

Dim primarykey As String = Regex.Match(sa(1), _

"(?<key>[^+]+),|(?<key>[^+]+$)").Groups("key").ToString

dr.Item("PrimaryKey") = primarykey

End Sub

Private Function PrettyKeyHtml(ByVal key As String) As String

If Not key.EndsWith("+") Then

key = Regex.Replace(key, "(\+|,\s)", "</span>$1<span class=""kbd"">")

End If

Return "<p class=""i20""><span class=""kbd"">" & key & "</span>"

End Function

Private Function ViewToHtmlTable(ByVal dv As DataView, _

ByVal groupColumnName As String) As String

Dim sb As New StringBuilder

Dim prevGroupName As String

Dim groupName As String

sb.Append("<table>")

sb.Append(NewLine)

For Each drv As DataRowView In dv

groupName = Convert.ToString(drv.Item(groupColumnName))

If groupName <> prevGroupName Then

sb.Append("<tr><td colspan=3><br/><h3>")

sb.Append(groupName)

sb.Append("<hr></h3>")

End If

sb.Append("<tr><td><code>")

sb.Append(PrettyKeyHtml(drv.Item("Key")))

sb.Append("</code><td>")

sb.Append(drv.Item("Category"))

sb.Append("<td><b>")

sb.Append(drv.Item("Command"))

sb.Append("</b>")

sb.Append(NewLine)

prevGroupName = groupName

Next

sb.Append("</table>")

sb.Append(NewLine)

Return sb.ToString

End Function

End Module

 

Renaming Cruise Control .Net Project Maintaining Logs and State Data

I just came across this little gotcha.

I needed to rename a cruise control .net build so I edited the .config file project block:

<project>

<name>Put my new name here</name>

....

</project>

Sure enough the build appeared under the new name in Web Dashboard.

CCTray had to be edited to remove the build with the old name and pick up the new - all was well until I noticed that the project page had lost it's log files.

The culprit was the xmlLogger configuration in the .config file - I had used the default setting which is a relative path which uses the project name and so was looking in the wrong place.

A quick change to point the logger at a specific path and hey presto!

<xmllogger>

<logDir>Full path to Logs directory here</logDir>

</xmllogger>

Next was the loss of the previous build state info - again simply renaming the state file fixed the issue since Cruise names the state file automatically using the project name:

e.g. oldName.state -> newName.state