Por qué construir un LSP para Rust es más difícil de lo que parece
El desarrollador de Rust Glancer, un LSP experimental para Rust, publica un repaso arquitectónico de los problemas que aparecen al montar un servidor de lenguaje y que el protocolo no resuelve.
Quien está detrás de Rust Glancer, un LSP experimental para Rust, ha publicado un repaso arquitectónico de por qué construir un servidor de lenguaje para este lenguaje es bastante más complicado de lo que sugiere el propio protocolo. La idea que atraviesa todo el texto: un compilador tiene un final claro, pero un LSP no compila nada, trabaja con información parcial y tiene que devolver respuestas útiles desde el primer segundo.
El handshake no es el problema, el índice sí
Todo empieza con un initialize del cliente. Hasta que el servidor no responde, el editor no manda nada; cuando responde, llega initialized y arranca la conversación. La pregunta interesante es cuándo contestar. En ese momento no se sabe nada del proyecto, y para atender cualquier consulta hay que indexar el código, que es un trabajo largo.
Bloquear la respuesta hasta terminar el indexado dejaría al usuario esperando decenas de segundos con un editor inservible. La salida que adoptan tanto rust-analyzer como Rust Glancer es responder cuanto antes validando la configuración, y posponer el descubrimiento del workspace. rust-analyzer lo lanza justo después; Rust Glancer se queda pasivo hasta la primera consulta real.
Ahí está la ruptura con la lógica de un compilador: a este le da igual tener 715 de 716 crates listos, el binario está o no está. Un servidor de lenguaje, en cambio, puede aportar valor casi de inmediato si acepta trabajar con lo que tiene.
No hay sistema de ficheros, hay documentos
El protocolo evita hablar de ficheros: solo conoce documentos y ediciones. Tiene sentido porque el buffer abierto puede no estar guardado en disco, pero en cuanto el análisis necesita más de un archivo la aproximación se queda corta y toca acceder al sistema de ficheros por su cuenta, de forma sincronizada con las notificaciones del cliente. Y no todas llegan: hay cambios que ocurren fuera del editor y el cliente no siempre los comunica.
La solución pasa por cargar las fuentes en memoria como un sistema de ficheros virtual y aplicar los cambios encima. Cada modificación actualiza una generación de fuentes, que da un estado interno consistente y permite cancelar las consultas en vuelo que quedan invalidadas. Sin esa capa, dicen, el proyecto se convierte en una condición de carrera permanente. Combinar acceso directo al disco con las notificaciones del protocolo a pelo es justo lo que evita este diseño.
El texto es la primera entrega de una serie y se corta cuando empieza a hablar del coste real de ejecutar consultas, que no es uniforme ni barato. Para quien mantiene un servidor de lenguaje, un plugin de editor o una herramienta de análisis estático, el interés está en ese catálogo de trampas: el orden de las respuestas, la coherencia del estado y la cancelación no son detalles de implementación, son la arquitectura.


