local module = {}
local insert = table.insert
local concat = table.concat
local getArgs = require('Module:Arguments').getArgs
local NOWIKI_STRIP_MARKER_PATTERN = '\127\'"`UNIQ%-%-nowiki%-%x%x%x%x%x%x%x%x%-QINU`"\'\127'
local function _main(args, frame)
local codes = args[1]
local isPrint = args[2] == 'print'
local preTag = frame:extensionTag('pre', codes)
local executedResult = frame:preprocess(
mw.text.decode(
mw.text.unstripNoWiki(codes)
)
)
if isPrint then
return preTag..mw.text.trim(executedResult)
else
return preTag
end
end
local unstripNoWiki = mw.text.unstripNoWiki
local entityToChar = {['<'] = '<', ['>'] = '>'}
local charToEntity = {
['<'] = '<',
['>'] = '>',
['&'] = '&',
[':'] = ':', -- 防止自动超链接
['['] = '[',
[']'] = ']',
['{'] = '{',
['|'] = '|',
['}'] = '}',
}
--- 从文本中提取出用于显示的代码(经过转义)和用于执行的代码
local function extractCodeForDisplayAndForExec(text)
local codeForDisplay = {}
local codeForExec = {}
local function appendWikitext(normalText)
codeForDisplay[#codeForDisplay + 1] = normalText
end
local function appendNowiki(nowikiStripMarker)
-- 妈的mw.text.unstripNoWiki(<nowiki>< > < ></nowiki>)会得到'< > < >',
-- 这导致<nowiki>< ></nowiki>与<nowiki>< ></nowiki>之间的区别丢失了。
-- 因此,我们只能择其一:
-- - 将unstripNoWiki得到的所有'<'和'>'替换为'<'和'>',在调用模板时以其他方式表达'<'和'>'
-- - 不转换unstripNoWiki得到的'<'和'>',在调用模板时以其他方式表达'<'和'>'
-- 考虑到'<'、'>'的使用频率更高,此模块选择了前者。
local encodedSrcCode
local srcCode = unstripNoWiki(nowikiStripMarker):gsub('&[lg]t;', entityToChar)
do
-- <_nowiki>和</_nowiki>转换为<nowiki>和</nowiki>
-- <__nowiki>和</__nowiki>转换为<_nowiki>和</_nowiki>
-- 以此类推
local matchTimes = 0
srcCode, matchTimes =
srcCode:gsub('<(/?_-)_([nN][oO][wW][iI][kK][iI]%s*)>', '<%1%2>')
if matchTimes > 0 then
encodedSrcCode = srcCode
end
end
if encodedSrcCode or srcCode:find('[<>&]') then
encodedSrcCode = (encodedSrcCode or srcCode):gsub('[<>&:%[%]{|}]', charToEntity)
end
codeForDisplay[#codeForDisplay + 1] = encodedSrcCode or nowikiStripMarker
codeForExec[#codeForExec + 1] = srcCode
end
local last = 1
local nowikiStart, nowikiEnd = text:find(NOWIKI_STRIP_MARKER_PATTERN)
local beginsWithNowiki = nowikiStart == 1 -- 这个值用来稍后去除多余换行
while nowikiStart do
if nowikiStart > last then
-- 补上<nowiki>之前的部分
appendWikitext(text:sub(last, nowikiStart - 1))
end
appendNowiki(text:sub(nowikiStart, nowikiEnd))
last = nowikiEnd + 1
nowikiStart, nowikiEnd = text:find(NOWIKI_STRIP_MARKER_PATTERN, last)
end
if last <= #text then
appendWikitext(text:sub(last))
else
local len = #codeForExec
codeForExec[len] = codeForExec[len]:gsub('\n$', '', 1)
end
-- 删除多余换行
if beginsWithNowiki then
codeForExec[1] = codeForExec[1]:gsub('^\n', '', 1)
end
return concat(codeForDisplay), concat(codeForExec)
end
local function canary(args, frame)
local tag, code, seperator
if args.pre then
tag = 'pre'
code = args.pre
seperator = '\n'..(args[1] or '')
elseif args.code then
tag = 'code'
code = args.code
seperator = args[1] or ''
elseif args.bare then
tag = nil
code = args.bare
seperator = args[1] or ''
elseif args[1] then
tag = 'pre'
code = args[1]
seperator = '\n'..(args[2] or '')
else
return '<strong class="error">{{[[Template:Example|Example]]}}调用错误</strong>'
end
assert(code)
assert(seperator)
local codeForDisplay, codeForExec = extractCodeForDisplayAndForExec(code)
local result = tag and {'<', tag, '>', codeForDisplay, '</', tag, '>'} or {codeForDisplay}
if args.echo == '' then
return concat(result)
end
result[#result + 1] = seperator
result[#result + 1] = frame:preprocess(codeForExec)
return concat(result)
end
function module.main(frame)
local parent = frame:getParent()
if parent and parent:getTitle() == 'Template:Example' then
-- frame = parent
else
parent = nil
-- 为了兼容旧函数才这样写
-- canary状态结束后改掉
end
local args = (parent or frame).args
if args.pre or args.code or args.bare then
return canary(args, parent or frame)
end
return _main(getArgs(frame), frame)
end
return module