Aracılığıyla paylaş


İzlenecek yol: Deyim tamamlamayı görüntüleme

Tamamlama sağlamak istediğiniz tanımlayıcıları tanımlayıp bir tamamlama oturumu tetikleyerek dil tabanlı deyim tamamlama uygulayabilirsiniz. Deyim tamamlama işlemini bir dil hizmeti bağlamında tanımlayabilir, kendi dosya adı uzantınızı ve içerik türünüzü tanımlayabilir ve ardından yalnızca bu tür için tamamlama işlemini görüntüleyebilirsiniz. Alternatif olarak, var olan bir içerik türü için tamamlanmayı tetikleyebilirsiniz; örneğin, "düz metin". Bu kılavuzda, metin dosyalarının içerik türü olan "düz metin" içerik türü için deyim tamamlamanın nasıl tetiklendiği gösterilir. "Metin" içerik türü, kod ve XML dosyaları da dahil olmak üzere diğer tüm içerik türlerinin atasıdır.

Deyim tamamlama işlemi genellikle belirli karakterler yazılarak tetikler; örneğin, "using" gibi bir tanımlayıcının başlangıcı yazılarak. Seçim yapmak için genellikle Ara Çubuğu, Sekme veya Enter tuşuna basılarak kapatılır. Tuş vuruşları ( IOleCommandTarget arabirim) için bir komut işleyicisi ve arabirimi uygulayan IVsTextViewCreationListener bir işleyici sağlayıcısı kullanarak karakter yazarken tetikleyen IntelliSense özelliklerini uygulayabilirsiniz. Tamamlamaya katılan tanımlayıcıların listesi olan tamamlanma kaynağını oluşturmak için arabirimini ve bir tamamlama kaynağı sağlayıcısını (ICompletionSourceProviderarabirim) uygulayınICompletionSource. Sağlayıcılar Yönetilen Genişletilebilirlik Çerçevesi (MEF) bileşen parçalarıdır. Kaynak ve denetleyici sınıflarını dışarı aktarmak ve hizmetleri ve aracıları içeri aktarmak, örneğin, metin arabelleğinde gezinmeyi ITextStructureNavigatorSelectorServiceetkinleştiren ve ICompletionBrokertamamlama oturumunu tetikleyen ' den sorumludur.

Bu izlenecek yol, sabit kodlanmış bir tanımlayıcı kümesi için deyim tamamlamanın nasıl uygulandığını gösterir. Tam uygulamalarda, dil hizmeti ve dil belgeleri bu içeriği sağlamakla sorumludur.

MEF Projesi Oluşturma

MEF projesi oluşturmak için

  1. C# VSIX projesi oluşturun. (Yeni Proje iletişim kutusu, Visual C# / Genişletilebilirlik'i ve ardından VSIX Projesi'ni seçin.) Çözümü CompletionTestolarak adlandırın.

  2. Projeye bir Düzenleyici Sınıflandırıcısı öğesi şablonu ekleyin. Daha fazla bilgi için bkz . Düzenleyici öğesi şablonuyla uzantı oluşturma.

  3. Varolan sınıf dosyalarını silin.

  4. Projeye aşağıdaki başvuruları ekleyin ve CopyLocal öğesinin olarak falseayarlandığından emin olun:

    Microsoft.VisualStudio.Editor

    Microsoft.VisualStudio.Language.Intellisense

    Microsoft.visualstudio.ole

    Microsoft.VisualStudio.Shell.15.0

    Microsoft.VisualStudio.Shell.Immutable.10.0

    Microsoft.VisualStudio.TextManager.Interop

Tamamlanma kaynağını uygulama

Kullanıcı bir tanımlayıcının ilk harfleri gibi bir tamamlama tetikleyicisi yazdığında, tamamlanma kaynağı tanımlayıcı kümesini toplamak ve içeriği tamamlama penceresine eklemekle sorumludur. Bu örnekte, tanımlayıcılar ve açıklamaları yönteminde AugmentCompletionSession sabit kodlanmıştır. Gerçek dünya kullanımlarının çoğunda, tamamlama listesini doldurmak için belirteçleri almak için dilinizin ayrıştırıcısını kullanırsınız.

Tamamlanma kaynağını uygulamak için

  1. Bir sınıf dosyası ekleyin ve adını verin TestCompletionSource.

  2. Şu içeri aktarmaları ekleyin:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Language.Intellisense;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Operations;
    using Microsoft.VisualStudio.Utilities;
    
  3. için sınıf bildirimini TestCompletionSource , uygulamasının gerçekleştirileceği ICompletionSourceşekilde değiştirin:

    internal class TestCompletionSource : ICompletionSource
    
  4. Kaynak sağlayıcı, metin arabelleği ve nesne listesi Completion (tamamlama oturumuna katılacak tanımlayıcılara karşılık gelen) için özel alanlar ekleyin:

    private TestCompletionSourceProvider m_sourceProvider;
    private ITextBuffer m_textBuffer;
    private List<Completion> m_compList;
    
  5. Kaynak sağlayıcıyı ve arabelleği ayarlayan bir oluşturucu ekleyin. sınıfı TestCompletionSourceProvider sonraki adımlarda tanımlanır:

    public TestCompletionSource(TestCompletionSourceProvider sourceProvider, ITextBuffer textBuffer)
    {
        m_sourceProvider = sourceProvider;
        m_textBuffer = textBuffer;
    }
    
  6. Bağlam içinde AugmentCompletionSession sağlamak istediğiniz tamamlamaları içeren bir tamamlama kümesi ekleyerek yöntemini uygulayın. Her tamamlama kümesi bir tamamlama kümesi Completion içerir ve tamamlama penceresinin bir sekmesine karşılık gelir. (Visual Basic projelerinde tamamlama penceresi sekmelerinin adı Ortak ve Tümü.) FindTokenSpanAtPosition yöntemi bir sonraki adımda tanımlanır.

    void ICompletionSource.AugmentCompletionSession(ICompletionSession session, IList<CompletionSet> completionSets)
    {
        List<string> strList = new List<string>();
        strList.Add("addition");
        strList.Add("adaptation");
        strList.Add("subtraction");
        strList.Add("summation");
        m_compList = new List<Completion>();
        foreach (string str in strList)
            m_compList.Add(new Completion(str, str, str, null, null));
    
        completionSets.Add(new CompletionSet(
            "Tokens",    //the non-localized title of the tab
            "Tokens",    //the display title of the tab
            FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                session),
            m_compList,
            null));
    }
    
  7. İmlecin konumundan geçerli sözcüğü bulmak için aşağıdaki yöntem kullanılır:

    private ITrackingSpan FindTokenSpanAtPosition(ITrackingPoint point, ICompletionSession session)
    {
        SnapshotPoint currentPoint = (session.TextView.Caret.Position.BufferPosition) - 1;
        ITextStructureNavigator navigator = m_sourceProvider.NavigatorService.GetTextStructureNavigator(m_textBuffer);
        TextExtent extent = navigator.GetExtentOfWord(currentPoint);
        return currentPoint.Snapshot.CreateTrackingSpan(extent.Span, SpanTrackingMode.EdgeInclusive);
    }
    
  8. Dispose() Yöntemini uygulayın:

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

Tamamlanma kaynağı sağlayıcısını uygulama

Tamamlanma kaynağı sağlayıcısı, tamamlanma kaynağının örneğini oluşturan MEF bileşen bölümüdür.

Tamamlanma kaynağı sağlayıcısını uygulamak için

  1. uygulayan ICompletionSourceProvideradlı TestCompletionSourceProvider bir sınıf ekleyin. Bu sınıfı "düz metin" ve NameAttribute "test tamamlama" ile ContentTypeAttribute dışarı aktarın.

    [Export(typeof(ICompletionSourceProvider))]
    [ContentType("plaintext")]
    [Name("token completion")]
    internal class TestCompletionSourceProvider : ICompletionSourceProvider
    
  2. Tamamlanma kaynağındaki geçerli sözcüğü bulan bir ITextStructureNavigatorSelectorServiceöğesini içeri aktarın.

    [Import]
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
    
  3. TryCreateCompletionSource Tamamlanma kaynağının örneğini görüntülemek için yöntemini uygulayın.

    public ICompletionSource TryCreateCompletionSource(ITextBuffer textBuffer)
    {
        return new TestCompletionSource(this, textBuffer);
    }
    

Tamamlama komut işleyici sağlayıcısını uygulama

Tamamlama komut işleyicisi sağlayıcısı, bir IVsTextViewCreationListenermetin görünümü oluşturma olayını dinleyen ve bir görünümünden görünümü dönüştüren (komutun Visual Studio kabuğunun komut zincirine eklenmesini sağlayan) 'ITextViewden IVsTextViewtüretilir. Bu sınıf bir MEF dışarı aktarması olduğundan, komut işleyicisinin kendisi için gerekli olan hizmetleri içeri aktarmak için de kullanabilirsiniz.

Tamamlama komut işleyici sağlayıcısını uygulamak için

  1. adlı TestCompletionCommandHandlerbir dosya ekleyin.

  2. Bunları kullanarak yönergelerini ekleyin:

    using System;
    using System.ComponentModel.Composition;
    using System.Runtime.InteropServices;
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.Editor;
    using Microsoft.VisualStudio.Language.Intellisense;
    using Microsoft.VisualStudio.OLE.Interop;
    using Microsoft.VisualStudio.Shell;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.TextManager.Interop;
    using Microsoft.VisualStudio.Utilities;
    
  3. uygulayan IVsTextViewCreationListeneradlı TestCompletionHandlerProvider bir sınıf ekleyin. Bu sınıfı bir "belirteç tamamlama işleyicisi", "ContentTypeAttributedüz metin" ve bir TextViewRoleAttribute ile dışarı NameAttribute aktarınEditable.

    [Export(typeof(IVsTextViewCreationListener))]
    [Name("token completion handler")]
    [ContentType("plaintext")]
    [TextViewRole(PredefinedTextViewRoles.Editable)]
    internal class TestCompletionHandlerProvider : IVsTextViewCreationListener
    
  4. IVsEditorAdaptersFactoryServicestandart Visual Studio hizmetlerine erişim sağlayan bir IVsTextView ' den , ve ICompletionBrokerSVsServiceProvider 'ye ITextViewdönüştürmeyi etkinleştiren öğesini içeri aktarın.

    [Import]
    internal IVsEditorAdaptersFactoryService AdapterService = null;
    [Import]
    internal ICompletionBroker CompletionBroker { get; set; }
    [Import]
    internal SVsServiceProvider ServiceProvider { get; set; }
    
  5. Komut işleyicisini VsTextViewCreated örneklemek için yöntemini uygulayın.

    public void VsTextViewCreated(IVsTextView textViewAdapter)
    {
        ITextView textView = AdapterService.GetWpfTextView(textViewAdapter);
        if (textView == null)
            return;
    
        Func<TestCompletionCommandHandler> createCommandHandler = delegate() { return new TestCompletionCommandHandler(textViewAdapter, textView, this); };
        textView.Properties.GetOrCreateSingletonProperty(createCommandHandler);
    }
    

Tamamlama komut işleyicisini uygulama

Deyim tamamlama tuş vuruşları tarafından tetiklendiğinden, tamamlama oturumunu IOleCommandTarget tetikleyen, işleyen ve kapatan tuş vuruşlarını almak ve işlemek için arabirimini uygulamanız gerekir.

Tamamlama komut işleyicisini uygulamak için

  1. uygulayan IOleCommandTargetadlı TestCompletionCommandHandler bir sınıf ekleyin:

    internal class TestCompletionCommandHandler : IOleCommandTarget
    
  2. Sonraki komut işleyicisi (komutu geçirdiğiniz), metin görünümü, komut işleyici sağlayıcısı (çeşitli hizmetlere erişimi etkinleştirir) ve bir tamamlama oturumu için özel alanlar ekleyin:

    private IOleCommandTarget m_nextCommandHandler;
    private ITextView m_textView;
    private TestCompletionHandlerProvider m_provider;
    private ICompletionSession m_session;
    
  3. Metin görünümünü ve sağlayıcı alanlarını ayarlayan ve komutu komut zincirine ekleyen bir oluşturucu ekleyin:

    internal TestCompletionCommandHandler(IVsTextView textViewAdapter, ITextView textView, TestCompletionHandlerProvider provider)
    {
        this.m_textView = textView;
        this.m_provider = provider;
    
        //add the command to the command chain
        textViewAdapter.AddCommandFilter(this, out m_nextCommandHandler);
    }
    
  4. QueryStatus komutunu geçirerek yöntemini uygulayın:

    public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
    {
        return m_nextCommandHandler.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
    }
    
  5. Exec yöntemini uygulayın. Bu yöntem bir tuş vuruşu aldığında aşağıdakilerden birini yapmalıdır:

    • Karakterin arabelleğe yazılmasına izin verin ve ardından tamamlanmayı tetikleyin veya filtreleyin. (Yazdırma karakterleri bunu yapar.)

    • Tamamlama işlemini gerçekleştirin, ancak karakterin arabelleğe yazılmasına izin verme. (Boşluk, Sekme tuşuna basın ve Bir tamamlama oturumu görüntülendiğinde Enter bunu yapın.)

    • Komutun sonraki işleyiciye geçirilmesine izin verin. (Diğer tüm komutlar.)

      Bu yöntem kullanıcı arabirimini görüntüleyebileceğinden, otomasyon bağlamında çağrılmadığından emin olmak için çağrısı IsInAutomationFunction yapın:

      public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
      {
          if (VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider))
          {
              return m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
          }
          //make a copy of this so we can look at it after forwarding some commands
          uint commandID = nCmdID;
          char typedChar = char.MinValue;
          //make sure the input is a char before getting it
          if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR)
          {
              typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn);
          }
      
          //check for a commit character
          if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN
              || nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB
              || (char.IsWhiteSpace(typedChar) || char.IsPunctuation(typedChar)))
          {
              //check for a selection
              if (m_session != null && !m_session.IsDismissed)
              {
                  //if the selection is fully selected, commit the current session
                  if (m_session.SelectedCompletionSet.SelectionStatus.IsSelected)
                  {
                      m_session.Commit();
                      //also, don't add the character to the buffer
                      return VSConstants.S_OK;
                  }
                  else
                  {
                      //if there is no selection, dismiss the session
                      m_session.Dismiss();
                  }
              }
          }
      
          //pass along the command so the char is added to the buffer
          int retVal = m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
          bool handled = false;
          if (!typedChar.Equals(char.MinValue) && char.IsLetterOrDigit(typedChar))
          {
              if (m_session == null || m_session.IsDismissed) // If there is no active session, bring up completion
              {
                  this.TriggerCompletion();
                  m_session.Filter();
              }
              else    //the completion session is already active, so just filter
              {
                  m_session.Filter();
              }
              handled = true;
          }
          else if (commandID == (uint)VSConstants.VSStd2KCmdID.BACKSPACE   //redo the filter if there is a deletion
              || commandID == (uint)VSConstants.VSStd2KCmdID.DELETE)
          {
              if (m_session != null && !m_session.IsDismissed)
                  m_session.Filter();
              handled = true;
          }
          if (handled) return VSConstants.S_OK;
          return retVal;
      }
      

  6. Bu kod, tamamlama oturumunu tetikleyen özel bir yöntemdir:

    private bool TriggerCompletion()
    {
        //the caret must be in a non-projection location 
        SnapshotPoint? caretPoint =
        m_textView.Caret.Position.Point.GetPoint(
        textBuffer => (!textBuffer.ContentType.IsOfType("projection")), PositionAffinity.Predecessor);
        if (!caretPoint.HasValue)
        {
            return false;
        }
    
        m_session = m_provider.CompletionBroker.CreateCompletionSession
     (m_textView,
            caretPoint.Value.Snapshot.CreateTrackingPoint(caretPoint.Value.Position, PointTrackingMode.Positive),
            true);
    
        //subscribe to the Dismissed event on the session 
        m_session.Dismissed += this.OnSessionDismissed;
        m_session.Start();
    
        return true;
    }
    
  7. Sonraki örnek, olay aboneliğini Dismissed kaldıran özel bir yöntemdir:

    private void OnSessionDismissed(object sender, EventArgs e)
    {
        m_session.Dismissed -= this.OnSessionDismissed;
        m_session = null;
    }
    

Kodu derleme ve test etme

Bu kodu test etmek için CompletionTest çözümünü derleyin ve deneysel örnekte çalıştırın.

CompletionTest çözümünü derlemek ve test etmek için

  1. Çözümü oluşturun.

  2. Bu projeyi hata ayıklayıcıda çalıştırdığınızda, Visual Studio'nun ikinci bir örneği başlatılır.

  3. Bir metin dosyası oluşturun ve "ekle" sözcüğünü içeren bir metin yazın.

  4. Önce "a" ve sonra "d" yazdığınızda, "toplama" ve "uyarlama" içeren bir liste görünmelidir. Eklemenin seçili olduğuna dikkat edin. Başka bir "d" yazdığınızda, listede yalnızca seçili olan "toplama" bulunmalıdır. Ara Çubuğu, Sekme veya Enter tuşuna basarak "toplama" işlemi yapabilir veya Esc veya başka bir tuş yazarak listeyi kapatabilirsiniz.