local mArguments = require('Module:Arguments')local mTableTools = require('Module:TableTools')local mUnicode = require('Module:Unicode data')local mAge = require('Module:Unicode data/age')local mAliases = require('Module:Unicode data/aliases')local mBlocks = require('Module:Unicode data/blocks')local mCategory = require('Module:Unicode data/category')local mControl = require('Module:Unicode data/control')local mScripts = require('Module:Unicode data/scripts')local mVersion = require('Module:Unicode data/version')local mEntities = require('Module:Unicode chart/entities')local mDisplay = require('Module:Unicode chart/display')local mSubsets = require('Module:Unicode chart/subsets')local p = local args = local config =
local refGrammar =
local infoTable = local err =
function debug(...) local a = if type(a[1]) ~= "string" then mw.log(a[1]) return end local _,c = string.gsub(string.gsub(a[1], "%%%%", ""), "%%", "") for i = 1,math.max(#a, c+1) do if (type(a[i])
"boolean") then a[i] = tostring(a[i]) end end return mw.log(string.format(unpack(a)))end
table.concat2 = function(t1,t2) for i=1,#t2 do t1[#t1+1] = t2[i] end return t1 endtable.last = function(t) if t then return t[#t] else return nil end end
string.formatAll = function(fmt, t) for i=1,#t do t[i] = string.format(fmt, t[i]) end return tendfunction getUtf8(n) local t = for b in mw.ustring.char(n):gmatch('.') do table.insert(t, b:byte) end return tendfunction getUtf16(n) if(n < 0 or n > 0x10FFFF) then return nil end if(n >= 0xD800 and n <= 0xDFFF) then return nil end if(n < 0x10000) then return end local u = (n - 0x10000) local low = (u % 0x400) local high = (u - low) / 0x400 return endfunction getUtf16toStr(n) t = getUtf16(n) for i=1,#t do t[i] = string.format("0x%04X", t[i]) end return tendfunction getUtf8toStr(n) return string.formatAll("0x%02X", getUtf8(n)) endfunction getUtf16toStr(n) return string.formatAll("0x%04X", getUtf16(n)) end
function makeRange(a,b) if(b) then return else return endendfunction rangeContains(r, n) return (n >= r.first and n <= r.last) endfunction rangeCombine(r1,r2) return endfunction rangesMergeable(r1,r2) if not r1 or not r2 then return false end return rangeContains(r1, r2.first-1) or rangeContains(r1, r2.last+1) or rangeContains(r2, r1.first-1) or rangeContains(r2, r1.last+1)endfunction rangeSort(r1,r2) if r1 and not r2 then return true end if not r1 then return false end if r1.first
function parseHex(s) if s then return tonumber(s,16) else return nil end endfunction parseRanges(str) local r = str = str:upper:gsub("AND", ",") --avoid parsing A and D as single control chars in row U+000x, whoops for x in mw.ustring.gmatch(str, "[%dA-FUX%+%-]+") do local a,b = mw.ustring.match(x, "^[UX0%+%-]*([%dA-F]+)[-–][UX0%+%-]*([%dA-F]+)$") if(a and b) then table.insert(r, makeRange(parseHex(a),parseHex(b))) else local c = mw.ustring.match(x, "^[UX0%+%-]*([%dA-F]+)$") if c then table.insert(r, makeRange(parseHex(c))) else err.format(err.badRange, x) end end end for i = #r,2,-1 do for j = i-1,1,-1 do if rangesMergeable(r[i], r[j]) then r[j] = rangeCombine(r[i], r[j]) r[i] = nil end end end r2 = for k,v in pairs(r) do table.insert(r2,v) end table.sort(r2, rangeSort) return r2end
-- Official way to match property values that are strings (including block names):-- Ignore case, whitespace, underscore ('_'), hyphens, and any initial prefix string "is".-- http://www.unicode.org/reports/tr44/#UAX44-LM3local function propertyValueKey(val) return val:lower:gsub('^is', ):gsub('[-_%s]+', )end
function getDefaultRange(blockName) if not blockName then return nil end blockName = propertyValueKey(blockName) for i,b in ipairs(mBlocks) do if blockName
function getAge(n) local a = mAge.singles[n] if(a) then return a end for k,v in pairs(mAge.ranges) do if n >= v[1] and n <= v[2] then return v[3] end end return nilendfunction getCategory(n) local cc = mUnicode.lookup_category(n) local cat = mCategory.long_names[cc] if cat then return string.gsub(string.lower(cat), "_", " ") else return nil endend
function getControlAbbrs(n) return getAliasValues(n, "abbreviation") endfunction getControlAliases(n) return table.concat2(getAliasValues(n, "control"), getAliasValues(n, "figment")) end
function getAliasValues(n, key) local b,r = mAliases[n], if b then for i,t in ipairs(b) do if(not key or t[1]
function getAnchorId(n) return string.format("info-%04X", n) endfunction getTarget(n) if(config.infoMode) then return "#"..getAnchorId(n) end local t = getParamNx("link", n, true) if(t
"no" or t
"wikt") then t = ":wikt:"..mw.ustring.char(n) end return tend
function getNamedEntity(n) local e = mEntities[n] if e then return string.gsub(e, "&", "&") else return nil endend
function getEntities(n) local entH = getNamedEntity(n) local entN = string.format('&#%d;', n) local entXN = string.format('&#x%X;', n) local t = if(entH) then table.insert(t, entH) end table.insert(t, entN) table.insert(t, entXN) return tend
function isControl(n) return mUnicode.lookup_control(n)
"format" end
function isBadTitle(str) if str
"number" then str = mw.ustring.char(str) end if not mUnicode.is_valid_pagename(str) then return true end if mw.ustring.match(str, "[\<\>]") then return true end if #str
function makeVersionRef if(not config.showRefs or mVersion
) then return else return string.format('[1] ', mw.text.nowiki(mVersion)) endend
function makeAutoRefs if not config.showRefs then return end local refs = for i,refType in ipairs(refGrammar.order) do local g = refGrammar[refType] local refText = nil if(g.count
--TODO: remove any garbage around/between refs and downgrade this to a warningfunction sanitizeUserRefs(refTxt) if not config.showRefs then return end local trim1 = mw.text.killMarkers(refTxt) local trim2 = mw.ustring.gsub(trim1, '%s', ) if string.len(trim2) > 0 then err.format(err.refGarbage, mw.text.nowiki(trim1)) else return refTxt endendfunction makeSpan(str, title, repl) local c,t = , if title then t = string.format(' title="%s"', title) end if repl then local s,x = mw.ustring.gsub(str, '%s+', '\n') if x > 0 then c = string.format(' class="small-%s"', x) str = s end end return string.format('
%s', c, t, str)endfunction makeLink(a, b) if not a or (isBadTitle(a) and not config.infoMode) then return (b or ) end if not b then b = a end return string.format("%s",a,b)endfunction makeAliasList(n) if not mAliases[n] then return end local t = table.insert(t, '
') return table.concat(t)endfunction makeDivUl(t, class) return makeDiv(makeUl(t), class) endfunction makeUl(t, class) if not t then return end if class then class = string.format(' class="%s"', class) else class = end return string.format('
%s
', class, s)end function makeInfoRow(info) local alii = makeAliasList(info.n) local html = makeDivUl(getEntities(info.n), 'html') local utf8 = makeDivUl(getUtf8toStr(info.n), 'utf8') local utf16 = makeDivUl(getUtf16toStr(info.n), 'utf16') local age = getAge(info.n) if(age) then age = string.format('
Introduced in Unicode version %s.
', age) else age = end if(info.category
'space separator') then info.cBox = ' box' end local class = if config.useFontCss then class = class..'script-'..info.sCode end local charInfo = '
'..table.concat..'
' local titleBarFmt = '
%s %s
%s
' local titleBar = string.format(titleBarFmt, info.uPlus, info.name, info.category) local fmt = '
function getParamNx(key, n, c) local key4 = string.format("%s_%04X", key, n) if args[key4] then return args[key4] end if c then local key3 = string.format("%s_%03Xx", key, math.floor(n/16)) return args[key3] or args[key] end return nilend
function makeGridCell(n, charMask) local uPlus = string.format("U+%04X", n) local char = mw.ustring.char(n) local cfFmt = '
\n%s\n
\n%s\n
\n%s\n
function p.main(frame) for k, v in pairs(mArguments.getArgs(frame)) do args[k] = v end config.infoMode = (args["info"] or 'no'):lower ~= "no" config.useFontCss = (args["fonts"] or args["font"] or 'yes'):lower ~= "no" local userRefs = args["refs"] or args["notes"] or args["ref"] or args["note"] or "" config.showRefs = not(userRefs
'no') local state = args["state"] or "expanded"
local subset = args["subset"] local subsetRangeTxt = if subset then subsetRangeTxt = mSubsets[subset:lower:gsub('%s+', '_')] if(not subsetRangeTxt) then err.format(err.badSubset, subset) end end
local blockName = args["block_name"] or args["block"] or args["name"] or args[1] local blockNameLink = args["link_block"] or args["link_name"] local blockNameDisplay = args["display_block"] or args["display_name"] or subset or blockName
local defaultRange = getDefaultRange(blockName) local actualBlock = (defaultRange ~= nil)
local ranges = parseRanges(subsetRangeTxt..','..(args["ranges"] or args["range"] or ))
if actualBlock then config.pdf = string.format('https://www.unicode.org/charts/PDF/U%04X.pdf', defaultRange.first) if #ranges
0 then err.format(err.noRange,) end end
local charMask,rowMask = getMask(ranges) local tableBody = for i=1,#rowMask do local rowStart = rowMask[i] local trClass= if(i > 1 and rowStart ~= (rowMask[i-1]+16)) then trClass = ' class="skip"' refGrammar.skip.count = refGrammar.skip.count + 1 end local dataRow = local rowOpen, rowClose = string.format('', trClass), ' ' local rowHeader = string.format('
local allRefs = table.concat if blockNameLink then blockNameLink = string.format("%s", blockNameLink, blockNameDisplay) else blockNameLink = blockNameDisplay end local titleBar = string.format('
%s%s
', blockNameLink, allRefs) local fmtpdf = '
[%s Official Unicode Consortium code chart] (PDF)
' if config.pdf then titleBar = titleBar..string.format(fmtpdf, config.pdf) end local titleBarRow = '
local columnHeaders = for c = 0,15,1 do table.insert(columnHeaders, string.format('
local infoFooter = if(config.infoMode) then infoFooter = table.concat(infoTable) end
local notesFooter = if config.showRefs and string.len(allRefs) > 0 then notesFooter = ' ' end'.."Notes:"..'
local tStyles = frame:extensionTag local cStyles = if config.useFontCss then cStyles = frame:extensionTag end local html = table.concat return frame:preprocess(html)end return p