すべての作業の主な成果物は、ほとんどの場合プレーンテキストファイルです。では、メモ帳を使用して作成してみませんか?
構文の強調表示と自動フォーマットは、氷山の一角にすぎません。リンティング、コード補完、および半自動リファクタリングについてはどうですか?これらはすべて、「実際の」コードエディタを使用する非常に良い理由です。これらは私たちの日常にとって不可欠ですが、私たちはそれらがどのように機能するかを理解していますか?
このLanguageServer Protocolチュートリアルでは、これらの質問を少し調べて、テキストエディタを動かしている理由を見つけます。最後に、VSCode、Sublime Text 3、Vimのサンプルクライアントとともに、基本的な言語サーバーを一緒に実装します。
ここでは、静的分析(それ自体が興味深いトピック)で処理される構文の強調表示と書式設定をスキップし、これらのツールから得られる主なフィードバックに焦点を当てます。コンパイラと言語サービスの2つの主要なカテゴリがあります。
コンパイラはソースコードを取り込み、別の形式を吐き出します。コードが言語の規則に従わない場合、コンパイラはエラーを返します。これらは非常によく知られています。これに伴う問題は、通常、非常に遅く、範囲が限られていることです。コードを作成している間に支援を提供するのはどうですか?
これが言語サービスが提供するものです。コードベースがまだ作業中である間、コードベースについての洞察を得ることができ、おそらくプロジェクト全体をコンパイルするよりもはるかに高速です。
これらのサービスの範囲はさまざまです。プロジェクト内のすべてのシンボルのリストを返すような単純なものでも、コードをリファクタリングするステップを返すような複雑なものでもかまいません。これらのサービスが、コードエディタを使用する主な理由です。コンパイルしてエラーを確認したいだけの場合は、数回のキーストロークでそれを行うことができます。言語サービスは、より多くの洞察を非常に迅速に提供します。
特定のテキストエディタをまだ呼び出していないことに注意してください。その理由を例を挙げて説明しましょう。
Lapineという新しいプログラミング言語を開発したとします。それは美しい言語であり、コンパイラは素晴らしいものを提供します エルム -エラーメッセージのように。さらに、コードの補完、参照、リファクタリングのヘルプ、および診断を提供できます。
どのコード/テキストエディタを最初にサポートしますか?その後はどうですか?あなたは人々にそれを採用させるための困難な戦いをしているので、あなたはそれをできるだけ簡単にしたいのです。間違ったエディターを選んでユーザーを見逃したくない。コードエディタから距離を置き、専門分野である言語とその機能に焦点を当てるとどうなるでしょうか。
入る 言語サーバー 。これらは話しかけるツールです 言語クライアント 私たちが言及した洞察を提供します。これらは、仮定の状況で説明した理由により、テキストエディタから独立しています。
いつものように、抽象化の別のレイヤーは私たちが必要としているものです。これらは、言語ツールとコードエディタの緊密な結合を断ち切ることを約束します。言語作成者は機能をサーバーに一度ラップでき、コード/テキストエディターは小さな拡張機能を追加して自分自身をクライアントに変えることができます。それは誰にとっても勝利です。ただし、これを容易にするために、これらのクライアントとサーバーがどのように通信するかについて合意する必要があります。
私たちにとって幸運なことに、これは架空のものではありません。マイクロソフトはすでに定義することから始めています 言語サーバープロトコル 。
ほとんどの素晴らしいアイデアと同様に、それは先見性ではなく必然的に成長しました。多くのコードエディタは、すでにさまざまな言語機能のサポートの追加を開始しています。一部の機能はサードパーティのツールにアウトソーシングされており、一部はエディター内で内部的に実行されています。スケーラビリティの問題が発生し、Microsoftが主導権を握って物事を分割しました。はい、Microsoftは、これらの機能をVSCode内に蓄積するのではなく、コードエディターから移動する道を開きました。彼らはエディターを構築し続け、ユーザーを閉じ込めることができたかもしれませんが、彼らは彼らを解放しました。
言語サーバープロトコル(LSP)は、言語ツールとエディターを分離するために2016年に定義されました。まだ多くのVSCodeフィンガープリントがありますが、これは編集者の不可知論の方向への大きな一歩です。プロトコルを少し調べてみましょう。
AWS認定はどのくらい続きますか
クライアントとサーバー(コードエディタや言語ツールを考えてください)は、単純なテキストメッセージで通信します。これらのメッセージにはHTTPのようなヘッダーとJSON-RPCコンテンツがあり、クライアントまたはサーバーのいずれかから発信される可能性があります。 JSON-RPCプロトコルは、リクエスト、レスポンス、通知、およびそれらに関するいくつかの基本的なルールを定義します。重要な機能は、非同期で動作するように設計されているため、クライアント/サーバーがメッセージを順不同である程度の並列処理で処理できることです。
つまり、JSON-RPCを使用すると、クライアントは別のプログラムにパラメーターを使用してメソッドを実行し、結果またはエラーを返すように要求できます。 LSPはこれに基づいて構築され、使用可能なメソッド、予想されるデータ構造、およびトランザクションに関するいくつかのルールを定義します。たとえば、クライアントがサーバーを起動するときにハンドシェイクプロセスがあります。
サーバーはステートフルであり、一度に1つのクライアントのみを処理することを目的としています。ただし、通信に明示的な制限はないため、言語サーバー たぶん......だろう クライアントとは異なるマシンで実行します。ただし、実際には、リアルタイムのフィードバックにはかなり時間がかかります。言語サーバーとクライアントは同じファイルで動作し、かなりおしゃべりです。
ザ・ LSP まともな量を持っています ドキュメンテーション 何を探すべきかがわかったら。前述のように、これの多くはVSCodeのコンテキスト内で記述されていますが、アイデアの用途ははるかに広くなっています。たとえば、プロトコル仕様はすべてTypeScriptで記述されています。 VSCodeとTypeScriptに慣れていない探索者を支援するために、ここに入門書があります。
言語サーバープロトコルで定義されているメッセージのグループは多数あります。それらは大きく「管理」と「言語機能」に分けることができます。管理メッセージには、クライアント/サーバーハンドシェイク、ファイルのオープン/変更などで使用されるメッセージが含まれます。重要なことに、これはクライアントとサーバーが処理する機能を共有する場所です。確かに、異なる言語とツールは異なる機能を提供します。これにより、段階的な採用も可能になります。 Langserver.org クライアントとサーバーがサポートする必要のある半ダースの主要な機能に名前を付けます。リストを作成するには、そのうちの少なくとも1つが必要です。
言語機能は、私たちが最も関心を持っているものです。これらのうち、具体的に呼び出す必要があるのは、診断メッセージです。診断は重要な機能の1つです。ファイルを開くと、ほとんどの場合、これが実行されると想定されます。編集者は、ファイルに何か問題があるかどうかを教えてくれるはずです。これがLSPで発生する方法は次のとおりです。
textDocument/didOpen
を送信しますサーバーに。textDocument/publishDiagnostics
を送信しますお知らせ。これは、言語サービスから洞察を得るための受動的な方法です。よりアクティブな例は、カーソルの下にあるシンボルのすべての参照を見つけることです。これは次のようになります。
textDocument/references
を送信しますサーバーに送信し、ファイル内の場所を指定します。確かにLanguageServer Protocolの詳細を掘り下げることはできますが、それはクライアントの実装者に任せましょう。エディターと言語ツールの分離のアイデアを固めるために、ツール作成者の役割を果たします。
シンプルに保ち、新しい言語や機能を作成する代わりに、診断に固執します。診断は最適です。診断はファイルの内容に関する単なる警告です。リンターは診断を返します。似たようなものを作ります。
避けたい言葉を知らせるツールを作ります。次に、その機能をいくつかの異なるテキストエディタに提供します。
古いクレジットカード番号を見つける方法
まず、ツール。これを言語サーバーに焼き付けます。簡単にするために、これは Node.js アプリですが、読み取りと書き込みにストリームを使用できる任意の技術でそれを行うことができます。
これがロジックです。いくつかのテキストが与えられると、このメソッドは、一致したブラックリストに登録された単語の配列とそれらが見つかったインデックスを返します。
const getBlacklisted = (text) => { const blacklist = [ 'foo', 'bar', 'baz', ] const regex = new RegExp(`\b($'))\b`, 'gi') const results = [] while ((matches = regex.exec(text)) && results.length <100) { results.push({ value: matches[0], index: matches.index, }) } return results }
それでは、サーバーにしましょう。
const { TextDocuments, createConnection, } = require('vscode-languageserver') const {TextDocument} = require('vscode-languageserver-textdocument') const connection = createConnection() const documents = new TextDocuments(TextDocument) connection.onInitialize(() => ({ capabilities: { textDocumentSync: documents.syncKind, }, })) documents.listen(connection) connection.listen()
ここでは、vscode-languageserver
を利用しています。この名前は、VSCodeの外部でも確実に機能するため、誤解を招く恐れがあります。これは、LSPの起源について見られる多くの「指紋」の1つです。 vscode-languageserver
下位レベルのプロトコルを処理し、ユースケースに集中できるようにします。このスニペットは接続を開始し、それをドキュメントマネージャーに結び付けます。クライアントがサーバーに接続すると、サーバーは、開かれているテキストドキュメントの通知を希望することを通知します。
ここでやめることができます。これは、無意味ではありますが、完全に機能するLSPサーバーです。代わりに、いくつかの診断情報を使用してドキュメントの変更に対応しましょう。
documents.onDidChangeContent(change => { connection.sendDiagnostics({ uri: change.document.uri, diagnostics: getDiagnostics(change.document), }) })
最後に、変更されたドキュメント、ロジック、および診断応答の間のドットを接続します。
const getDiagnostics = (textDocument) => getBlacklisted(textDocument.getText()) .map(blacklistToDiagnostic(textDocument)) const { DiagnosticSeverity, } = require('vscode-languageserver') const blacklistToDiagnostic = (textDocument) => ({ index, value }) => ({ severity: DiagnosticSeverity.Warning, range: { start: textDocument.positionAt(index), end: textDocument.positionAt(index + value.length), }, message: `${value} is blacklisted.`, source: 'Blacklister', })
診断ペイロードは、関数を介してドキュメントのテキストを実行した結果であり、クライアントが期待する形式にマッピングされます。
このスクリプトはあなたのためにそれらすべてを作成します。
curl -o- https://raw.githubusercontent.com/reergymerej/lsp-article-resources/revision-for-6.0.0/blacklist-server-install.sh | bash
注:見知らぬ人がマシンに実行可能ファイルを追加することに不安がある場合は、 ソースを確認してください 。プロジェクトを作成し、index.js
をダウンロードし、npm link
sします。
最後のblacklist-server
ソースは:
#!/usr/bin/env node const { DiagnosticSeverity, TextDocuments, createConnection, } = require('vscode-languageserver') const {TextDocument} = require('vscode-languageserver-textdocument') const getBlacklisted = (text) => { const blacklist = [ 'foo', 'bar', 'baz', ] const regex = new RegExp(`\b($'))\b`, 'gi') const results = [] while ((matches = regex.exec(text)) && results.length ({ index, value }) => ({ severity: DiagnosticSeverity.Warning, range: { start: textDocument.positionAt(index), end: textDocument.positionAt(index + value.length), }, message: `${value} is blacklisted.`, source: 'Blacklister', }) const getDiagnostics = (textDocument) => getBlacklisted(textDocument.getText()) .map(blacklistToDiagnostic(textDocument)) const connection = createConnection() const documents = new TextDocuments(TextDocument) connection.onInitialize(() => ({ capabilities: { textDocumentSync: documents.syncKind, }, })) documents.onDidChangeContent(change => { connection.sendDiagnostics({ uri: change.document.uri, diagnostics: getDiagnostics(change.document), }) }) documents.listen(connection) connection.listen()
プロジェクトがlink
されたら、stdio
を指定してサーバーを実行してみてください。輸送メカニズムとして:
blacklist-server --stdio
stdio
でリッスンしていますさて、前に話したLSPメッセージについてです。それらを手動で提供することもできますが、代わりにクライアントを作成しましょう。
このテクノロジーはVSCodeで始まったので、そこから始めるのが適切だと思われます。 LSPクライアントを作成し、作成したサーバーに接続する拡張機能を作成します。
がある いくつかの方法 Yeomanと適切なジェネレーターgenerator-code
の使用を含む、VSCode拡張機能を作成します。ただし、簡単にするために、必要最低限の例を見てみましょう。
ボイラープレートのクローンを作成し、その依存関係をインストールしましょう。
git clone [email protected] :reergymerej/standalone-vscode-ext.git blacklist-vscode cd blacklist-vscode npm i # or yarn
blacklist-vscode
を開きますVSCodeのディレクトリ。
F5キーを押して、別のVSCodeインスタンスを開始し、拡張機能をデバッグします。
最初のVSCodeインスタンスの「デバッグコンソール」に、「Look、ma。拡張!'
これで、基本的なVSCode拡張機能がすべてのベルやホイッスルなしで機能するようになりました。それをLSPクライアントにしましょう。両方のVSCodeインスタンスを閉じ、blacklist-vscode
内から閉じますディレクトリ、実行:
npm i vscode-languageclient
交換 extension.js と:
const { LanguageClient } = require('vscode-languageclient') module.exports = { activate(context) { const executable = { command: 'blacklist-server', args: ['--stdio'], } const serverOptions = { run: executable, debug: executable, } const clientOptions = { documentSelector: [{ scheme: 'file', language: 'plaintext', }], } const client = new LanguageClient( 'blacklist-extension-id', 'Blacklister', serverOptions, clientOptions ) context.subscriptions.push(client.start()) }, }
これはvscode-languageclient
を使用しますVSCode内にLSPクライアントを作成するためのパッケージ。 vscode-languageserver
とは異なり、これはVSCodeと緊密に結合されています。つまり、この拡張機能で行っているのは、クライアントを作成し、前の手順で作成したサーバーを使用するようにクライアントに指示することです。 VSCode拡張機能の詳細を確認すると、プレーンテキストファイルにこのLSPクライアントを使用するように指示していることがわかります。
試乗するには、blacklist-vscode
を開きますVSCodeのディレクトリ。 F5キーを押して別のインスタンスを開始し、拡張機能をデバッグします。
新しいVSCodeインスタンスで、プレーンテキストファイルを作成して保存します。 「foo」または「bar」と入力して、しばらく待ちます。これらがブラックリストに登録されているという警告が表示されます。
ソフトウェア会社の勘定科目表
それでおしまい!ロジックを再作成する必要はなく、クライアントとサーバーを調整するだけで済みました。
別の編集者、今回はSublime Text 3でもう一度やりましょう。プロセスは非常に似ており、少し簡単になります。
まず、ST3を開き、コマンドパレットを開きます。エディターをLSPクライアントにするためのフレームワークが必要です。 「パッケージ制御:パッケージのインストール」と入力し、Enterキーを押します。パッケージ「LSP」を見つけてインストールします。完了すると、 能力 LSPクライアントを指定します。多くのプリセットがありますが、それらは使用しません。独自に作成しました。
もう一度、コマンドパレットを開きます。 「設定:LSP設定」を見つけてEnterキーを押します。これにより、LSPパッケージの構成ファイルLSP.sublime-settings
が開きます。カスタムクライアントを追加するには、以下の構成を使用します。
{ 'clients': { 'blacklister': { 'command': [ 'blacklist-server', '--stdio' ], 'enabled': true, 'languages': [ { 'syntaxes': [ 'Plain text' ] } ] } }, 'log_debug': true }
これは、VSCode拡張機能からは見覚えがあるかもしれません。クライアントを定義し、プレーンテキストファイルで動作するように指示し、言語サーバーを指定しました。
設定を保存してから、プレーンテキストファイルを作成して保存します。 「foo」または「bar」と入力して待ちます。繰り返しになりますが、これらがブラックリストに登録されているという警告が表示されます。処理(メッセージがエディターでどのように表示されるか)は異なります。ただし、機能は同じです。今回は、エディターにサポートを追加するためにほとんど何もしませんでした。
この関心の分離によってテキストエディタ間で機能を簡単に共有できるとまだ確信が持てない場合は、次の方法で同じ機能をVimに追加する手順をご覧ください。 Coc 。
Vimを開いて:CocConfig
と入力し、次を追加します。
'languageserver': { 'blacklister': { 'command': 'blacklist-server', 'args': ['--stdio'], 'filetypes': ['text'] } }
完了。
言語サービスの責任を、それらが使用されているテキストエディタから分離することは明らかに勝利です。これにより、言語機能の作成者は専門分野に集中でき、編集者の作成者も同じことができます。これはかなり新しいアイデアですが、採用が広がっています。
作業の基礎ができたので、プロジェクトを見つけて、このアイデアを前進させるのに役立つかもしれません。編集者の炎上戦争は決して終わらないが、それは問題ない。言語能力が特定のエディターの外に存在できる限り、好きなエディターを自由に使用できます。
として マイクロソフトゴールドパートナー 、ApeeScapeは、マイクロソフトの専門家のエリートネットワークです。必要なときに必要な場所で正確に、必要な専門家と一緒に高性能チームを構築してください!
言語サーバープロトコルは、言語クライアントと言語サーバーが通信する方法を説明する一連のルールです。これは、編集者をtsserverなどの言語固有のツールから切り離すのに役立つように2016年に定義されました。
C ++、Java、Erlang、Go、およびCommon Lispはすべてコンパイルされた言語です。つまり、実行前に、それらのソースがマシンコードなどの別の形式に変換されます。 PythonやJavaScriptなどのインタープリター型言語では、プログラムの実行時にインタープリターを介してソースコードが実行されます。
コンパイラの役割は、ソースコードを実行用の別の形式(通常はマシンコード)に変換することです。これは、ソースコードをTypeScriptからJavaScriptなどの別のタイプのソースコードに変換するトランスパイラーとは異なります。コンパイラはソースコードのエラーを報告します。
コンパイラの主な機能は、ソースコードをマシンコードに変換することです。これには、プログラムのモデルを構築するための字句解析と解析、最適化の実装、およびターゲットコードの生成が含まれます。フロントエンド分析は、開発者が構文のエラーを特定するのに役立つフィードバックを提供します。
C ++のコーディング方法
テキストエディタは、メモ帳、Word、Notepad ++、Sublime Text、Vim、Emacsなどのテキストファイルを変更するために使用されるプログラムです。通常、開発者は、プログラミング言語のコンテキスト内でテキストを理解するように拡張して、効果的にIDEに変換できない限り、プログラミングに単純なテキストエディタを使用することを避けます。
VSCodeは、Electronを介してNode.jsで作成されます。ソースは、GithubのMicrosoftのリポジトリリストから入手できます。