9.1 KiB
| id | ticket | title | status | created | resolved | decision | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| AGD-0035 | studio-new-lsp-api-and-v1-boundary | Novo boundary entre lsp-api, lsp-v1 e a extensao VS Code | accepted | 2026-05-05 | 2026-05-05 | DEC-0032 |
|
Pain
O stack legado de editor, prometeu-lsp e prometeu-vfs acabou de ser removido. O próximo passo natural é reconstruir o backend de linguagem, mas sem repetir o erro anterior de misturar engine semântica, transporte LSP, sessão editorial e host UI em um único desenho.
Ao mesmo tempo, já existe uma extensão em tools/vscode-extension que hoje sabe conectar via TCP em 127.0.0.1:7777 e falar LSP como cliente real. Isso reduz incerteza no lado do FE, mas aumenta a exigência arquitetural do backend: o servidor novo precisa nascer com boundary correto.
O risco central é reintroduzir acoplamento acidental entre:
- contratos internos de linguagem;
- transporte externo LSP;
- implementação concreta baseada em
LSP4J; - e necessidades específicas do VS Code.
Context
- O cleanup do stack legado foi fechado por
DEC-0031. - A extensão VS Code já existe em
tools/vscode-extension. - A extensão usa
vscode-languagecliente conecta por socket TCP configurável. - O usuário quer explicitamente que
LSP4Jnão vaze delsp-v1. - A intenção geral do produto é que o Studio fale a própria língua internamente e exponha adapters externos para FEs, no mesmo espírito já discutido para integrações como Tiled.
Hoje, a pergunta não é "como implementar o LSP inteiro", mas sim:
- que módulos recriar;
- qual boundary o
lsp-apirealmente deve carregar; - e qual responsabilidade cabe a
lsp-v1como adapter concreto.
Também já existe um direcionamento adicional do produto:
lsp-v1deve consumir serviços existentes decompiler;lsp-apideve expor funcionalidades reutilizáveis por outras partes do sistema;- o bootstrap do servidor deve acontecer quando um projeto é aberto, e o shutdown quando o projeto é fechado;
- a API pode começar mínima, por exemplo com
boot servereshutdown server, e crescer só quando houver necessidade real.
Open Questions
- O
lsp-apideve expor contratos próprios de domínio/serviço ou DTOs alinhados diretamente ao protocolo LSP? R: o lsp-api deve expor somente servicos que serao usados por outras partes do sistema, e nao ser um espelho do protocolo. - O
lsp-v1deve ser somente um adapterLSP4Jsobre serviços internos decompiler, ou também pode carregar parte da orquestração de sessão? R: O lsp-v1 deve conter o servidor e todo o necessario para falar LSP, incluindo DTOs e dependencias de LSP4J (e fazer uso de compiler quando necessario). o start e o stop do servidor podem ser chamados via lsp-api, mas a logica de orquestracao de sessao deve ficar dentro do lsp-v1. - O lifecycle de bootstrap/shutdown do servidor por projeto pertence ao
lsp-api, aolsp-v1, ou a outro serviço do Studio? R: o contrato fica no lsp-api, mas a logica de orquestracao fica no lsp-v1. o lsp-api pode expor um contrato comobootServer(project)eshutdownServer(project), mas a implementacao concreta e a logica de associar o servidor ao projeto fica no lsp-v1. - O canal de automação (
compile/build/run/debug) deve viver fora do novolsp-apidesde o início? R: o canal de automacao deve viver fora do lsp-api. nesse primeiro momento o foco principal deve ser o LSP e o comportamento editorial/semantico. o canal de automacao pode ser discutido e implementado separadamente, sem misturar responsabilidades. - O
tools/vscode-extensiondeve continuar falando LSP puro em socket TCP, ou o produto precisa reservar outra estratégia de transporte já nesta fase? R: o vscode-extension deve continuar falando LSP puro em socket TCP. o lsp-api deve ser agnóstico ao transporte, mas ainda aceito recomendacoes q sejam mais faceis ou performaticas.
Options
Option A - lsp-api como API diretamente moldada pelo protocolo LSP
- Approach: recriar
lsp-apicom tipos e serviços muito próximos da superfície do protocolo, deixandolsp-v1apenas como bootstrapLSP4Je roteamento paracompiler. - Pro: acelera integração com o cliente existente e reduz tradução entre camadas.
- Con: tende a tornar o protocolo externo dono do desenho interno; muda mal quando surgir outro FE ou outro adapter.
- Maintainability: fraca. O risco de vazamento conceitual do protocolo para dentro do domínio é alto, mesmo sem importar classes
LSP4Jfora delsp-v1.
Option B - lsp-api mínima e operacional; lsp-v1 como adapter LSP4J que consome compiler
- Approach:
lsp-apiexpõe uma surface mínima e reutilizável para o sistema, começando com operações comoboot server(project)eshutdown server(project)e, no máximo, contratos estáveis que outras partes do Studio precisem enxergar.lsp-v1concentra a implementação concreta do servidor, depende exclusivamente deLSP4J, e consome os serviços docompilerpara responder às capacidades LSP. - Pro: respeita a regra de não vazamento de
LSP4J, evita inflar a API cedo demais e alinha o lifecycle do servidor ao projeto aberto, não ao processo global do Studio. - Con: exige disciplina para não transformar
lsp-apiem um espelho parcial do protocolo nemlsp-v1em um segundo backend semântico solto docompiler. - Maintainability: forte. O backend nasce hexagonal e o custo de evolução fica mais previsível.
Option C - Sem lsp-api; expor apenas um servidor LSP concreto em lsp-v1
- Approach: pular a separação e concentrar tudo em um único módulo novo de servidor, com contratos locais apenas package-private ou internos.
- Pro: menor custo inicial de scaffolding.
- Con: repete exatamente o tipo de colapso arquitetural que gerou o legado descartado; dificulta teste, substituição de transporte e integração com outros FEs.
- Maintainability: ruim. A velocidade inicial é comprada com dívida estrutural imediata.
Discussion
O dado novo mais importante é que o cliente VS Code já está funcional como cliente LSP puro. Isso elimina a necessidade de desenhar o protocolo "pensando no editor". O editor já sabe falar LSP; quem precisa de disciplina agora é o Studio.
Isso empurra a arquitetura para uma separação bem objetiva:
lsp-apinão deve ser "API pública do protocolo";lsp-apideve ser uma API interna e mínima do backend de linguagem do Studio;lsp-v1deve ser o adapter LSP concreto e consumidor dos serviços decompiler;LSP4Jdeve existir exclusivamente emlsp-v1.
O ponto sensível é não confundir "API interna" com "engine concreta". Se lsp-api virar um lugar para pôr qualquer detalhe de sessão, thread, socket, CompletableFuture de transporte, ou estruturas do LSP4J, ele já nasce errado. Pelo direcionamento atual, a API deve começar deliberadamente estreita:
- boot do servidor por projeto;
- shutdown do servidor por projeto;
- e só depois crescer quando outro consumidor real do sistema exigir isso.
Também vale separar desde já o que não pertence ao LSP:
compile/build/run/debugnão devem entrar nolsp-apipor conveniência;- esses fluxos pertencem a um contrato de automação paralelo;
- o LSP deve se limitar ao que é comportamento editorial/semântico.
Outro ponto: o usuário já fixou que o Studio é o backend autoritativo e o cliente externo é só cliente. Isso reforça que o lifecycle do servidor precisa acompanhar o projeto aberto. Em outras palavras:
- abrir Studio não implica subir servidor LSP global;
- abrir projeto pode implicar subir o servidor LSP daquele projeto;
- fechar projeto deve encerrar o servidor correspondente.
As respostas atuais também fecharam um boundary operacional importante:
- quem "fala LSP" de verdade é o
lsp-v1; lsp-apinão é adapter nem espelho do protocolo;lsp-apiexiste para expor um boundary interno consumível pelo Studio;- o contrato mínimo inicial pode ser pequeno, desde que suficiente para boot/shutdown por projeto;
- DTOs, tipos e dependências do protocolo podem existir em
lsp-v1sem contaminar a API interna.
Resolution
Direção recomendada para convergir:
- recriar
lsp-apicomo surface interna mínima e reutilizável do sistema, começando com bootstrap e shutdown por projeto; - recriar
lsp-v1como adapter LSP/JSON-RPC concreto, com dependência exclusiva deLSP4J; - fazer
lsp-v1consumir serviços existentes decompiler, em vez de reconstruir pipeline semântico próprio; - deixar a lógica concreta de orquestração de sessão e associação
projeto -> servidordentro delsp-v1, mesmo quando o bootstrap/shutdown for disparado através delsp-api; - tratar qualquer tipo
LSP4Jfora delsp-v1como violação arquitetural; - manter
tools/vscode-extensioncomo cliente LSP puro em socket TCP; - discutir separadamente o contrato de automação para
compile/build/run/debug, em vez de empurrá-lo para dentro do LSP.
Neste ponto, a agenda já tem direção clara o bastante para virar decision. O que ainda resta fechar depois disso é implementação, não escolha arquitetural principal.