(https://github.com/matarillo/vscode-languageserver-csharp-example “vscode-languageserver-csharp-example”)
Client
客户端用于设置选项,激活插件并启动语言服务器。
服务端选项
let serverOptions: ServerOptions =
(os.platform() === 'win32') ? {
run : <Executable>{ command: serverCommand, options: commandOptions },
debug: <Executable>{ command: serverCommand, options: commandOptions }
} : {
run : <Executable>{ command: 'mono', args: [serverCommand], options: commandOptions },
debug: <Executable>{ command: 'mono', args: [serverCommand], options: commandOptions }
};
客户端选项
let clientOptions: LanguageClientOptions = {
// 为文本文档注册语言服务器
documentSelector: ['plaintext'],
synchronize: {
// 同步设置到语言服务器
configurationSection: 'languageServerExample',
// 告知服务器工作区中clientrc文件的更改
fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
}
};
新建客户端、设置服务端并启动
client = new LanguageClient(
'languageServerExample',
'Language Server Example',
serverOptions,
clientOptions
);
// 启动客户端,同时启动服务端
client.start();
Server
服务器的工作主要为监听文件变化,接收用户行为信息,返回响应信息。
初始化(Initialize)
“`c#
protected override Result<InitializeResult, ResponseError<InitializeErrorData>> Initialize(InitializeParams @params)
{
_workerSpaceRoot = @params.rootUri;
var result = new InitializeResult
{
capabilities = new ServerCapabilities
{
textDocumentSync = TextDocumentSyncKind.Full,
completionProvider = new CompletionOptions
{
resolveProvider = true
}
}
};
return Result<InitializeResult, ResponseError<InitializeErrorData>>.Success(result);
}
<pre><code class="line-numbers">[](https://adobie.top/wp-content/uploads/2022/09/wp_editor_md_9675f44ee44eed21c024032ecb3fbda4.jpg)
在库中的定义:
“`c#
public class InitializeParams
{
/// <summary>
/// The process Id of the parent process that started the server.
/// </summary>
public int? processId { get; set; }
/// <summary>
/// The rootUri of the workspace.
/// </summary>
public Uri rootUri { get; set; }
/// <summary>
/// User provided initialization options.
/// </summary>
public dynamic initializationOptions { get; set; }
/// <summary>
/// The capabilities provided by the client (editor or tool)
/// </summary>
public ClientCapabilities capabilities { get; set; }
/// <summary>
/// The initial trace setting.
/// </summary>
/// <remarks>
/// If omitted trace is disabled (‘off’).
/// </remarks>
/// <value>
/// See <see cref=”LanguageServer.Parameters.TraceKind”/> for an enumeration of standardized kinds.
/// </value>
/// <seealso cref=”LanguageServer.Parameters.TraceKind”/>
public string trace { get; set; }
/// <summary>
/// The workspace folders configured in the client when the server starts.
/// </summary>
/// <remarks>
/// This property is only available if the client supports workspace folders.
/// It can be <c>null</c> if the client supports workspace folders but none are
/// configured.
/// </remarks>
/// <seealso>Spec 3.6.0</seealso>
public WorkspaceFolder[] workspaceFolders { get; set; }
}
打开文件(DidOpenTextDocument)
“`C#
protected override void DidOpenTextDocument(DidOpenTextDocumentParams @params)
{
_documents.Add(@params.textDocument);
Logger.Instance.Log($"{@params.textDocument.uri} opened.");
}
<pre><code class="line-numbers">在库中的定义:
“`C#
public class DidOpenTextDocumentParams
{
public TextDocumentItem textDocument { get; set; }
}
其中,textDocument的定义如下:
“`C#
public class TextDocumentItem
{
public Uri uri { get; set; }
<pre><code> public string languageId { get; set; }
public long version { get; set; }
public string text { get; set; }
}
</code></pre>
<pre><code class="line-numbers">##### 编辑文件(DidChangeTextDocument)
“`C#
protected override void DidChangeTextDocument(DidChangeTextDocumentParams @params)
{
_documents.Change(@params.textDocument.uri, @params.textDocument.version, @params.contentChanges);
Logger.Instance.Log($”{@params.textDocument.uri} changed.”);
}
在库中的定义:
“`C#
public class DidChangeTextDocumentParams
{
public VersionedTextDocumentIdentifier textDocument { get; set; }
<pre><code> public TextDocumentContentChangeEvent[] contentChanges { get; set; }
}
</code></pre>
<pre><code class="line-numbers">其中**VersionedTextDocumentIdentifier**的定义如下:
“`C#
public class VersionedTextDocumentIdentifier : TextDocumentIdentifier
{
public long version { get; set; }
}
其中TextDocumentContentChangeEvent的定义如下:
“`C#
public class TextDocumentContentChangeEvent
{
public Range range { get; set; }
<pre><code> public long? rangeLength { get; set; }
public string text { get; set; }
}
</code></pre>
<pre><code class="line-numbers">##### 关闭文件(DidCloseTextDocument)
“`C#
protected override void DidCloseTextDocument(DidCloseTextDocumentParams @params)
{
_documents.Remove(@params.textDocument.uri);
Logger.Instance.Log($”{@params.textDocument.uri} closed.”);
}
在库中的定义:
“`C#
public class DidCloseTextDocumentParams
{
public TextDocumentIdentifier textDocument { get; set; }
}
<pre><code class="line-numbers">其中**TextDocumentIdentifier**的定义如下:
“`C#
public class TextDocumentIdentifier
{
public Uri uri { get; set; }
}
以上函数都与C#中的特性进行绑定,从而控制调用时机。库中自定义特性如下:
“`C#
[AttributeUsage(AttributeTargets.Method)]
public class JsonRpcMethodAttribute : Attribute
{
private string _method;
<pre><code> public JsonRpcMethodAttribute(string method)
{
_method = method;
}
public string Method
{
get => _method;
}
}
</code></pre>
<pre><code class="line-numbers">特性应用如下:
“`C#
[JsonRpcMethod(“initialize”)]
protected virtual Result<InitializeResult, ResponseError<InitializeErrorData>> Initialize(InitializeParams @params)
{
throw new NotImplementedException();
}
[JsonRpcMethod(“textDocument/didOpen”)]
protected virtual void DidOpenTextDocument(DidOpenTextDocumentParams @params)
{
}
[JsonRpcMethod(“textDocument/didChange”)]
protected virtual void DidChangeTextDocument(DidChangeTextDocumentParams @params)
{
}
[JsonRpcMethod(“textDocument/didClose”)]
protected virtual void DidCloseTextDocument(DidCloseTextDocumentParams @params)
{
}
自动补全及语法检测等
先根据事件处理委托构建编辑事件:
“`C#
public event EventHandler<TextDocumentChangedEventArgs> Changed;
<pre><code class="line-numbers">之后构造触发事件的函数:
“`C#
protected virtual void OnChanged(TextDocumentItem document)
{
Changed?.Invoke(this, new TextDocumentChangedEventArgs(document));
}
再新建该事件所在类的对象,并对该事件设置触发时所执行的函数:
“`C#
public App(Stream input, Stream output)
: base(input, output)
{
_documents = new TextDocumentManager();
_documents.Changed += Documents_Changed;
}
<pre><code class="line-numbers">其中**Documents_Changed**定义如下:
“`C#
private void Documents_Changed(object sender, TextDocumentChangedEventArgs e)
{
ValidateTextDocument(e.Document);
}
在ValidateTextDocument
监听和等待(Listen&Wait)
“`C#
try
{
app.Listen().Wait();
}
catch (AggregateException ex)
{
Console.Error.WriteLine(ex.InnerExceptions[0]);
Environment.Exit(-1);
}
“`
其中Listen与Wait函数直接使用库中定义。