--- 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.