Compartir vía


Tutorial: Mostrar información sobre herramientas de QuickInfo

QuickInfo es una característica de IntelliSense que muestra las firmas y descripciones del método cuando un usuario mueve el puntero sobre un nombre de método. Puede implementar características basadas en lenguaje, como QuickInfo, definiendo los identificadores para los que desea proporcionar descripciones de QuickInfo y, a continuación, creando una información sobre herramientas en la que mostrar el contenido. Puede definir QuickInfo en el contexto de un servicio de lenguaje, o puede definir su propia extensión de nombre de archivo y tipo de contenido y mostrar QuickInfo solo para ese tipo, o puede mostrar QuickInfo para un tipo de contenido existente (como "texto"). En este tutorial se muestra cómo mostrar QuickInfo para el tipo de contenido "text".

El ejemplo QuickInfo de este tutorial muestra la información sobre herramientas cuando un usuario mueve el puntero sobre un nombre de método. Este diseño requiere que implemente estas cuatro interfaces:

  • interfaz de origen

  • interfaz del proveedor de origen

  • interfaz del controlador

  • interfaz del proveedor de controlador

    Los proveedores de controladores y de origen son componentes de Managed Extensibility Framework (MEF) y son responsables de exportar las clases de origen y controlador e importar servicios y agentes como ITextBufferFactoryService, que crea el búfer de texto de información sobre herramientas y , IQuickInfoBrokerque desencadena la sesión quickInfo.

    En este ejemplo, el origen quickInfo usa una lista codificada de forma rígida de nombres y descripciones de métodos, pero en implementaciones completas, el servicio de lenguaje y la documentación del lenguaje son responsables de proporcionar ese contenido.

Creación de un proyecto MEF

Para crear un nuevo proyecto de MEF

  1. Cree un proyecto VSIX de C#. (En Cuadro de diálogo Nuevo proyecto , seleccione Visual C# / Extensibilidad y, después , Proyecto VSIX). Asigne un nombre a la solución QuickInfoTest.

  2. Agregue una plantilla de elemento clasificador del editor al proyecto. Para obtener más información, vea Creación de una extensión con una plantilla de elemento de editor.

  3. Elimine los archivos de clase existentes.

Implementación del origen quickInfo

El origen quickInfo es responsable de recopilar el conjunto de identificadores y sus descripciones y agregar el contenido al búfer de texto de información sobre herramientas cuando se encuentra uno de los identificadores. En este ejemplo, los identificadores y sus descripciones solo se agregan en el constructor de origen.

Para implementar el origen de QuickInfo

  1. Agregue un archivo de clase y asígnele el nombre TestQuickInfoSource.

  2. Agregue una referencia a Microsoft.VisualStudio.Language.IntelliSense.

  3. Agregue las importaciones siguientes.

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Language.Intellisense;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Text.Operations;
    using Microsoft.VisualStudio.Text.Tagging;
    using Microsoft.VisualStudio.Utilities;
    
  4. Declare una clase que implemente IQuickInfoSourcey asígne el TestQuickInfoSourcenombre .

    internal class TestQuickInfoSource : IQuickInfoSource
    
  5. Agregue campos para el proveedor de origen QuickInfo, el búfer de texto y un conjunto de nombres de método y firmas de método. En este ejemplo, los nombres de método y las firmas se inicializan en el TestQuickInfoSource constructor.

    private TestQuickInfoSourceProvider m_provider;
    private ITextBuffer m_subjectBuffer;
    private Dictionary<string, string> m_dictionary;
    
  6. Agregue un constructor que establezca el proveedor de origen QuickInfo y el búfer de texto, y rellene el conjunto de nombres de método y las firmas y descripciones del método.

    public TestQuickInfoSource(TestQuickInfoSourceProvider provider, ITextBuffer subjectBuffer)
    {
        m_provider = provider;
        m_subjectBuffer = subjectBuffer;
    
        //these are the method names and their descriptions
        m_dictionary = new Dictionary<string, string>();
        m_dictionary.Add("add", "int add(int firstInt, int secondInt)\nAdds one integer to another.");
        m_dictionary.Add("subtract", "int subtract(int firstInt, int secondInt)\nSubtracts one integer from another.");
        m_dictionary.Add("multiply", "int multiply(int firstInt, int secondInt)\nMultiplies one integer by another.");
        m_dictionary.Add("divide", "int divide(int firstInt, int secondInt)\nDivides one integer by another.");
    }
    
  7. Implemente el método AugmentQuickInfoSession. En este ejemplo, el método busca la palabra actual o la palabra anterior si el cursor está al final de una línea o un búfer de texto. Si la palabra es uno de los nombres de método, la descripción de ese nombre de método se agrega al contenido quickInfo.

    public void AugmentQuickInfoSession(IQuickInfoSession session, IList<object> qiContent, out ITrackingSpan applicableToSpan)
    {
        // Map the trigger point down to our buffer.
        SnapshotPoint? subjectTriggerPoint = session.GetTriggerPoint(m_subjectBuffer.CurrentSnapshot);
        if (!subjectTriggerPoint.HasValue)
        {
            applicableToSpan = null;
            return;
        }
    
        ITextSnapshot currentSnapshot = subjectTriggerPoint.Value.Snapshot;
        SnapshotSpan querySpan = new SnapshotSpan(subjectTriggerPoint.Value, 0);
    
        //look for occurrences of our QuickInfo words in the span
        ITextStructureNavigator navigator = m_provider.NavigatorService.GetTextStructureNavigator(m_subjectBuffer);
        TextExtent extent = navigator.GetExtentOfWord(subjectTriggerPoint.Value);
        string searchText = extent.Span.GetText();
    
        foreach (string key in m_dictionary.Keys)
        {
            int foundIndex = searchText.IndexOf(key, StringComparison.CurrentCultureIgnoreCase);
            if (foundIndex > -1)
            {
                applicableToSpan = currentSnapshot.CreateTrackingSpan
                    (
                    //querySpan.Start.Add(foundIndex).Position, 9, SpanTrackingMode.EdgeInclusive
                                            extent.Span.Start + foundIndex, key.Length, SpanTrackingMode.EdgeInclusive
                    );
    
                string value;
                m_dictionary.TryGetValue(key, out value);
                if (value != null)
                    qiContent.Add(value);
                else
                    qiContent.Add("");
    
                return;
            }
        }
    
        applicableToSpan = null;
    }
    
  8. También debe implementar un método Dispose(), ya que IQuickInfoSource implementa IDisposable:

    private bool m_isDisposed;
    public void Dispose()
    {
        if (!m_isDisposed)
        {
            GC.SuppressFinalize(this);
            m_isDisposed = true;
        }
    }
    

Implementación de un proveedor de origen quickInfo

El proveedor del origen QuickInfo sirve principalmente para exportarse como parte de componente MEF y crear instancias del origen quickInfo. Dado que es una parte de componente MEF, puede importar otras partes de componentes MEF.

Para implementar un proveedor de origen quickInfo

  1. Declare un proveedor de origen quickInfo denominado TestQuickInfoSourceProvider que implementa IQuickInfoSourceProvidery lo exporte con un NameAttribute de "Origen de quickInfo de información sobre herramientas", un OrderAttribute de Before="default" y un ContentTypeAttribute de "text".

    [Export(typeof(IQuickInfoSourceProvider))]
    [Name("ToolTip QuickInfo Source")]
    [Order(Before = "Default Quick Info Presenter")]
    [ContentType("text")]
    internal class TestQuickInfoSourceProvider : IQuickInfoSourceProvider
    
  2. Importe dos servicios de editor y ITextStructureNavigatorSelectorService ITextBufferFactoryService, como propiedades de TestQuickInfoSourceProvider.

    [Import]
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
    
    [Import]
    internal ITextBufferFactoryService TextBufferFactoryService { get; set; }
    
  3. Implemente TryCreateQuickInfoSource para devolver un nuevo TestQuickInfoSource.

    public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer)
    {
        return new TestQuickInfoSource(this, textBuffer);
    }
    

Implementación de un controlador QuickInfo

Los controladores QuickInfo determinan cuándo se muestra QuickInfo. En este ejemplo, QuickInfo aparece cuando el puntero está sobre una palabra que corresponde a uno de los nombres de método. El controlador QuickInfo implementa un controlador de eventos de puntero del mouse que desencadena una sesión de QuickInfo.

Para implementar un controlador QuickInfo

  1. Declare una clase que implemente IIntellisenseControllery asígne el TestQuickInfoControllernombre .

    internal class TestQuickInfoController : IIntellisenseController
    
  2. Agregue campos privados para la vista de texto, los búferes de texto representados en la vista de texto, la sesión QuickInfo y el proveedor del controlador QuickInfo.

    private ITextView m_textView;
    private IList<ITextBuffer> m_subjectBuffers;
    private TestQuickInfoControllerProvider m_provider;
    private IQuickInfoSession m_session;
    
  3. Agregue un constructor que establezca los campos y agregue el controlador de eventos de puntero del mouse.

    internal TestQuickInfoController(ITextView textView, IList<ITextBuffer> subjectBuffers, TestQuickInfoControllerProvider provider)
    {
        m_textView = textView;
        m_subjectBuffers = subjectBuffers;
        m_provider = provider;
    
        m_textView.MouseHover += this.OnTextViewMouseHover;
    }
    
  4. Agregue el controlador de eventos de puntero del mouse que desencadena la sesión QuickInfo.

    private void OnTextViewMouseHover(object sender, MouseHoverEventArgs e)
    {
        //find the mouse position by mapping down to the subject buffer
        SnapshotPoint? point = m_textView.BufferGraph.MapDownToFirstMatch
             (new SnapshotPoint(m_textView.TextSnapshot, e.Position),
            PointTrackingMode.Positive,
            snapshot => m_subjectBuffers.Contains(snapshot.TextBuffer),
            PositionAffinity.Predecessor);
    
        if (point != null)
        {
            ITrackingPoint triggerPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position,
            PointTrackingMode.Positive);
    
            if (!m_provider.QuickInfoBroker.IsQuickInfoActive(m_textView))
            {
                m_session = m_provider.QuickInfoBroker.TriggerQuickInfo(m_textView, triggerPoint, true);
            }
        }
    }
    
  5. Implemente el Detach método para que quite el controlador de eventos del mouse cuando el controlador se desasocie de la vista de texto.

    public void Detach(ITextView textView)
    {
        if (m_textView == textView)
        {
            m_textView.MouseHover -= this.OnTextViewMouseHover;
            m_textView = null;
        }
    }
    
  6. Implemente el ConnectSubjectBuffer método y el DisconnectSubjectBuffer método como métodos vacíos para este ejemplo.

    public void ConnectSubjectBuffer(ITextBuffer subjectBuffer)
    {
    }
    
    public void DisconnectSubjectBuffer(ITextBuffer subjectBuffer)
    {
    }
    

Implementación del proveedor del controlador QuickInfo

El proveedor del controlador QuickInfo sirve principalmente para exportarse como parte de componente MEF y crear instancias del controlador QuickInfo. Dado que es una parte de componente MEF, puede importar otras partes de componentes MEF.

Para implementar el proveedor del controlador QuickInfo

  1. Declare una clase denominada TestQuickInfoControllerProvider que implementa IIntellisenseControllerProvidery expórtela con un NameAttribute elemento de "Controlador quickInfo de información sobre herramientas" y un ContentTypeAttribute de "texto":

    [Export(typeof(IIntellisenseControllerProvider))]
    [Name("ToolTip QuickInfo Controller")]
    [ContentType("text")]
    internal class TestQuickInfoControllerProvider : IIntellisenseControllerProvider
    
  2. Importe el IQuickInfoBroker como una propiedad.

    [Import]
    internal IQuickInfoBroker QuickInfoBroker { get; set; }
    
  3. Implemente el método mediante la TryCreateIntellisenseController creación de instancias del controlador QuickInfo.

    public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList<ITextBuffer> subjectBuffers)
    {
        return new TestQuickInfoController(textView, subjectBuffers, this);
    }
    

Compilación y prueba del código

Para probar este código, compile la solución QuickInfoTest y ejecútela en la instancia experimental.

Para compilar y probar la solución QuickInfoTest

  1. Compile la solución.

  2. Al ejecutar este proyecto en el depurador, se inicia una segunda instancia de Visual Studio.

  3. Cree un archivo de texto y escriba algún texto que incluya las palabras "agregar" y "restar".

  4. Mueva el puntero sobre una de las apariciones de "add". Se debe mostrar la firma y la descripción del add método.