Condividi tramite


Uso del testo nell'editor

Il codice di estensione può essere configurato per l'esecuzione in risposta a vari punti di ingresso (situazioni che si verificano quando un utente interagisce con Visual Studio). L'estendibilità dell'editor supporta attualmente tre punti di ingresso: ascoltatori, l'oggetto del servizio EditorExtensibility e comandi.

I listener di eventi vengono attivati quando si verificano determinate azioni in una finestra dell'editor, rappresentate nel codice da un TextView. Ad esempio, quando un utente digita qualcosa nell'editor, si verifica un evento TextViewChanged. Quando una finestra dell'editor viene aperta o chiusa, si verificano TextViewOpened e TextViewClosed eventi.

L'oggetto servizio editor è un'istanza della classe EditorExtensibility, che espone funzionalità dell'editor in tempo reale, ad esempio l'esecuzione di modifiche di testo.

comandi vengono avviati dall'utente facendo clic su un elemento, che è possibile posizionare su un menu, un menu di scelta rapida o una barra degli strumenti.

Aggiungere un listener per la visualizzazione del testo

Esistono due tipi di listener, ITextViewChangedListener e ITextViewOpenClosedListener. Insieme, questi listener possono essere usati per osservare l'apertura, la chiusura e la modifica degli editor di testo.

Creare quindi una nuova classe, implementare ExtensionPart classe base e ITextViewChangedListener, ITextViewOpenClosedListenero entrambi e aggiungere un attributo VisualStudioContribution.

Implementare quindi la proprietà TextViewExtensionConfiguration, come richiesto da ITextViewChangedListener e ITextViewOpenClosedListener, rendendo il listener applicabile durante la modifica dei file C#:

public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
    AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") },
};

I tipi di documento disponibili per altri linguaggi di programmazione e tipi di file sono elencati più avanti in questo articoloe i tipi di file personalizzati possono essere definiti anche quando necessario.

Supponendo di decidere di implementare entrambi i listener, la dichiarazione di classe completata dovrebbe essere simile alla seguente:

  [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") },
      };
      ...

Poiché sia ITextViewOpenClosedListener che ITextViewChangedListener dichiarano la proprietà TextViewExtensionConfiguration, la configurazione si applica a entrambi i listener.

Quando si esegue l'estensione, verrà visualizzato quanto illustrato di seguito:

Ognuno di questi metodi viene passato un ITextViewSnapshot contenente lo stato della visualizzazione testo e del documento di testo al momento in cui l'utente ha richiamato l'azione e un CancellationToken che avrà IsCancellationRequested == true quando l'IDE desidera annullare un'azione in sospeso.

Definire quando l'estensione è pertinente

L'estensione è in genere rilevante solo per determinati tipi e scenari di documento supportati ed è quindi importante definirne chiaramente l'applicabilità. È possibile utilizzare la configurazione AppliesTo) in diversi modi per definire chiaramente l'applicabilità di un'estensione. È possibile specificare i tipi di file, ad esempio i linguaggi di codice supportati dall'estensione, e/o perfezionare ulteriormente l'applicabilità di un'estensione associando un criterio in base al nome file o al percorso.

Specificare i linguaggi di programmazione con la configurazione AppliesTo

La configurazione AppliesTo indica gli scenari del linguaggio di programmazione in cui deve essere attivata l'estensione. Viene scritto come AppliesTo = new[] { DocumentFilter.FromDocumentType("CSharp") }, dove il tipo di documento è un nome noto di un linguaggio incorporato in Visual Studio o personalizzato definito in un'estensione di Visual Studio.

Nella tabella seguente sono illustrati alcuni tipi di documenti noti:

TipoDocumento Descrizione
"CSharp" C#
"C/C++" C, C++, intestazioni e IDL
"TypeScript" Linguaggi di tipo TypeScript e JavaScript.
"HTML" HTML
"JSON" JSON
testo File di testo, inclusi discendenti gerarchici di "codice", che derivano da "text".
codice C, C++, C# e così via.

I DocumentType sono gerarchici. Ovvero, C# e C++ derivano entrambi da "codice", quindi la dichiarazione di "codice" fa sì che l'estensione venga attivata per tutti i linguaggi di codice, C#, C, C++ e così via.

Definire un nuovo tipo di documento

È possibile definire un nuovo tipo di documento, ad esempio per supportare un linguaggio di codice personalizzato, aggiungendo una proprietà statica DocumentTypeConfiguration a qualsiasi classe nel progetto di estensione e contrassegnando la proprietà con l'attributo VisualStudioContribution.

DocumentTypeConfiguration consente di definire un nuovo tipo di documento, specificare che eredita uno o più tipi di documento e specificare una o più estensioni di file utilizzate per identificare il tipo di file:

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,
    };
}

Le definizioni dei tipi di documento vengono unite con le definizioni dei tipi di contenuto fornite dall'estendibilità legacy di Visual Studio, che consente di eseguire il mapping di estensioni di file aggiuntive ai tipi di documento esistenti.

Selettori di documenti

Oltre a DocumentFilter.FromDocumentType, DocumentFilter.FromGlobPattern consente di limitare ulteriormente l'applicabilità dell'estensione attivandola solo quando il percorso del file del documento corrisponde a un modello GLOB (con caratteri jolly):

[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),
        },
    };

Il parametro pattern rappresenta un modello GLOB corrispondente al percorso assoluto del documento.

I modelli Glob possono avere la sintassi seguente:

  • * per utilizzare zero o più caratteri in un segmento di percorso
  • ? per corrispondere a un carattere in un segmento di percorso
  • ** per corrispondere a qualsiasi numero di segmenti di percorso, inclusi nessuno
  • {} a raggruppare le condizioni (ad esempio, **​/*.{ts,js} corrisponde a tutti i file TypeScript e JavaScript)
  • [] dichiarare una gamma di caratteri da corrispondere a un segmento di percorso (ad esempio, example.[0-9] per corrispondere a example.0, example.1, …)
  • [!...] per negare un intervallo di caratteri in un segmento di percorso (ad esempio, example.[!0-9] per trovare una corrispondenza con example.a, example.b, ma non con example.0)

Una barra rovesciata (\) non è valida all'interno di un modello glob. Assicurarsi di convertire qualsiasi barra rovesciata in barra obliqua durante la creazione del modello glob.

Accedi alla funzionalità dell'editor

Le classi di estensioni dell'editor ereditano da ExtensionPart. La classe ExtensionPart espone la proprietà Extensibility. Usando questa proprietà, è possibile richiedere un'istanza dell'oggetto EditorExtensibility. È possibile usare questo oggetto per accedere alle funzionalità dell'editor in tempo reale, ad esempio l'esecuzione di modifiche.

EditorExtensibility editorService = this.Extensibility.Editor();

Accedere allo stato dell'editor all'interno di un comando

ExecuteCommandAsync() in ogni Command viene passato un IClientContext che contiene un'istantanea dello stato dell'IDE quando è stato richiamato il comando. È possibile accedere al documento attivo tramite l'interfaccia ITextViewSnapshot, ottenuta dall'oggetto EditorExtensibility chiamando il metodo asincrono GetActiveTextViewAsync:

using ITextViewSnapshot textView = await this.Extensibility.Editor().GetActiveTextViewAsync(clientContext, cancellationToken);

Una volta che hai ITextViewSnapshot, è possibile accedere allo stato dell'editor. ITextViewSnapshot è una visualizzazione non modificabile dello stato dell'editor in un momento specifico, quindi è necessario usare le altre interfacce nel modello a oggetti dell'editor per apportare modifiche.