Visual Studio 文本编辑器扩展

发布于 2024-11-24 17:11:44 字数 202 浏览 2 评论 0原文

我正在尝试开始使用 Visual Studio (2010) 扩展,但很难找到合适的材料。我有 SDK,但包含的示例似乎是诸如装饰器、窗口和图标之类的东西。

我正在尝试制作一个可以直接与文本编辑器一起使用的扩展(例如,将类中的所有方法名称按字母顺序排列,或者将所有常量名称设为大写),但我找不到此类功能的演示,甚至是教程。

有谁知道我在哪里可以找到这类东西?

I am trying to get started in Visual Studio (2010) extensions and I am having a hard time finding the right materials. I have the SDK, but the included samples seem to be things like adorners, windows, and icons.

I am trying to make an extension that will work directly with the text editor (to alphabetize all of my method names in a class, or make all constant names upper case for example) but I can't find a demo for this type of functionality, or even a tutorial.

Does anyone know where I can find this kind of stuff?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

挽心 2024-12-01 17:11:44

我有完全相同的问题,现在已经浏览了网络几个小时,直到我能够理解并解释您需要如何开始这样的扩展。

在下面的示例中,我们将创建一个小而笨的扩展,当进行编辑时,它将始终将“Hello”添加到代码文件的开头。这是非常基础的,但应该让您了解如何继续开发这个东西。

请注意:您必须完全自行解析代码文件 - Visual Studio 不会向您提供有关类、方法或其他内容的位置以及它们包含的内容的任何信息。这是制作代码格式化工具时遇到的最大障碍,本答案不会涵盖。[*]

对于那些跳到此答案的人,请确保您先下载并安装了 Visual Studio SDK,否则您将找不到第一步中提到的项目类型。

创建项目

  1. 首先创建一个类型为“Visual C# > Extensibility > VSIX Project”的新项目(仅当您选择 .NET Framework 4 作为目标框架时才可见)。 请注意,您可能必须选择“编辑器分类器”项目类型而不是“VSIX 项目”类型才能使其正常工作。 。

  2. 项目创建完成后,会打开“source.extension.vsixmanifest”文件,可以设置产品名称、作者、版本、描述、图标等。我认为这一步非常不言自明,您可以现在关闭选项卡,稍后通过打开 vsixmanifest 文件来恢复它。

创建一个侦听器类以获取有关文本编辑器实例创建的通知

接下来,我们需要在 Visual Studio 中创建文本编辑器时进行侦听,并将代码格式化工具绑定到它。 VS2010 中的文本编辑器是 IWpfTextView 的一个实例。

  1. 向我们的项目添加一个新类并将其命名为 TextViewCreationListener。此类必须实现 Microsoft.VisualStudio.Text.Editor.IWpfTextViewCreationListener 接口。您需要将对 Microsoft.VisualStudio.Text.UI.Wpf 的引用添加到您的项目中。程序集 DLL 位于 Visual Studio SDK 目录中的 VisualStudioIntegration\Common\Assemblies\v4.0 下。

  2. 您必须实现该界面的TextViewCreated方法。此方法有一个参数指定已创建的文本编辑器的实例。我们将创建一个新的代码格式化类,稍后将此实例传递给该类。

  3. 我们需要通过指定属性[Export(typeof(IWpfTextViewCreationListener))],使TextViewCreationListener类对Visual Studio可见。将对 System.ComponentModel.Composition 的引用添加到项目中的 Export 属性。

  4. 此外,我们需要指定代码格式化程序应与文本编辑器绑定的文件类型。我们只喜欢格式化代码文件而不是纯文本文件,因此我们将属性 [ContentType("code")] 添加到侦听器类。为此,您必须向您的项目添加对 Microsoft.VisualStudio.CoreUtility 的引用。

  5. 此外,我们只想更改可编辑代码,而不是更改其周围的颜色或装饰(如示例项目中所示),因此我们将属性 [TextViewRole(PredefinedTextViewRoles.Editable)] 添加到班级。您再次需要一个新的引用,这次是 Microsoft.VisualStudio.Text.UI

  6. 将该类标记为内部密封。至少这是我的建议。现在您的类应该类似于以下内容:

    <前><代码>[ContentType(“代码”)]
    [导出(typeof(IWpfTextViewCreationListener))]
    [TextViewRole(预定义TextViewRoles.Editable)]
    内部密封类 TextViewCreationListener : IWpfTextViewCreationListener
    {
    公共无效TextViewCreated(IWpfTextView textView)
    {
    }
    }

创建用于代码格式化的类

接下来,我们需要一个处理代码格式化逻辑、排序方法等的类。同样,在此示例中,每当进行编辑时,它都会简单地将“Hello”添加到文件的开头。

  1. 向您的项目添加一个名为 Formatter 的新类。

  2. 添加一个采用一个 IWpfTextView 参数的构造函数。请记住,我们希望将创建的编辑器实例传递给监听器类的 TextViewCreated 方法中的格式化类(只需将 new Formatter(textView); 到该方法中添加即可) .

  3. 将传递的实例保存在成员变量中。稍后格式化代码时(例如检索插入符位置)它会变得很方便。还要绑定编辑器实例的 TextBuffer 属性的 ChangedPostChanged 事件:

    公共格式化程序(IWpfTextView视图)
    {
        _view = 视图;
        _view.TextBuffer.Changed += new EventHandler(TextBuffer_Changed);
        _view.TextBuffer.PostChanged += new EventHandler(TextBuffer_PostChanged);
    }
    
  4. The Changed每次进行编辑(例如键入字符、粘贴代码或编程更改)时都会调用该事件。因为它也会对编程更改做出反应,所以我使用 bool 确定我们的扩展程序或用户/其他任何东西当前是否正在更改代码,并且仅当我们的扩展程序尚未更改时才调用我的自定义 FormatCode() 方法编辑。否则,您将递归调用此方法,这会导致 Visual Studio 崩溃:

    private void TextBuffer_Changed(对象发送者,TextContentChangedEventArgs e)
    {
        if (!_isChangingText)
        {
            _isChangingText = true;
            格式代码(e);
        }
    }
    
  5. 我们必须在 PostChanged 事件处理程序中再次将这个 bool 成员变量重置为 false。 p>

  6. 让我们将 Changed 事件的事件参数传递给我们的自定义 FormatCode 方法,因为它们包含上次编辑与现在之间发生的更改。这些编辑存储在 INormalizedTextChangeCollection 类型的数组 e.Changes 中(参见我的文章末尾的链接,了解有关此类型的更多信息)。我们循环遍历所有这些编辑,并使用此编辑生成的新文本调用自定义 HandleChange 方法。

    private void FormatCode(TextContentChangedEventArgs e)
    {
        if (e.Changes != null)
        {
            for (int i = 0; i < e.Changes.Count; i++)
            {
                HandleChange(e.Changes[0].NewText);
            }
        }
    }
    
  7. HandleChange 方法中,我们实际上可以扫描关键字以以特定方式处理这些关键字(记住,您必须自己解析任何代码!) - 但在这里我们只是愚蠢地添加“Hello”到文件的开头以进行测试。例如,我们必须更改编辑器实例的TextBuffer。为此,我们需要创建一个 ITextEdit 对象,用它我们可以操作文本并随后应用它的更改。该代码非常不言自明:

    private void HandleChange(string newText)
    {
        ITextEdit编辑=_view.TextBuffer.CreateEdit();
        编辑.插入(0,“你好”);
        编辑。应用();
    }
    

编译此加载项时,Visual Studio 的实验配置单元会启动,仅加载我们的扩展。创建一个新的 C# 文件并开始键入以查看结果。

我希望这能给您一些如何继续该主题的想法。我现在必须亲自探索一下。

我强烈推荐 MSDN 上的编辑器文本模型文档,以获取有关如何执行此操作的提示。
http://msdn.microsoft.com/en-us/library/dd885240 .aspx#textmodel


脚注

[*] 请注意,Visual Studio 2015 或更高版本附带 Rosyln 编译器平台,该平台确实已经分析为您提供 C# 和 VB.NET 文件(可能还有其他预装语言)并公开它们的分层语法结构,但我不是该主题的专家,尚未给出如何使用这些新服务的答案。无论如何,启动编辑器扩展的基本进度与此答案中描述的相同。请注意,如果您使用这些服务,您将变得依赖于 Visual Studio 2015+,并且该扩展将无法在早期版本中运行。

I had the exact same question and now have browsed the web several hours until I was being able to understand and explain how you'd need to start with such an extension.

In my following example we will create a small and dumb extension which will always add "Hello" to the beginning of a code file when an edit has been made. It's very basic but should give you an idea how to continue developing this thing.

Be warned: You have to parse the code files completely on your own - Visual Studio does not give you any information about where classes, methods or whatever are and what they contain. That's the biggest hurdle to be taken when doing a code formatting tool and will not be covered in this answer.[*]

For those who skipped to this answer, make sure you downloaded and installed the Visual Studio SDK first or you will not find the project type mentioned in step one.

Creating the project

  1. Start by creating a new project of the type "Visual C# > Extensibility > VSIX Project" (only visible if you selected .NET Framework 4 as the target framework). Please note that you may have to select the "Editor Classifier" project type instead of the "VSIX Project" type to get it working, s. comment below.

  2. After the project has been created, the "source.extension.vsixmanifest" file will be opened, giving you the ability to set up product name, author, version, description, icon and so on. I think this step is pretty self-explaining, you can close the tab now and restore it later by opening the vsixmanifest file.

Creating a listener class to get notified about text editor instance creations

Next, we need to listen whenever a text editor has been created in Visual Studio and bind our code formatting tool to it. A text editor in VS2010 is an instance of IWpfTextView.

  1. Add a new class to our project and name it TextViewCreationListener. This class has to implement the Microsoft.VisualStudio.Text.Editor.IWpfTextViewCreationListener interface. You need to add a reference to Microsoft.VisualStudio.Text.UI.Wpf to your project. The assembly DLL is found in your Visual Studio SDK directory under VisualStudioIntegration\Common\Assemblies\v4.0.

  2. You have to implement the TextViewCreated method of the interface. This method has a parameter specifying the instance of the text editor which has been created. We will create a new code formatting class which this instance is passed to later on.

  3. We need to make the TextViewCreationListener class visible to Visual Studio by specifying the attribute [Export(typeof(IWpfTextViewCreationListener))]. Add a reference to System.ComponentModel.Composition to your project for the Export attribute.

  4. Additionally, we need to specify with which types of files the code formatter should be bound to the text editor. We only like to format code files and not plain text files, so we add the attribute [ContentType("code")] to the listener class. You have to add a reference to Microsoft.VisualStudio.CoreUtility to your project for this.

  5. Also, we only want to change editable code and not the colors or adornments around it (as seen in the example projects), so we add the attribute [TextViewRole(PredefinedTextViewRoles.Editable)] to the class. Again you need a new reference, this time to Microsoft.VisualStudio.Text.UI.

  6. Mark the class as internal sealed. At least that's my recommendation. Now your class should look similar to this:

    [ContentType("code")]
    [Export(typeof(IWpfTextViewCreationListener))]
    [TextViewRole(PredefinedTextViewRoles.Editable)]
    internal sealed class TextViewCreationListener : IWpfTextViewCreationListener
    {
        public void TextViewCreated(IWpfTextView textView)
        {
        }
    }
    

Creating a class for code formatting

Next, we need a class handling the code formatting logic, sorting methods and so on. Again, in this example it will simply add "Hello" to the start of the file whenever an edit has been made.

  1. Add a new class called Formatter to your project.

  2. Add a constructor which takes one IWpfTextView argument. Remember that we wanted to pass the created editor instance to this formatting class in the TextViewCreated method of our listener class (simply add new Formatter(textView); to the method there).

  3. Save the passed instance in a member variable. It'll become handy when formatting the code later on (e.g. for retrieving the caret position). Also tie up the Changed and PostChanged events of the TextBuffer property of the editor instance:

    public Formatter(IWpfTextView view)
    {
        _view = view;
        _view.TextBuffer.Changed += new EventHandler<TextContentChangedEventArgs>(TextBuffer_Changed);
        _view.TextBuffer.PostChanged += new EventHandler(TextBuffer_PostChanged);
    }
    
  4. The Changed event is called every time an edit has been made (e.g. typing a char, pasting code or programmatical changes). Because it also reacts on programmatical changes I use a bool determining if our extension or the user / anything else is changing the code at the moment and call my custom FormatCode() method only if our extension is not already editing. Otherwise you'll recursively call this method which would crash Visual Studio:

    private void TextBuffer_Changed(object sender, TextContentChangedEventArgs e)
    {
        if (!_isChangingText)
        {
            _isChangingText = true;
            FormatCode(e);
        }
    }
    
  5. We have to reset this bool member variable in the PostChanged event handler again to false.

  6. Let's pass the event args of the Changed event to our custom FormatCode method because they contain what has changed between the last edit and now. Those edits are stored in the array e.Changes of the type INormalizedTextChangeCollection (s. the link at the end of my post for more information about this type). We loop through all those edits and call our custom HandleChange method with the new text which this edit has produced.

    private void FormatCode(TextContentChangedEventArgs e)
    {
        if (e.Changes != null)
        {
            for (int i = 0; i < e.Changes.Count; i++)
            {
                HandleChange(e.Changes[0].NewText);
            }
        }
    }
    
  7. In the HandleChange method we could actually scan for keywords to handle those in a specific way (remember, you have to parse any code on yourself!) - but here we just dumbly add "Hello" to the start of the file for testing purposes. E.g. we have to change the TextBuffer of our editor instance. To do so, we need to create an ITextEdit object with which we can manipulate text and apply it's changes afterwards. The code is pretty self-explaining:

    private void HandleChange(string newText)
    {
        ITextEdit edit = _view.TextBuffer.CreateEdit();
        edit.Insert(0, "Hello");
        edit.Apply();
    }
    

When compiling this add-in, an experimental hive of Visual Studio starts up with only our extension loaded. Create a new C# file and start typing to see the results.

I hope this gives you some ideas how to continue in this topic. I have to explore it myself now.

I highly recommend the documentation of the text model of the editor on MSDN to get hints about how you could do this and that.
http://msdn.microsoft.com/en-us/library/dd885240.aspx#textmodel


Footnotes

[*] Note that Visual Studio 2015 or newer come with the Rosyln Compiler Platform, which indeed already analyzes C# and VB.NET files for you (and probably other pre-installed languages too) and exposes their hierarchical syntactical structure, but I'm not an expert in this topic yet to give an answer on how to use these new services. The basic progress of starting an editor extension stays the same as described in this answer anyway. Be aware that - if you use these services - you will become dependent on Visual Studio 2015+, and the extension will not work in earlier versions.

╭⌒浅淡时光〆 2024-12-01 17:11:44

只需查看 MSDN 上的“编辑器扩展入门”网站 http://msdn.microsoft .com/en-us/library/dd885122.aspx

托尔斯滕

just have a look at the "Getting started with Editor extensions" site on the MSDN http://msdn.microsoft.com/en-us/library/dd885122.aspx

Thorsten

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文