Custom writer: default to single quotes for strings

Makes the code more consistent and makes it easier to use double quotes
in strings, which is the usual quoting style used for HTML attributes.

Closes: #7487
This commit is contained in:
Albert Krewinkel 2022-01-31 10:21:00 +01:00
parent 0e5ab9760b
commit 46e5937628
No known key found for this signature in database
GPG key ID: 388DC0B21F631124
2 changed files with 84 additions and 84 deletions

View file

@ -14,7 +14,7 @@
-- syntax errors. -- syntax errors.
local pipe = pandoc.pipe local pipe = pandoc.pipe
local stringify = (require "pandoc.utils").stringify local stringify = (require 'pandoc.utils').stringify
-- The global variable PANDOC_DOCUMENT contains the full AST of -- The global variable PANDOC_DOCUMENT contains the full AST of
-- the document which is going to be written. It can be used to -- the document which is going to be written. It can be used to
@ -25,19 +25,19 @@ local meta = PANDOC_DOCUMENT.meta
-- `image_format` meta value. -- `image_format` meta value.
local image_format = meta.image_format local image_format = meta.image_format
and stringify(meta.image_format) and stringify(meta.image_format)
or "png" or 'png'
local image_mime_type = ({ local image_mime_type = ({
jpeg = "image/jpeg", jpeg = 'image/jpeg',
jpg = "image/jpeg", jpg = 'image/jpeg',
gif = "image/gif", gif = 'image/gif',
png = "image/png", png = 'image/png',
svg = "image/svg+xml", svg = 'image/svg+xml',
})[image_format] })[image_format]
or error("unsupported image format `" .. image_format .. "`") or error('unsupported image format `' .. image_format .. '`')
-- Character escaping -- Character escaping
local function escape(s, in_attribute) local function escape(s, in_attribute)
return s:gsub("[<>&\"']", return s:gsub('[<>&"\']',
function(x) function(x)
if x == '<' then if x == '<' then
return '&lt;' return '&lt;'
@ -60,7 +60,7 @@ end
local function attributes(attr) local function attributes(attr)
local attr_table = {} local attr_table = {}
for x,y in pairs(attr) do for x,y in pairs(attr) do
if y and y ~= "" then if y and y ~= '' then
table.insert(attr_table, ' ' .. x .. '="' .. escape(y,true) .. '"') table.insert(attr_table, ' ' .. x .. '="' .. escape(y,true) .. '"')
end end
end end
@ -72,7 +72,7 @@ local notes = {}
-- Blocksep is used to separate block elements. -- Blocksep is used to separate block elements.
function Blocksep() function Blocksep()
return "\n\n" return '\n\n'
end end
-- This function is called once for the whole document. Parameters: -- This function is called once for the whole document. Parameters:
@ -106,31 +106,31 @@ function Str(s)
end end
function Space() function Space()
return " " return ' '
end end
function SoftBreak() function SoftBreak()
return "\n" return '\n'
end end
function LineBreak() function LineBreak()
return "<br/>" return '<br/>'
end end
function Emph(s) function Emph(s)
return "<em>" .. s .. "</em>" return '<em>' .. s .. '</em>'
end end
function Strong(s) function Strong(s)
return "<strong>" .. s .. "</strong>" return '<strong>' .. s .. '</strong>'
end end
function Subscript(s) function Subscript(s)
return "<sub>" .. s .. "</sub>" return '<sub>' .. s .. '</sub>'
end end
function Superscript(s) function Superscript(s)
return "<sup>" .. s .. "</sup>" return '<sup>' .. s .. '</sup>'
end end
function SmallCaps(s) function SmallCaps(s)
@ -142,33 +142,33 @@ function Strikeout(s)
end end
function Link(s, tgt, tit, attr) function Link(s, tgt, tit, attr)
return "<a href='" .. escape(tgt,true) .. "' title='" .. return '<a href="' .. escape(tgt,true) .. '" title="' ..
escape(tit,true) .. "'" .. attributes(attr) .. ">" .. s .. "</a>" escape(tit,true) .. '"' .. attributes(attr) .. '>' .. s .. '</a>'
end end
function Image(s, src, tit, attr) function Image(s, src, tit, attr)
return "<img src='" .. escape(src,true) .. "' title='" .. return '<img src="' .. escape(src,true) .. '" title="' ..
escape(tit,true) .. "'/>" escape(tit,true) .. '"/>'
end end
function Code(s, attr) function Code(s, attr)
return "<code" .. attributes(attr) .. ">" .. escape(s) .. "</code>" return '<code' .. attributes(attr) .. '>' .. escape(s) .. '</code>'
end end
function InlineMath(s) function InlineMath(s)
return "\\(" .. escape(s) .. "\\)" return '\\(' .. escape(s) .. '\\)'
end end
function DisplayMath(s) function DisplayMath(s)
return "\\[" .. escape(s) .. "\\]" return '\\[' .. escape(s) .. '\\]'
end end
function SingleQuoted(s) function SingleQuoted(s)
return "&lsquo;" .. s .. "&rsquo;" return '&lsquo;' .. s .. '&rsquo;'
end end
function DoubleQuoted(s) function DoubleQuoted(s)
return "&ldquo;" .. s .. "&rdquo;" return '&ldquo;' .. s .. '&rdquo;'
end end
function Note(s) function Note(s)
@ -184,11 +184,11 @@ function Note(s)
end end
function Span(s, attr) function Span(s, attr)
return "<span" .. attributes(attr) .. ">" .. s .. "</span>" return '<span' .. attributes(attr) .. '>' .. s .. '</span>'
end end
function RawInline(format, str) function RawInline(format, str)
if format == "html" then if format == 'html' then
return str return str
else else
return '' return ''
@ -200,8 +200,8 @@ function Cite(s, cs)
for _,cit in ipairs(cs) do for _,cit in ipairs(cs) do
table.insert(ids, cit.citationId) table.insert(ids, cit.citationId)
end end
return "<span class=\"cite\" data-citation-ids=\"" .. table.concat(ids, ",") .. return '<span class="cite" data-citation-ids="' .. table.concat(ids, ',') ..
"\">" .. s .. "</span>" '">' .. s .. '</span>'
end end
function Plain(s) function Plain(s)
@ -209,16 +209,16 @@ function Plain(s)
end end
function Para(s) function Para(s)
return "<p>" .. s .. "</p>" return '<p>' .. s .. '</p>'
end end
-- lev is an integer, the header level. -- lev is an integer, the header level.
function Header(lev, s, attr) function Header(lev, s, attr)
return "<h" .. lev .. attributes(attr) .. ">" .. s .. "</h" .. lev .. ">" return '<h' .. lev .. attributes(attr) .. '>' .. s .. '</h' .. lev .. '>'
end end
function BlockQuote(s) function BlockQuote(s)
return "<blockquote>\n" .. s .. "\n</blockquote>" return '<blockquote>\n' .. s .. '\n</blockquote>'
end end
function HorizontalRule() function HorizontalRule()
@ -234,39 +234,39 @@ function CodeBlock(s, attr)
-- If code block has class 'dot', pipe the contents through dot -- If code block has class 'dot', pipe the contents through dot
-- and base64, and include the base64-encoded png as a data: URL. -- and base64, and include the base64-encoded png as a data: URL.
if attr.class and string.match(' ' .. attr.class .. ' ',' dot ') then if attr.class and string.match(' ' .. attr.class .. ' ',' dot ') then
local img = pipe("base64", {}, pipe("dot", {"-T" .. image_format}, s)) local img = pipe('base64', {}, pipe('dot', {'-T' .. image_format}, s))
return '<img src="data:' .. image_mime_type .. ';base64,' .. img .. '"/>' return '<img src="data:' .. image_mime_type .. ';base64,' .. img .. '"/>'
-- otherwise treat as code (one could pipe through a highlighter) -- otherwise treat as code (one could pipe through a highlighter)
else else
return "<pre><code" .. attributes(attr) .. ">" .. escape(s) .. return '<pre><code' .. attributes(attr) .. '>' .. escape(s) ..
"</code></pre>" '</code></pre>'
end end
end end
function BulletList(items) function BulletList(items)
local buffer = {} local buffer = {}
for _, item in pairs(items) do for _, item in pairs(items) do
table.insert(buffer, "<li>" .. item .. "</li>") table.insert(buffer, '<li>' .. item .. '</li>')
end end
return "<ul>\n" .. table.concat(buffer, "\n") .. "\n</ul>" return '<ul>\n' .. table.concat(buffer, '\n') .. '\n</ul>'
end end
function OrderedList(items) function OrderedList(items)
local buffer = {} local buffer = {}
for _, item in pairs(items) do for _, item in pairs(items) do
table.insert(buffer, "<li>" .. item .. "</li>") table.insert(buffer, '<li>' .. item .. '</li>')
end end
return "<ol>\n" .. table.concat(buffer, "\n") .. "\n</ol>" return '<ol>\n' .. table.concat(buffer, '\n') .. '\n</ol>'
end end
function DefinitionList(items) function DefinitionList(items)
local buffer = {} local buffer = {}
for _,item in pairs(items) do for _,item in pairs(items) do
local k, v = next(item) local k, v = next(item)
table.insert(buffer, "<dt>" .. k .. "</dt>\n<dd>" .. table.insert(buffer, '<dt>' .. k .. '</dt>\n<dd>' ..
table.concat(v, "</dd>\n<dd>") .. "</dd>") table.concat(v, '</dd>\n<dd>') .. '</dd>')
end end
return "<dl>\n" .. table.concat(buffer, "\n") .. "\n</dl>" return '<dl>\n' .. table.concat(buffer, '\n') .. '\n</dl>'
end end
-- Convert pandoc alignment to something HTML can use. -- Convert pandoc alignment to something HTML can use.
@ -303,13 +303,13 @@ function Table(caption, aligns, widths, headers, rows)
local function add(s) local function add(s)
table.insert(buffer, s) table.insert(buffer, s)
end end
add("<table>") add('<table>')
if caption ~= "" then if caption ~= '' then
add("<caption>" .. escape(caption) .. "</caption>") add('<caption>' .. escape(caption) .. '</caption>')
end end
if widths and widths[1] ~= 0 then if widths and widths[1] ~= 0 then
for _, w in pairs(widths) do for _, w in pairs(widths) do
add('<col width="' .. string.format("%.0f%%", w * 100) .. '" />') add('<col width="' .. string.format('%.0f%%', w * 100) .. '" />')
end end
end end
local header_row = {} local header_row = {}
@ -317,7 +317,7 @@ function Table(caption, aligns, widths, headers, rows)
for i, h in pairs(headers) do for i, h in pairs(headers) do
local align = html_align(aligns[i]) local align = html_align(aligns[i])
table.insert(header_row,'<th align="' .. align .. '">' .. h .. '</th>') table.insert(header_row,'<th align="' .. align .. '">' .. h .. '</th>')
empty_header = empty_header and h == "" empty_header = empty_header and h == ''
end end
if not empty_header then if not empty_header then
add('<tr class="header">') add('<tr class="header">')
@ -326,9 +326,9 @@ function Table(caption, aligns, widths, headers, rows)
end end
add('</tr>') add('</tr>')
end end
local class = "even" local class = 'even'
for _, row in pairs(rows) do for _, row in pairs(rows) do
class = (class == "even" and "odd") or "even" class = (class == 'even' and 'odd') or 'even'
add('<tr class="' .. class .. '">') add('<tr class="' .. class .. '">')
for i,c in pairs(row) do for i,c in pairs(row) do
add('<td align="' .. html_align(aligns[i]) .. '">' .. c .. '</td>') add('<td align="' .. html_align(aligns[i]) .. '">' .. c .. '</td>')
@ -340,7 +340,7 @@ function Table(caption, aligns, widths, headers, rows)
end end
function RawBlock(format, str) function RawBlock(format, str)
if format == "html" then if format == 'html' then
return str return str
else else
return '' return ''
@ -348,7 +348,7 @@ function RawBlock(format, str)
end end
function Div(s, attr) function Div(s, attr)
return "<div" .. attributes(attr) .. ">\n" .. s .. "</div>" return '<div' .. attributes(attr) .. '>\n' .. s .. '</div>'
end end
-- The following code will produce runtime warnings when you haven't defined -- The following code will produce runtime warnings when you haven't defined
@ -358,6 +358,6 @@ local meta = {}
meta.__index = meta.__index =
function(_, key) function(_, key)
io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key)) io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key))
return function() return "" end return function() return '' end
end end
setmetatable(_G, meta) setmetatable(_G, meta)

View file

@ -5,7 +5,7 @@ John Grubers markdown test suite.</p>
<h1 id="headers">Headers</h1> <h1 id="headers">Headers</h1>
<h2 id="level-2-with-an-embedded-link">Level 2 with an <a href='/url' title=''>embedded link</a></h2> <h2 id="level-2-with-an-embedded-link">Level 2 with an <a href="/url" title="">embedded link</a></h2>
<h3 id="level-3-with-emphasis">Level 3 with <em>emphasis</em></h3> <h3 id="level-3-with-emphasis">Level 3 with <em>emphasis</em></h3>
@ -525,7 +525,7 @@ Blah
<p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p> <p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p>
<p>An <em><a href='/url' title=''>emphasized link</a></em>.</p> <p>An <em><a href="/url" title="">emphasized link</a></em>.</p>
<p><strong><em>This is strong and em.</em></strong></p> <p><strong><em>This is strong and em.</em></strong></p>
@ -560,7 +560,7 @@ So is &lsquo;pine.&rsquo;</p>
<p>&lsquo;He said, &ldquo;I want to go.&rdquo;&rsquo; Were you alive in the <p>&lsquo;He said, &ldquo;I want to go.&rdquo;&rsquo; Were you alive in the
70s?</p> 70s?</p>
<p>Here is some quoted &lsquo;<code>code</code>&rsquo; and a &ldquo;<a href='http://example.com/?foo=1&amp;bar=2' title=''>quoted link</a>&rdquo;.</p> <p>Here is some quoted &lsquo;<code>code</code>&rsquo; and a &ldquo;<a href="http://example.com/?foo=1&amp;bar=2" title="">quoted link</a>&rdquo;.</p>
<p>Some dashes: one—two — three—four — five.</p> <p>Some dashes: one—two — three—four — five.</p>
@ -660,70 +660,70 @@ So is &lsquo;pine.&rsquo;</p>
<h2 id="explicit">Explicit</h2> <h2 id="explicit">Explicit</h2>
<p>Just a <a href='/url/' title=''>URL</a>.</p> <p>Just a <a href="/url/" title="">URL</a>.</p>
<p><a href='/url/' title='title'>URL and title</a>.</p> <p><a href="/url/" title="title">URL and title</a>.</p>
<p><a href='/url/' title='title preceded by two spaces'>URL and title</a>.</p> <p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>
<p><a href='/url/' title='title preceded by a tab'>URL and title</a>.</p> <p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>
<p><a href='/url/' title='title with &quot;quotes&quot; in it'>URL and title</a></p> <p><a href="/url/" title="title with &quot;quotes&quot; in it">URL and title</a></p>
<p><a href='/url/' title='title with single quotes'>URL and title</a></p> <p><a href="/url/" title="title with single quotes">URL and title</a></p>
<p><a href='/url/with_underscore' title=''>with_underscore</a></p> <p><a href="/url/with_underscore" title="">with_underscore</a></p>
<p><a href='mailto:nobody@nowhere.net' title=''>Email link</a></p> <p><a href="mailto:nobody@nowhere.net" title="">Email link</a></p>
<p><a href='' title=''>Empty</a>.</p> <p><a href="" title="">Empty</a>.</p>
<h2 id="reference">Reference</h2> <h2 id="reference">Reference</h2>
<p>Foo <a href='/url/' title=''>bar</a>.</p> <p>Foo <a href="/url/" title="">bar</a>.</p>
<p>With <a href='/url/' title=''>embedded [brackets]</a>.</p> <p>With <a href="/url/" title="">embedded [brackets]</a>.</p>
<p><a href='/url/' title=''>b</a> by itself should be a link.</p> <p><a href="/url/" title="">b</a> by itself should be a link.</p>
<p>Indented <a href='/url' title=''>once</a>.</p> <p>Indented <a href="/url" title="">once</a>.</p>
<p>Indented <a href='/url' title=''>twice</a>.</p> <p>Indented <a href="/url" title="">twice</a>.</p>
<p>Indented <a href='/url' title=''>thrice</a>.</p> <p>Indented <a href="/url" title="">thrice</a>.</p>
<p>This should [not][] be a link.</p> <p>This should [not][] be a link.</p>
<pre><code>[not]: /url</code></pre> <pre><code>[not]: /url</code></pre>
<p>Foo <a href='/url/' title='Title with &quot;quotes&quot; inside'>bar</a>.</p> <p>Foo <a href="/url/" title="Title with &quot;quotes&quot; inside">bar</a>.</p>
<p>Foo <a href='/url/' title='Title with &quot;quote&quot; inside'>biz</a>.</p> <p>Foo <a href="/url/" title="Title with &quot;quote&quot; inside">biz</a>.</p>
<h2 id="with-ampersands">With ampersands</h2> <h2 id="with-ampersands">With ampersands</h2>
<p>Heres a <a href='http://example.com/?foo=1&amp;bar=2' title=''>link with an ampersand in the URL</a>.</p> <p>Heres a <a href="http://example.com/?foo=1&amp;bar=2" title="">link with an ampersand in the URL</a>.</p>
<p>Heres a link with an amersand in the link text: <a href='http://att.com/' title='AT&amp;T'>AT&amp;T</a>.</p> <p>Heres a link with an amersand in the link text: <a href="http://att.com/" title="AT&amp;T">AT&amp;T</a>.</p>
<p>Heres an <a href='/script?foo=1&amp;bar=2' title=''>inline link</a>.</p> <p>Heres an <a href="/script?foo=1&amp;bar=2" title="">inline link</a>.</p>
<p>Heres an <a href='/script?foo=1&amp;bar=2' title=''>inline link in pointy braces</a>.</p> <p>Heres an <a href="/script?foo=1&amp;bar=2" title="">inline link in pointy braces</a>.</p>
<h2 id="autolinks">Autolinks</h2> <h2 id="autolinks">Autolinks</h2>
<p>With an ampersand: <a href='http://example.com/?foo=1&amp;bar=2' title='' class="uri">http://example.com/?foo=1&amp;bar=2</a></p> <p>With an ampersand: <a href="http://example.com/?foo=1&amp;bar=2" title="" class="uri">http://example.com/?foo=1&amp;bar=2</a></p>
<ul> <ul>
<li>In a list?</li> <li>In a list?</li>
<li><a href='http://example.com/' title='' class="uri">http://example.com/</a></li> <li><a href="http://example.com/" title="" class="uri">http://example.com/</a></li>
<li>It should.</li> <li>It should.</li>
</ul> </ul>
<p>An e-mail address: <a href='mailto:nobody@nowhere.net' title='' class="email">nobody@nowhere.net</a></p> <p>An e-mail address: <a href="mailto:nobody@nowhere.net" title="" class="email">nobody@nowhere.net</a></p>
<blockquote> <blockquote>
<p>Blockquoted: <a href='http://example.com/' title='' class="uri">http://example.com/</a></p> <p>Blockquoted: <a href="http://example.com/" title="" class="uri">http://example.com/</a></p>
</blockquote> </blockquote>
<p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p> <p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p>
@ -740,7 +740,7 @@ So is &lsquo;pine.&rsquo;</p>
<img src="lalune.jpg" id="" alt="lalune"/><figcaption>lalune</figcaption> <img src="lalune.jpg" id="" alt="lalune"/><figcaption>lalune</figcaption>
</figure> </figure>
<p>Here is a movie <img src='movie.jpg' title=''/> icon.</p> <p>Here is a movie <img src="movie.jpg" title=""/> icon.</p>
<hr/> <hr/>
@ -774,7 +774,7 @@ footnote (as with list items).</p>
lazy and just indent the first line of each block. <a href="#fnref2">&#8617;</a></p></li> lazy and just indent the first line of each block. <a href="#fnref2">&#8617;</a></p></li>
<li id="fn3"><p>This <li id="fn3"><p>This
is <em>easier</em> to type. Inline notes may contain is <em>easier</em> to type. Inline notes may contain
<a href='http://google.com' title=''>links</a> and <code>]</code> verbatim characters, <a href="http://google.com" title="">links</a> and <code>]</code> verbatim characters,
as well as [bracketed text]. <a href="#fnref3">&#8617;</a></p></li> as well as [bracketed text]. <a href="#fnref3">&#8617;</a></p></li>
<li id="fn4"><p>In quote. <a href="#fnref4">&#8617;</a></p></li> <li id="fn4"><p>In quote. <a href="#fnref4">&#8617;</a></p></li>
<li id="fn5"><p>In list. <a href="#fnref5">&#8617;</a></p></li> <li id="fn5"><p>In list. <a href="#fnref5">&#8617;</a></p></li>