Protokol jazyka serveru
Co je protokol jazykového serveru?
Podpora bohatých funkcí pro úpravy, jako jsou automatické dokončování zdrojového kódu nebo Přejít k definici pro programovací jazyk v editoru nebo integrovaném vývojovém prostředí , je tradičně velmi náročná a časově náročná. Obvykle vyžaduje zápis doménového modelu (skener, analyzátor, kontrola typů, tvůrce a další) v programovacím jazyce editoru nebo integrovaného vývojového prostředí . Například modul plug-in Eclipse CDT, který poskytuje podporu jazyka C/C++ v integrovaném vývojovém prostředí (IDE) Eclipse, je napsaný v Javě, protože samotné prostředí Eclipse IDE je napsané v Javě. Po tomto přístupu by to znamenalo implementaci doménového modelu C/C++ v TypeScriptu pro Visual Studio Code a samostatného doménového modelu v jazyce C# pro Visual Studio.
Vytváření doménových modelů specifických pro konkrétní jazyk je také mnohem jednodušší, pokud vývojový nástroj může opakovaně používat existující knihovny specifické pro jazyk. Tyto knihovny se ale obvykle implementují v samotném programovacím jazyce (například správné doménové modely C/C++ se implementují v jazyce C/C++). Integrace knihovny C/C++ do editoru napsaného v TypeScriptu je technicky možná, ale těžko se to dělá.
Jazykové servery
Dalším přístupem je spuštění knihovny ve vlastním procesu a použití komunikace mezi procesy ke komunikaci s knihovnou. Zprávy odeslané zpět a zpět tvoří protokol. Protokol LSP (Language Server Protocol) je produkt standardizace zpráv vyměňovaných mezi vývojovým nástrojem a procesem jazykového serveru. Použití jazykových serverů nebo démonů není nová nebo nová myšlenka. Editory, jako je Vim a Emacs, už nějakou dobu prováděly podporu sémantického automatického dokončování. Cílem LSP bylo zjednodušit tyto druhy integrací a poskytnout užitečnou architekturu pro zveřejnění jazykových funkcí pro různé nástroje.
Použití společného protokolu umožňuje integraci funkcí programovacího jazyka do vývojového nástroje s minimálním využitím opětovného použití stávající implementace doménového modelu jazyka. Back-end jazykového serveru může být napsaný v PHP, Pythonu nebo Javě a LSP umožňuje snadno integrovat do různých nástrojů. Protokol funguje na běžné úrovni abstrakce, aby nástroj mohl nabízet bohaté jazykové služby, aniž by bylo nutné plně pochopit drobné odlišnosti specifické pro základní doménový model.
Jak začít pracovat na LSP
LSP se v průběhu času vyvinul a dnes je ve verzi 3.0. Začalo to, když společnost OmniSharp vybrala koncept jazykového serveru, aby poskytovala bohaté funkce pro úpravy jazyka C#. OmniSharp zpočátku použil protokol HTTP s datovou částí JSON a byl integrovaný do několika editorů, včetně editoru Visual Studio Code.
Ve stejnou dobu microsoft začal pracovat na serveru jazyka TypeScript s myšlenkou podpory TypeScriptu v editorech, jako je Emacs a Sublime Text. V této implementaci editor komunikuje přes stdin/stdout s procesem serveru TypeScript a používá datovou část JSON inspirovanou protokolem ladicího programu V8 pro požadavky a odpovědi. Server TypeScript byl integrovaný do modulu plug-in TypeScript Sublime a VS Code pro bohaté úpravy TypeScriptu.
Po integraci dvou různých jazykových serverů začal tým VS Code zkoumat protokol společného jazykového serveru pro editory a integrované vývojové prostředí (IDE). Běžný protokol umožňuje poskytovateli jazyka vytvořit jeden jazykový server, který může využívat různé prostředí IDE. Příjemce jazykového serveru musí implementovat pouze stranu klienta protokolu jednou. Výsledkem je situace win-win pro poskytovatele jazyka i příjemce jazyka.
Protokol jazykového serveru začal protokolem používaným serverem TypeScript a rozšířil se o další jazykové funkce inspirované rozhraním API jazyka VS Code. Protokol je založený na formátu JSON-RPC pro vzdálené vyvolání kvůli jednoduchosti a existujícím knihovnám.
Tým VS Code vytvořil prototyp protokolu implementací několika linter jazykových serverů, které reagují na požadavky na lint (scan) soubor a vrátil sadu zjištěných upozornění a chyb. Cílem bylo lintovat soubor jako uživatel upravuje v dokumentu, což znamená, že během relace editoru bude mnoho požadavků na lintování. Dávalo smysl udržovat server v provozu, aby nový proces lintování nemusel být spuštěn pro každou úpravu uživatele. Implementovalo se několik linter serverů, včetně rozšíření ESLint a TSLint v nástroji VS Code. Tyto dva linter servery jsou implementované v TypeScriptu nebo JavaScriptu a běží na Node.js. Sdílejí knihovnu, která implementuje klientskou a serverovou část protokolu.
Jak LSP funguje
Jazykový server běží ve vlastním procesu a nástroje, jako je Visual Studio nebo VS Code, komunikují se serverem pomocí jazykového protokolu přes JSON-RPC. Další výhodou jazykového serveru, který pracuje ve vyhrazeném procesu, je, že se vyhnete problémům s výkonem souvisejícím s jedním procesovým modelem. Skutečný přenosový kanál může být buď stdio, sokety, pojmenované kanály, nebo ipc uzlu, pokud jsou klient i server zapsány v Node.js.
Níže je příklad, jak nástroj a jazykový server komunikují během rutinní relace úprav:
Uživatel v nástroji otevře soubor (označovaný jako dokument): Nástroj upozorní jazykový server, že je dokument otevřený (textDocument/didOpen). Odteď platí, že pravda o obsahu dokumentu už není v systému souborů, ale nástroj je uchová v paměti.
Uživatel provede úpravy: Nástroj upozorní server na změnu dokumentu (textDocument/didChange) a sémantické informace programu se aktualizují serverem jazyka. V takovém případě jazykový server analyzuje tyto informace a upozorní nástroj zjištěnými chybami a upozorněními (textDocument/publishDiagnostics).
Uživatel spustí "Přejít k definici" na symbolu v editoru: Nástroj odešle požadavek "textDocument/definition" se dvěma parametry: (1) identifikátor URI dokumentu a (2) umístění textu, ze kterého byl požadavek Přejít na definici inicializován na server. Server odpoví identifikátorem URI dokumentu a umístěním definice symbolu uvnitř dokumentu.
Uživatel zavře dokument (soubor):: Z nástroje se odešle oznámení "textDocument/didClose", informuje jazykový server, že dokument už není v paměti a že aktuální obsah je teď aktuální v systému souborů.
Tento příklad ukazuje, jak protokol komunikuje se serverem jazyků na úrovni funkcí editoru, jako je Přejít k definici, Najít všechny odkazy. Datové typy používané protokolem jsou editor nebo "datové typy", jako jsou aktuálně otevřený textový dokument a pozice kurzoru. Datové typy nejsou na úrovni doménového modelu programovacího jazyka, který by obvykle poskytoval abstraktní stromy syntaxe a symboly kompilátoru (například vyřešené typy, obory názvů, ...). To výrazně zjednodušuje protokol.
Teď se podrobněji podíváme na požadavek textDocument/definition. Níže jsou uvedené datové části, které se nacházejí mezi klientským nástrojem a jazykovým serverem pro požadavek Přejít k definici v dokumentu jazyka C++.
Toto je požadavek:
{
"jsonrpc": "2.0",
"id" : 1,
"method": "textDocument/definition",
"params": {
"textDocument": {
"uri": "file:///p%3A/mseng/VSCode/Playgrounds/cpp/use.cpp"
},
"position": {
"line": 3,
"character": 12
}
}
}
Toto je odpověď:
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"uri": "file:///p%3A/mseng/VSCode/Playgrounds/cpp/provide.cpp",
"range": {
"start": {
"line": 0,
"character": 4
},
"end": {
"line": 0,
"character": 11
}
}
}
}
V retrospektivě je popis datových typů na úrovni editoru, nikoli na úrovni programovacího jazykového modelu, jedním z důvodů úspěchu protokolu jazykového serveru. Je mnohem jednodušší standardizovat identifikátor URI textového dokumentu nebo pozici kurzoru v porovnání se standardizací abstraktního stromu syntaxe a symbolů kompilátoru v různých programovacích jazycích.
Když uživatel pracuje s různými jazyky, nástroj VS Code obvykle spustí jazykový server pro každý programovací jazyk. Následující příklad ukazuje relaci, ve které uživatel pracuje se soubory Java a SASS.
Funkce
Ne každý jazykový server může podporovat všechny funkce definované protokolem. Klient a server proto oznámí svou podporovanou funkci nastavenou prostřednictvím možností. Server například oznámí, že může zpracovat požadavek textDocument/definition, ale nemusí zpracovat požadavek workspace/symbol. Podobně můžou klienti oznámit, že před uložením dokumentu můžou poskytnout oznámení o tom, že se mají uložit, aby server mohl vypočítat textové úpravy, aby automaticky naformátoval upravený dokument.
Integrace jazykového serveru
Skutečná integrace jazykového serveru do konkrétního nástroje není definována protokolem jazykového serveru a je ponechána implementátorům nástrojů. Některé nástroje integrují jazykové servery obecně tím, že mají rozšíření, které může začít a mluvit s jakýmkoli druhem jazykového serveru. Jiné, jako je VS Code, vytvářejí vlastní rozšíření pro každý jazykový server, aby rozšíření stále dokázalo poskytovat některé vlastní jazykové funkce.
Pro zjednodušení implementace jazykových serverů a klientů existují knihovny nebo sady SDK pro klientské a serverové části. Tyto knihovny jsou k dispozici pro různé jazyky. K dispozici je například modul npm klienta jazyka, který usnadňuje integraci jazykového serveru do rozšíření VS Code a jiného modulu npm jazykového serveru pro zápis jazykového serveru pomocí Node.js. Toto je aktuální seznam knihoven podpory.
Použití protokolu jazykového serveru v sadě Visual Studio
- Přidání rozšíření Language Server Protocol – Přečtěte si informace o integraci jazykového serveru do sady Visual Studio.