Design da Extensão de Sintaxe Markdown
Contexto
Este documento mantém as referências de implementação para o PR integrado de
extensão de sintaxe Markdown. Ele é baseado na pesquisa de otimização TUI de
origin/docs/tui-optimization-design, especialmente:
docs/design/tui-optimization/00-overview.mddocs/design/tui-optimization/03-rendering-extensibility.mddocs/design/tui-optimization/04-gemini-cli-research.mddocs/design/tui-optimization/05-claude-code-research.mddocs/design/tui-optimization/06-implementation-rollout-checklist.mddocs/design/tui-optimization/08-execution-plan-and-test-matrix.md
A pesquisa referenciada recomenda uma arquitetura Markdown de longo prazo construída em torno de um parser de AST, cache de blocos/tokens, streaming com prefixo estável, painéis de detalhes limitados e detecção de capacidade do terminal. Esta primeira implementação mantém a pegada de runtime pequena e torna o novo comportamento visível imediatamente.
Escopo do PR Integrado
Este PR trata a expansão da sintaxe Markdown como uma melhoria coesa do renderizador, não como PRs de recursos separados.
Incluído na primeira implementação:
- Blocos de código Mermaid renderizam visualmente no TUI.
- Diagramas Mermaid renderizam através de imagens PNG no terminal quando a
renderização de imagens está explicitamente ativada,
mmdcestá disponível e o terminal suporta um caminho de imagem. - Diagramas Mermaid
flowchart/graphrecorrem a pré-visualizações de caixa e seta. - Diagramas Mermaid
sequenceDiagramrecorrem a pré-visualizações de participante e seta. - Blocos básicos
classDiagram,stateDiagram,erDiagram,gantt,pie,journey,mindmap,gitGraph, erequirementDiagramrecorrem a pré-visualizações de texto limitadas. - Tipos Mermaid sem pré-visualização de texto recorrem ao seu código-fonte delimitado original para que o usuário ainda possa ler e copiar a definição do diagrama.
- Itens de lista de tarefas renderizam marcadores de concluído/não concluído.
- Citações em bloco renderizam com uma barra de citação visível.
- Matemática inline
$...$e em bloco$$...$$renderizam com substituições Unicode comuns. - As tabelas Markdown existentes continuam usando
TableRenderer. - Os blocos de código não-Mermaid existentes continuam usando
CodeColorizer. - Os blocos visuais renderizados mantêm a fonte acessível através de
/copy mermaid N,/copy latex N,/copy latex inline Ne modo raw. ui.renderModecontrola se as sessões iniciam no modo renderizado ou raw/fonte, enquantoAlt/Option+Malterna a visualização da sessão ativa.
Estratégia de Renderização Mermaid
Primeira versão: renderização de imagem com verificação de capacidade e fallback de texto
A implementação agora trata o próprio layout do Mermaid como o caminho preferido. Quando o ambiente local suporta, o TUI renderiza blocos Mermaid através deste pipeline:
Código-fonte Mermaid
-> mmdc / CLI Mermaid
-> PNG
-> Protocolo de imagem de terminal Kitty ou iTerm2Se o terminal não suportar imagens inline mas chafa estiver instalado, o
mesmo PNG é renderizado como gráficos de bloco ANSI. Se nem o protocolo de
imagem nem chafa estiverem disponíveis, o renderizador recorre à
pré-visualização de texto síncrona descrita abaixo.
A renderização de imagem não é tentada enquanto uma resposta ainda está sendo
transmitida. Durante a transmissão, blocos Mermaid mostram uma pré-visualização
pendente limitada. Quando a resposta é finalizada, o caminho da imagem é
tentado apenas quando explicitamente ativado. Isso mantém a inicialização lenta
do mmdc, especialmente o caminho npx opt-in, fora do caminho de
renderização interativo padrão.
A geração de PNG é armazenada em cache independentemente da colocação no terminal. Renderizações repetidas da mesma fonte Mermaid, incluindo atualizações de redimensionamento do terminal, reutilizam o PNG gerado e apenas recalculam as dimensões de colocação do Kitty/iTerm2.
O caminho da imagem é intencionalmente opt-in e verificado por capacidade, em
vez de sempre empacotar ou invocar Puppeteer/Chromium a partir do caminho CLI
ativo. Um usuário pode ativar o caminho da imagem com
QWEN_CODE_MERMAID_IMAGE_RENDERING=1, depois fornecer
@mermaid-js/mermaid-cli instalando mmdc no PATH ou definindo
QWEN_CODE_MERMAID_MMD_CLI para o caminho do binário. Para verificação local
ad-hoc, QWEN_CODE_MERMAID_ALLOW_NPX=1 permite que o renderizador invoque
npx -y @mermaid-js/mermaid-cli@11.12.0; isso é intencionalmente opt-in porque
a primeira execução pode instalar Puppeteer/Chromium e bloquear a renderização.
Renderizadores locais do repositório node_modules/.bin não são descobertos
automaticamente, a menos que QWEN_CODE_MERMAID_ALLOW_LOCAL_RENDERERS=1 esteja
definido. A seleção do protocolo de terminal pode ser forçada com
QWEN_CODE_MERMAID_IMAGE_PROTOCOL=kitty|iterm2|off.
Para terminais compatíveis com Kitty, como Ghostty, o renderizador usa
placeholders Unicode Kitty em vez de escrever o payload da imagem como texto
Ink. O PNG é transmitido através de stdout bruto em modo silencioso (q=2)
com uma colocação virtual (U=1), e a árvore React renderiza a grade de
caractere placeholder normal (U+10EEEE) com diacríticos explícitos de linha
e coluna para cada célula. Isso mantém o Ink responsável pelo layout e
redimensionamento enquanto evita que bytes de payload APC sejam envolvidos
em texto base64 visível.
Fallback: pré-visualização de wireframe redimensionável
O fallback evita trabalho assíncrono porque o caminho <Static> do Ink é
apenas de anexação: uma mensagem finalizada não pode aguardar de forma
confiável uma renderização em segundo plano e então atualizar no lugar sem
forçar uma atualização estática completa. O fallback deve, portanto, produzir
saída de terminal durante o passe de renderização React normal.
Para diagramas flowchart / graph, o fallback constrói um modelo de grafo leve em vez de imprimir uma aresta por vez:
- Os nós são normalizados pelo id Mermaid, rótulo e forma básica.
- Os rótulos dos nós suportam quebras de linha no estilo Mermaid (
\n/<br>). - Diagramas de cima para baixo são classificados em camadas horizontais.
- Diagramas da esquerda para a direita são classificados em colunas verticais quando cabem.
- Múltiplas arestas de saída de um mesmo nó são desenhadas como uma única bifurcação com rótulos de aresta entre colchetes, como
[Sim],[Não],[是]e[否]. - Arestas de retorno e ciclos são resumidos em uma seção
Ciclos:com marcadores explícitos↩ para <nó>. Isso evita rotas instáveis e longas entre diagramas em fontes de terminal, mantendo a semântica do loop visível. - O grafo é recalculado a partir de
contentWidth, então o redimensionamento altera largura dos nós, espaçamento e caminhos dos conectores. - Pré-visualizações grandes são limitadas antes do layout do grafo, para que blocos Mermaid muito grandes não aloquem uma tela de terminal ilimitada durante a renderização.
Exemplo:
renderiza como uma pré-visualização visual no terminal em vez de código-fonte Mermaid.
Outras famílias comuns de diagramas Mermaid usam resumos de texto limitados em vez de um mecanismo completo de layout: relacionamentos/membros de classes, transições de estado, entidades/relacionamentos ER, tarefas Gantt, fatias de pizza, etapas de jornada, árvores de mindmap, entradas de git graph e árvores de requisitos. Se um tipo de diagrama é desconhecido ou não pode ser pré-visualizado, o renderizador mostra o código-fonte Mermaid original entre fences em vez de um placeholder, para que o conteúdo permaneça legível e selecionável/copiável no terminal. Cabeçalhos Mermaid renderizados também mostram o comando de cópia específico do Mermaid, por exemplo /copy mermaid 2, para que os usuários possam recuperar o código-fonte original do diagrama sem precisar mudar a visualização inteira para o modo bruto.
O fallback ainda não é um mecanismo Mermaid completo. É uma camada rápida de pré-visualização com poucas dependências para diagramas comuns gerados por LLM quando a renderização de alta fidelidade não está disponível.
Provedores futuros
O limite do provedor é intencionalmente aberto para provedores adicionais de imagem nativa:
mmdc/@mermaid-js/mermaid-clipara saída SVG/PNG.terminal-imagepara Kitty/iTerm2 com fallback ANSI.chafaquando presente para mosaicos Sixel/Kitty/iTerm2/Unicode.
Esse caminho deve permanecer opcional, armazenado em cache e controlado por capacidade, com chaves de cache baseadas no hash da fonte, largura do terminal, provedor do renderizador e protocolo do terminal. Não deve bloquear a inicialização nem adicionar trabalho empacotado do Mermaid/Puppeteer ao caminho TUI ativo por padrão.
Compatibilidade com Renderizador AST
A primeira versão estende o analisador existente para minimizar o impacto. Os limites dos recursos ainda são compatíveis com um futuro pipeline de tokens marked:
code(lang=mermaid)->MermaidDiagramcode(lang=*)->CodeColorizerexistentetable->TableRendererexistenteblockquote-> renderizador de bloco de citaçãolist(task=true)-> renderizador de lista de tarefasparagraph/text-> renderizador inline com suporte a matemática/link/estilo
A implementação não armazena em cache nós React. Um futuro renderizador AST deve armazenar em cache tokens/blocos e depois renderizar a partir das props atuais de largura/tema/configurações.
Segurança e Desempenho
- O código-fonte Mermaid é tratado como entrada não confiável.
- O primeiro renderizador não executa JavaScript Mermaid.
- A renderização de imagem nativa deve ser opt-in ou controlada por capacidade.
- Futuras renderizações baseadas em navegador devem usar timeouts e limites de tamanho.
- A renderização deve degradar para texto do terminal em vez de lançar exceções.
- Blocos grandes devem respeitar a altura e largura disponíveis.
Validação
Verificação unitária direcionada:
cd packages/cli
npx vitest run \
src/config/settingsSchema.test.ts \
src/ui/AppContainer.test.tsx \
src/ui/utils/MarkdownDisplay.test.tsx \
src/ui/utils/mermaidImageRenderer.test.ts \
src/ui/commands/copyCommand.test.ts \
src/ui/components/BaseTextInput.test.tsx \
src/ui/keyMatchers.test.ts \
src/ui/contexts/KeypressContext.test.tsxVerificação mais ampla antes do envio do PR:
npm run build --workspace=packages/cli
npm run typecheck --workspace=packages/cli
npm run lint --workspace=packages/cli
git diff --checkCenário de integração com captura de terminal:
npm run build && npm run bundle
cd integration-tests/terminal-capture
npm run capture:markdown-renderingEsse cenário captura uma resposta de modelo com muito Markdown, alterna entre modo bruto/fonte com Alt/Option+M e verifica os fluxos de cópia de fonte visível com /copy mermaid 1 e /copy latex 1.
Cenários manuais:
- Resposta do assistente com um bloco Mermaid
flowchart LR. - Resposta do assistente com um bloco Mermaid
sequenceDiagram. - Tabela Markdown mais Mermaid na mesma resposta.
- Bloco de código JavaScript com fences ainda mostrando formatação de código.
- Largura de terminal estreita.
- Superfície de ferramenta/detalhe reduzida.
ui.renderMode: "raw"inicia uma sessão no modo orientado a fonte.Alt/Option+Malterna a mesma resposta entre o modo renderizado e o modo bruto/fonte.- Blocos visuais Mermaid e LaTeX exibem dicas de cópia que mapeiam para a ordem de origem real de
/copy mermaid Ne/copy latex N.