Extensibility 言語サーバー プロバイダー
言語サーバー プロバイダーには、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)
{
}
}
プロバイダーの定義後、次の手順を実行する必要があります。
LanguageServerProviderConfiguration
プロパティをオーバーライドして、プロバイダーを構成します。 この構成プロパティは、サーバーの表示名と適用可能なドキュメント タイプを定義します。LanguageServerBaseDocumentType
は、すべてのサーバーで利用でき、すべてのドキュメント タイプでトリガーされます。 「カスタム ドキュメント タイプの定義」を参照してください。public override LanguageServerProviderConfiguration LanguageServerProviderConfiguration => new("My Language Server", new[] { DocumentFilter.FromDocumentType(LanguageServerBaseDocumentType), });
CreateServerConnectionAsync
メソッドをオーバーライドします。このメソッドは、LSP サーバーを起動する必要があることを拡張機能に通知するために、Visual Studio によって呼び出されます。// 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())); }
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
が "initialize" プロトコル メッセージを添えてサーバーに追加データを送信するためのコンストラクターに設定できます。
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,
};
このスニペットは、2 つの新しいドキュメント タイプ rust
と markdown
を定義します。 これらのタイプには、ファイル拡張子と基本型の一覧が含まれています。これを 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;
}
}
}
このコード スニペットは、初期化に失敗したら ServerInitializationResult
が Failed
に設定されるように this.Enabled
を false
に設定して、言語サーバーを無効にします。
Note
このフラグはパブリックであり、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)
});
}
次のステップ
- 「初めての拡張機能の作成」チュートリアルに従って、拡張機能の作成を開始します。
- 言語サーバー プロバイダーを使用して拡張機能を作成する作業をフルに説明した例については、「Rust 言語サーバー プロバイダー」のサンプルを参照してください。