zoukankan      html  css  js  c++  java
  • Visual Studio 宏的高级用法

    因为自 Visual Studio 2012 开始,微软已经取消了对宏的支持,所以本篇文章所述内容只适用于 Visual Studio 2010 或更早期版本的 VS。

      在上一篇中,我已经介绍了如何编写一个最简单的宏,本文将进一步介绍如何用宏来实现对代码编辑窗口控制。在本文结束的时候,你应该能自己实现如下两个功能,第一个用于对方法体进行 phase0 标记;第二个可以将当前窗口中的代码进行归类,将所有方法、属性、变量通过region进行分块。

    动画演示:phase0 

    动画演示:设置 region

    为什么使用宏

      在计算机行业内,宏的出现由来已久,因为它能替代人们执行一些重复发生的简单但烦琐的事情,所以广受人们欢迎。在 Visual Studio 中也提供了进行宏编程的方法,从而方便开发人员录制一些宏脚本来扩展Visual Studio,以提高开发效率。

      要想在 Visual Studio 中操作宏来操控代码编辑窗口,就必须要了解如下几个东东:EnvDTEDTETextSelectionEditPoint。宏可实现地远不止是操控代码编辑窗口,关于其它能力请见参考资源[1]

      本文中的内容在阅读过程中最好能结合实践进行练习,这样印象会更深刻。 

    EnvDTE

      EnvDTE 是最核心的程序集,所有后续要讲到的东西都归于它名下。

      MSDN上对它的介绍:

    EnvDTE 是包含 Visual Studio 内核自动化的对象和成员的用程序集包装的 COM 库。 在 EnvDTE80、EnvDTE90、 EnvDTE90a 和 EnvDTE100 命名空间中包含更改和新功能。

      EnvDTE80、90、100按照数字,越大的表示越新,因为Visual Stuido有好多版本,不同的版本会提供新的功能,而这几个版本的 EnvDTE 正是对应了这些更新,不同的版本只是在功能上做了补充,并没有谁能替代谁的关系,比如editPoint2 比 editPoint 可能多了某些新特性,当你要使用这些新特性的时候,就应该使用editPoint2,否则还是使用 editPoint。

      在编写自己的扩展前,可以把EnvDTE、EnvDTE80 等全部引用进来。

    Imports EnvDTE
    Imports EnvDTE80
    Imports EnvDTE90
    Imports EnvDTE90a
    Imports EnvDTE100

    DTE对象

      在 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 的属性

      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


    动画演示:选中一段文本

    EditPoint

      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


    动画演示:如何剪贴一个方法

    Have a try

      辛苦了,看到这里实在不容易。既然已经看到这了,何不来尝试着自己写一个呢?回到开头的两个示例,看看能不能写出来了。答案请凶猛的点击这里

    参考资源

      [1] 自动化与扩展性参考

      [2] Find 接口

      [3] 如何:控制代码编辑器 (Visual Basic)

      [4] vsCMElement 枚举

      本文来源于 《Visual Studio 宏的高级用法》

  • 相关阅读:
    Ubuntu 16 安装redis客户端
    crontab 参数详解
    PHP模拟登录发送闪存
    Nginx配置端口访问的网站
    Linux 增加对外开放的端口
    Linux 实用指令之查看端口开启情况
    无敌的极路由
    不同的域名可以指向同一个项目
    MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error
    Redis 创建多个端口
  • 原文地址:https://www.cnblogs.com/stg609/p/3702784.html
Copyright © 2011-2022 走看看