Mô đun:Section sizes

require('strict');
--[=[-----------------------------------------------------------------------

Gets the display text from a wikilink like B or B gives B

The str:gsub() returns either A|B froma B or B from B or B from B (no wikilink markup).

In l(), l:gsub() removes the link and pipe (if they exist); the second :gsub() trims white space from the label
if str was wrapped in wikilink markup. Presumably, this is because without wikimarkup in str, there is no match
in the initial gsub, the replacement function l() doesn't get called.

]=]

local function remove_wiki_link (str)
return (str:gsub( "%[%[([^%[%]])%]%]", function(l)
return l:gsub( "^[^|]|(.)$", "%1" ):gsub("^%s(.-)%s$", "%1");
end));
end

--[=[ Inspired from above, removes everything between
Used to remove html containers from headers to fix breaking section links, but legitimate text within are removed too
]=]
local function remove_container (str)
return (str:gsub( "%])%>", function(l)
return l:gsub("^%s(.-)%s$", "");
end));
end

--[=[-----------------------------------------------------------------------------

Makes a wikilink; when both link and display text is provided, returns a wikilink in the form D; if only
link is provided, returns a wikilink in the form L; if neither are provided or link is omitted, returns an
empty string.

]=]

local function make_wikilink (link, display)
if link and ( ~= link) then
if display and ( ~= display) then
return table.concat ({, display, });
else
return table.concat ({, link, });
end
end
return display or ; -- link not set so return the display text
end

--------------------------------------------------------------------------------------------------

module entry point

create a wikilinked list of 's sections and their size in bytes in a sortable wikitable

local function size (frame)
local A = {}; -- table to hold section names and sizes
local section_name_list = {} -- an interim list that holds just the section names
local section_content; -- section content used for counting
local section = mw.title.new ("MediaWiki:Vector-toc-beginning"):getContent(); -- lead section doen't have a heading, call the text in MediaWiki:Vector-toc-beginning instead
local count = {}; -- number of bytes in a section including the header text
local totcount = {};
local lastlevel;
local maxlevels;
local levelcounts = {};
local upperlevel;
local highlight;
local highlighttot;
local total; -- sum of all byte counts
local max; -- largest section so far encountered
local totmax; -- largest section so far encountered (section total)
local _; -- dummy for using gsub to count bytes
local lang = mw.language.getContentLanguage(); -- language object for number formatting appropriate to local language
local s; -- start position of found heading (returned from string.find())
local e = 1; -- end position of found heading (returned from string.find())
local section_name; -- captured heading name (returned from string.find())
local level = {}; -- number of leading '=' in heading markup; used for indenting subsections in the rendered list
local wl_name; -- anchor and display portion for wikilinks in rendered list

local content = mw.title.new (frame.args[1]):getContent(); -- get unparsed wikitext from the article
if not content then
return 'error: no article:' .. frame.args[1] .. ;
end

if content:find ('REDIRECT') then -- redirects don't have sections
return 'error: ' .. frame.args[1] .. ' is a redirect';
end

section_content = content:match ('(.-)==='); -- get the lead section
if section_content then
_, count[0] = section_content:gsub ('.', '%1'); -- count the size of the lead section
else
return 'error: no sections found in: ' .. frame.args[1] .. ;
end
total = count[0];
max = count[0];

table.insert (A, make_wikilink (frame.args[1], section) .. '|| style="text-align:right"|' .. lang:formatNum (count[0]) .. '|| style="text-align:right"|' .. lang:formatNum (count[0]));

while (1) do -- done this way because some articles reuse section names
s, e, section_name = string.find (content, '\n+ (.-) +', e); -- get start, end, and section name beginning a end of last find; newline must precede '==' heading markup
if s then
table.insert (section_name_list, {section_name, s}); -- save section name and start location of this find
else
break;
end
end

for i, section_name in ipairs (section_name_list) do
local escaped_section_name = string.gsub (section_name[1], '([%(%)%.%%%+%-%%?%[%^%$%]])', '%%%1'); -- escape lua patterns in section name
local pattern = '(+ ' .. escaped_section_name .. ' +.-)==+'; -- make a pattern to get the content of a section
section_content = string.match (content, pattern, section_name[2]); -- get the content beginning at the string.find() start location
if section_content then
_, count[i] = section_content:gsub ('.', '%1'); -- count the bytes in the section
total = total + count[i];
max = max =lastlevel then
totcount[i]=count[i];
end
if level[i]>0 then
upperlevel=level[i]-1;
levelcounts[upperlevel]=levelcounts[upperlevel]+totcount[i];
end
lastlevel=level[i];
if totcount[i]>totmax then
totmax=totcount[i];
end
end

for i, section_name in ipairs (section_name_list) do

if count[i]==max then
highlight='background:red;"|';
else
local proportion = count[i] / max -- get value of "how much of the max" the count is
local gb = 250 - math.floor(250 proportion) -- approach f8f9fa [r=248,g=249,b=250] (default wikitable cell color) for small bytecounts
highlight = string.format('background:F8%02X%02X;"|', gb, gb) -- shade the bg as r: 248, g: gb, and b: gb
end

highlighttot=; -- start the style declaration
if totcount[i]==totmax then
highlighttot=highlighttot .. 'background:red;';
else
local proportion = totcount[i] / totmax -- get value of "how much of the max" the count is
local gb = 250 - math.floor(250 proportion) -- approach f8f9fa [r=248,g=249,b=250] (default wikitable cell color) for small bytecounts
highlighttot=highlighttot .. string.format('background:F8%02X%02X;', gb, gb) -- shade the bg as r: 248, g: gb, and b: gb
end
if level[i]==2 then
highlighttot=highlighttot .. 'font-weight:bold;'; -- if main section, make it bold
elseif totcount[i]==count[i] then
highlighttot='color:transparent;'; -- hide totals for subsections with no subsubsections, values required for proper sorting
end
highlighttot=highlighttot .. '"|'; -- close the style declaration

level[i] = (2 ' or ; -- indent per heading level (number of '=' in heading markup)
make_wikilink (frame.args[1] .. '' .. wl_name, wl_name), -- section link
level[i] and or , -- close the span if opened
'||', -- table column separator
'style="text-align:right;', -- the byte count column is right aligned
highlight ,
lang:formatNum (count[i]), -- commafied byte count for section
'||',
'style="text-align:right;', -- the section total column is right aligned
highlighttot ,
lang:formatNum (totcount[i]), -- section total count!!
}));
end

local out = {}; -- make a sortable wikitable for output
table.insert (out, string.format (); -- close the wikitable

--max = lang:formatNum (max); -- commafy so that the commafied value in the table can be found
--local result = table.concat (out, ):gsub (max, .. max .. ); -- make a big string, make largest count(s) red, and done
local result = table.concat (out, );
return result; -- because gsub returns string and number of replacements
end

----------------------------------------------------------------------

return
{
size = size,
}