由于自 Visual Studio 2012 开始,微软已经取消了对宏的支持,因此本篇文章所述内容只适用于 Visual Studio 2010 或更早期版本的 VS。html
在上一篇中,我已经介绍了如何编写一个最简单的宏,本文将进一步介绍如何用宏来实现对代码编辑窗口控制。在本文结束的时候,你应该能本身实现以下两个功能,第一个用于对方法体进行 phase0 标记;第二个能够将当前窗口中的代码进行归类,将全部方法、属性、变量经过region进行分块。编程
动画演示:phase0 编辑器
动画演示:设置 region
工具
在计算机行业内,宏的出现由来已久,由于它能替代人们执行一些重复发生的简单但烦琐的事情,因此广受人们欢迎。在 Visual Studio 中也提供了进行宏编程的方法,从而方便开发人员录制一些宏脚原本扩展Visual Studio,以提升开发效率。post
要想在 Visual Studio 中操做宏来操控代码编辑窗口,就必需要了解以下几个东东:EnvDTE、DTE、TextSelection、EditPoint。宏可实现地远不止是操控代码编辑窗口,关于其它能力请见参考资源[1]。动画
本文中的内容在阅读过程当中最好能结合实践进行练习,这样印象会更深入。 ui
EnvDTE 是最核心的程序集,全部后续要讲到的东西都归于它名下。spa
MSDN上对它的介绍:3d
EnvDTE 是包含 Visual Studio 内核自动化的对象和成员的用程序集包装的 COM 库。 在 EnvDTE80、EnvDTE90、 EnvDTE90a 和 EnvDTE100 命名空间中包含更改和新功能。code
EnvDTE80、90、100按照数字,越大的表示越新,由于Visual Stuido有好多版本,不一样的版本会提供新的功能,而这几个版本的 EnvDTE 正是对应了这些更新,不一样的版本只是在功能上作了补充,并无谁能替代谁的关系,好比editPoint2 比 editPoint 可能多了某些新特性,当你要使用这些新特性的时候,就应该使用editPoint2,不然仍是使用 editPoint。
在编写本身的扩展前,能够把EnvDTE、EnvDTE80 等所有引用进来。
Imports EnvDTE Imports EnvDTE80 Imports EnvDTE90 Imports EnvDTE90a Imports EnvDTE100
在 Visual Studio 中, DTE 对象是自动化模型中的顶级对象,经过操做DTE对象能够获取对 Visual Studio 的控制,好比你能够获得当前活动的文档、活动的窗口、活动的项目、查找与替换、向解决方案中添加文件、执行预约义命令、录制宏等。
DTE包含的属性(局部)
上面只是截取了一部分,完整的请查看 MSDN
DTE包含的方法
经过操控这些属性和方法就能够实现强大的功能,下面的例子中经过操纵DTE对象的TextSelecion子对象和Find子对象来调用 Visual Studio 的查找功能。
1 Dim selection As TextSelection = DTE.ActiveDocument.Selection 2 3 DTE.Find.MatchWholeWord = False 4 DTE.Find.Action = vsFindAction.vsFindActionFind 5 DTE.Find.Target = vsFindTarget.vsFindTargetCurrentDocument 6 DTE.Find.MatchCase = False 7 DTE.Find.Backwards = False 8 DTE.Find.MatchInHiddenText = True 9 DTE.Find.PatternSyntax = vsFindPatternSyntax.vsFindPatternSyntaxLiteral 10 11 '跳出输入框,接收你的输入 12 what = InputBox(prompt) 13 If (what <> "") Then 14 DTE.Find.FindWhat = what 15 16 '至关于在当前文档向下搜索一次 17 Dim result = DTE.Find.Execute() 18 If (result = vsFindResult.vsFindResultFound) Then 19 20 ’若是找到,就把那一行选中 21 selection.SelectLine() 22 End If 23 End If
上面的代码并不复杂,就是简单地对 Find 的调用和赋值。若是你正好看到这里,不仿也试着写一下吧~ Find 相关内容请查看参考资源[2]。
用于表明当前选定的区域,一个文档有且只有一个实例,即便你在代码中建立了多个实例,这些实例其实都是指向同一个选定区域。对 TextSelection 的操控会直接体如今界面上。经过控制该对象能够剪切、复制、删除选中的文本,插入删除空白行,大小写转换,定位到某个位置、格式化等。
TextSelection 的属性
TextSelection 的方法(局部)
完整的请查看 MSDN
一句话获取 TextSelection 实例,由于 TextSelection 是针对文档的,因此在获取 Selection 以前,必须先获取文档。若是当前文档中并无选中任何文本,则 TextSelection 表示的是当前光标所在的位置。
Dim selection As TextSelection = DTE.ActiveDocument.Selection
下面演示几个例子,来讲明 TextSelection 的能力。
第一个例子将演示如何获取当前光标所在的方法的名称,主要经过获取当前光标所在位置的 CodeElement 元素来获得具体的方法信息,经过传入 CodeElement 的参数不一致能够获取不一样块的信息,包括方法、枚举、属性、类、名称空间等。关于 vsCMElement 的枚举请见参考资源[4]。
1 Sub DemoFunctionInfo() 2 Dim selection As TextSelection = DTE.ActiveDocument.Selection 3 Dim func As CodeFunction = selection.ActivePoint.CodeElement(vsCMElement.vsCMElementFunction) 4 If Not func Is Nothing Then 5 MsgBox(func.Name) 6 End If 7 End Sub
动画演示:显示方法名
第二个示例,演示如何在光标位置所在的行上下加上Region。
1 Sub DemoRegion() 2 3 '获取 TextSelection 实例 4 Dim selection As TextSelection = DTE.ActiveDocument.Selection 5 6 '移动到当前光标所在行的最前面 7 selection.StartOfLine() 8 '在该位置插入一个新行,至关于按了下回车 9 selection.NewLine() 10 '将光标移回到新行 11 selection.LineUp() 12 '在当前光标所在的位置开始输入文字 13 selection.Text = "#region start" 14 15 '将光标移动到下一行 16 selection.LineDown() 17 '将光标移动到行末 18 selection.EndOfLine() 19 '回车 20 selection.NewLine() 21 selection.Text = "#endregion" 22 23 '格式化 24 selection.SmartFormat() 25 26 End Sub
动画演示:在特定行的上下添加region
再来看一个示例,用户输入起始和结束文字,而后自动选中位于这两个起始结束标记之间的一段文本。
1 Sub DemoSelectTextRange() 2 3 '获取 TextSelection 4 Dim selection As TextSelection = DTE.ActiveDocument.Selection 5 Dim startLine As Integer 6 Dim startLineOffset As Integer 7 Dim startPoint As TextPoint 8 Dim endLine As Integer 9 Dim endLineOffset As Integer 10 11 DTE.Find.Action = vsFindAction.vsFindActionFind 12 DTE.Find.MatchCase = False 13 14 '-------------- 找到起始的文字 ---------------------- 15 Dim input = InputBox("Enter a word to find as the start tag") 16 If input = "" Then 17 Exit Sub 18 End If 19 20 DTE.Find.FindWhat = input 21 Dim result As vsFindResult = DTE.Find.Execute() 22 If result <> vsFindResult.vsFindResultFound Then 23 Exit Sub 24 End If 25 26 startLineOffset = selection.BottomPoint.LineCharOffset 27 startLine = selection.BottomPoint.Line 28 '----------------------------------------------------- 29 30 '--------------- 找到结束的文字 ---------------------- 31 input = InputBox("Enter a word to find as the end tag") 32 If input = "" Then 33 Exit Sub 34 End If 35 36 DTE.Find.FindWhat = input 37 result = DTE.Find.Execute() 38 If result <> vsFindResult.vsFindResultFound Then 39 Exit Sub 40 End If 41 42 endLine = selection.TopPoint.Line 43 endLineOffset = selection.TopPoint.LineCharOffset 44 '----------------------------------------------------- 45 46 '------------- 遍历,记录通过的字符数用于选中 -------- 47 Dim index As Integer 48 Dim len As Integer = 0 49 50 selection.GotoLine(startLine) 51 len += selection.ActivePoint.LineLength - startLineOffset 52 For index = startLine + 1 To endLine - 1 53 selection.GotoLine(index) 54 len += selection.ActivePoint.LineLength 55 Next 56 selection.GotoLine(endLine) 57 len += endLineOffset 58 '----------------------------------------------------- 59 60 '设置起始位置 61 selection.MoveToLineAndOffset(startLine, startLineOffset) 62 'True 表示鼠标跟随移动,len 表示要移动的字符数 63 selection.CharRight(True, len) 64 65 End Sub
动画演示:选中一段文本
Visual Studio 除了在代码编辑窗口中会保留代码,还有一个叫代码缓冲区的地方(用户是看不到的)也会保留代码,但这个缓冲区中的代码不受自动换行和虚拟空格的影响。前面咱们说过 TextSelection 只能有一个,那若是开发人员事先选中了一行代码,而咱们又在宏中不当心改变了这个 TextSelection,那就会致使用户的选中被丢失。另外,EditPoint提供了一些TextSelection所不具有的操做能力。好比剪切一段文本,使用 EditPoint 的 Cut 方法只要设置起始位置而后直接传入结束的位置给 Cut 方法就能够完成,可是若是使用 TextSelection ,由于它的 Cut 不带参数,因此就必须先选中这段文本才能使用 Cut 方法。
这里补充一个小知识点,什么是虚拟空格?这个东东默认是关闭的,在 Visual Studio 开发的时候也不多用。通常咱们在写代码的时候,若是在一行的结尾处使用小键盘向右继续移动的话,光标很快就会自动跳转到下一行。若是开启以后,则永远不会自动跳转到下一行,你能够在任意一个位置进行编辑。开启的方式:工具 / 选项 / 文本编辑器 / 全部语言 -> 启用虚拟空格。
因此若是你在项目中会存在自动换行或开启了虚拟空格,那么想要精准的控制编辑器,仍是使用 EditPoint 吧。
下面同样举个例子来说解。该示例将把一个方法的位置进行移动,思路就是先剪切,而后粘贴。
1 Sub DemoCut() 2 Dim selection As TextSelection = DTE.ActiveDocument.Selection 3 '获取editPointer 4 Dim edit = selection.ActivePoint.CreateEditPoint 5 '获取 方法 6 Dim func As CodeFunction = selection.ActivePoint.CodeElement(vsCMElement.vsCMElementFunction) 7 If Not func Is Nothing Then 8 edit.MoveToPoint(func.StartPoint) 9 edit.Cut(func.EndPoint) 10 11 edit.MoveToLineAndOffset(20, 1) 12 edit.Paste() 13 End If 14 End Sub
动画演示:如何剪贴一个方法
辛苦了,看到这里实在不容易。既然已经看到这了,何不来尝试着本身写一个呢?回到开头的两个示例,看看能不能写出来了。答案请凶猛的点击这里。
[1] 自动化与扩展性参考
[2] Find 接口
[4] vsCMElement 枚举
本文来源于 《Visual Studio 宏的高级用法》