Werken met tekst in de editor
Uw extensiecode kan worden geconfigureerd om te worden uitgevoerd als reactie op verschillende toegangspunten (situaties die optreden wanneer een gebruiker communiceert met Visual Studio). Editor-uitbreidbaarheid ondersteunt momenteel drie toegangspunten: listeners, de EditorExtensibility serviceobject en opdrachten.
Gebeurtenislisteners worden geactiveerd wanneer bepaalde acties plaatsvinden in een editorvenster, vertegenwoordigd in code door een TextView
. Wanneer een gebruiker bijvoorbeeld iets in de editor typt, treedt er een TextViewChanged
gebeurtenis op. Wanneer een editorvenster wordt geopend of gesloten, vinden TextViewOpened
en TextViewClosed
gebeurtenissen plaats.
Het editorserviceobject is een exemplaar van de EditorExtensibility
-klasse, waarmee realtime editorfunctionaliteit beschikbaar wordt gesteld, zoals het uitvoeren van tekstbewerkingen.
Opdrachten worden gestart door de gebruiker door te klikken op een item, dat u kunt plaatsen in een menu, contextmenu of werkbalk.
Een listener voor tekstweergave toevoegen
Er zijn twee soorten listeners, ITextViewChangedListener en ITextViewOpenClosedListener. Samen kunnen deze listeners worden gebruikt om het openen, sluiten en wijzigen van teksteditors te observeren.
Vervolgens maakt u een nieuwe klasse, implementeert u het ExtensionPart basisklasse en ITextViewChangedListener
, ITextViewOpenClosedListener
of beide en voegt u een VisualStudioContribution-kenmerk toe.
Implementeer vervolgens de eigenschap TextViewExtensionConfiguration, zoals vereist voor ITextViewChangedListener en ITextViewOpenClosedListener, waardoor de listener van toepassing is bij het bewerken van C#-bestanden:
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") },
};
De beschikbare documenttypen voor andere programmeertalen en bestandstypen worden vermeld verderop in dit artikelen aangepaste bestandstypen kunnen ook worden gedefinieerd wanneer dat nodig is.
Ervan uitgaande dat u besluit beide listeners te implementeren, moet de voltooide klassedeclaratie er als volgt uitzien:
[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") },
};
...
Aangezien zowel ITextViewOpenClosedListener als ITextViewChangedListener de eigenschap TextViewExtensionConfiguration declareren, is de configuratie van toepassing op beide listeners.
Wanneer u uw extensie uitvoert, ziet u het volgende:
- ITextViewOpenClosedListener.TextViewOpenedAsync wordt iedere keer dat een tekstweergave door de gebruiker wordt geopend, aangeroepen.
- ITextViewOpenClosedListener.TextViewClosedAsync wordt aangeroepen wanneer een tekstweergave door de gebruiker wordt gesloten.
- ITextViewChangedListener.TextViewChangedAsync telkens wanneer een gebruiker een tekstwijziging aanbrengt in een tekstdocument dat door een tekstweergave wordt weergegeven.
Elk van deze methoden wordt doorgegeven aan een ITextViewSnapshot met de status van de tekstweergave en het tekstdocument op het moment dat de gebruiker de actie heeft aangeroepen en een CancellationToken dat IsCancellationRequested == true
heeft wanneer de IDE een actie in behandeling wil annuleren.
Definiëren wanneer uw extensie relevant is
Uw extensie is doorgaans alleen relevant voor bepaalde ondersteunde documenttypen en -scenario's, en daarom is het belangrijk om de toepasbaarheid duidelijk te definiëren. U kunt AppliesTo-configuratie) op verschillende manieren gebruiken om de toepasbaarheid van een extensie duidelijk te definiëren. U kunt opgeven welke bestandstypen, zoals codetalen die de extensie ondersteunt, en/of de toepasselijkheid van een extensie verder verfijnen door te vergelijken met een patroon op basis van de bestandsnaam of het pad.
Programmeertalen opgeven met de configuration AppliesTo
De AppliesTo-configuratie geeft de programmeertaalscenario's aan waarin de extensie moet worden geactiveerd. Het is geschreven als AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") }
, waarbij het documenttype een bekende naam is van een taal die is ingebouwd in Visual Studio, of aangepast is gedefinieerd in een Visual Studio-extensie.
Sommige bekende documenttypen worden weergegeven in de volgende tabel:
DocumentType | Beschrijving |
---|---|
"CSharp" | C# |
"C/C++" | C, C++, headers en IDL |
"TypeScript" | TypeScript- en JavaScript-typetalen. |
"HTML" | HTML |
"JSON" | JSON |
"tekst" | Tekstbestanden, waaronder hiërarchische afstammelingen van 'code', die afstammen van 'tekst'. |
"code" | C, C++, C#, enzovoort. |
DocumentTypes zijn hiërarchisch. C# en C++ komen dus beide af van 'code', dus als u 'code' declareren, wordt uw extensie geactiveerd voor alle codetalen, C#, C, C++, enzovoort.
Een nieuw documenttype definiëren
U kunt een nieuw documenttype definiëren, bijvoorbeeld ter ondersteuning van een aangepaste codetaal, door een statische eigenschap DocumentTypeConfiguration toe te voegen aan elke klasse in het extensieproject en de eigenschap te markeren met het kenmerk VisualStudioContribution
.
DocumentTypeConfiguration
kunt u een nieuw documenttype definiëren, opgeven dat het een of meer andere documenttypen over neemt en een of meer bestandsextensies opgeven die worden gebruikt om het bestandstype te identificeren:
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,
};
}
Definities van documenttypen worden samengevoegd met inhoudstypedefinities die worden geleverd door verouderde Visual Studio-uitbreiding, waarmee u extra bestandsextensies kunt toewijzen aan bestaande documenttypen.
Documentkiezers
Naast DocumentFilter.FromDocumentTypekunt u DocumentFilter.FromGlobPattern de toepasselijkheid van de extensie verder beperken door deze alleen te activeren wanneer het bestandspad van het document overeenkomt met een glob-patroon (jokerteken):
[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),
},
};
De parameter pattern
vertegenwoordigt een glob-patroon dat overeenkomt met het absolute pad van het document.
Glob-patronen kunnen de volgende syntaxis hebben:
-
*
om nul of meer tekens in een padsegment te matchen -
?
om overeen te komen met één teken in een padsegment -
**
komt overeen met een willekeurig aantal padsegmenten, inclusief geen enkele -
{}
om voorwaarden te groeperen (bijvoorbeeld**/*.{ts,js}
overeenkomt met alle TypeScript- en JavaScript-bestanden) -
[]
om een bereik van tekens te declareren dat binnen een padsegment overeenkomt (bijvoorbeeldexample.[0-9]
metexample.0
,example.1
, ...) -
[!...]
om een reeks tekens te negeren in een padsegment (bijvoorbeeldexample.[!0-9]
om overeen te komen metexample.a
,example.b
, maar nietexample.0
)
Een backslash (\
) is niet geldig binnen een glob patroon. Zorg ervoor dat u een backslash in een slash converteert bij het maken van een glob-patroon.
Functionaliteit van access-editor
Uw editoruitbreidingsklassen nemen over van ExtensionPart-. De klasse ExtensionPart
maakt de eigenschap Extensibility beschikbaar. Met deze eigenschap kunt u een exemplaar van de EditorExtensibility-object aanvragen. U kunt dit object gebruiken om toegang te krijgen tot realtime editorfunctionaliteit, zoals het uitvoeren van bewerkingen.
EditorExtensibility editorService = this.Extensibility.Editor();
Toegang tot de bewerkingsstatus binnen een opdracht
ExecuteCommandAsync()
in elke Command
wordt een IClientContext
doorgegeven die een momentopname van de status van de IDE bevat op het moment dat de opdracht werd aangeroepen. U kunt het actieve document openen via de ITextViewSnapshot
-interface, die u van het EditorExtensibility
object ontvangt door de asynchrone methode aan te roepen GetActiveTextViewAsync
:
using ITextViewSnapshot textView = await this.Extensibility.Editor().GetActiveTextViewAsync(clientContext, cancellationToken);
Zodra u ITextViewSnapshot
hebt, hebt u toegang tot de editorstatus.
ITextViewSnapshot
is een onveranderbare weergave van de editorstatus op een bepaald moment, dus u moet de andere interfaces in het Editor-objectmodel gebruiken om wijzigingen aan te brengen.