Jump to content

Module:Unicode chart and Module:Unicode chart/sandbox: Difference between pages

(Difference between pages)
Page 1
Page 2
Content deleted Content added
several changes to range handling to allow, among other things, referring to predefined subsets
 
No edit summary
 
Line 1: Line 1:
local p = {}
local mArguments = require('Module:Arguments')
local mTableTools = require('Module:TableTools')
local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')

local mRedirect = require('Module:Redirect')

local mUnicode = require('Module:Unicode data')
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 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 mVersion = require('Module:Unicode data/version')
local mEntities = require('Module:Unicode chart/entities')
local mAliases = require('Module:Unicode data/aliases')

local mDisplay = require('Module:Unicode chart/display')
local frame
local mSubsets = require('Module:Unicode chart/subsets')
local p = {}
local args = {}
local config = {
useFontCss = true,
showRefs = true,
infoMode = false,
}


-------------------
local refGrammar = {
-- General settings
order = { "white", "combining", "control", "format", "reserved", "nonchar", "skip" },
-------------------
white = {
local pdfLink = "[https://www.unicode.org/charts/PDF/%s.pdf"
format = 'White area%s within light green cell%s show%s %s of %sotherwise invisible [[whitespace character]]%s.',
.. " Official Unicode Consortium code chart] (PDF)"
singular = { '', '', 's', 'the size', 'an ', '' },
local cellType = {
plural = { 's', 's', '', 'sizes', '', 's' },
count = 0,
},
combining = {
format = 'Yellow cell%s with [[dotted circle]]%s (◌) indicate%s %s[[combining character]]%s.',
singular = { '', '', 's', 'a ', '' },
plural = { 's', 's', '', '','s' },
count = 0,
},
control = {
format = 'Light blue cell%s indicate%s %snon-printable [[control character]]%s.',
singular = { '', 's', 'a ', '' },
plural = { 's', '', '', 's' },
count = 0,
},
format = {
format = 'Pink cell%s indicate%s %s[[format character]]%s.',
singular = { '', 's', 'a ', '' },
plural = { 's', '', '', 's' },
count = 0,
},
reserved = {
reserved = {
format = 'Gray cell%s indicate%s %sunassigned (reserved) code point%s.',
note = "Grey areas indicate non-assigned code points",
flag = false
singular = { '', 's', 'an ', '' },
},
plural = { 's', '', '', 's' },
noncharacter = {
count = 0,
note = "Black areas indicate [[Universal Character Set characters#Noncharacters|noncharacters]] (code points that are guaranteed never to be assigned as encoded characters in the Unicode Standard)",
},
flag = false
nonchar = {
format = 'Black cell%s indicate%s %s[[noncharacter]]%s (code point%s that %s guaranteed never to be assigned as %sencoded character%s in the Unicode Standard).',
singular = { '','s','a ', '', '', 'is','an ', '' },
plural = { 's','', '','s','s','are', '','s' },
count = 0,
},
skip = {
format = 'Black horizontal line%s indicate%s non-consecutive rows.',
singular = { '', 's' },
plural = { 's', '' },
count = 0,
},
}
}
}


local infoTable = {}
local hardcodedNumberedAbbrSets = {
-- Block: Variation Selectors
local err = {
{first = 0xFE00, last = 0xFE0F, str = "VS<br>", startNum = 1},
format = function(...) return error(string.format(...), 0) end,
-- Block: Variation Selectors Supplement
blockName = 'Unrecognized block name "%s" does not match those defined in [[Module:Unicode data/blocks]]',
{first = 0xE0100, last = 0xE01EF, str = "VS<br>", startNum = 17},
refGarbage = 'Refs contain non-ref content: "%s"',
-- Block: Sutton SignWriting
badRange = 'Invalid range "%s" specified. Ranges must match [[regular expression]] <code>^[0-9A-F]+(?:[-–][0-9A-F]+)?$</code>',
-- SIGNWRITING FILL MODIFIER-2 -> SW F#
noRange = 'Please specify a valid block name, range of code points, or named subset',
{first = 0x1DA9B, last = 0x1DA9F, str = 'SW<br>F', startNum = 2},
badSubset = 'Invalid subset "%s" specified',
-- Block: Sutton SignWriting
}
-- SIGNWRITING ROTATION MODIFIER-2 -> SW R#
{first = 0x1DAA1, last = 0x1DAAF, str = 'SW<br>R', startNum = 2},
}


local specialFormatSets = {
function debug(...)
--Unicode block: Tags
local a = {...}
--tag for character -> character
if type(a[1]) ~= "string" then mw.log(a[1]) return end
{first = 0xE0021, last = 0xE007E,
local _,c = string.gsub(string.gsub(a[1], "%%%%", ""), "%%", "")
func = function(codepoint, abbr)
for i = 1,math.max(#a, c+1) do
return '&#x'.. string.format("%04X", (codepoint - 0xE0000)) .. ';'
if (type(a[i]) == "nil" or type(a[i]) == "boolean") then a[i] = tostring(a[i]) end
end
},
}

-------------------------
-- pseudo-object oriented
-------------------------
function newCodepoint(x)
if type(x) == "string" then
return {
hex = x,
int = tonumber(x, 16)
}
elseif type(x) == "number" then
return {
int = x,
hex = string.format("%04X", x)
}
end
end
return mw.log(string.format(unpack(a)))
end
end


-------------------------
table.concat2 = function(t1,t2) for i=1,#t2 do t1[#t1+1] = t2[i] end return t1 end
-- Sundry small functions
table.last = function(t) if t then return t[#t] else return nil end end
-------------------------

local function expandTemplate(template, argslist)

return frame:expandTemplate{
string.formatAll = function(fmt, t)
title = template,
for i=1,#t do t[i] = string.format(fmt, t[i]) end
args = argslist
return t
}
end
end
function getUtf8(n)
local t = {}
for b in mw.ustring.char(n):gmatch('.') do table.insert(t, b:byte()) end
return t
end
function 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 { n } end
local u = (n - 0x10000)
local low = (u % 0x400)
local high = (u - low) / 0x400
return { 0xD800 + high, 0xDC00 + low }
end
function getUtf16toStr(n)
t = getUtf16(n)
for i=1,#t do t[i] = string.format("0x%04X", t[i]) end
return t
end
function getUtf8toStr(n) return string.formatAll("0x%02X", getUtf8(n) ) end
function getUtf16toStr(n) return string.formatAll("0x%04X", getUtf16(n)) end


function makeRange(a,b)
local function fromHex(hexStr)
return tonumber(hexStr, 16)
if(b) then return {first=math.min(a,b),last=math.max(a,b)} else return {first=a,last=a} end
end
function rangeContains(r, n) return (n >= r.first and n <= r.last) end
function rangeCombine(r1,r2) return {first=math.min(r1.first,r2.first), last=math.max(r1.last,r2.last)} end
function 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)
end
function rangeSort(r1,r2)
if r1 and not r2 then return true end
if not r1 then return false end
if r1.first == r2.first then return r1.last < r2.last end
return r1.first < r2.first
end
end


local function splitColonList(strList)
function parseHex(s) if s then return tonumber(s,16) else return nil end end
local tab = {}
function parseRanges(str)
local segments = mw.text.split(strList, '[;\n\t]')
local r = {}
for _,v in pairs(segments) do
str = str:upper():gsub("AND", ",") --avoid parsing A and D as single control chars in row U+000x, whoops
local tmp = mw.text.split(v, ':')
for x in mw.ustring.gmatch(str, "[%dA-FUX%+%-]+") do
if tmp[1] and tmp[2] then
local a,b = mw.ustring.match(x, "^[UX0%+%-]*([%dA-F]+)[-–][UX0%+%-]*([%dA-F]+)$")
tab[fromHex(tmp[1])] = mw.text.trim(tmp[2])
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
end
end
return tab
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 r2
end
end


local function getCategory(codepoint)
-- Official way to match property values that are strings (including block names):
local category = mUnicode.lookup_control(codepoint.int)
-- Ignore case, whitespace, underscore ('_'), hyphens, and any initial prefix string "is".
if category ~= "unassigned" then
-- http://www.unicode.org/reports/tr44/#UAX44-LM3
return category
local function propertyValueKey(val)
elseif mUnicode.is_noncharacter(codepoint.int) then
return val:lower():gsub('^is', ''):gsub('[-_%s]+', '')
return "noncharacter"
else
return "reserved"
end
end
end



function getDefaultRange(blockName)
local function getAliasValues(n, key)
if not blockName then return nil end
local tbl = {}
blockName = propertyValueKey(blockName)
if mAliases[n] then
for i,b in ipairs(mBlocks) do
for i,t in ipairs(mAliases[n]) do
if blockName == propertyValueKey(b[3]) then return makeRange(b[1],b[2]) end
if(not key or t[1] == key) then
table.insert(tbl, t[2])
end
end
end
end
return tbl
end
end


---------------------
function getAge(n)
-- A single unicode cell within the table
local a = mAge.singles[n]
---------------------
if(a) then return a end
local function getCellAbbr(codepoint, category, args)
for k,v in pairs(mAge.ranges) do
local function getHardcodedNumberedAbbr(codepoint)
if n >= v[1] and n <= v[2] then return v[3] end
for key, value in pairs(hardcodedNumberedAbbrSets) do
if codepoint.int >= value.first
and codepoint.int <= value.last then
return value.str .. (codepoint.int - value.first + value.startNum)
end
end
return nil
end
--for key, value in pairs(specialFormatSets) do
-- if codepoint.int >= value.first
-- and codepoint.int <= value.last then
-- return value.func(codepoint.int, alias)
-- end
--end
local function getAliasAbbr(codepoint)
local tbl = getAliasValues(codepoint.int, "abbreviation")
return tbl[1] or nil
end
local function abbrFromString(codepoint, args)
local abbr = ""
local name = mUnicode.lookup_name(codepoint.int)
local words = mw.text.split(name, ' ')
for _,w in pairs(words) do
abbr = abbr .. string.sub(w, 1, 1)
end
return abbr
end
end
return nil
end
function 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 end
end


--override
function getControlAbbrs(n) return getAliasValues(n, "abbreviation") end
if (args['abbr_sub'] and args['abbr_sub'][codepoint.int]) then
function getControlAliases(n) return table.concat2(getAliasValues(n, "control"), getAliasValues(n, "figment")) end
return args['abbr_sub'][codepoint.int]

end
function getAliasValues(n, key)
--exception listed at top
local b,r = mAliases[n], {}
local abbr1 = getHardcodedNumberedAbbr(codepoint)
if b then for i,t in ipairs(b) do
if(not key or t[1] == key) then table.insert(r, t[2]) end
if abbr1 then return abbr1 end
--abbr on list
end end
local abbr2 = getAliasAbbr(codepoint)
return r
if abbr2 then return abbr2 end
end
--make own abbr

if category == "control" or category == "format" then
function getAnchorId(n) return string.format("info-%04X", n) end
return '<span class="red">' .. abbrFromString(codepoint) .. '</span>'
function getTarget(n)
end
if(config.infoMode) then return "#"..getAnchorId(n) end
local t = getParamNx("link", n, true)
if(t=="yes") then t = char end
--"ifexist" is a deleted feature, now recognized equal to "no" to avoid linking to the article [[Ifexist]], which incidentally doesn't exist.
if(t=="no" or t=="ifexist") then t = nil end
if(t=="wikt") then t = ":wikt:"..mw.ustring.char(n) end
return t
end

function getNamedEntity(n)
local e = mEntities[n]
if e then return string.gsub(e, "&", "&amp;") else return nil end
end

function getEntities(n)
local entH = getNamedEntity(n)
local entN = string.format('&amp;#%d;', n)
local entXN = string.format('&amp;#x%X;', n)
local t = {}
if(entH) then table.insert(t, entH) end
table.insert(t, entN)
table.insert(t, entXN)
return t
end

function isControl(n) return mUnicode.lookup_control(n) == "control" end
function isFormat(n) return mUnicode.lookup_control(n) == "format" end

function isBadTitle(str)
if str == nil then return true end
if type(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 == 1 and mw.ustring.match(str, "[\/\.\:\_̸]") then return true end
return false
return false
end
end


function makeVersionRef()
local function aliasesStr(codepoint)
local aliasStr = ""
if(not config.showRefs or mVersion == nil or mVersion == '') then return ''
if mAliases[codepoint.int] then
else return string.format('<ref name="version">As of [[Unicode#Versions|Unicode version]] %s.</ref>', mw.text.nowiki(mVersion)) end
for i,t in ipairs(mAliases[codepoint.int]) do
end
aliasStr = aliasStr .. " (alias " .. t[2] .. ")"


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 == 1) then refText = string.format(g.format, unpack(g.singular)) end
if(g.count >= 2) then refText = string.format(g.format, unpack(g.plural)) end
if(refText) then
table.insert(refs, string.format('<ref name="%s">%s</ref>', refType, refText))
end
end
end
end
return table.concat(refs)
return aliasStr
end
end


local function linkChar(unicodeChar, codepoint, args)
--TODO: remove any garbage around/between refs and downgrade this to a warning
if (args['link_sub'] and args['link_sub'][codepoint.int]) then
function sanitizeUserRefs(refTxt)
return '[[' .. args['link_sub'][codepoint.int]
if not config.showRefs then return '' end
.. '|' .. unicodeChar .. ']]'
local trim1 = mw.text.killMarkers(refTxt)
elseif args['link'] == "wiki" then
local trim2 = mw.ustring.gsub(trim1, '%s', '')
local redir = mRedirect.luaMain(unicodeChar, false)
if string.len(trim2) > 0 then err.format(err.refGarbage, mw.text.nowiki(trim1))
-- '[[' .. redir .. '|' .. unicodeChar .. ']]'
else return refTxt end
return expandTemplate('Link if exists', {unicodeChar})
end
elseif args['link'] == "wikt" then
function makeSpan(str, title, repl)
return '[[wikt:' .. unicodeChar .. '|' .. unicodeChar .. ']]'
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
end
return string.format('<span %s%s>%s</span>', c, t, str)
end
function 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|%s]]",a,b)
end
end


function makeAliasList(n)
local function createCell(cell, codepoint, args)
-- sub functions
if not mAliases[n] then return '' end
local t = {}
local function emptyCell(categoryStr)
cellType[categoryStr].flag = true
table.insert(t, '<div class="alias"><ul>')
-- flag[categoryStr] = true
for k,v in ipairs(mAliases[n]) do
local tr = string.format('<li class="%s">%s</li>', v[1], v[2])
table.insert(t, tr)
end
end
local function abbrCell(abbr)
table.insert(t, '</ul></div>')
cell:addClass("abbr-cell")
return table.concat(t)
cell:tag("div"):addClass("abbr-box"):wikitext(abbr)
end
function makeDivUl(t, class) return makeDiv(makeUl(t), class) end
function makeUl(t, class)
if not t then return '' end
if class then class = string.format(' class="%s"', class) else class = '' end
return string.format('<ul%s><li>%s</li></ul>', class, table.concat(t, '</li><li>'))
end
function makeDiv(s, class)
if not s or string.len(s) == 0 then return '' end
if class then class = string.format(' class="%s"', class) else class = '' end
return string.format('<div%s>%s</div>', 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('<div class="age">Introduced in Unicode version %s.</div>', age) else age = '' end
if(info.category == 'control') then info.name = mw.text.nowiki('<control>') 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 = '<div class="char">'..table.concat({utf8, utf16, html, age})..'</div>'
local titleBarFmt = '<div><div class="title">%s %s</div><div class="category">%s</div></div>'
local titleBar = string.format(titleBarFmt, info.uPlus, info.name, info.category)
local fmt = '<tr class="info-row" id="%s"><th class="thumb %s%s">%s</th><td colspan="16" class="info">%s%s%s</td></tr>'
return string.format(fmt, getAnchorId(info.n), class, info.cBox, info.display, titleBar, alii, charInfo)
end

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
end
return nil
-- main func begins
end
local category = getCategory(codepoint)

cell:addClass(category)
function makeGridCell(n, charMask)
local uPlus = string.format("U+%04X", n)
local abbr = getCellAbbr(codepoint, category, args)
local char = mw.ustring.char(n)
if category == "reserved" or category == "noncharacter" then
local cfFmt = '<td title="%s" class="char%s"><div>\n%s\n</div></td>'
emptyCell(category)
local isControlN, isFormatN = isControl(n), isFormat(n)
elseif abbr then
local charName = table.last(getControlAliases(n)) or mUnicode.lookup_name(n)
abbrCell(abbr)
if isControlN then charName = charName or "&lt;control&gt;" end
local cBox = ''
local masterListDisplay = mDisplay[n]
if masterListDisplay then cBox = ' box' end
local display = masterListDisplay or char
local title = uPlus..' '..charName
if isControlN or isFormatN then display = makeSpan(display, title, true) end
local sCode = nil
if config.useFontCss then sCode = mUnicode.lookup_script(n) end
--default dir="ltr" need not be specified
local sDir = ''
if mUnicode.is_rtl(char) then sDir = ' dir="rtl"' end
local sClass = ""
local linkThis = getTarget(n)
local cell = ''
local generateInfoPanel = true
--3 types of empty cells
if(not charMask[n]) then
--fill extra spaces surrounding an irregular (non-multiple of 16) range of displayed chars
cell = '<td class="excluded"></td>'
generateInfoPanel = false
elseif string.match(charName, '<reserved') then
refGrammar.reserved.count = refGrammar.reserved.count + 1
cell = string.format('<td title="%s RESERVED" class="reserved"></td>', uPlus)
generateInfoPanel = false
elseif string.match(charName, '<noncharacter') then
refGrammar.nonchar.count = refGrammar.nonchar.count + 1
cell = string.format('<td title="%s NONCHARACTER" class="nonchar"></td>', uPlus)
generateInfoPanel = false
--actual chars
elseif mUnicode.is_whitespace(n) then
refGrammar.white.count = refGrammar.white.count + 1
local cellFmt = '<td title="%s" class="char whitespace"%s><div>\n%s\n</div></td>'
display = makeSpan(display, title, false)
cell = string.format(cellFmt, title, sDir, makeLink(linkThis, makeSpan(char, title, false)))
elseif isControlN then
refGrammar.control.count = refGrammar.control.count + 1
cell = string.format(cfFmt, title, " control box", makeLink(linkThis, display))
elseif isFormatN then
refGrammar.format.count = refGrammar.format.count + 1
cell = string.format(cfFmt, title, " format box", makeLink(linkThis, display))
else
else
local unicodeChar = '&#x'.. codepoint.hex .. ';'
if sCode then sClass = sClass..string.format(' script-%s', sCode) end
unicodeChar = linkChar(unicodeChar, codepoint, args) or unicodeChar
sClass = sClass..cBox
if args['suffix'] and args['suffix'][codepoint.int] then
isCombining = mUnicode.is_combining(n)
unicodeChar = unicodeChar
if isCombining then
.. '&#x' .. args['suffix'][codepoint.int] .. ';'
refGrammar.combining.count = refGrammar.combining.count + 1
cell:addClass("modified")
sClass = sClass.." combining"
display = "◌"..char
end
end
if args['wrapper'] then
display = makeSpan(display, title, true)
unicodeChar = expandTemplate(args['wrapper'], {unicodeChar})
local cellFmt = '<td title="%s" class="char%s"%s><div>\n%s\n</div></td>'
elseif args['font'] then
cell = string.format(cellFmt, title, sClass, sDir, makeLink(linkThis,display))
cell:css("font-family", "'" .. args['font'] .. "'")
end
--unicodeChar = tostring(
if(config.infoMode and generateInfoPanel) then
-- mw.html.create("div")
local printable = mUnicode.is_printable(n)
-- :css("font-family", "'" .. args['font'] .. "'")
local category = getCategory(n)
-- :wikitext(unicodeChar)
local info = {
n = n,
--)
char = char,
name = charName,
sCode = sCode,
display = display,
uPlus = uPlus,
printable = printable,
category = category,
cBox = cBox,
}
table.insert(infoTable, makeInfoRow(info))
end
return cell
end
function getMask(ranges)
local ch,r = {},{}
for i,range in ipairs(ranges) do
for n=range.first,range.last do
ch[n] = true
r[n-n%16] = true
end
end
cell:wikitext(unicodeChar)
end
end
local row = {}
local name = mUnicode.lookup_name(codepoint.int)
name = string.match(name, "<([a-z]+)-%w+>") or name
for i,x in pairs(r) do table.insert(row, i) end
cell:attr("title",
table.sort(row)
'U+' .. codepoint.hex ..
return ch,row
': ' .. name
.. aliasesStr(codepoint)
)
end
end


---------------------
function p.main( frame )
-- For loops creating the grid of cells
for k, v in pairs(mArguments.getArgs(frame)) do args[k] = v end
---------------------
config.infoMode = (args["info"] or 'no'):lower() ~= "no"
local function createTableBody(body, rangeStart, rangeEnd, args)
config.useFontCss = (args["fonts"] or args["font"] or 'yes'):lower() ~= "no"
--0 through F label row
local userRefs = args["refs"] or args["notes"] or args["ref"] or args["note"] or ""
local labelRow = body:tag("tr")
config.showRefs = not(userRefs=='off' or userRefs=='no')
labelRow:tag("th")--empty corner cell
local state = args["state"] or "expanded"
:css("width", "45pt")

for colIndex=0, 15 do
local subset = args["subset"]
labelRow:tag("th"):wikitext(string.format("%X", colIndex))
local subsetRangeTxt = ''
:css("width", "20pt")
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 ranges = { defaultRange } end
blockNameLink = blockNameLink or blockName.." (Unicode block)"
else
if #ranges == 0 then err.format(err.noRange, {}) end
end
end


--real body of table
local charMask,rowMask = getMask(ranges)
local rowStart = fromHex(rangeStart.hex:sub(1, -2))--subtract last char from string
local tableBody = {}
local rowEnd = fromHex(rangeEnd.hex:sub(1, -2))
for i=1,#rowMask do
local rowStart = rowMask[i]
for rowIndex=rowStart, rowEnd do
local rowHex = string.format("%03X", rowIndex)
local trClass=''
local row = body:tag("tr")
if(i > 1 and rowStart ~= (rowMask[i-1]+16)) then
row:tag("th"):wikitext("U+".. rowHex .. "<i>x</i>")
trClass = ' class="skip"'
:attr("rowspan", "2")
refGrammar.skip.count = refGrammar.skip.count + 1
for colIndex=0, 15 do
local cell = row:tag("td")
--rowHex .. string.format("%X", colIndex)
createCell(cell,
newCodepoint(rowIndex*16 + colIndex),
args
)
end
end
local dataRow = {}
local subrow = body:tag("tr")
for colIndex=0, 15 do
local rowOpen, rowClose = string.format('<tr%s>', trClass), '</tr>'
subrow:tag("td"):addClass("codepoint")
local rowHeader = string.format('<th class="row">U+%03Xx</th>', rowStart/16)
:wikitext(string.format("%04X", rowIndex*16 + colIndex))
for c = 0,15 do
table.insert(dataRow, makeGridCell(rowStart+c, charMask))
end
end
local rowHtml = {rowOpen, rowHeader, table.concat(dataRow), rowClose}
table.insert(tableBody, table.concat(rowHtml))
end
end
end
local tableOpenFmt = '<table class="wikitable nounderlines unicode-chart collapsible %s">'
local tableOpen, tableClose = string.format(tableOpenFmt, state), '</table>'


---------------------
local allRefs = table.concat({ makeVersionRef(), makeAutoRefs(), sanitizeUserRefs(userRefs) })
-- Header at top of table
if blockNameLink then
---------------------
blockNameLink = string.format("[[%s|%s]]", blockNameLink, blockNameDisplay)
local function createTableHeader(head, name, id)
else
local page = mRedirect.luaMain(name .. " (Unicode block)", false)
blockNameLink = blockNameDisplay
head:tag("th")
:addClass("header")
:attr("colspan", "100%")
:wikitext(
"<b>[[" .. page .. "|" .. name .. "]]</b>"
.. "<br />" .. string.format(pdfLink, id)
.. expandTemplate('ref label', {id .. '_as_of_Unicode_version', 1})
)
end

---------------------
-- Footer at bottom of table
---------------------
local function createTableFooter(foot, id, note)
local th = foot:tag("th")
:addClass("footer")
:attr("colspan", "100%")
:wikitext("<b>Notes</b>")
local list = th:tag("ol")
list:tag("li"):wikitext(
expandTemplate('note', {id .. '_as_of_Unicode_version'}),
expandTemplate(
'Unicode version',
{prefix= 'Asof', version= mVersion}
)
)
--Notes about categories of cells
for key, value in pairs(cellType) do
if value.flag then
list:tag("li"):wikitext(value.note)
end
end
end
--Manual note
local titleBar = string.format('<div class="title">%s%s</div>', blockNameLink, allRefs)
if note then
local fmtpdf = '<div class="pdf-link">[%s Official Unicode Consortium code chart] (PDF)</div>'
list:tag("li"):wikitext(note)
if config.pdf then
titleBar = titleBar..string.format(fmtpdf, config.pdf)
end
end
end
local titleBarRow = '<tr><th class="title-bar" colspan="17">'..titleBar..'</th></tr>'


---------------------
local columnHeaders = { '<tr>', '<th class="empty"></th>' }
-- Creates table
for c = 0,15,1 do table.insert(columnHeaders, string.format('<th class="column">%X</th>', c)) end
---------------------
table.insert(columnHeaders, '</tr>')
local function createTable(rangeStart, rangeEnd, args)
local id = 'U' .. rangeStart.hex
cellType.reserved.flag = false
cellType.noncharacter.flag = false


local infoFooter = ''
local tbl = mw.html.create("table")
:addClass("wikitable")
if(config.infoMode) then infoFooter = table.concat(infoTable) end
:addClass("unicode-block")

local notesFooter = ''
if args['blockname'] then
if config.showRefs and string.len(allRefs) > 0 then
createTableHeader(tbl, args['blockname'], id)
notesFooter = '<tr><td class="notes" colspan="17">'.."'''Notes:'''{{reflist}}"..'</td></tr>'
end
end
createTableBody(tbl, rangeStart, rangeEnd, args)
createTableFooter(tbl, id, args['note'])
return tostring(tbl)
end


---------------------
local tStyles = frame:extensionTag{ name = 'templatestyles', args = { src = 'Unicode chart/styles.css'} }
-- Main
local cStyles = ''
---------------------
if config.useFontCss then
function p.main(frameArg)
cStyles = frame:extensionTag{ name = 'templatestyles', args = { src = 'Unicode chart/script styles.css'} }
frame = frameArg
local args = getArgs(frame)
for _, argName in ipairs({'abbr_sub', 'link_sub', 'suffix'}) do
if args[argName] then
args[argName] = splitColonList(args[argName])
end
end
-- look up block by na,e
if args['blockname'] then
local range = mUnicode.get_block_info(args['blockname'])
if range == nil then
return "invalid blockname"
end
return createTable(
newCodepoint(range[1]),
newCodepoint(range[2]),
args
)
-- block given as start and end of range
elseif args['rangestart'] and args['rangeend'] then
return createTable(
newCodepoint(args['rangestart']),
newCodepoint(args['rangeend']),
args
)
end
end
local html = table.concat({
tStyles, cStyles, tableOpen, titleBarRow,
table.concat(columnHeaders), table.concat(tableBody),
infoFooter, notesFooter, tableClose
})
return frame:preprocess(html)
end
end

return p
return p