Skip to content

Commit 19a21f0

Browse files
committed
Improved parsing for {{url}} blocks.
Fixed Markdown parsing issue for links using angle brackets: [text](<url>)
1 parent 6d79638 commit 19a21f0

File tree

3 files changed

+101
-40
lines changed

3 files changed

+101
-40
lines changed

lib/markdown.lua

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
**Author:** Niklas Frykholm, <[email protected]>
77
**Date:** 31 May 2008
8-
**Edited by:** Marcus Thunström (2018-06-14)
8+
**Edited by:** Marcus Thunström (2018-06-14, 2021-05-06)
99
1010
This is an implementation of the popular text markup language Markdown in pure Lua.
1111
Markdown can convert documents written in a simple and easy to read text format
@@ -921,65 +921,101 @@ end
921921
function images(text)
922922
local function reference_link(alt, id)
923923
alt = encode_alt(alt:match("%b[]"):sub(2,-2))
924-
id = id:match("%[(.*)%]"):lower()
925-
if id == "" then id = text:lower() end
924+
id = id:match("%b[]"):sub(2,-2):lower() -- @Edit
925+
926+
if id == "" then id = text:lower() end
927+
926928
link_database[id] = link_database[id] or {}
927-
if not link_database[id].url then return nil end
928-
local url = link_database[id].url or id
929-
url = encode_alt(url)
929+
if not link_database[id].url then return nil end
930+
931+
local url = link_database[id].url or id
932+
url = encode_alt(url)
930933
local title = encode_alt(link_database[id].title)
931-
if title then title = " title=\"" .. title .. "\"" else title = "" end
934+
-- print(("images reference_link url=%-60s title=%s"):format(url, tostring(title)) -- DEBUG
935+
936+
if title then
937+
title = ' title="' .. title .. '"'
938+
else
939+
title = ""
940+
end
941+
932942
return add_escape ('<img src="' .. url .. '" alt="' .. alt .. '"' .. title .. ">") -- @Edit
933943
end
934944

935945
local function inline_link(alt, link)
936-
alt = encode_alt(alt:match("%b[]"):sub(2,-2))
937-
local url, title = link:match("%(<?(.-)>?[ \t]*['\"](.+)['\"]")
938-
url = url or link:match("%(<?(.-)>?%)")
939-
url = encode_alt(url)
940-
title = encode_alt(title)
946+
alt = encode_alt(alt:match"%b[]":sub(2,-2))
947+
local url, title = link:match"%(<?(.-)>?[ \t]*['\"](.+)['\"]"
948+
url = url or link:match"%(<(.-)>%)" or link:match"%((.-)%)" or "" -- @Edit
949+
url = encode_alt(url)
950+
title = encode_alt(title)
951+
-- print(("images inline_link url=%-60s title=%s"):format(url, tostring(title)) -- DEBUG
952+
941953
if title then
942954
return add_escape('<img src="' .. url .. '" alt="' .. alt .. '" title="' .. title .. '">') -- @Edit
943955
else
944956
return add_escape('<img src="' .. url .. '" alt="' .. alt .. '">') -- @Edit
945957
end
946958
end
947959

960+
-- ![alt] [id]
948961
text = text:gsub("!(%b[])[ \t]*\n?[ \t]*(%b[])", reference_link)
962+
-- ![alt](link)
963+
-- ![alt](<link>)
964+
-- ![alt](link "title")
965+
-- ![alt](<link> "title")
949966
text = text:gsub("!(%b[])(%b())", inline_link)
967+
950968
return text
951969
end
952970

953971
-- Handle anchor references
954972
function anchors(text)
955973
local function reference_link(text, id)
956974
text = text:match("%b[]"):sub(2,-2)
957-
id = id:match("%b[]"):sub(2,-2):lower()
958-
if id == "" then id = text:lower() end
975+
id = id:match("%b[]"):sub(2,-2):lower()
976+
977+
if id == "" then id = text:lower() end
978+
959979
link_database[id] = link_database[id] or {}
960-
if not link_database[id].url then return nil end
961-
local url = link_database[id].url or id
962-
url = encode_alt(url)
980+
if not link_database[id].url then return nil end
981+
982+
local url = link_database[id].url or id
983+
url = encode_alt(url)
963984
local title = encode_alt(link_database[id].title)
964-
if title then title = " title=\"" .. title .. "\"" else title = "" end
965-
return add_escape("<a href=\"" .. url .. "\"" .. title .. ">") .. text .. add_escape("</a>")
985+
-- print(("anchors reference_link url=%-60s title=%s"):format(url, tostring(title)) -- DEBUG
986+
987+
if title then
988+
title = ' title="' .. title .. '"'
989+
else
990+
title = ""
991+
end
992+
993+
return add_escape('<a href="' .. url .. '"' .. title .. ">") .. text .. add_escape("</a>")
966994
end
967995

968996
local function inline_link(text, link)
969-
text = text:match("%b[]"):sub(2,-2)
970-
local url, title = link:match("%(<?(.-)>?[ \t]*['\"](.+)['\"]")
971-
title = encode_alt(title)
972-
url = url or link:match("%(<?(.-)>?%)") or ""
973-
url = encode_alt(url)
997+
text = text:match"%b[]":sub(2,-2)
998+
local url, title = link:match"%(<?(.-)>?[ \t]*['\"](.+)['\"]"
999+
url = url or link:match"%(<(.-)>%)" or link:match"%((.-)%)" or "" -- @Edit
1000+
url = encode_alt(url)
1001+
title = encode_alt(title)
1002+
-- print(("anchors inline_link url=%-60s title=%s"):format(url, tostring(title)) -- DEBUG
1003+
9741004
if title then
975-
return add_escape("<a href=\"" .. url .. "\" title=\"" .. title .. "\">") .. text .. "</a>"
1005+
return add_escape('<a href="' .. url .. '" title="' .. title .. '">') .. text .. "</a>"
9761006
else
977-
return add_escape("<a href=\"" .. url .. "\">") .. text .. add_escape("</a>")
1007+
return add_escape('<a href="' .. url .. '">') .. text .. add_escape("</a>")
9781008
end
9791009
end
9801010

1011+
-- [text] [id]
9811012
text = text:gsub("(%b[])[ \t]*\n?[ \t]*(%b[])", reference_link)
1013+
-- [text](link)
1014+
-- [text](<link>)
1015+
-- [text](link "title")
1016+
-- [text](<link> "title")
9821017
text = text:gsub("(%b[])(%b())", inline_link)
1018+
9831019
return text
9841020
end
9851021

@@ -1127,9 +1163,9 @@ function strip_link_definitions(text)
11271163
end
11281164

11291165
local def_no_title = "\n ? ? ?(%b[]):[ \t]*\n?[ \t]*<?([^%s>]+)>?[ \t]*"
1130-
local def_title1 = def_no_title .. "[ \t]+\n?[ \t]*[\"'(]([^\n]+)[\"')][ \t]*"
1131-
local def_title2 = def_no_title .. "[ \t]*\n[ \t]*[\"'(]([^\n]+)[\"')][ \t]*"
1132-
local def_title3 = def_no_title .. "[ \t]*\n?[ \t]+[\"'(]([^\n]+)[\"')][ \t]*"
1166+
local def_title1 = def_no_title .. "[ \t]+\n?[ \t]*[\"'(]([^\n]+)[\"')][ \t]*"
1167+
local def_title2 = def_no_title .. "[ \t]*\n[ \t]*[\"'(]([^\n]+)[\"')][ \t]*"
1168+
local def_title3 = def_no_title .. "[ \t]*\n?[ \t]+[\"'(]([^\n]+)[\"')][ \t]*"
11331169

11341170
text = text:gsub(def_title1, link_def)
11351171
text = text:gsub(def_title2, link_def)

src/functions.lua2p

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,26 @@ do
184184
["["] = "]",
185185
}
186186

187+
-- position, isUrlBlock = findEndOfBlockContents( path, template, position )
187188
local function findEndOfBlockContents(path, template, pos)
188189
!local PRINT_PROGRESS = DEV and 1==0
189190
!if PRINT_PROGRESS then __LUA`printf("%s(%d):%d: >>>>>>>>", path, pos, getLineNumber(template, pos))` end
190191

192+
-- URL block:
193+
-- /(...)
194+
-- ./(...)
195+
-- ../(...)
196+
-- proto:/(...)
197+
if template:find("^ *%.?%.?/", pos) or template:find("^ *%a%w*:/", pos) then
198+
local i1 = template:find("%*?}}", pos)
199+
if not i1 then
200+
fileError(path, template, pos, "Incomplete URL block.")
201+
end
202+
return i1-1, true
203+
end
204+
205+
-- Lua code block:
206+
191207
local blockContentsI1 = pos
192208

193209
local bracketBalance = 0
@@ -220,7 +236,7 @@ do
220236
if posNext == posBlockEnd then
221237
!if PRINT_PROGRESS then __LUA`printf("%s(%d):%d: <<<<<<<<", path, posNext, getLineNumber(template, posNext))` end
222238
pos = posBlockEnd - 1
223-
return pos
239+
return pos, false
224240

225241
elseif posNext == posComment then
226242
!if PRINT_PROGRESS then __LUA`printf("%s(%d):%d: Comment", path, posNext, getLineNumber(template, posNext))` end
@@ -378,9 +394,9 @@ do
378394

379395
table.insert(out, "do end ") -- Statement divider.
380396

381-
local blockContentsI2 = findEndOfBlockContents(path, template, pos)
382-
local blockContents = template:sub(blockContentsI1, blockContentsI2)
383-
pos = blockContentsI2 + 1
397+
local blockContentsI2, isUrlBlock = findEndOfBlockContents(path, template, pos)
398+
local blockContents = template:sub(blockContentsI1, blockContentsI2)
399+
pos = blockContentsI2 + 1
384400

385401
!if DEV and 1==0 then
386402
print("BLOCK: "..trim(blockContents))
@@ -400,11 +416,17 @@ do
400416

401417
----------------------------------------------------------------
402418

419+
-- URL block.
420+
if isUrlBlock then
421+
table.insert(out, F("echo__(url__%q)", trim(blockContents)))
422+
-- @Incomplete: Fix line numbers if blockContents has newlines (which is probably rare).
423+
!!(TRIM_POS_AFTER_BLOCK)
424+
403425
-- Match custom keywords first so we don't confuse those with normal Lua identifiers later.
404426

405427
-- fori [<] item in <array> (...) end
406428
-- fori [<] <array> (...) end
407-
if blockContents:find!("^ *fori"..PATTERN_IDENT_END) then
429+
elseif blockContents:find!("^ *fori"..PATTERN_IDENT_END) then
408430
local reverse, ident, expr = blockContents:match!(NOSPACE("^ %s* fori %s* (< ) %s* ("..PATTERN_IDENT..") %s+ in "..PATTERN_IDENT_END.." %s* (%S.*)"))
409431
if not expr then ident, expr = blockContents:match!(NOSPACE("^ %s* fori %s+ ("..PATTERN_IDENT..") %s+ in "..PATTERN_IDENT_END.." %s* (%S.*)"))
410432
if not expr then reverse, expr = blockContents:match!(NOSPACE("^ %s* fori %s* (<?) %s* (%S.*)"))
@@ -609,12 +631,6 @@ do
609631
local blockI2 = pos - 1
610632
return blockI1, blockI2, blockContents
611633

612-
-- URL short-form.
613-
elseif blockContents:find"^ */" or blockContents:find"^ *%a+:/" then
614-
table.insert(out, F("echo__(url__%q)", trim(blockContents)))
615-
-- @Incomplete: Fix line numbers if blockContents has newlines (which is probably rare).
616-
!!(TRIM_POS_AFTER_BLOCK)
617-
618634
-- Value expression.
619635
elseif insertLuaForEchoingIfExpression(out, blockContents) then
620636
if blockContents:find"^%s*function%s*%(" then -- We do allow echoing functions, but this specifically is probably an error made by the user.

testsite/content/tests.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ One {{* "Space" }} Allowed
9999
- {{it}}
100100
{{end}}
101101

102+
URL: {{ /foo }}
103+
URL: {{ ./foo }}
104+
URL: {{ ../foo }}
105+
URL: {{ http://example.com/foo }}
106+
107+
Markdown parsing, problematic link: [Snake!](https://en.wikipedia.org/wiki/Snake_(video_game_genre))
108+
109+
Markdown parsing, solution: [Snake!](<https://en.wikipedia.org/wiki/Snake_(video_game_genre)>)
110+
102111

103112

104113
## Value Expressions

0 commit comments

Comments
 (0)