Tabelas normais no Markdown


As tabelas de remarcação são infernais:


  1. Você não pode escrever texto em células com mais de duas palavras e menos ainda uma lista.
  2. Se o dialeto permitir o parágrafo 1, é inconveniente formatar.
  3. Se as células não estiverem alinhadas, a tabela não poderá ser lida.
  4. Não há suporte para tabelas do mesmo tipo e automação, como numeração de linhas.

É hora de escrever um filtro para o Pandoc que desenhe tabelas do YAML estruturado, com numeração de linhas, orientação horizontal, padrões de gráficos e, ao mesmo tempo, descobrir como escrever filtros Lua.


Normalmente, escrevo textos em Markdown e converto para o formato de destino usando Pandoc. Este é um programa que converte documentos entre formatos, por exemplo, do Markdown, você pode obter HTML e outro dialeto do MD, DOCX e PDF (mais de 30 formatos de entrada e mais de 50 formatos de saída). O Pandoc Markdown possui muitas extensões convenientes para links, notas de rodapé, assinaturas e fórmulas.


Pandoc funciona como uma composição de funções (teria sido escrita em Haskell): um formato de entrada específico → representação abstrata de um documento → um formato de saída específico. Uma representação abstrata pode ser modificada usando filtros escritos em Lua. Os filtros não precisam saber sobre o formato de saída, mas podem levar em consideração.


Nosso filtro procurará blocos abstratos de código na table linguagem condicional em uma representação abstrata, lerá o YAML dentro deles e gerará representações abstratas de tabelas que o próprio Pandoc produzirá no formato de destino.


 pandoc --lua-filter table.lua input.md -o output.html 

Quais são as alternativas e por que elas são piores?


  • As tabelas HTML funcionam apenas no Markdown e são convertidas apenas em HTML; apenas o problema de formatação rica em células é resolvido.
  • Os geradores de tabela exigem a troca de um editor de texto; é inconveniente editar o conteúdo das células neles ( exemplo ).
  • Os plug-ins de editores ( Emacs Org-Mode , plug-ins VIM ) não são universais e nem sempre estão disponíveis.

Por outro lado, pandoc-crossref e todos os pães Pandoc trabalham com o filtro para tabelas de resumo. O filtro também pode ser usado para gerar tabelas Markdown padrão, especificando o formato de saída apropriado. Das desvantagens:


  • As células não podem ser mescladas; o Pandoc ainda não suporta isso.
  • Para tabelas horizontais, a estilização deve ser feita usando o formato de saída, por exemplo, através de CSS.

A descrição da tabela inclui três partes:


  1. Estrutura da tabela


    Uma lista ordenada de gráficos (colunas):


    • No mínimo, a coluna deve ter um título.
    • Para poder reorganizar as colunas sem tocar nos dados, o atributo de registro exibido na coluna ( id ) deve ser especificado.
    • As colunas especiais não têm ID, mas têm uma descrição de como preenchê-las. Primeiro você precisa de um número de série ( special: number ).
    • Alinhamento da coluna ( align ).

    Além disso, a tabela pode ser vertical ou horizontal ( orientation ). Neste último caso, os gráficos serão linhas.


  2. Propriedades da tabela: ID para links ( id ) e assinatura ( caption ). O Pandoc permite que você assine tabelas, mas não blocos de código.


  3. Dados na forma de uma matriz de dicionários YAML.



A estrutura pode ser comum a várias tabelas, para que você possa descrevê-la diretamente com a tabela e uma vez nos metadados (assunto principal) e, em seguida, consultar o modelo nomeado.


Plano de Implementação:


  1. A partir dos metadados do documento, formamos um dicionário de modelos.


  2. Para cada bloco de código com a table classes:


    1. Analisamos as tabelas YAML.
    2. Se um modelo for especificado, nós o retiramos do dicionário, caso contrário, preenchemos o modelo no YAML.
    3. Nós preenchemos as propriedades individuais da tabela do YAML.
    4. Formamos entradas de tabela do YAML (um registro é uma linha em uma tabela regular ou uma coluna em uma horizontal).
    5. Nós "desenhamos" uma tabela de acordo com um modelo, propriedades e registros.


O nível superior é implementado conforme escrito (todo o código está disponível no link no final do artigo):


 function Pandoc(doc) local meta_templates = doc.meta['table-templates'] if meta_templates then for name, value in pairs(meta_templates) do templates[name] = parse_template(value) end end local blocks = pandoc.walk_block(pandoc.Div(doc.blocks), { CodeBlock = create_table }) return pandoc.Pandoc(blocks, doc.meta) end 

A função parse_template() converte levemente o formato de metadados. Pandoc representa seus valores como MetaInline e MetaInline . São criadas linhas simples pandoc.utils.stringify() função pandoc.utils.stringify() (por exemplo, orientação) ou elementos visuais (por exemplo, um bloco de texto no cabeçalho da coluna).


Sobre a depuração. Existem muitos exemplos na documentação do Pandoc, mas os tipos não são muito detalhados. Para filtros de depuração, é conveniente ter uma função de despejo variável. Bibliotecas sérias imprimem muitos detalhes; prefiro uma das opções simples.


Funções para converter metadados em elementos do documento
 local function to_inlines(content) if content == nil then return {} elseif type(content) == 'string' then return {pandoc.Str(content)} elseif type(content) == 'number' then return to_inlines(tostring(content)) elseif content.t == 'MetaInlines' then inlines = {} for i, item in ipairs(content) do inlines[i] = item end return inlines end end local function to_blocks(content) if (type(content) == 'table') and content.t == 'MetaBlocks' then return content else return {pandoc.Plain(to_inlines(content))} end end 

A função create_table() é chamada para cada bloco de código em triplo backtics.


Estamos interessados ​​apenas nos blocos de código "no idioma" da table :


 if not contains('table', block.classes) then return block end 

Para analisar o YAML dentro de um bloco de código, criamos um documento que consiste apenas em metadados do YAML, o analisamos com Pandoc e deixamos apenas os metadados:


 local meta = pandoc.read('---\n' .. block.text .. '\n---').meta 

Em seguida, a partir da meta é lido meta link para um modelo ou estrutura de tabela e propriedades de uma tabela específica.


A função fill_table() lê os meta nos atributos especificados na descrição do gráfico. No mesmo estágio, se a coluna estiver marcada como especial, seu conteúdo será gerado:


 local data = {} for i, serie in ipairs(template.series) do if serie.special == 'number' then data[i] = to_blocks(#datum + 1) else data[i] = to_blocks(item[serie.id]) end end 

A função format_table() forma a matriz resultante de células, dependendo da orientação da tabela e cria um objeto abstrato da tabela. Note-se que se as larguras ou cabeçalhos devem ser definidos para todas as colunas ou para nenhuma, caso contrário, o Pandoc simplesmente não criará uma tabela.


O script final pode ser colocado em ~/.local/share/pandoc (o diretório de dados ~/.local/share/pandoc ) para acessá-lo pelo nome de qualquer lugar.


PS


Sobre a contabilização dos filtros de formato de saída. Por exemplo, escrevo spoilers no Pandoc assim:


 ::: {.spoiler title=""}  . ::: 

Não há spoilers no modelo de documento Pandoc, portanto, o filtro deve produzir blocos brutos aproximadamente da seguinte maneira. Obviamente, o código real ( spoiler.lua ) deve levar em consideração o formato de saída por meio da variável FORMAT , e não mecanicamente: o fragmento abaixo produz blocos brutos em HTML, embora o formato de saída seja de redução.


 function Div(el) if not el.attr or not contains('spoiler', el.attr.classes) then return el end local title = el.attr.attributes['title'] or '' table.insert(el.content, 1, pandoc.RawBlock('html', '<' .. 'spoiler title="' .. title .. '">', 'RawBlock')) table.insert(el.content, pandoc.RawBlock('html', '<' .. '/spoiler>', 'RawBlock')) return el.content end 

Referências


Source: https://habr.com/ru/post/pt474826/


All Articles