Lock DSC-0066 on Q1-A and Q2-A. Retire AGD-0048 through AGD-0056 into AGD-0069, DEC-0058, and PLN-0137. Published editor diagnostics use the bound frontend language id as source. For PBS that is pbs. The stable compiler code stays in code and is not copied into source. Related locations, phase, and repair payload stay unpublished.
128 lines
11 KiB
Markdown
128 lines
11 KiB
Markdown
---
|
|
id: AGD-0069
|
|
ticket: pbs-lsp-remaining-editor-surface
|
|
title: PBS LSP Remaining Editor Surface
|
|
status: accepted
|
|
created: 2026-09-22
|
|
resolved:
|
|
decision:
|
|
tags: [studio, lsp, vscode, compiler-pbs, editor]
|
|
---
|
|
|
|
## Pain
|
|
|
|
Domain owner: `studio`
|
|
|
|
Nove agendas de LSP (AGD-0048 a AGD-0056, discussões DSC-0045 a DSC-0053) continuavam abertas como se cada tema partisse do zero. O servidor já anuncia hover, completion, signature help, definition, references, document symbols, workspace symbols, rename, quick fix e semantic tokens. Várias perguntas dessas agendas já foram respondidas pelo código, ou pedem trabalho cuja premissa deixou de existir. Decidir uma a uma repetiria debate vencido e produziria nove decisions para uma superfície só.
|
|
|
|
## Context
|
|
|
|
Esta agenda substitui, sem herdar o texto como normativo:
|
|
|
|
| Agenda aposentada | Discussão | O que o código já fez com o tema |
|
|
| --- | --- | --- |
|
|
| AGD-0048 formatting | DSC-0045 | Não há `documentFormattingProvider`, `rangeFormatting` nem `onTypeFormatting`. |
|
|
| AGD-0049 import assistance | DSC-0046 | Não há auto-import nem organize imports. Imports existem como `ImportDecl` / `ModuleRef`. |
|
|
| AGD-0050 semantic tokens | DSC-0047 | Tokens full-document já saem de `PBSSemanticTokenProvider`. |
|
|
| AGD-0051 cache e snapshots | DSC-0048 | Cada pedido reconstrói análise. References e rename já existem sem cache. |
|
|
| AGD-0052 completion depth | DSC-0049 | Completion já existe, eager, gatilho `.`, `resolveProvider` falso. |
|
|
| AGD-0053 folding e selection | DSC-0050 | Não há folding nem selection range. Outline não é folding. |
|
|
| AGD-0054 diagnostics UX | DSC-0051 | Diagnóstico já publica range, severity, message e code. Quick fix já casa code + range. |
|
|
| AGD-0055 document links | DSC-0052 | Não há `documentLinkProvider`. Definition já recusa alvo que não seja arquivo físico. |
|
|
| AGD-0056 call e type hierarchy | DSC-0053 | Não há call hierarchy nem type hierarchy. References não são grafo de chamadas. |
|
|
|
|
O que o initialize anuncia hoje, em `Lsp4jProtocolMessageMapper`: sync full, hover, completion, signature help, definition, references, document symbol, workspace symbol, rename com prepare, code action só `quickfix`, semantic tokens full. Nada além disso.
|
|
|
|
Fatos que esta agenda trata como fechados, porque o código já os fixou:
|
|
|
|
1. Análise de LSP é local ao pedido. `CompilerLanguageServiceBridge.analyzeDocument` monta um `AnalysisSnapshot` novo com overlay do documento aberto. Não há cache de projeto, cancelamento nem reanálise em background. References, rename e workspace symbols já foram entregues em cima desse modelo. Cache não é pré-requisito de mais nenhuma feature desta onda.
|
|
2. Semantic tokens não estão por fazer. `PBSSemanticTokenProvider` lexa o arquivo, classifica token léxico direto e classifica identificador por token vizinho, mapa de declaração do próprio arquivo e kinds importados da stdlib. A legenda é `PbsSemanticKind`. Não existem keys de field, local ou parameter. Arquivo quebrado continua tokenizável porque o lexer não depende do sucesso semântico.
|
|
3. Completion não está por fazer. `PbsEditorialSupportService.completion` faz duas coisas: se o token anterior é `.`, membros do tipo; senão keywords, parâmetros, locals, símbolos importados e top-level do arquivo. Documentação volta no próprio item. Não há snippets, não há `completionItem/resolve`, não há score de ranking.
|
|
4. Diagnóstico não carrega remediação. Spec 23 §8.3 e o quick fix já entregue exigem que o reparo não seja campo do diagnóstico nem venha de parse da mensagem. O mapper copia range, severity, message e code. O campo `source` está errado: `toBaselineIssue` grava o code estável também em `source` (ou `"Prometeu Studio"` quando o code vem vazio). Não há `relatedInformation`.
|
|
5. Não há um code de diagnóstico cujo significado seja "nome não importado". Os codes de nome não resolvido que existem são casos pontuais (`E_SEM_CONST_UNRESOLVED_REFERENCE`, `E_SEM_APPLY_UNRESOLVED_OVERLOAD`, `E_SEM_ASSIGN_TARGET_UNRESOLVED`, `E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE`). Inserir import em cima deles mistura typo com import faltando.
|
|
6. Definition, references e rename só apontam arquivo físico. Alvo virtual de stdlib não é destino de navegação.
|
|
7. A política de indentação em `LSN-0033` pertence ao editor embutido removido. Não é estilo canônico de PBS e não manda no formatter do LSP.
|
|
8. Outline, workspace symbols, rename e quick fix não absorvem folding, links, hierarquia nem organize imports.
|
|
|
|
Fora desta onda, de propósito:
|
|
|
|
- cache de snapshot, cancelamento e reanálise em background;
|
|
- type hierarchy, implementações de contract e grafo de host/intrinsic como feature separada;
|
|
- `completionItem/resolve`, snippets e modelo de ranking;
|
|
- formatting por range ou on-type;
|
|
- organize imports e quick fix de import faltando;
|
|
- `relatedInformation`, fase do compilador dentro do diagnóstico, e campo de remediação;
|
|
- keys novas de semantic token;
|
|
- links para assets, addressables, docs ou URI virtual de stdlib.
|
|
|
|
## Open Questions
|
|
|
|
- [x] **Q1. Qual pacote o plano único executa?** Travada em 2026-09-22: **A**.
|
|
- **A.** Os sete passos da recomendação, nesta ordem, um commit cada. Inclui formatter e call hierarchy.
|
|
- **B.** Os mesmos passos sem o 7 (call hierarchy fica fora).
|
|
- **C.** Os mesmos passos sem o 4 (formatter fica fora até existir estilo aceito).
|
|
- **D.** Só os passos que não escolhem estilo nem grafo novo: 1, 2, 3 e 6.
|
|
|
|
- [x] **Q2. Se o passo 4 entrar, qual estilo o formatter aplica?** Travada em 2026-09-22: **A**.
|
|
- **A.** Reimpressão do token stream. Não reordena declarações. Não junta nem parte linhas para embelezar. Indentação de 4 espaços só onde o aninhamento de chaves, parênteses ou bloco muda. Interior de text block `Doc` intocado. Comentário permanece na linha do token a que já estava preso. Documento inteiro apenas.
|
|
- **B.** Não travar estilo. O passo 4 sai do plano mesmo se Q1 escolher A ou B.
|
|
|
|
## Options
|
|
|
|
### Option A - Uma onda, um plano, commits por passo
|
|
|
|
- **Approach:** Uma decision e um plan. O plan copia os passos abaixo que Q1/Q2 deixarem vivos. Cada passo é um commit na mesma branch. Lesson e housekeep só depois do último passo.
|
|
- **Pro:** O código atual vira o piso. Tema vencido não vira decision. A série continua um commit por entrega, sem nove discussões.
|
|
- **Con:** Formatter e call hierarchy ainda são maiores que links ou o rótulo de `source`.
|
|
- **Maintainability:** Forte se cada passo não reabrir cache, type hierarchy ou auto-import.
|
|
|
|
### Option B - Só o que já não tem escolha de produto
|
|
|
|
- **Approach:** Mesma discussão única, mas o plano fica em diagnóstico `source`, document links físicos, folding/selection e completion de module ref.
|
|
- **Pro:** Evita travar estilo e evita um grafo de chamadas novo.
|
|
- **Con:** Formatting e call hierarchy continuam sem dono depois de aposentar as agendas velhas.
|
|
- **Maintainability:** Boa, e menor.
|
|
|
|
## Tradeoffs
|
|
|
|
Juntar as nove agendas num plano só é seguro porque o piso já está no código. O risco é enfiar de volta, como "passo pequeno", cache, contrato novo de diagnóstico ou auto-import. Esses três não cabem: o primeiro perdeu a premissa, o segundo quebra o quick fix já aceito, o terceiro não tem diagnóstico estável para se pendurar.
|
|
|
|
Formatter é o único passo que ainda escolhe estilo. Por isso ele é um passo isolado: recusar Q2 tira só esse commit. Call hierarchy não pode reusar o índice de references; references são usos da mesma identidade, não chamadas. Ou entra como caminhada de `CallExpr` no último commit, ou fica de fora.
|
|
|
|
## Recommendation
|
|
|
|
Aceitar Option A com Q1-A e Q2-A.
|
|
|
|
Forma do plano, obrigatória:
|
|
|
|
- uma decision e um plan desta discussão;
|
|
- branch `dev/pbs-lsp-remaining-editor-surface`, não uma branch por passo e não commit em `master`;
|
|
- cada passo vivo vira um commit `implements PLN-NNNN (k/N) <slug>`;
|
|
- sem push;
|
|
- spec 23 §8.3 só ganha parágrafo do passo que a superfície realmente passa a anunciar;
|
|
- lesson e `discussion housekeep` só no commit do último passo.
|
|
|
|
Passos, nesta ordem. Passo que Q1 ou Q2 tirar não é renumerado no meio da implementação: o plan lista só os que sobreviverem, em ordem.
|
|
|
|
1. **Diagnostic source.** `source` passa a ser o language id do frontend (`pbs`). `code` continua o code estável. Sem `relatedInformation`, sem fase, sem data de reparo.
|
|
2. **Document links.** Link só no span do `ModuleRef` de um import cujo destino já resolve para arquivo físico regular. Sem destino físico, sem link. Stdlib virtual, asset e doc ficam de fora.
|
|
3. **Folding e selection range.** Span de AST quando a árvore recuperada tem o nó: declaração top-level (`fn`, `struct`, `service`, `contract`, `enum`, `error`, `callback`, `host`), corpo, lista de parâmetros e text block `Doc`. Fallback de token só para chave, parêntese ou text block que a árvore não cobre. Selection, do interno para o externo: identificador, lista de argumento ou parâmetro, bloco ou text block, declaração. Lista vazia quando não houver range. Não reutilizar document symbols.
|
|
4. **Formatting de documento inteiro.** Só se Q2 travar estilo. Sem range e sem on-type. Preserva comentário e interior de text block `Doc`. Não é pretty-printer de AST.
|
|
5. **Overlay semântico em cima do token atual.** Não substituir `PBSSemanticTokenProvider`. Onde a mesma resolução de hover já nomeia o símbolo, trocar o kind fraco por um `PbsSemanticKind` que já existe. Falha, arquivo quebrado ou símbolo desconhecido mantém o token de hoje. Nenhuma key nova.
|
|
6. **Completion de module ref.** No cursor dentro de `ModuleRef`, candidatos que o resolver atual já sabe nomear, módulo de projeto e stdlib. Continua eager. `resolveProvider` continua falso. Sem snippets e sem score novo. Fora de module ref, o completion atual não muda.
|
|
7. **Call hierarchy.** Incoming e outgoing de função e método por caminhada de callsite na AST, não pelo índice de references. Cursor que não é callable devolve vazio. Sem type hierarchy e sem cache.
|
|
|
|
## Discussion
|
|
|
|
As agendas AGD-0048 a AGD-0056 foram aposentadas a pedido, neste consolidado, antes de qualquer accept. O texto delas não é decisão. A CLI `discussion` não tem comando de abandon; a aposentadoria ficou no índice e no frontmatter, com a lacuna registrada para um comando futuro.
|
|
|
|
Não aceitar esta agenda até Q1 e Q2 terem resposta explícita. A recomendação é o pacote, não um convite para preencher o resto na implementação.
|
|
|
|
## Resolution
|
|
|
|
Q1-A e Q2-A travados pelo usuário em 2026-09-22. O pacote da recomendação é a escolha que a decision torna normativa.
|
|
|
|
## Next Step
|
|
|
|
Decision aceita e plan desta discussão. Implementar os sete passos em série, um commit cada.
|