在編輯器中處理文字
您的擴充功能程式碼可以設定執行,以回應各種進入點(這些是使用者與 Visual Studio 互動時發生的情況)。 編輯器擴充性目前支援三個進入點:接聽程式、EditorExtensibility 服務對象和命令。
當編輯器窗口中發生特定操作時,事件監聽器會被觸發,並以 TextView
程式代碼表示。 例如,當使用者在編輯器中輸入某個專案時,就會發生 TextViewChanged
事件。 當編輯器視窗開啟或關閉時,會發生 TextViewOpened
和 TextViewClosed
事件。
編輯器服務對像是 EditorExtensibility
類別的實例,其會公開即時編輯器功能,例如執行文字編輯。
命令 是由使用者透過點擊項目來啟動的,您可以將其放在選單、內容選單或工具列上。
新增文字視圖監聽器
有兩種類型的監聽器,ITextViewChangedListener 和 ITextViewOpenClosedListener。 這些監聽器可以用來觀察文本編輯器的開啟、關閉與修改。
然後,建立新的類別,實作 ExtensionPart 基類和 ITextViewChangedListener
、ITextViewOpenClosedListener
或兩者,並新增 VisualStudioContribution 屬性。
然後,實作 TextViewExtensionConfiguration 屬性,這是 ITextViewChangedListener 和 ITextViewOpenClosedListener所要求的,讓接聽程式能在編輯 C# 檔案時套用。
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") },
};
本文稍後 列出其他程式設計語言和文件類型的可用檔類型,而且必要時也可以定義自定義檔類型。
假設您決定實作這兩個接聽程式,則完成的類別宣告看起來應該如下所示:
[VisualStudioContribution]
public sealed class TextViewOperationListener :
ExtensionPart, // This is the extension part base class containing infrastructure necessary to use VS services.
ITextViewOpenClosedListener, // Indicates this part listens for text view lifetime events.
ITextViewChangedListener // Indicates this part listens to text view changes.
{
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
// Indicates this part should only light up in C# files.
AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") },
};
...
由於 ITextViewOpenClosedListener 和 ITextViewChangedListener 宣告 TextViewExtensionConfiguration 属性,因此組態適用於這兩個接聽程式。
當您執行擴充功能時,應該會看到:
- 當用戶開啟文字檢視時,會呼叫 ITextViewOpenClosedListener.TextViewOpenedAsync。
- ITextViewOpenClosedListener.TextViewClosedAsync 使用者關閉文字檢視時呼叫。
- ITextViewChangedListener.TextViewChangedAsync 會在使用者對文字檢視器顯示的文本進行更改時被呼叫。
每一種方法都會傳遞 ITextViewSnapshot,其中包含使用者叫用動作時文字檢視和文字文件的狀態,以及 IDE 想要取消暫止動作時會有 IsCancellationRequested == true
的 CancellationToken。
定義您的延伸模組何時相關
您的延伸模組通常只與某些支援的文件類型和案例相關,因此請務必清楚定義其適用性。 您可以使用 AppliesTo 組態以數種方式清楚定義擴充功能的適用性。 您可以指定延伸套件支援的檔案類型,例如程式語言,並且/或根據檔名或路徑模式比對進一步調整延伸套件的適用範圍。
使用 AppliesTo 組態指定程式設計語言
AppliesTo 設定表示應啟動擴充功能的程式語言情境。 它會撰寫為 AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") }
,其中檔類型是Visual Studio內建語言的已知名稱,或Visual Studio延伸模組中定義的自定義名稱。
下表顯示一些已知的檔案類型:
文件類型 | 描述 |
---|---|
“CSharp” | C# |
“C/C++” | C、C++、標頭和IDL |
“TypeScript” | TypeScript 和 JavaScript 類型語言。 |
“HTML” | HTML |
“JSON” | JSON |
"text" | 文本檔案,包括從“text”衍生出的階層式“code”子系。 |
“code” | C、C++、C#等等。 |
DocumentTypes 是階層式的。 也就是說,C# 和 C++都是從 「code」 遞減而來,因此宣告 「code」 會導致您的延伸模組針對所有程式碼語言、C#、C、C++等等啟用。
定義新的檔案類型
您可以定義新的文件類型,例如支援自定義程式代碼語言,方法是將靜態 DocumentTypeConfiguration 屬性新增至擴充專案中的任何類別,並使用 VisualStudioContribution
屬性標記屬性。
DocumentTypeConfiguration
可讓您定義新的檔案類型、指定它繼承一或多個其他檔案類型,以及指定一或多個用來識別檔類型的擴展名:
using Microsoft.VisualStudio.Extensibility.Editor;
internal static class MyDocumentTypes
{
[VisualStudioContribution]
internal static DocumentTypeConfiguration MarkdownDocumentType => new("markdown")
{
FileExtensions = new[] { ".md", ".mdk", ".markdown" },
BaseDocumentType = DocumentType.KnownValues.Text,
};
}
檔類型定義會與舊版 Visual Studio 擴充性所提供的內容類型定義合併,可讓您將其他擴展名對應至現有的檔類型。
文件選擇器
除了 DocumentFilter.FromDocumentType之外,DocumentFilter.FromGlobPattern 允許您設定當文件的檔案路徑符合 glob(通配符)模式時才啟用擴充功能,藉此進一步限制擴充功能的適用性。
[VisualStudioContribution]
public sealed class TextViewOperationListener
: ExtensionPart, ITextViewOpenClosedListener, ITextViewChangedListener
{
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
AppliesTo = new[]
{
DocumentFilter.FromDocumentType("CSharp"),
DocumentFilter.FromGlobPattern("**/tests/*.cs"),
},
};
[VisualStudioContribution]
public sealed class TextViewOperationListener
: ExtensionPart, ITextViewOpenClosedListener, ITextViewChangedListener
{
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
AppliesTo = new[]
{
DocumentFilter.FromDocumentType(MyDocumentTypes.MarkdownDocumentType),
DocumentFilter.FromGlobPattern("docs/*.md", relativePath: true),
},
};
pattern
參數表示一種在文件絕對路徑上匹配的 glob 模式。
Glob 模式可以具有下列語法:
-
*
,以比對路徑區段中的零或多個字元 -
?
用於匹配路徑區段中的一個字元 -
**
用於配對任何數量的路徑段,包括零路徑段 -
{}
群組條件(例如,**/*.{ts,js}
符合所有 TypeScript 和 JavaScript 檔案) -
[]
宣告路徑區段中要符合的字元範圍(例如,example.[0-9]
example.0
、example.1
、...) -
[!...]
否定路徑區段中要比對的字元範圍(例如,example.[!0-9]
在example.a
、example.b
上比對,但不example.0
)
反斜杠(\
)在 glob 模式中無效。 建立 glob 樣式時,請務必將任何反斜杠(\)轉換為斜線(/)。
存取編輯器功能
您的編輯器擴充類別繼承自 ExtensionPart。
ExtensionPart
類別會公開 可擴充性 屬性。 使用這個屬性,您可以要求 EditorExtensibility 對象的實例。 您可以使用這個物件來存取即時編輯器功能,例如執行編輯。
EditorExtensibility editorService = this.Extensibility.Editor();
存取命令內的編輯器狀態
每個 Command
中的 ExecuteCommandAsync()
都會傳遞 IClientContext
,其中包含命令被調用時 IDE 狀態的快照。 您可以透過 ITextViewSnapshot
介面存取活動文件,只需從 EditorExtensibility
物件呼叫非同步方法 GetActiveTextViewAsync
來取得。
using ITextViewSnapshot textView = await this.Extensibility.Editor().GetActiveTextViewAsync(clientContext, cancellationToken);
一旦擁有 ITextViewSnapshot
,您就可以存取編輯器狀態。
ITextViewSnapshot
是編輯器狀態在某個時間點不可變的檢視,因此您必須使用 Editor 物件模型中的其他介面, 進行編輯。