擴充性語言伺服器提供者

語言伺服器提供者牽涉到裝載於Visual Studio外部的程式,並提供Visual Studio中不存在的語言功能。

這些伺服器必須遵守 語言伺服器通訊協定,由 延伸模組專案撰寫,並實作 LanguageServerProvider

使用語言伺服器提供者

本概觀涵蓋使用語言伺服器提供者的下列熱門案例:

建立語言伺服器提供者

建立語言伺服器提供者牽涉到新增可擴充 Microsoft.VisualStudio.Extensibility.LanguageServer.LanguageServerProvider 和套用 VisualStudioContribution 屬性的新類別。

[VisualStudioContribution]
public class MyLanguageServerProvider : LanguageServerProvider
{
    public MyLanguageServerProvider(ExtensionCore container, VisualStudioExtensibility extensibilityObject, TraceSource traceSource)
        : base(container, extensibilityObject)
    {
    }
}

定義提供者之後,您必須:

  1. 覆寫 屬性來 LanguageServerProviderConfiguration 設定提供者。 此組態屬性會定義伺服器顯示名稱和適用的檔案類型。 LanguageServerBaseDocumentType 適用於所有伺服器和所有檔類型的觸發程式。 請參閱 定義自定義檔案類型

    public override LanguageServerProviderConfiguration LanguageServerProviderConfiguration => new("My Language Server",
        new[]
        {
           DocumentFilter.FromDocumentType(LanguageServerBaseDocumentType),
        });
    
  2. CreateServerConnectionAsync覆寫 Visual Studio 呼叫的方法,以通知延伸模組應該啟動 LSP 伺服器。

    // Activate the language server and return a duplex pipe that communicates with the server. 
    public override Task<IDuplexPipe?> CreateServerConnectionAsync(CancellationToken cancellationToken)
    {
        (Stream PipeToServer, Stream PipeToVS) = FullDuplexStream.CreatePair();
    
        // Connect "PipeToServer" to the language server
    
        return Task.FromResult<IDuplexPipe?>(new DuplexPipe(PipeToVS.UsePipeReader(), PipeToVS.UsePipeWriter()));
    }
    
  3. OnServerInitializationResultAsync覆寫 方法,在 LSP 伺服器完成其啟動和設定步驟之後,Visual Studio 會呼叫此方法。 ServerInitializationResult 會提供伺服器的結果狀態,並提供 LanguageServerInitializationFailureInfo 例外狀況。

    public override Task OnServerInitializationResultAsync(ServerInitializationResult startState,LanguageServerInitializationFailureInfo?     initializationFailureInfo, CancellationToken cancellationToken)
    {
        // Method called when server activation was completed successfully or failed, denoted by "startState".
        return Task.CompletedTask;
    }
    

以下是完成所有步驟之後,範例語言伺服器提供者的外觀:

[VisualStudioContribution]
public class MyLanguageServerProvider : LanguageServerProvider
{
    public MyLanguageServerProvider(ExtensionCore container, VisualStudioExtensibility extensibilityObject, TraceSource traceSource)
        : base(container, extensibilityObject)
    {
    }

    public override LanguageServerProviderConfiguration LanguageServerProviderConfiguration =>
        new("My Language Server",
            new[]
            {
               DocumentFilter.FromDocumentType(LanguageServerBaseDocumentType),
            });

    // Activate the language server and return a duplex pipe that communicates with the server. 
    public override Task<IDuplexPipe?> CreateServerConnectionAsync(CancellationToken cancellationToken)
    {
        (Stream PipeToServer, Stream PipeToVS) = FullDuplexStream.CreatePair();

        // Connect "PipeToServer" to the language server

        return Task.FromResult<IDuplexPipe?>(new DuplexPipe(PipeToVS.UsePipeReader(), PipeToVS.UsePipeWriter()));
    }

    public override Task OnServerInitializationResultAsync(ServerInitializationResult startState, LanguageServerInitializationFailureInfo? initializationFailureInfo, CancellationToken cancellationToken)
    {
        // Method called when server activation was completed successfully or failed, denoted by "startState".
        return Task.CompletedTask;
    }
}

啟動語言伺服器時傳送其他數據

LanguageServerOptions.InitializationOptions 您可以在 建構函 LanguageServerProvider 式中設定 ,以使用 「初始化」通訊協定訊息將其他數據傳送至伺服器。

public MyLanguageServerProvider(ExtensionCore container, VisualStudioExtensibility extensibilityObject, TraceSource traceSource)
    : base(container, extensibilityObject)
{
    this.LanguageServerOptions.InitializationOptions = JToken.Parse(@"[{""server"":""initialize""}]");
}

定義自訂檔案類型

當延伸模組支援Visual Studio原生支援的文件類型時,延伸模組作者可以實作自定義檔類型。 定義 以指定支援的檔案類型時 LanguageServerProviderConfiguration ,可以使用這些類型。

[VisualStudioContribution]
internal static DocumentTypeConfiguration RustDocumentType => new("rust")
{
    FileExtensions = new[] { ".rs", ".rust" },
    BaseDocumentType = LanguageServerBaseDocumentType,
};

[VisualStudioContribution]
internal static DocumentTypeConfiguration MarkdownDocumentType => new("markdown")
{
    FileExtensions = new[] { ".md" },
    BaseDocumentType = LanguageServerBaseDocumentType,
};

這個代碼段會定義兩個新的檔案類型: rustmarkdown。 這些類型包含擴展名清單和基底類型,可 LanguageServerBaseDocumentType 涵蓋所有類型。

在 中 LanguageServerProviderConfiguration 使用這些類型,在開啟這些檔案類型時啟動您的伺服器:

public override LanguageServerProviderConfiguration LanguageServerProviderConfiguration =>
    new("My Language Server",
        new[]
        {
            DocumentFilter.FromDocumentType(RustDocumentType),
            DocumentFilter.FromDocumentType(MarkdownDocumentType),
        });

啟用或停用語言伺服器

開啟適用的檔案類型後,允許啟用的語言伺服器「啟動」。 停用時,停止訊息會傳送至任何適用的使用中語言伺服器,並防止進一步啟用。

[VisualStudioContribution]
public class MyLanguageServerProvider : LanguageServerProvider
{
    ...

    public override Task OnServerInitializationResultAsync(ServerInitializationResult startState, LanguageServerInitializationException? initializationFailureInfo, CancellationToken cancellationToken)
    {
        if (startState == ServerInitializationResult.Failed)
        {
            Telemetry.LogEvent(initializationFailureInfo.StatusMessage, initializationFailureInfo.Exception)

            // Disable the language server.
            this.Enabled = false;
        }
    }
}

此代碼段會藉由將 設定為 在無法初始化之後設定 this.EnabledfalseServerInitializationResultFailed 為 ,來停用語言伺服器。

注意

此旗標是公用的,如果設定為 false,則會停止任何執行中的伺服器。

使用本地化的資源

我們支援使用當地語系化,方法是定義 string-resources.json 檔案,並使用 %tokens% 來指定當地語系化的內容。

string-resources.json

{
  { "LocalizedResource": "LangaugeServerLocalized" }
}

存取本地化的資源

[VisualStudioContribution]
public class MyLanguageServer : LanguageServerProvider
{
    ...

    /// <inheritdoc/>
    public override LanguageServerProviderConfiguration LanguageServerProviderConfiguration =>
        new("%LocalizedResource%",
            new[]
            {
                DocumentFilter.FromDocumentType(LanguageServerBaseDocumentType)
            });
}

下一步