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
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