Compartilhar via


Estender os documentos do Visual Studio

Um documento é a representação na memória de um arquivo que é aberto no Visual Studio. É referido pelo apelido, que é um uso absoluto Uri do file:// esquema. Um documento é representado pela DocumentSnapshot classe, que tem as seguintes propriedades:

  • Moniker
  • IsDirty
  • IsReadOnly
  • IsInitialized

O DocumentsExtensibility objeto fornece vários métodos que são usados para obter e trabalhar com DocumentSnapshot instâncias de objeto.

Trabalhar com documentos

Este guia foi criado para cobrir os principais cenários de usuário ao trabalhar com documentos:

Abrir um documento

Dado o caminho para um arquivo no disco, é simples abrir o arquivo no Visual Studio:

DocumentsExtensibility documents = this.Extensibility.Documents();

Uri uri = new Uri(@"C:\path\to\Class1.cs", UriKind.Absolute);
DocumentSnapshot document = await documents.OpenDocumentAsync(uri, cancellationToken);

// optionally do something with the document

Obter um instantâneo de documento de texto

A DocumentSnapshot é uma representação abstrata de um documento. Se você quiser ler ou escrever o texto em um DocumentSnapshot, você pode fazê-lo usando a ITextDocumentSnapshot interface, que pode ser obtida com o método de AsTextDocumentAsync extensão para DocumentSnapshot.

public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
    DocumentsExtensibility documents = this.Extensibility.Documents();

    Uri moniker = await context.GetSelectedPathAsync(cancellationToken);
    DocumentSnapshot document = await documents.GetDocumentAsync(moniker, cancellationToken);
    ITextDocumentSnapshot snapshot = await document.AsTextDocumentAsync(this.Extensibility, cancellationToken);

    // insert the current date/time
    EditorExtensibility editor = this.Extensibility.Editor();
    using ITextViewSnapshot textView = await context.GetActiveTextViewAsync(cancellationToken);

    await editor.EditAsync(
        batch => snapshot.AsEditable(batch).Replace(textView.Selection.Extent, DateTime.Now.ToString()),
        cancellationToken);
}

Há cenários em que os componentes podem querer reagir a eventos relacionados a documentos (ou seja, quando eles são abertos, fechados ou salvos). Isso pode ser feito implementando a interface e usando DocumentsExtensibility.SubscribeAsync para configurar a IDocumentEventsListener assinatura do evento.

internal sealed class SubscribeCommand : Command, IToggleCommand
{
    private IDisposable? subscription;

    bool? IToggleCommand.IsChecked => this.subscription is not null;

    public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
    {
        if (this.subscription is null)
        {
            // subscribe for events
            this.subscription = await Subscription.CreateInstanceAsync(this.Extensibility, cancellationToken);
        }
        else
        {
            // remove the event subscription
            this.subscription.Dispose();
            this.subscription = null;
        }

        this.OnPropertyChanged(new PropertyChangedEventArgs(nameof(IToggleCommand.IsChecked)));
    }

    private class Subscription : IDisposable, IDocumentEventsListener
    {
        private readonly OutputWindowExtensibility output;
        private IDisposable? rawSubscription;

        private Subscription(VisualStudioExtensibility extensibility)
        {
            this.output = extensibility.Views().Output;
        }

        public static async Task<Subscription> CreateInstanceAsync(
            VisualStudioExtensibility extensibility,
            CancellationToken cancellationToken)
        {
            var subscription = new Subscription(extensibility);

            DocumentsExtensibility documents = extensibility.Documents();
            subscription.rawSubscription = await documents.SubscribeAsync(subscription, filterRegex: null, cancellationToken);

            return subscription;
        }

        public void Dispose()
        {
            this.rawSubscription?.Dispose();
            this.rawSubscription = null;
        }

        Task IDocumentEventsListener.ClosedAsync(DocumentEventArgs e, CancellationToken token)
        {
            string text = $"IDocumentEventsListener.ClosedAsync ({e.Moniker})";
            return this.OutputEventTextAsync(text, token);
        }

        Task IDocumentEventsListener.HiddenAsync(DocumentEventArgs e, CancellationToken token)
        {
            string text = $"IDocumentEventsListener.HiddenAsync ({e.Moniker})";
            return this.OutputEventTextAsync(text, token);
        }

        Task IDocumentEventsListener.OpenedAsync(DocumentEventArgs e, CancellationToken token)
        {
            string text = $"IDocumentEventsListener.OpenedAsync ({e.Moniker})";
            return this.OutputEventTextAsync(text, token);
        }

        Task IDocumentEventsListener.RenamedAsync(RenamedDocumentEventArgs e, CancellationToken token)
        {
            string text = $"IDocumentEventsListener.RenamedAsync ({e.OldMoniker} -> {e.Moniker})";
            return this.OutputEventTextAsync(text, token);
        }

        Task IDocumentEventsListener.SavedAsync(DocumentEventArgs e, CancellationToken token)
        {
            string text = $"IDocumentEventsListener.SavedAsync ({e.Moniker})";
            return this.OutputEventTextAsync(text, token);
        }

        Task IDocumentEventsListener.SavingAsync(DocumentEventArgs e, CancellationToken token)
        {
            string text = $"IDocumentEventsListener.SavingAsync ({e.Moniker})";
            return this.OutputEventTextAsync(text, token);
        }

        Task IDocumentEventsListener.ShownAsync(DocumentEventArgs e, CancellationToken token)
        {
            string text = $"IDocumentEventsListener.ShownAsync ({e.Moniker})";
            return this.OutputEventTextAsync(text, token);
        }

        private async Task OutputEventTextAsync(string text, CancellationToken token)
        {
            using OutputWindow outputWindow = await this.output.GetChannelAsync(
                identifier: "Document Sample Command Output",
                displayNameResourceId: nameof(Strings.DocumentsSampleOutputWindowPaneName),
                token);

            await outputWindow.Writer.WriteLineAsync($"Event received: {text}");
        }
    }
}

Próximas etapas

  • Siga o guia de início rápido para criar o projeto na seção Introdução.