Created
          September 2, 2010 09:22 
        
      - 
      
 - 
        
Save agross/562087 to your computer and use it in GitHub Desktop.  
    A Visual Studio macro that exports key bindings for ReSharper and a set of custom bindings
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | Imports System | |
| Imports EnvDTE | |
| Imports EnvDTE80 | |
| Imports EnvDTE90 | |
| Imports System.Diagnostics | |
| Imports System.Collections.Generic | |
| ' Comment the following line if you're running the macro in Visual Studio .NET 2003. | |
| Imports Microsoft.VisualStudio.CommandBars | |
| Class CommandBarRecursion | |
| Shared ShowExcessiveDebugOutput As Boolean = False | |
| Public Delegate Function CommandBarControlFilter(ByVal control As CommandBarControl) As Boolean | |
| Public Delegate Function CommandFilter(ByVal command As Command) As Boolean | |
| ' Recurses a collection of CommandBars returning a list of CommandBarControls matching the specified filter. | |
| Public Shared Function RecurseCommandBars(ByVal commandBars As CommandBars, ByVal filter As CommandBarControlFilter) As List(Of CommandBarControl) | |
| Dim result As List(Of CommandBarControl) | |
| result = New List(Of CommandBarControl)() | |
| For Each bar As CommandBar In CType(DTE.CommandBars, CommandBars) | |
| Debug.WriteLine(String.Format("Processing command bar: {0}", GetPath(bar))) | |
| result.AddRange(RecurseCommandBar(bar.Controls, filter)) | |
| Next | |
| Return result | |
| End Function | |
| ' Recurses a collection of CommandBarControls returning a list of CommandBarControls matching the specified filter. | |
| Public Shared Function RecurseCommandBar(ByVal controls As CommandBarControls, ByVal filter As CommandBarControlFilter) As List(Of CommandBarControl) | |
| Dim result As List(Of CommandBarControl) | |
| result = New List(Of CommandBarControl)() | |
| For Each control As CommandBarControl In controls | |
| If ShowExcessiveDebugOutput Then | |
| Debug.WriteLine(String.Format("Processing command bar control: {0}", GetPath(control))) | |
| End If | |
| If filter <> Nothing Then | |
| If filter(control) Then | |
| result.Add(control) | |
| End If | |
| End If | |
| ' Recurse childs. | |
| If control.accChildCount > 0 Then | |
| If control.Type = MsoControlType.msoControlPopup Then | |
| result.AddRange(RecurseCommandBar(CType(control, CommandBarPopup).Controls, filter)) | |
| End If | |
| End If | |
| Next | |
| Return result | |
| End Function | |
| ' Deletes a list of command bar controls. | |
| Public Shared Sub DeleteCommandBarControls(ByVal commandBarControls As List(Of CommandBarControl), ByVal testMode As Boolean) | |
| Dim testModeMessage As String | |
| If testMode Then | |
| testModeMessage = "Test mode" | |
| Else | |
| testModeMessage = "Committing changes" | |
| End If | |
| Debug.WriteLine(String.Format("Deleting {0} command bar controls ({1})", commandBarControls.Count, testModeMessage)) | |
| For Each commandBarControl As CommandBarControl In commandBarControls | |
| Try | |
| Debug.WriteLine(String.Format("Deleting command bar control: {0} ({1})", GetPath(commandBarControl), testModeMessage)) | |
| Catch ex As System.Runtime.InteropServices.COMException | |
| End Try | |
| Try | |
| If testMode = False Then | |
| commandBarControl.Delete() | |
| End If | |
| Catch ex As System.Runtime.InteropServices.COMException | |
| Debug.WriteLine(String.Format("Error deleting command bar control: {0}", GetPath(commandBarControl))) | |
| End Try | |
| Next | |
| End Sub | |
| ' Enumerates all commands returning a list of commands matching the specified filter. | |
| Public Shared Function EnumerateCommands(ByVal commands As Commands, ByVal filter As CommandFilter) As List(Of Command) | |
| Debug.WriteLine(String.Format("Enumerating {0} commands", commands.Count)) | |
| Dim result As List(Of Command) | |
| result = New List(Of Command)() | |
| For Each command As Command In commands | |
| If ShowExcessiveDebugOutput Then | |
| Debug.WriteLine(String.Format("Processing command: {0}", command.Name)) | |
| End If | |
| If filter <> Nothing Then | |
| If filter(command) Then | |
| result.Add(command) | |
| End If | |
| End If | |
| Next | |
| Return result | |
| End Function | |
| ' Deletes a list of commands. | |
| Public Shared Sub DeleteCommands(ByVal commands As List(Of Command), ByVal testMode As Boolean) | |
| Dim testModeMessage As String | |
| If testMode Then | |
| testModeMessage = "Test mode" | |
| Else | |
| testModeMessage = "Committing changes" | |
| End If | |
| Debug.WriteLine(String.Format("Deleting {0} commands ({1})", commands.Count, testModeMessage)) | |
| For Each command As Command In commands | |
| Debug.WriteLine(String.Format("Deleting command: {0} ({1})", command.Name, testModeMessage)) | |
| If testMode = False Then | |
| Try | |
| command.Delete() | |
| Catch ex As System.Runtime.InteropServices.COMException | |
| Debug.WriteLine(String.Format("Error deleting command: {0}", command.Name)) | |
| End Try | |
| End If | |
| Next | |
| End Sub | |
| ' Returns the path to a command bar control. | |
| Shared Function GetPath(ByVal control As Object) As String | |
| If TypeOf (control) Is CommandBarControl Then | |
| Dim cbc As CommandBarControl | |
| cbc = CType(control, CommandBarControl) | |
| Return GetPath(cbc.Parent) + "->" + cbc.Caption | |
| End If | |
| If TypeOf (control) Is CommandBar Then | |
| Dim cb As CommandBar | |
| cb = CType(control, CommandBar) | |
| Return GetPath(cb.Parent) + "->" + cb.Name | |
| End If | |
| Return "DTE" | |
| End Function | |
| End Class | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | Imports System | |
| Imports EnvDTE | |
| Imports EnvDTE80 | |
| Imports EnvDTE90 | |
| Imports System.Diagnostics | |
| Imports System.Globalization | |
| Class CommandFilter | |
| Friend Shared CustomCommands As String() | |
| Shared CurrentCommandName As String | |
| Friend Shared Function FilterReSharperCommands(ByVal command As Command) As Boolean | |
| If command.Name <> Nothing Then | |
| If CultureInfo.InvariantCulture.CompareInfo.IndexOf(command.Name, "ReSharper", CompareOptions.OrdinalIgnoreCase) <> -1 Then | |
| Return True | |
| End If | |
| End If | |
| Return False | |
| End Function | |
| Friend Shared Function FilterCustomCommands(ByVal command As Command) As Boolean | |
| If command.Name <> Nothing Then | |
| CurrentCommandName = command.Name | |
| Return Array.Exists(Of String)(CustomCommands, AddressOf CompareCommandName) | |
| End If | |
| Return False | |
| End Function | |
| Shared Function CompareCommandName(ByVal commandName As String) As Boolean | |
| Return commandName.Equals(CurrentCommandName, StringComparison.InvariantCultureIgnoreCase) | |
| End Function | |
| Friend Shared Function CommandSorter(ByVal x As Command, ByVal y As Command) As Integer | |
| Return x.Name.CompareTo(y.Name) | |
| End Function | |
| End Class | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | Imports System | |
| Imports EnvDTE | |
| Imports EnvDTE80 | |
| Imports EnvDTE90 | |
| Imports System.Diagnostics | |
| Imports System.Collections.Generic | |
| Imports System.IO | |
| Imports System.Text | |
| Imports System.Text.RegularExpressions | |
| Imports System.Windows.Forms | |
| Public Module KeyBindings | |
| ' Export/import file. | |
| Const Filename As String = "C:\path\to\save\the\shortcuts\Keyboard Shortcuts.txt" | |
| ' Additional shortcuts to export. "Resharper*" is exported automatically -- see the Helper class. | |
| ReadOnly _vsCommands As String() = New String() {"Edit.GoTo", _ | |
| "Edit.GoToPrevLocation", _ | |
| "Edit.LineDelete", _ | |
| "File.CloseAllButThis", _ | |
| "TestDriven.NET.RerunTests", _ | |
| "TestDriven.NET.RunTests", _ | |
| "Window.CloseAllDocuments", _ | |
| "Window.CloseDocumentWindow"} | |
| Public Sub ExportKeyboardBindings() | |
| Dim shortcuts = New ShortcutCollection() | |
| ' ReSharper bindings. | |
| Dim resharperCommands = CommandBarRecursion.EnumerateCommands(CType(DTE.Commands, Commands), AddressOf CommandFilter.FilterReSharperCommands) | |
| AddCommandBindingsTo(shortcuts, resharperCommands) | |
| ' Additional Visual Studio bindings. | |
| CommandFilter.CustomCommands = _vsCommands | |
| Dim vsCommands = CommandBarRecursion.EnumerateCommands(CType(DTE.Commands, Commands), AddressOf CommandFilter.FilterCustomCommands) | |
| AddCommandBindingsTo(shortcuts, vsCommands) | |
| SerializeShortcuts(shortcuts, Filename) | |
| End Sub | |
| Sub AddCommandBindingsTo(ByRef shortcuts As ShortcutCollection, ByVal commands As List(Of Command)) | |
| For Each command In commands | |
| Dim bindings = CType(command.Bindings, Object()) | |
| For Each binding In bindings | |
| shortcuts.Add(New Shortcut(command.Name, binding.ToString())) | |
| Next | |
| Next | |
| End Sub | |
| Sub SerializeShortcuts(ByVal shortcuts As ShortcutCollection, ByVal filename As String) | |
| Dim file = New StringBuilder() | |
| For Each shortcut In shortcuts | |
| file.AppendLine(shortcut.ToString()) | |
| Next | |
| Debug.WriteLine(file.ToString()) | |
| System.IO.File.WriteAllText(filename, file.ToString(), Encoding.UTF8) | |
| End Sub | |
| Public Sub ImportKeyboardBindings() | |
| Dim file = System.IO.File.ReadAllText(Filename, Encoding.UTF8) | |
| Dim commands = CType(DTE.Commands, Commands) | |
| For Each shortcut As Shortcut In Shortcut.ParseFile(file) | |
| Debug.WriteLine(shortcut.ToString()) | |
| Try | |
| Dim command = commands.Item(shortcut.Command) | |
| Dim bindings = CType(command.Bindings, Object()) | |
| Array.Resize(bindings, bindings.Length + 1) | |
| Array.Reverse(bindings) | |
| bindings(0) = shortcut.Shortcuts(0) | |
| ' Comment the following two lines if the new binding should be added to the list of bindings | |
| ' instead of replacing the current bindings. | |
| Array.Resize(bindings, shortcut.Shortcuts.Count) | |
| shortcut.Shortcuts.ToArray().CopyTo(bindings, 0) | |
| command.Bindings = bindings | |
| Catch ex As Exception | |
| Debug.WriteLine(String.Format("Error: {0}", ex.Message)) | |
| MessageBox.Show(String.Format("Error while importing {0}: {1}", _ | |
| shortcut, _ | |
| ex.Message), _ | |
| "Error", _ | |
| MessageBoxButtons.OK, _ | |
| MessageBoxIcon.Error) | |
| End Try | |
| Next | |
| End Sub | |
| End Module | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | Imports System | |
| Imports System.Text.RegularExpressions | |
| Imports System.Collections.Generic | |
| Public Class Shortcut | |
| Implements IEquatable(Of Shortcut), IComparable(Of Shortcut) | |
| Private _command As String | |
| Private _shortcuts As List(Of String) = New List(Of String) | |
| ' A description of the regular expression: | |
| ' | |
| ' Beginning of line or string | |
| ' [Command]: A named capture group. [.+] | |
| ' Any character, one or more repetitions | |
| ' -> | |
| ' Space | |
| ' -> | |
| ' Space | |
| ' [Shortcut]: A named capture group. [.*] | |
| ' Any character, any number of repetitions | |
| ' \r$ | |
| ' Carriage return | |
| ' End of line or string | |
| Private Shared _regex As Regex = New Regex("^(?<Command>.+) -> (?<Shortcut>.*)\r$", _ | |
| RegexOptions.IgnoreCase _ | |
| Or RegexOptions.Multiline _ | |
| Or RegexOptions.CultureInvariant _ | |
| Or RegexOptions.Compiled) | |
| Public Property Shortcuts() As List(Of String) | |
| Get | |
| Return _shortcuts | |
| End Get | |
| Private Set(ByVal value As List(Of String)) | |
| _shortcuts = value | |
| End Set | |
| End Property | |
| Public Property Command() As String | |
| Get | |
| Return _command | |
| End Get | |
| Private Set(ByVal value As String) | |
| _command = value | |
| End Set | |
| End Property | |
| Public Sub New(ByVal command As String, ByVal shortcut As String) | |
| Me.Command = command | |
| Me.Shortcuts.Add(shortcut) | |
| End Sub | |
| Public Overrides Function ToString() As String | |
| Shortcuts.Sort() | |
| Dim shortcutArray = Shortcuts.ConvertAll(New Converter(Of String, String)(AddressOf ShortcutToParsableString)).ToArray() | |
| Return String.Join(Environment.NewLine, shortcutArray) | |
| End Function | |
| Public Function ShortcutToParsableString(ByVal shortcut As String) As String | |
| Return String.Format("{0} -> {1}", Command, shortcut) | |
| End Function | |
| Public Overrides Function GetHashCode() As Integer | |
| Return Command.GetHashCode() | |
| End Function | |
| Public Function CompareTo(ByVal other As Shortcut) As Integer Implements IComparable(Of Shortcut).CompareTo | |
| Return Command.CompareTo(other.Command) | |
| End Function | |
| Public Function Equals(ByVal other As Shortcut) As Boolean Implements IEquatable(Of Shortcut).Equals | |
| Return Me.CompareTo(other) = 0 | |
| End Function | |
| Public Shared Function ParseFile(ByVal contents As String) As IEnumerable(Of Shortcut) | |
| Dim result As Dictionary(Of Shortcut, Shortcut) = New Dictionary(Of Shortcut, Shortcut) | |
| For Each lineMatch As Match In _regex.Matches(contents) | |
| Dim command As String = lineMatch.Groups("Command").Value | |
| Dim shortcut As String = lineMatch.Groups("Shortcut").Value | |
| Dim parsed As Shortcut = New Shortcut(command, shortcut) | |
| If result.ContainsKey(parsed) Then | |
| result(parsed).Shortcuts.Add(shortcut) | |
| Else | |
| result.Add(parsed, parsed) | |
| End If | |
| Next | |
| Return result.Values | |
| End Function | |
| End Class | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | Imports System | |
| Imports System.Collections | |
| Imports System.Collections.Generic | |
| Public Class ShortcutCollection | |
| Implements IEnumerable(Of Shortcut) | |
| Private _inner As List(Of Shortcut) = New List(Of Shortcut) | |
| Sub Add(ByVal item As Shortcut) | |
| If _inner.Contains(item) Then | |
| _inner(_inner.IndexOf(item)).Shortcuts.AddRange(item.Shortcuts) | |
| Else | |
| _inner.Add(item) | |
| End If | |
| End Sub | |
| ReadOnly Property Count() As Integer | |
| Get | |
| Return _inner.Count | |
| End Get | |
| End Property | |
| Function GetEnumerator() As IEnumerator(Of Shortcut) Implements IEnumerable(Of Shortcut).GetEnumerator | |
| _inner.Sort() | |
| Return _inner.GetEnumerator | |
| End Function | |
| Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator | |
| _inner.Sort() | |
| Return _inner.GetEnumerator | |
| End Function | |
| End Class | 
Sorry, it should be fixed now. Please see the revision 532e5c.
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment
  
            
Thanks for those handy scripts!
But there is a reference to "CommandBarRecursion" which seems to be missing in your gist.