如果我有这样的东西:
namespace SomeNameSpace
{
#region Usings
using System.Collections.Generic;
using System.Security;
#endregion
/// <summary> Implements a dictionary with several keys. </summary>
/// <typeparam name="Value"> What type of elements we will be storing in the dictionary</typeparam>
public class MultiKeyDic<Value>
{
/// <summary> a very long summary that can be
/// collapsed and expanded. </summary>
public int SomeInt {get;set;}
public void someMethod()
{
}
}
}
如何创建一个宏来查找所有可以展开的位置(节点)。如果我想折叠所有节点,我必须按照someMethod()
、summary of SomeInt
、class MultiKeyDic
、summary of class MultiKeyDic
、#region Usings
以及最后的namespace
的顺序折叠节点。
我知道命令ctrl+M+O 到目前为止,我已经创建了这个宏,它将找到大多数节点: 它看起来比实际情况更复杂。在任何文档上运行它,它都会显示所有属性、类、枚举等,但由于某些原因,它找不到注释或区域。Sub VisitAllNodes()
Dim i As Integer
Dim fileCM As FileCodeModel
Dim elts As EnvDTE.CodeElements
Dim elt As EnvDTE.CodeElement
fileCM = DTE.ActiveDocument.ProjectItem.FileCodeModel
elts = fileCM.CodeElements
For i = 1 To elts.Count
elt = elts.Item(i)
CollapseE(elt, elts, i)
Next
End Sub
'' Helper to OutlineCode. Recursively outlines members of elt.
''
Sub CollapseE(ByVal elt As EnvDTE.CodeElement, ByVal elts As EnvDTE.CodeElements, ByVal loc As Integer)
Dim epStart As EnvDTE.EditPoint
Dim epEnd As EnvDTE.EditPoint
epStart = elt.GetStartPoint(vsCMPart.vsCMPartWholeWithAttributes).CreateEditPoint()
epEnd = elt.GetEndPoint(vsCMPart.vsCMPartWholeWithAttributes).CreateEditPoint() ' Copy it because we move it later.
epStart.EndOfLine()
If ((elt.IsCodeType()) And (elt.Kind <> EnvDTE.vsCMElement.vsCMElementDelegate)) Then
Dim i As Integer
Dim mems As EnvDTE.CodeElements
mems = elt.Members
For i = 1 To mems.Count
Dim temp As EnvDTE.CodeElement = mems.Item(i)
Dim t As String = [Enum].GetName(GetType(EnvDTE.vsCMElement), temp.Kind)
MsgBox("Found member (" & t & ") at line# " & temp.StartPoint.Line)
CollapseE(mems.Item(i), mems, i)
Next
ElseIf (elt.Kind = EnvDTE.vsCMElement.vsCMElementNamespace) Then
Dim i As Integer
Dim mems As EnvDTE.CodeElements
mems = elt.Members
For i = 1 To mems.Count
Dim temp As EnvDTE.CodeElement = mems.Item(i)
Dim t As String = [Enum].GetName(GetType(EnvDTE.vsCMElement), temp.Kind)
MsgBox("Found member (" & t & ") at line# " & temp.StartPoint.Line)
CollapseE(mems.Item(i), mems, i)
Next
End If
'Return
' collapse the element
If (epStart.LessThan(epEnd)) Then
loc = loc + 1
If (loc <= elts.Count) Then
epEnd.MoveToPoint(elts.Item(loc).GetStartPoint(vsCMPart.vsCMPartHeader))
epEnd.LineUp()
epEnd.EndOfLine()
End If
epStart.OutlineSection(epEnd)
End If
End Sub
第一个函数IncludeMember
用于确定要排除的成员类型。例如,在本例中,我不折叠名称空间并使用指令:
' filter some mebers. for example using statemets cannot be collapsed so exclude them.
Function IncludeMember(ByVal member As EnvDTE.CodeElement)
If member.Kind = vsCMElement.vsCMElementIDLImport Then
Return False
ElseIf member.Kind = vsCMElement.vsCMElementNamespace Then
Return False ' I do not want to colapse enums
End If
Return True
End Function
Sub CollapseNodes()
' activate working window
DTE.Windows.Item(DTE.ActiveDocument.Name).Activate()
' expand everything to start
Try
DTE.ExecuteCommand("Edit.StopOutlining")
Catch
End Try
Try
DTE.ExecuteCommand("Edit.StartAutomaticOutlining")
Catch
End Try
' get text of document and replace all new lines with rn
Dim objTextDoc As TextDocument
Dim objEditPt As EnvDTE.EditPoint
Dim text As String
' Get a handle to the new document and create an EditPoint.
objTextDoc = DTE.ActiveDocument.Object("TextDocument")
objEditPt = objTextDoc.StartPoint.CreateEditPoint
' Get all Text of active document
text = objEditPt.GetText(objTextDoc.EndPoint)
text = System.Text.RegularExpressions.Regex.Replace( _
text, _
"(rn?|nr?)", ChrW(13) & ChrW(10) _
)
' add new line to text so that lines of visual studio match with index of array
Dim lines As String() = System.Text.RegularExpressions.Regex.Split(vbCrLf & text, vbCrLf)
' list where whe will place all colapsable items
Dim targetLines As New System.Collections.Generic.List(Of Integer)
' regex that we will use to check if a line contains a #region
Dim reg As New System.Text.RegularExpressions.Regex(" *#region( |$)")
Dim i As Integer
For i = 1 To lines.Length - 1
If reg.Match(lines(i)).Success Then
targetLines.Add(i)
End If
Next
Dim fileCM As FileCodeModel
Dim elts As EnvDTE.CodeElements
Dim elt As EnvDTE.CodeElement
Dim projectItem = DTE.ActiveDocument.ProjectItem
Dim temp = projectItem.Collection.Count
Dim b = DirectCast(DirectCast(projectItem.Document, EnvDTE.Document).ActiveWindow, EnvDTE.Window).ContextAttributes
fileCM = projectItem.FileCodeModel
elts = fileCM.CodeElements
For i = 1 To elts.Count
elt = elts.Item(i)
CollapseE(elt, elts, i, targetLines)
Next
' now that we have the lines that we will plan to collapse sort them. it is important to go in order
targetLines.Sort()
ActivateWorkingWindow()
' go in reverse order so that we can collapse nested regions
For i = targetLines.Count - 1 To 0 Step -1
DTE.ExecuteCommand("Edit.Goto", targetLines(i))
DTE.ExecuteCommand("Edit.ToggleOutliningExpansion")
Next
End Sub
'' Helper to OutlineCode. Recursively outlines members of elt.
''
Sub CollapseE(ByVal elt As EnvDTE.CodeElement, ByVal elts As EnvDTE.CodeElements, ByVal loc As Integer, ByRef targetLines As System.Collections.Generic.List(Of Integer))
Dim epStart As EnvDTE.EditPoint
Dim epEnd As EnvDTE.EditPoint
epStart = elt.GetStartPoint(vsCMPart.vsCMPartWholeWithAttributes).CreateEditPoint()
epEnd = elt.GetEndPoint(vsCMPart.vsCMPartWholeWithAttributes).CreateEditPoint() ' Copy it because we move it later.
epStart.EndOfLine()
If ((elt.IsCodeType()) And (elt.Kind <> EnvDTE.vsCMElement.vsCMElementDelegate) Or elt.Kind = EnvDTE.vsCMElement.vsCMElementNamespace) Then
Dim i As Integer
Dim mems As EnvDTE.CodeElements
mems = elt.Members
For i = 1 To mems.Count
CollapseE(mems.Item(i), mems, i, targetLines)
Next
End If
If (epStart.LessThan(epEnd)) Then
If IncludeMember(elt) Then
targetLines.Add(epStart.Line)
End If
End If
End Sub