Het Language Server Protocol en de implementatie ervan onderzoeken

Het Language Server Protocol en de implementatie ervan onderzoeken

Wat je leert:

  • Details achter het Language Server Protocol.
  • Waarom het nodig is.
  • Waar te beginnen.

Meer dan waarschijnlijk heb je al een softwareontwikkelingstool gebruikt die gebruikmaakt van het Language Server Protocol (LSP), maar je hebt je dat niet eens gerealiseerd. LSP is ontworpen om de ondersteuning van verschillende talen te vergemakkelijken, wat een reden is waarom uw favoriete tool mogelijk meer talen ondersteunt dan in het verleden.

LSP wordt gedefinieerd als een open set regels die beschrijft hoe taalclients en taalservers moeten communiceren (Figuur 1). Alle services worden afgehandeld door de server en via het protocol aan de client blootgesteld. De client is ofwel een standaard teksteditor of de geïntegreerde ontwikkelomgevingen (IDE’s) die door een ontwikkelaar worden gebruikt, terwijl de server het proces is dat alle slimme dingen over een bepaalde taal bevat.

Microsoft heeft het protocol in 2015 ontwikkeld om taalhulpmiddelen en editors te scheiden, waardoor programmeertaalondersteuning kan worden geïmplementeerd en gedistribueerd onafhankelijk van een bepaalde editor of IDE. Zoals met sommige programmeeromgevingen, is de LSP ontstaan ​​uit noodzaak in plaats van innovatie. Vóór LSP moest het meeste werk worden herhaald voor elke ontwikkelingstool, aangezien elke tool verschillende Application Programming Interfaces (API’s) bood om dezelfde functies te implementeren.

Het ondersteunen van deze functies, zoals het automatisch aanvullen van broncode of “Ga naar definitie” voor een programmeertaal in een editor of IDE, is meestal een uitdagend en tijdrovend proces. Het vereist het schrijven van een domeinmodel (scanner, parser, typechecker, builder, etc.) in de programmeertaal van de editor of IDE.

De Eclipse CDT-plug-in, die C/C++ in de Eclipse IDE ondersteunt, is bijvoorbeeld geschreven in Java, aangezien de IDE zelf ook in Java is geschreven. Het volgen van deze aanpak zou betekenen dat een C/C++-domeinmodel in de TypeScript-taal voor Visual Studio Code moet worden geïmplementeerd en een afzonderlijk domeinmodel in C# voor Microsoft Visual Studio.

Hoe de LSP werkt

Clients en servers kunnen worden gezien als code-editors en taalhulpmiddelen die communiceren in eenvoudige tekstberichten. Deze berichten hebben HTTP-achtige headers en JSON-RPC-inhoud en kunnen afkomstig zijn van de client of server. Het JSON-RPC-protocol definieert verzoeken, antwoorden en meldingen en een paar basisregels eromheen (Figuur 2). Een van de belangrijkste kenmerken is dat het is ontworpen om asynchroon te werken, zodat clients/servers berichten in de juiste volgorde en met een zekere mate van parallellisme kunnen afhandelen.

Bij het Language Server Protocol draait alles om het verminderen van inspanning, en niemand houdt van meedogenloze herhalingen als het gaat om coderen. Daarom is LSP ontwikkeld: het JSON-RPC-protocol stelt de editor/IDE in staat om met een taalserver te praten en zo die inspanning en herhaling te elimineren.

Een ander voordeel van de taalserver die in een specifiek proces werkt, is dat het prestatieproblemen met betrekking tot een enkel procesmodel vermindert. Het feitelijke transportkanaal kan ofwel stdio, sockets, named pipes of node ipc zijn als zowel de client als de server in Node.js zijn geschreven.

Het volgende is een voorbeeld van hoe het LSP-proces werkt:

  1. Een gebruiker opent een bestand (dwz een document) in de tool en laat de taalserver weten dat een document geopend is (“textDocument/didOpen”). Op dit moment staat de waarheid over de inhoud van het document niet langer in het bestandssysteem; het wordt eerder door de tool in het geheugen bewaard en blijft daar gedurende het hele proces.
  2. Terwijl de gebruiker wijzigingen aanbrengt, informeert de tool de server over de documentwijziging (‘textDocument/didChange’) en wordt de semantische informatie van het programma bijgewerkt door de taalserver. De taalserver analyseert deze informatie tijdens het proces en brengt de tool op de hoogte van de gedetecteerde fouten en waarschuwingen (“textDocument/publishDiagnostics”).
  3. Eenmaal voltooid, voert de gebruiker “Ga naar definitie” uit op een symbool in de editor: de tool verzendt een ‘textDocument/definition’-verzoek met twee parameters: de document-URI en de tekstpositie van waaruit het Go to Definition-verzoek is gestart om de server. De server reageert dan met de document-URI en de positie van de symbooldefinitie in het document.
  4. Wanneer het proces is voltooid, sluit de gebruiker het document (bestand) en wordt een “textDocument/didClose”-melding verzonden vanuit de tool. Het informeert de taalserver dat het document zich nu niet meer in het geheugen bevindt en dat de huidige inhoud nu up-to-date is in het bestandssysteem.

Het voorbeeld laat zien hoe het protocol communiceert met de server op documentreferentie- en positieniveau. De datatypes zijn programmeertaalneutraal, wat betekent dat ze van toepassing zijn op alle programmeertalen.

Het is belangrijk op te merken dat de gegevenstypen zich niet op het niveau van een programmeertaaldomeinmodel bevinden, dat gewoonlijk abstracte syntaxisbomen en compilersymbolen zou bieden, zoals opgeloste typen, naamruimten en andere. Omdat de datatypes eenvoudig zijn en de programmeertaal neutraal, vereenvoudigt dit het protocol aanzienlijk.

De LSP is geen universele oplossing

Hoewel het Language Server Protocol enorm voordelig is, is het geen allesomvattende oplossing en heeft het enkele nadelen. Sommige ontwikkelaars ontdekten dat sommige servers zich anders gedroegen op specifieke verzoeken of anders reageerden dan verwacht. Andere serverontwikkelaars kunnen vertrouwen op één clientimplementatie om hun server te ontwikkelen, wat leidt tot discrepanties tussen verwachte en werkelijke resultaten. Zelfs protocoluitbreidingen, zoals CodeAction, kunnen serverspecifiek zijn, waardoor het voor clients moeilijk wordt om generieke code te schrijven voor verwachte reacties.

Bovendien zal niet elke server op dezelfde manier worden geconfigureerd en kan niet elke taalserver alle functies ondersteunen die door het protocol worden gedefinieerd, wat de one-stop-oplossing verder tenietdoet. In plaats daarvan biedt de LSP mogelijkheden die een reeks taalfuncties groeperen.

Een ontwikkelingstool en de taalserver kondigen hun ondersteunde functies aan met behulp van mogelijkheden. Een server kondigt bijvoorbeeld aan dat hij het “textDocument/definition”-verzoek kan verwerken, maar mogelijk niet het “workspace/symbol”-verzoek.

Daartoe blijven talloze ondersteunde talen profiteren van LSP. Onder hen zijn nieuwe talen zoals Rust, die kunnen profiteren van het protocol om moderne IDE’s en teksteditors te ondersteunen. Dit is slechts een eenvoudig overzicht van het Language Server Protocol en wat het kan bereiken. Meer diepgaande informatie, inclusief specificaties en implementaties, is te vinden op de GitHub-pagina van Microsoft.

Leave a Reply

Your email address will not be published.