GitHub Markdown Math: Regras de Renderização e Soluções Alternativas
O GitHub renderiza matemática em Markdown em duas etapas:
- Lado servidor (
cmark-gfm+ sanitizador de math): encontra os limites de$ ... $e$$ ... $$, aplica a remoção de escape CommonMark em pontuação ASCII e rejeita macros LaTeX não permitidas antes de emitir tags<math-renderer>. - Lado cliente (
<math-renderer>+MathJax.tex2mml): converte TeX para MathML e injeta na página para layout MathML Core nativo do navegador.
Ambas as etapas têm bugs que quebram LaTeX comum. As regras abaixo são soluções alternativas para esses bugs.
Quando usar esta skill
- Escrevendo ou editando matemática em um arquivo
.mdque será lido no GitHub. - Corrigindo equações que renderizam esmagadas, vermelhas ou como texto
$$bruto no GitHub. - Não é necessário para arquivos que passam apenas por LaTeX, Pandoc, Jupyter, MkDocs ou VS Code. Se um arquivo for lido em ambos os lugares, as substituições abaixo são TeX/MathJax comuns, então ainda renderizam em outros lugares.
Fluxo de trabalho
- Durante a escrita, siga as regras 1 a 4 abaixo.
- Antes de commitar, execute o script de verificação nos arquivos Markdown alterados (veja Script). Execute-o sem
--checkpara corrigi-los no local. - Revise o resultado com
git diff. O script é baseado em regex, então trate sua saída como um rascunho. A renderização não pode ser verificada localmente; se houver dúvida, visualize no GitHub.
Referência rápida
| Em vez de | Escreva | Por quê |
|---|---|---|
\tag{2.1} | \qquad\text{(2.1)} | \tag esmaga a equação em uma faixa vertical |
\operatorname{Foo} | \mathrm{Foo} | operatorname é bloqueado pelo sanitizador |
\mathrm{Im} D_t | \mathrm{Im}\thinspace D_t | restaura o espaçamento de operador |
\hbox{...}, {\rm ...} | \text{...}, {\mathrm{...}} | macros plain-TeX são bloqueadas |
\{, \} | \lbrace, \rbrace | CommonMark transforma \{ em { |
\\\\ em uma única linha | \cr | CommonMark transforma \\\\ em \ |
\, | \thinspace | CommonMark transforma \, em , |
\,, | , | renderizaria como vírgula dupla |
q_* (vários * em um bloco) | q_\ast | * emparelhado vira ênfase Markdown |
1. Nunca use \tag{...} (evita esmagamento vertical de 1 caractere)
- Bug:
MathJax.tex2mmlserializa qualquer equação contendo\tag{2.1}como<mtable displaystyle="true"><mlabeledtr><mtd>.... O MathML Core do navegador removeu<mlabeledtr>, então Chromium/Blink e Firefox não o tratam como uma linha de tabela e comprimem a equação em uma coluna de 1 caractere de largura. - Solução alternativa: coloque
\qquad\text{(2.1)}no final da equação de exibição. Para uma linha no rótulo, use o Unicode′dentro de\text{(3.3′)}em vez de um\tag{3.3$'$}$aninhado.
<!-- Quebrado no GitHub (esmagado em uma coluna vertical) -->
$$
\partial_t \mathcal{Q} + \partial_x \mathcal{J} = 0 \tag{2.1}
$$
<!-- Funciona no GitHub -->
$$
\partial_t \mathcal{Q} + \partial_x \mathcal{J} = 0 \qquad\text{(2.1)}
$$
2. Nunca use \operatorname{...}, \hbox{...} ou {\rm ...} (evita erros de macro não permitida)
- Bug: O sanitizador do lado servidor do GitHub bloqueia
\operatornamee\operatorname*com a mensagem "As seguintes macros não são permitidas: operatorname". - Solução alternativa:
- Substitua
\operatorname{Foo}por\mathrm{Foo}. Quando for seguido diretamente por uma letra ou uma macro de barra invertida (por exemplo\operatorname{Im} D_tou\operatorname{pr} v), adicione\thinspace(\mathrm{Im}\thinspace D_t) para manter o espaçamento de operador. - Substitua
\hbox{...}do plain-TeX por\text{...}, e{\rm ...}por{\mathrm{...}}.
- Substitua
<!-- Quebrado no GitHub ("As seguintes macros não são permitidas: operatorname") -->
$\operatorname{diag}(1, -1)$ and $\operatorname{Im} D_t$
<!-- Funciona no GitHub -->
$\mathrm{diag}(1, -1)$ and $\mathrm{Im}\thinspace D_t$
3. Faça delimitadores, espaçamento e quebras de linha sobreviverem à remoção de escape do CommonMark
- Bug: antes da matemática chegar a
<math-renderer>, o parser Markdown do GitHub aplica a remoção de escape de pontuação ASCII CommonMark dentro de$ ... $e$$ ... $$:\{vira{e\}vira}. Isso causa "Delimitador ausente ou não reconhecido para \left" em\left\{, e silenciosamente remove as chaves de colchetes de Poisson\{F, G\}.\\\\(quando não seguido por uma nova linha) vira\. Isso quebra matrizes de linha única e casos como\begin{pmatrix} 0 & 1 \\ -1 & 0 \end{pmatrix}em\-1, dando erros vermelhos de macro não definida.\,,vira,,(vírgula dupla) e\,vira,(uma vírgula literal antes dedx).*emparelhado dentro de um bloco de matemática (por exemploU_+(z - 2q_*), \quad z = w + Dq_*) pode ser interpretado como ênfase<em>Markdown.
- Solução alternativa:
- Use
\lbracee\rbraceem vez de\{e\}(adicione um espaço se uma letra seguir:\lbrace F, G\rbrace). - Use
\crem vez de\\\\para quebras de linha em matrizes e ambientes de linha única, ou coloque uma nova linha imediatamente após\\\\dentro de blocos$$...$$de várias linhas. - Use
\thinspaceem vez de\,(com um espaço à direita antes de letras:dt\thinspace dx), e substitua\,,por,. - Use
\ast(q_\ast) em vez de*(q_*) quando uma equação contiver vários asteriscos.
- Use
<!-- Quebrado no GitHub -->
Colchete de Poisson inline $\{F, G\} = 0$, conjunto $\left\{ x : x > 0 \right\}$, integral $\int dx\,dy$, matriz $\bigl(\begin{smallmatrix} 0 & 1 \\ -1 & 0 \end{smallmatrix}\bigr)$.
<!-- Funciona no GitHub -->
Colchete de Poisson inline $\lbrace F, G\rbrace = 0$, conjunto $\left\lbrace x : x > 0 \right\rbrace$, integral $\int dx\thinspace dy$, matriz $\bigl(\begin{smallmatrix} 0 & 1 \cr -1 & 0 \end{smallmatrix}\bigr)$.
4. Formate limites de blocos $$ ... $$ para cmark-gfm
- Bug: quando uma equação contém vários caracteres
_ou*, ocmark-gfmfalha ao reconhecer blocos$$ ... $$em três situações, deixando texto$$bruto e itálico no texto entre sublinhados:- Blocos
$$ ... $$de nível superior sem linhas em branco antes e depois. - Blocos
$$\begin{aligned} ... \end{aligned}$$de várias linhas onde$$está na mesma linha que\begin{aligned}em vez de em sua própria linha. - Blocos
$$...$$de várias linhas indentados dentro de itens de lista (1. ...ou- ...) ou blockquotes (> ...).
- Blocos
- Solução alternativa:
-
Matemática de exibição de nível superior: coloque a abertura e fechamento
$$em suas próprias linhas na coluna 0, com uma linha em branco antes e depois:$$ \begin{aligned} a &= b + c, \\ d &= e + f. \end{aligned} \qquad\text{(1.1)} $$ -
Matemática de exibição dentro de itens de lista ou blockquotes: mantenha toda a equação em uma única linha como
$$\displaystyle ...$$(use\crpara quebras de linha dentro de ambientes), rodeada por linhas em branco:1. Dentro de um item de lista numerada: $$\displaystyle S_d = \int_{\mathbb{R}} dt\thinspace \mathcal{L}_d(\phi_t, \psi_t) \qquad\text{(1.2)}$$
-
Script
scripts/fix_github_math.py aplica as regras acima a arquivos Markdown. Ele reescreve apenas o conteúdo de $...$ e $$...$$, deixa código em blocos de código e código inline intactos, não toca em arquivos sem matemática e é idempotente. Execute-o de qualquer lugar:
# Verificar sem modificar (sai com 1 se algum arquivo precisar de alterações; utilizável em CI ou hook pre-commit)
python3 ~/.claude/skills/github-markdown-math/scripts/fix_github_math.py --check caminho/para/arquivo.md
# Corrigir no local
python3 ~/.claude/skills/github-markdown-math/scripts/fix_github_math.py caminho/para/arquivo.md
Se esta skill estiver instalada em um projeto (.claude/skills/github-markdown-math/), use esse caminho.
Limitações
- É baseado em regex, então revise o diff. Também não pode confirmar que o GitHub renderiza o resultado corretamente.
\operatorname{...}é convertido apenas quando seu argumento não tem chaves aninhadas.\thinspaceé adicionado após\mathrm{...}apenas para uma lista fixa de nomes (Im,im,pr,graph,Div,ker,dim,deg,span,spec,End,Re,tr,rank); adicione manualmente para outros.- Dos asteriscos, apenas
q_*é reescrito paraq_\ast; verifique outros*manualmente (regra 3). - Equações em blockquote são tratadas a um nível de profundidade (
>), não aninhado (> >). - Uma linha com dois cifrões (
$5 e $10) pode ser lida como matemática inline. Isso é inofensivo a menos que o texto entre eles contenha uma sequência de barra invertida que as regras reescrevam. - As regras descrevem o comportamento do GitHub conforme observado. Se o GitHub corrigir um desses bugs, a solução alternativa correspondente se torna desnecessária.