web-dev-qa-db-ja.com

VisualStudioテキストエディター拡張機能

Visual Studio(2010)拡張機能を使い始めようとしていますが、適切な資料を見つけるのに苦労しています。 SDKを持っていますが、含まれているサンプルは装飾品、ウィンドウ、アイコンなどのようです。

テキストエディタで直接機能する拡張機能を作成しようとしています(たとえば、クラス内のすべてのメソッド名をアルファベット順に並べたり、すべての定数名を大文字にしたりします)が、このタイプの機能のデモが見つかりません、またはチュートリアルですら。

私がこの種のものをどこで見つけることができるか誰かが知っていますか?

36
A.R.

私はまったく同じ質問をしましたが、そのような拡張機能から始める必要がある方法を理解して説明できるようになるまで、数時間Webを閲覧しました。

次の例では、編集が行われたときにコードファイルの先頭に常に「Hello」を追加する小さくてばかげた拡張機能を作成します。それは非常に基本的ですが、このことを開発し続ける方法のアイデアをあなたに与えるはずです。

警告:コードファイルを完全に自分で解析する必要があります-Visual Studioは、クラスやメソッドなどがどこにあり、それらに何が含まれているかについての情報を提供しません。これは、コードフォーマットツールを実行するときに取るべき最大のハードルであり、この回答ではカバーされません。[*]

この回答にスキップした場合は、最初にVisual Studio SDKをダウンロードしてインストールしたことを確認してください。そうしないと、手順1で説明したプロジェクトの種類が見つかりません。

プロジェクトの作成

  1. タイプ「VisualC#>拡張性> VSIXプロジェクト」の新しいプロジェクトを作成することから始めます(ターゲットフレームワークとして.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\Assembly\v4.0にあります。

  2. インターフェイスのTextViewCreatedメソッドを実装する必要があります。このメソッドには、作成されたテキストエディタのインスタンスを指定するパラメータがあります。このインスタンスが後で渡される新しいコードフォーマットクラスを作成します。

  3. 属性[Export(typeof(IWpfTextViewCreationListener))]を指定して、TextViewCreationListenerクラスをVisualStudioから見えるようにする必要があります。 Export属性のプロジェクトにSystem.ComponentModel.Compositionへの参照を追加します。

  4. さらに、コードフォーマッタをテキストエディタにバインドするファイルの種類を指定する必要があります。プレーンテキストファイルではなくコードファイルのみをフォーマットするのが好きなので、属性[ContentType("code")]をリスナークラスに追加します。このために、プロジェクトにMicrosoft.VisualStudio.CoreUtilityへの参照を追加する必要があります。

  5. また、編集可能なコードのみを変更し、その周りの色や装飾は変更したくないので(サンプルプロジェクトに見られるように)、属性[TextViewRole(PredefinedTextViewRoles.Editable)]をクラスに追加します。ここでも、Microsoft.VisualStudio.Text.UIへの新しい参照が必要です。

  6. クラスを内部密閉としてマークします。少なくともそれが私の推薦です。これで、クラスは次のようになります。

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

コードフォーマット用のクラスの作成

次に、コードのフォーマットロジックやソートメソッドなどを処理するクラスが必要です。この例でも、編集が行われるたびに、ファイルの先頭に「Hello」が追加されます。

  1. Formatterという新しいクラスをプロジェクトに追加します。

  2. 1つのIWpfTextView引数を取るコンストラクターを追加します。作成したエディターインスタンスを、リスナークラスのTextViewCreatedメソッドのこのフォーマットクラスに渡したかったことを思い出してください(メソッドにnew Formatter(textView);を追加するだけです)。

  3. 渡されたインスタンスをメンバー変数に保存します。後でコードをフォーマットするときに便利になります(キャレットの位置を取得する場合など)。また、エディターインスタンスのChangedプロパティのPostChangedイベントとTextBufferイベントを結び付けます。

    _public Formatter(IWpfTextView view)
    {
        _view = view;
        _view.TextBuffer.Changed += new EventHandler<TextContentChangedEventArgs>(TextBuffer_Changed);
        _view.TextBuffer.PostChanged += new EventHandler(TextBuffer_PostChanged);
    }
    _
  4. Changedイベントは、編集が行われるたびに呼び出されます(たとえば、文字の入力、コードの貼り付け、プログラムによる変更)。プログラムの変更にも反応するため、拡張機能またはユーザー/その他が現在コードを変更しているかどうかを判断するブール値を使用し、拡張機能がまだ編集されていない場合にのみカスタムFormatCode()メソッドを呼び出します。それ以外の場合は、このメソッドを再帰的に呼び出すと、VisualStudioがクラッシュします。

    _private void TextBuffer_Changed(object sender, TextContentChangedEventArgs e)
    {
        if (!_isChangingText)
        {
            _isChangingText = true;
            FormatCode(e);
        }
    }
    _
  5. PostChangedイベントハンドラーのこのboolメンバー変数を再びfalseにリセットする必要があります。

  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 edit = _view.TextBuffer.CreateEdit();
        edit.Insert(0, "Hello");
        edit.Apply();
    }
    _

このアドインをコンパイルすると、実験的なHive of Visual Studioが起動し、拡張機能のみが読み込まれます。新しいC#ファイルを作成し、入力を開始して結果を確認します。

これにより、このトピックを続行する方法についていくつかのアイデアが得られることを願っています。私は今それを自分で探求しなければなりません。

これとそれを行う方法についてのヒントを得るために、MSDNのエディターのテキストモデルのドキュメントを強くお勧めします。 http://msdn.Microsoft.com/en-us/library/dd885240.aspx#textmodel


脚注

[*] Visual Studio 2015以降にはRosylnコンパイラプラットフォームが付属していることに注意してください。Rosylnコンパイラプラットフォームは、C#ファイルとVB.NETファイル(およびおそらく他のプレインストールされた言語も)を分析し、それらの階層構文構造を公開していますが、私はこれらの新しいサービスの使用方法については、まだこのトピックの専門家ではありません。エディター拡張機能を開始する基本的な進捗状況は、とにかくこの回答で説明されているものと同じです。これらのサービスを使用すると、Visual Studio 2015+に依存するようになり、拡張機能は以前のバージョンでは機能しないことに注意してください。

58
Ray

mSDNの「Gettingstartedwith Editorextensions」サイトをご覧ください http://msdn.Microsoft.com/en-us/library/dd885122.aspx

トルステン

7
Thorsten Hans