<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://salisford.net/index.php?action=history&amp;feed=atom&amp;title=Module%3ASection_sizes</id>
	<title>Module:Section sizes - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://salisford.net/index.php?action=history&amp;feed=atom&amp;title=Module%3ASection_sizes"/>
	<link rel="alternate" type="text/html" href="https://salisford.net/index.php?title=Module:Section_sizes&amp;action=history"/>
	<updated>2026-05-01T00:19:16Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.36.1</generator>
	<entry>
		<id>https://salisford.net/index.php?title=Module:Section_sizes&amp;diff=2148&amp;oldid=prev</id>
		<title>Cascadia2: Created page with &quot; require('strict'); --[=[-------------------------&lt; R E M O V E _ W I K I _ L I N K &gt;----------------------------------------------  Gets the display text from a wikilink like...&quot;</title>
		<link rel="alternate" type="text/html" href="https://salisford.net/index.php?title=Module:Section_sizes&amp;diff=2148&amp;oldid=prev"/>
		<updated>2023-04-12T18:21:02Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot; require(&amp;#039;strict&amp;#039;); --[=[-------------------------&amp;lt; R E M O V E _ W I K I _ L I N K &amp;gt;----------------------------------------------  Gets the display text from a wikilink like...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;
require('strict');&lt;br /&gt;
--[=[-------------------------&amp;lt; R E M O V E _ W I K I _ L I N K &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Gets the display text from a wikilink like [[A|B]] or [[B]] gives B&lt;br /&gt;
&lt;br /&gt;
The str:gsub() returns either A|B froma [[A|B]] or B from [[B]] or B from B (no wikilink markup).&lt;br /&gt;
&lt;br /&gt;
In l(), l:gsub() removes the link and pipe (if they exist); the second :gsub() trims white space from the label&lt;br /&gt;
if str was wrapped in wikilink markup.  Presumably, this is because without wikimarkup in str, there is no match&lt;br /&gt;
in the initial gsub, the replacement function l() doesn't get called.&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local function remove_wiki_link (str)&lt;br /&gt;
	return (str:gsub( &amp;quot;%[%[([^%[%]]*)%]%]&amp;quot;, function(l)&lt;br /&gt;
		return l:gsub( &amp;quot;^[^|]*|(.*)$&amp;quot;, &amp;quot;%1&amp;quot; ):gsub(&amp;quot;^%s*(.-)%s*$&amp;quot;, &amp;quot;%1&amp;quot;);&lt;br /&gt;
	end));&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[=[ Inspired from above, removes everything between &amp;lt; &amp;amp; &amp;gt;&lt;br /&gt;
Used to remove html containers from headers to fix breaking section links, but legitimate text within &amp;lt; &amp;amp; &amp;gt; are removed too&lt;br /&gt;
]=]&lt;br /&gt;
local function remove_container (str)&lt;br /&gt;
	return (str:gsub( &amp;quot;%&amp;lt;([^%&amp;gt;]*)%&amp;gt;&amp;quot;, function(l)&lt;br /&gt;
		return l:gsub(&amp;quot;^%s*(.-)%s*$&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
	end));&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[=[-------------------------&amp;lt; M A K E _ W I K I L I N K &amp;gt;----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Makes a wikilink; when both link and display text is provided, returns a wikilink in the form [[L|D]]; if only&lt;br /&gt;
link is provided, returns a wikilink in the form [[L]]; if neither are provided or link is omitted, returns an&lt;br /&gt;
empty string.&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local function make_wikilink (link, display)&lt;br /&gt;
	if link and ('' ~= link) then&lt;br /&gt;
		if display and ('' ~= display) then&lt;br /&gt;
			return table.concat ({'[[', link, '|', display, ']]'});&lt;br /&gt;
		else&lt;br /&gt;
			return table.concat ({'[[', link, ']]'});&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return display or '';														-- link not set so return the display text&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S I Z E &amp;gt;----------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
module entry point&lt;br /&gt;
&lt;br /&gt;
create a wikilinked list of &amp;lt;article name&amp;gt;'s sections and their size in bytes in a sortable wikitable&lt;br /&gt;
&lt;br /&gt;
{{#invoke:Section sizes|size|&amp;lt;article name&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function size (frame)&lt;br /&gt;
	local A = {};																-- table to hold section names and sizes&lt;br /&gt;
	local section_name_list = {}												-- an interim list that holds just the section names&lt;br /&gt;
	local section_content;														-- section content used for counting&lt;br /&gt;
	local section = mw.title.new (&amp;quot;MediaWiki:Vector-toc-beginning&amp;quot;):getContent();	-- lead section doen't have a heading, call the text in MediaWiki:Vector-toc-beginning instead&lt;br /&gt;
	local count = {};															-- number of bytes in a section including the header text&lt;br /&gt;
	local totcount = {};&lt;br /&gt;
	local lastlevel;&lt;br /&gt;
	local maxlevels;&lt;br /&gt;
	local levelcounts = {};&lt;br /&gt;
	local upperlevel;&lt;br /&gt;
	local highlight;&lt;br /&gt;
	local highlighttot;&lt;br /&gt;
	local total;																-- sum of all byte counts&lt;br /&gt;
	local max;																	-- largest section so far encountered&lt;br /&gt;
	local totmax;																-- largest section so far encountered (section total)&lt;br /&gt;
	local _;																	-- dummy for using gsub to count bytes&lt;br /&gt;
	local lang = mw.language.getContentLanguage();								-- language object for number formatting appropriate to local language&lt;br /&gt;
	local s;																	-- start position of found heading (returned from string.find())&lt;br /&gt;
	local e = 1;																-- end position of found heading (returned from string.find())&lt;br /&gt;
	local section_name;															-- captured heading name (returned from string.find())&lt;br /&gt;
	local level = {};															-- number of leading '=' in heading markup; used for indenting subsections in the rendered list&lt;br /&gt;
	local wl_name;																-- anchor and display portion for wikilinks in rendered list&lt;br /&gt;
&lt;br /&gt;
	local content = mw.title.new (frame.args[1]):getContent();					-- get unparsed wikitext from the article&lt;br /&gt;
	if not content then&lt;br /&gt;
		return '&amp;lt;span style=&amp;quot;font-size:100%;&amp;quot; class=&amp;quot;error&amp;quot;&amp;gt;error: no article:' .. frame.args[1] .. '&amp;lt;/span&amp;gt;';&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if content:find ('#REDIRECT') then											-- redirects don't have sections&lt;br /&gt;
		return '&amp;lt;span style=&amp;quot;font-size:100%;&amp;quot; class=&amp;quot;error&amp;quot;&amp;gt;error: ' .. frame.args[1] .. ' is a redirect&amp;lt;/span&amp;gt;';&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	section_content = content:match ('(.-)===*');								-- get the lead section&lt;br /&gt;
	if section_content then&lt;br /&gt;
		_, count[0] = section_content:gsub ('.', '%1');							-- count the size of the lead section&lt;br /&gt;
	else&lt;br /&gt;
		return '&amp;lt;span style=&amp;quot;font-size:100%;&amp;quot; class=&amp;quot;error&amp;quot;&amp;gt;error: no sections found in: ' .. frame.args[1] .. '&amp;lt;/span&amp;gt;';&lt;br /&gt;
	end&lt;br /&gt;
	total = count[0];&lt;br /&gt;
	max = count[0];&lt;br /&gt;
	&lt;br /&gt;
	table.insert (A, make_wikilink (frame.args[1], section) .. '|| style=&amp;quot;text-align:right&amp;quot;|' .. lang:formatNum (count[0]) .. '|| style=&amp;quot;text-align:right&amp;quot;|' .. lang:formatNum (count[0]));&lt;br /&gt;
&lt;br /&gt;
	while (1) do																-- done this way because some articles reuse section names&lt;br /&gt;
		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&lt;br /&gt;
		if s then&lt;br /&gt;
			table.insert (section_name_list, {section_name, s});				-- save section name and start location of this find&lt;br /&gt;
		else&lt;br /&gt;
			break;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	for i, section_name in ipairs (section_name_list) do&lt;br /&gt;
		local escaped_section_name = string.gsub (section_name[1], '([%(%)%.%%%+%-%*%?%[%^%$%]])', '%%%1');		-- escape lua patterns in section name&lt;br /&gt;
		local pattern = '(==+ *' .. escaped_section_name .. ' *==+.-)==+';		-- make a pattern to get the content of a section&lt;br /&gt;
		section_content = string.match (content, pattern, section_name[2]);		-- get the content beginning at the string.find() start location&lt;br /&gt;
		if section_content then&lt;br /&gt;
			_, count[i] = section_content:gsub ('.', '%1');						-- count the bytes in the section&lt;br /&gt;
			total = total + count[i];&lt;br /&gt;
			max = max &amp;lt; count[i] and count[i] or max;							-- keep track of largest count&lt;br /&gt;
		else																	-- probably the last section (no proper header follows this section name)&lt;br /&gt;
			pattern = '(==+ *' .. escaped_section_name .. ' *==+.+)';			-- make a new pattern&lt;br /&gt;
			section_content = string.match (content, pattern, section_name[2]);		-- try to get content&lt;br /&gt;
			if section_content then&lt;br /&gt;
				_, count[i] = section_content:gsub ('.', '%1');					-- count the bytes in the section&lt;br /&gt;
				total = total + count[i];&lt;br /&gt;
				max = max &amp;lt; count[i] and count[i] or max;						-- keep track of largest count&lt;br /&gt;
			else&lt;br /&gt;
				count[i] = '—';													-- no content so show that&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		_, level[i] = section_content:find ('^=+');								-- should always be the first n characters of section content&lt;br /&gt;
		&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	totmax=0;&lt;br /&gt;
	lastlevel=0;&lt;br /&gt;
	maxlevels=7;&lt;br /&gt;
	for j=1,maxlevels do&lt;br /&gt;
		levelcounts[j]=0;&lt;br /&gt;
	end&lt;br /&gt;
    for i=#count,1,-1 do&lt;br /&gt;
    	--totcount[i]=level[i];&lt;br /&gt;
    	if level[i]&amp;lt;lastlevel then	-- reset all&lt;br /&gt;
    		totcount[i]=levelcounts[level[i]]+count[i];&lt;br /&gt;
    		for j=level[i],maxlevels do&lt;br /&gt;
				levelcounts[j]=0;&lt;br /&gt;
			end&lt;br /&gt;
    	end&lt;br /&gt;
    	if level[i]&amp;gt;=lastlevel then&lt;br /&gt;
    		totcount[i]=count[i];&lt;br /&gt;
    	end&lt;br /&gt;
		if level[i]&amp;gt;0 then&lt;br /&gt;
	    	upperlevel=level[i]-1;&lt;br /&gt;
	    	levelcounts[upperlevel]=levelcounts[upperlevel]+totcount[i];&lt;br /&gt;
    	end&lt;br /&gt;
		lastlevel=level[i];&lt;br /&gt;
		if totcount[i]&amp;gt;totmax then&lt;br /&gt;
			totmax=totcount[i];&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for i, section_name in ipairs (section_name_list) do&lt;br /&gt;
&lt;br /&gt;
		if count[i]==max then&lt;br /&gt;
			highlight='color:red;&amp;quot;|';&lt;br /&gt;
		else &lt;br /&gt;
			highlight='&amp;quot;|';&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		highlighttot='';														-- start the style declaration&lt;br /&gt;
		if level[i]==2 then&lt;br /&gt;
			highlighttot=highlighttot .. 'font-weight:bold;';					-- if main section, make it bold&lt;br /&gt;
		elseif totcount[i]==count[i] then&lt;br /&gt;
			highlighttot='color:transparent;';									-- hide totals for subsections with no subsubsections, values required for proper sorting&lt;br /&gt;
		end&lt;br /&gt;
		if totcount[i]==totmax then&lt;br /&gt;
			highlighttot=highlighttot .. 'color:red;';							-- if the largest size, make it red&lt;br /&gt;
		end&lt;br /&gt;
		highlighttot=highlighttot .. '&amp;quot;|';										-- close the style declaration&lt;br /&gt;
		&lt;br /&gt;
		level[i] = (2 &amp;lt; level[i]) and ((level[i]-2) * 1.6) or nil;				-- remove offset and mult by 1.6em (same indent as ':' markup which doesn't work in a table)&lt;br /&gt;
		&lt;br /&gt;
		wl_name = remove_wiki_link (section_name[1]):gsub ('%b{}', '');			-- remove wikilinks and templates from section headings so that we can link to the section&lt;br /&gt;
		wl_name = remove_container (wl_name);									-- remove html containers from section headings so that we can link to the section&lt;br /&gt;
		wl_name = wl_name:gsub ('[%[%]]', {['[']='&amp;amp;#91;', [']']='&amp;amp;#93;'});		-- replace '[' and ']' characters with html entities so that wikilinked section names work&lt;br /&gt;
		wl_name = mw.text.trim (wl_name);										-- trim leading/trailing white space if any because white space buggers up url anchor links&lt;br /&gt;
		&lt;br /&gt;
		table.insert (A, table.concat ({										-- build most of a table row here because here we have heading information that we won't have later&lt;br /&gt;
			level[i] and '&amp;lt;span style=&amp;quot;margin-left:' .. level[i] .. 'em&amp;quot;&amp;gt;' or '';		-- indent per heading level (number of '=' in heading markup)&lt;br /&gt;
			make_wikilink (frame.args[1] .. '#' .. wl_name, wl_name),			-- section link&lt;br /&gt;
			level[i] and '&amp;lt;/span&amp;gt;' or '',										-- close the span if opened&lt;br /&gt;
			'||',																-- table column separator&lt;br /&gt;
			'style=&amp;quot;text-align:right;',											-- the byte count column is right aligned&lt;br /&gt;
			highlight ,&lt;br /&gt;
			lang:formatNum (count[i]),											-- commafied byte count for section&lt;br /&gt;
			'||',&lt;br /&gt;
			'style=&amp;quot;text-align:right;',											-- the section total column is right aligned&lt;br /&gt;
			highlighttot ,&lt;br /&gt;
			lang:formatNum (totcount[i]),										-- section total count!!&lt;br /&gt;
		}));																&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local out = {};																-- make a sortable wikitable for output&lt;br /&gt;
	table.insert (out, string.format ('{| class=&amp;quot;wikitable sortable&amp;quot; style=&amp;quot;%s&amp;quot;\n|+Section size for [[%s]] (%d sections)', frame.args.style or '', frame.args[1], #A));							-- output table header&lt;br /&gt;
	table.insert (out, '\n!Section name!!Byte&amp;lt;br/&amp;gt;count!!Section&amp;lt;br/&amp;gt;total\n|-\n|');		-- column headers, and first row pipe&lt;br /&gt;
	table.insert (out, table.concat (A, '\n|-\n|'));							-- section rows with leading pipes (except first row already done)&lt;br /&gt;
	table.insert (out, '\n|-\n!Total!!style=&amp;quot;text-align:right&amp;quot;|' .. lang:formatNum (total) .. '!!style=&amp;quot;text-align:right&amp;quot;|' .. lang:formatNum (total));		-- total number of bytes counted as column headers so that sorting doesn't move this row from the bottom to top&lt;br /&gt;
	table.insert (out, '\n|}');													-- close the wikitable&lt;br /&gt;
	&lt;br /&gt;
	--max = lang:formatNum (max);												-- commafy so that the commafied value in the table can be found&lt;br /&gt;
	--local result = table.concat (out, ''):gsub (max, '&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;' .. max .. '&amp;lt;/span&amp;gt;');		-- make a big string, make largest count(s) red, and done&lt;br /&gt;
	local result = table.concat (out, '');&lt;br /&gt;
	return result;																-- because gsub returns string and number of replacements&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; E X P O R T E D   F U N C T I O N S &amp;gt;------------------------------------------&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
return&lt;br /&gt;
	{&lt;br /&gt;
	size = size,&lt;br /&gt;
	}&lt;/div&gt;</summary>
		<author><name>Cascadia2</name></author>
	</entry>
</feed>