124 lines
9.3 KiB
Markdown
124 lines
9.3 KiB
Markdown
---
|
|
id: AGD-0017
|
|
ticket: studio-editor-scope-guides-and-brace-anchoring
|
|
title: Scope guides do Code Editor com active container, active scope e ancoragem estrutural
|
|
status: accepted
|
|
created: 2026-04-03
|
|
resolved: 2026-04-03
|
|
decision:
|
|
tags:
|
|
- studio
|
|
- editor
|
|
- scope-guides
|
|
- braces
|
|
- semantic-read
|
|
- frontend-contract
|
|
---
|
|
|
|
## Pain
|
|
|
|
Os scope guides do Code Editor hoje comunicam hierarquia de escopo, mas ainda falham em dois pontos visuais importantes:
|
|
|
|
- o guide nao comeca no `{` real do bloco; ele nasce aproximadamente no meio da linha inicial do simbolo;
|
|
- o editor nao destaca o escopo em que o cursor esta, entao o usuario nao recebe feedback imediato de qual bloco esta ativo.
|
|
|
|
Isso deixa a feature util, mas incompleta. Em blocos aninhados, a leitura espacial do editor perde precisao justamente no momento em que o guide deveria ajudar mais.
|
|
|
|
## Context
|
|
|
|
Domain owner: `studio`
|
|
Owner surfaces: `docs/specs/studio/5. Code Editor Workspace Specification.md`, `docs/specs/studio/7. Integrated LSP Semantic Read Phase Specification.md`
|
|
Cross-domain input: frontends que produzem `documentSymbols()` para o Studio
|
|
|
|
Superficies relevantes hoje:
|
|
|
|
- `EditorWorkspace` monta os guides a partir de `analysis.documentSymbols()` e repassa o modelo para a paragraph graphic factory em `prometeu-studio/src/main/java/p/studio/workspaces/editor/EditorWorkspace.java`;
|
|
- `EditorDocumentScopeGuideModel` projeta guias por linha com `depth` e `GuideSegmentKind`, mas nao carrega coluna nem offset estrutural do brace em `prometeu-studio/src/main/java/p/studio/workspaces/editor/EditorDocumentScopeGuideModel.java`;
|
|
- `EditorDocumentScopeGuideGraphicFactory` desenha `START` e `END` a partir do centro vertical da linha, nao de um token estrutural real, em `prometeu-studio/src/main/java/p/studio/workspaces/editor/EditorDocumentScopeGuideGraphicFactory.java`;
|
|
- os testes atuais do modelo validam apenas shape por linha, nao ancoragem precisa de brace nem estado ativo por cursor, em `prometeu-studio/src/test/java/p/studio/workspaces/editor/EditorDocumentScopeGuideModelTest.java`.
|
|
|
|
Hoje o schema semantico exposto ao Studio entrega `documentSymbols` com `LspRangeDTO(startOffset, endOffset)`, o que e suficiente para inferir linhas de escopo, mas nao suficiente para afirmar onde o `{` de abertura e o `}` de fechamento realmente estao quando:
|
|
|
|
- o brace esta em outra coluna da mesma linha;
|
|
- o header do simbolo se estende por mais de uma linha;
|
|
- a linguagem tem formas de bloco em que o range do simbolo nao coincide com o token estrutural que queremos destacar.
|
|
|
|
## Open Questions
|
|
|
|
- [x] O escopo ativo deve ser definido sempre como o menor range estrutural que contem o caret, ou existem casos em que o Studio deve promover o parent em vez do bloco mais interno?
|
|
Fechado: `active scope` deve ser sempre o menor range estrutural que contem o caret.
|
|
- [x] Como o Studio escolhe o `active container` quando o caret esta em blocos aninhados: funcao owner, tipo owner, ou simplesmente o menor ancestor acima do `active scope`?
|
|
Fechado: `active container` deve ser o ancestor estrutural imediato acima do `active scope`, sem excecoes semanticas especiais para funcao, tipo ou outro owner.
|
|
- [x] O guide deve ancorar no token estrutural real (`{`/`}`), ou basta uma heuristica local no editor que encontre o primeiro brace plausivel dentro do range do simbolo?
|
|
Fechado: a ancoragem exata nao deve depender de heuristica textual local como contrato final; o objetivo correto e um anchor estrutural real.
|
|
- [x] O contrato correto para essa precisao estrutural pertence ao frontend/LSP semantic read, ou o Studio deve derivar isso localmente a partir do texto do documento?
|
|
Fechado: a precisao estrutural pertence ao frontend e deve ser exposta ao Studio como metadata semanticamente owned pelo produtor da linguagem.
|
|
- [x] Como tratar linguagens que nao usam braces ou usam formas mistas de delimitacao, sem acoplar o Studio a PBS?
|
|
Fechado: o contrato deve falar em `structural anchors` genericos, nao em braces como primitivo normativo.
|
|
- [x] O schema atual de `documentSymbols` deve ser enriquecido, ou devemos introduzir uma surface estrutural paralela dedicada a guides/brackets?
|
|
Fechado: devemos introduzir uma surface semantica propria para guides/anchors em vez de inflar `documentSymbols`.
|
|
|
|
## Options
|
|
|
|
### Option A - Heuristica local no Studio sobre os ranges atuais
|
|
- **Approach:** Manter o contrato atual de `documentSymbols` e fazer o Studio procurar braces plausiveis dentro do texto/range de cada simbolo, alem de calcular o escopo ativo localmente pelo caret.
|
|
- **Pro:** Menor custo inicial e pouca mudanca de contrato entre frontend e Studio.
|
|
- **Con:** A heuristica tende a ser fragil para headers multiline, linguagens sem braces, ranges amplos demais e futuras linguagens com sintaxe diferente de PBS.
|
|
- **Maintainability:** Media para baixa. Resolve rapido, mas cristaliza logica estrutural no host visual em vez de no owner da linguagem.
|
|
|
|
### Option B - Metadata estrutural explicita fornecida pelo frontend
|
|
- **Approach:** Enriquecer o payload semantico consumido pelo Studio com posicoes estruturais explicitas para abertura/fechamento de blocos, ou com uma surface propria para scope/bracket guides; o editor usa esse contrato para ancoragem exata e para determinar o escopo ativo.
|
|
- **Pro:** Fecha ownership correto no frontend, preserva neutralidade do Studio em relacao a sintaxe e permite ancoragem precisa sem heuristica textual fraca.
|
|
- **Con:** Exige mudar o contrato entre semantic read e Studio, propagar implementacao para o frontend e decidir um schema que nao fique PBS-especifico.
|
|
- **Maintainability:** Forte. A precisao estrutural fica no produtor semantico, onde o parse e o conhecimento de linguagem ja existem.
|
|
|
|
### Option C - Abordagem hibrida em duas waves
|
|
- **Approach:** Implementar primeiro um gutter minimalista com no maximo duas linhas visiveis: `active container` e `active scope`, ambos calculados localmente a partir dos ranges atuais; tratar a ancoragem exata no `{` como uma extensao posterior baseada em metadata estrutural explicita.
|
|
- **Pro:** Entrega contexto e foco ao mesmo tempo, com pouco ruido, sem bloquear na extensao de contrato e sem puxar o Studio para heuristica sintatica como solucao final.
|
|
- **Con:** Exige definir semanticamente o que conta como `active container` e pode exigir retrabalho pequeno no modelo do editor quando a metadata estrutural chegar.
|
|
- **Maintainability:** Boa, se a primeira wave permanecer estritamente limitada a duas linhas sem ancestry aberta.
|
|
|
|
## Discussion
|
|
|
|
Os dois sintomas nao tem o mesmo peso arquitetural.
|
|
|
|
Destacar o escopo ativo parece um problema majoritariamente local do editor, especialmente se a primeira wave for minimalista e restrita ao gutter:
|
|
|
|
- o `CodeArea` ja conhece caret/paragrafo atual;
|
|
- o modelo atual ja conhece os ranges de escopo por linha;
|
|
- em primeira aproximacao, o editor consegue descobrir qual range contem o cursor sem precisar saber a coluna exata do `{`;
|
|
- renderizar no maximo duas linhas (`active container` e `active scope`) preserva contexto sem voltar ao mapa completo de ancestry.
|
|
|
|
Ja a ancoragem precisa do guide no brace parece um problema de contrato estrutural:
|
|
|
|
- o modelo atual nao sabe onde o brace real esta;
|
|
- usar apenas `startOffset/endOffset` do simbolo empurra heuristica sintatica para dentro do Studio;
|
|
- isso fica especialmente fraco num editor que ja foi desenhado para ser multi-frontend.
|
|
|
|
Por isso, vale separar claramente:
|
|
|
|
1. `active container` e `active scope` como comportamento visual local, minimalista, restrito ao gutter e derivado dos ranges atuais;
|
|
2. `brace anchoring` como capacidade estrutural que talvez exija metadata adicional do frontend.
|
|
|
|
O risco de tentar resolver tudo localmente no Studio e transformar o host visual em pseudo-parser por linguagem.
|
|
O risco oposto e bloquear uma melhoria visual simples do cursor enquanto esperamos um contrato estrutural maior ficar pronto.
|
|
|
|
## Resolution
|
|
|
|
Recommended direction: seguir com **Option C**.
|
|
|
|
A agenda deve convergir para uma decisao com os seguintes fechamentos:
|
|
|
|
1. a primeira wave deve manter o scope indicator no gutter, de forma minimalista e sem poluicao visual;
|
|
2. a primeira wave pode renderizar no maximo duas linhas no gutter: `active container` e `active scope`, sem ancestry arbitraria e sem mapa completo de guides;
|
|
3. `active scope` deve ser o menor range estrutural que contem o caret;
|
|
4. `active container` deve ser o ancestor estrutural imediato acima do `active scope`;
|
|
5. o destaque desses estados pelo cursor deve ser tratado como capacidade local do editor, usando os ranges semanticos ja disponiveis, desde que a regra fique language-agnostic;
|
|
6. a apresentacao visual concreta desses indicadores deve continuar frontend-owned; o contrato do Studio nao deve fixar cores, tracos ou estilos especificos como regra normativa;
|
|
7. a ancoragem exata do guide nao deve ser resolvida por heuristica textual como contrato final;
|
|
8. a precisao estrutural deve ser exposta por metadata frontend-owned;
|
|
9. essa metadata deve falar em `structural anchors` genericos, nao em braces como primitivo normativo;
|
|
10. guides/anchors devem viver em uma surface semantica propria, em vez de estender `documentSymbols`.
|
|
|
|
Next step suggestion: converter esta agenda em uma `decision` que feche o boundary entre Studio e frontend para structural scope metadata, diferencie formalmente `active scope` de `brace anchor`, e declare a wave inicial aceitavel para o Code Editor.
|