<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3Acategory_tree%2Fscripts%2Fblocks</id>
	<title>Module:category tree/scripts/blocks - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3Acategory_tree%2Fscripts%2Fblocks"/>
	<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:category_tree/scripts/blocks&amp;action=history"/>
	<updated>2026-05-18T13:25:27Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://linguifex.com/w/index.php?title=Module:category_tree/scripts/blocks&amp;diff=515682&amp;oldid=prev</id>
		<title>Sware: Created page with &quot;local m_str_utils = require(&quot;Module:string utilities&quot;)  local concat = table.concat local cp = m_str_utils.codepoint local floor = math.floor local gmatch = m_str_utils.gmatch local gsub = m_str_utils.gsub local insert = table.insert local sort = table.sort local u = m_str_utils.char  local export = {}  local fun = require &quot;Module:fun&quot; local Array = require &quot;Module:array&quot;  local function compare_script_codes(code1, code2) 	-- Sort four-letter codes and non-four-letter co...&quot;</title>
		<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:category_tree/scripts/blocks&amp;diff=515682&amp;oldid=prev"/>
		<updated>2026-05-08T11:57:34Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;local m_str_utils = require(&amp;quot;Module:string utilities&amp;quot;)  local concat = table.concat local cp = m_str_utils.codepoint local floor = math.floor local gmatch = m_str_utils.gmatch local gsub = m_str_utils.gsub local insert = table.insert local sort = table.sort local u = m_str_utils.char  local export = {}  local fun = require &amp;quot;Module:fun&amp;quot; local Array = require &amp;quot;Module:array&amp;quot;  local function compare_script_codes(code1, code2) 	-- Sort four-letter codes and non-four-letter co...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local m_str_utils = require(&amp;quot;Module:string utilities&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local concat = table.concat&lt;br /&gt;
local cp = m_str_utils.codepoint&lt;br /&gt;
local floor = math.floor&lt;br /&gt;
local gmatch = m_str_utils.gmatch&lt;br /&gt;
local gsub = m_str_utils.gsub&lt;br /&gt;
local insert = table.insert&lt;br /&gt;
local sort = table.sort&lt;br /&gt;
local u = m_str_utils.char&lt;br /&gt;
&lt;br /&gt;
local export = {}&lt;br /&gt;
&lt;br /&gt;
local fun = require &amp;quot;Module:fun&amp;quot;&lt;br /&gt;
local Array = require &amp;quot;Module:array&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local function compare_script_codes(code1, code2)&lt;br /&gt;
	-- Sort four-letter codes and non-four-letter codes alphabetically.&lt;br /&gt;
	if (#code1 == 4) == (#code2 == 4) then&lt;br /&gt;
		return code1 &amp;lt; code2&lt;br /&gt;
	&lt;br /&gt;
	-- Put four-letter codes before non-four-letter codes.&lt;br /&gt;
	else&lt;br /&gt;
		return #code1 == 4&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sort_scripts(script_codes)&lt;br /&gt;
	sort(script_codes, compare_script_codes)&lt;br /&gt;
	return script_codes&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local block_data = require &amp;quot;Module:Unicode data/blocks&amp;quot;&lt;br /&gt;
&lt;br /&gt;
-- Add position of range in the array of blocks to the range tables.&lt;br /&gt;
for i, range in ipairs(block_data) do&lt;br /&gt;
	range[4] = i&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Binary search, to avoid iterating over entire table in order to look up the&lt;br /&gt;
-- higher codepoints.&lt;br /&gt;
local function binary_lookup_block(codepoint)&lt;br /&gt;
	local iStart, iEnd = 1, block_data.length or #block_data&lt;br /&gt;
	while iStart &amp;lt;= iEnd do&lt;br /&gt;
		local iMid = floor((iStart + iEnd) / 2)&lt;br /&gt;
		local range = block_data[iMid]&lt;br /&gt;
		if codepoint &amp;lt; range[1] then&lt;br /&gt;
			iEnd = iMid - 1&lt;br /&gt;
		elseif codepoint &amp;lt;= range[2] then&lt;br /&gt;
			return range&lt;br /&gt;
		else&lt;br /&gt;
			iStart = iMid + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	error(string.format(&amp;quot;No block found for codepoint U+%04X.&amp;quot;, codepoint))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.lookup_block(char)&lt;br /&gt;
	local codepoint = cp(char)&lt;br /&gt;
	local range = binary_lookup_block(codepoint)&lt;br /&gt;
	if range then&lt;br /&gt;
		return range&lt;br /&gt;
	else&lt;br /&gt;
		error(string.format(&amp;quot;No block found for U+%04X (%s).&amp;quot;, codepoint, u(codepoint)))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.get_singles_and_ranges(pattern)&lt;br /&gt;
	local ranges, singles = {}, {}&lt;br /&gt;
	pattern = gsub(&lt;br /&gt;
		pattern,&lt;br /&gt;
		&amp;quot;(.)%-(.)&amp;quot;,&lt;br /&gt;
		function(lower, higher)&lt;br /&gt;
			insert(ranges, { lower, higher })&lt;br /&gt;
			return &amp;quot;&amp;quot;&lt;br /&gt;
		end)&lt;br /&gt;
	&lt;br /&gt;
	for character in gmatch(pattern, &amp;quot;.&amp;quot;) do&lt;br /&gt;
		insert(singles, character)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return singles, ranges&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.get_block_arrays(pattern)&lt;br /&gt;
	local singles, ranges = export.get_singles_and_ranges(pattern)&lt;br /&gt;
	&lt;br /&gt;
	local blocks = {}&lt;br /&gt;
	&lt;br /&gt;
	for _, character in ipairs(singles) do&lt;br /&gt;
		blocks[export.lookup_block(character)] = true&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	for _, range in ipairs(ranges) do&lt;br /&gt;
		local block_array1, block_array2 = export.lookup_block(range[1]), export.lookup_block(range[2])&lt;br /&gt;
		for i = block_array1[4], block_array2[4] do&lt;br /&gt;
			blocks[block_data[i]] = true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return Array.keysToList(blocks, function (block1, block2) return block1[4] &amp;lt; block2[4] end)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function format_block_info(block_array)&lt;br /&gt;
	return (&amp;quot;[[Appendix:Unicode/%s|%s]] (U+%04X&amp;amp;ndash;U+%04X)&amp;quot;):format(block_array[3], block_array[3], block_array[1], block_array[2])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.print_blocks(block_arrays, prefix)&lt;br /&gt;
	sort(&lt;br /&gt;
		block_arrays,&lt;br /&gt;
		function (block_array1, block_array2)&lt;br /&gt;
			return block_array1[1] &amp;lt; block_array2[1]&lt;br /&gt;
		end)&lt;br /&gt;
	local block_names = fun.map(&lt;br /&gt;
		function (block_array)&lt;br /&gt;
			return &amp;quot;* &amp;quot; .. format_block_info(block_array)&lt;br /&gt;
		end,&lt;br /&gt;
		block_arrays)&lt;br /&gt;
	if prefix then&lt;br /&gt;
		insert(block_names, 1, prefix)&lt;br /&gt;
	end&lt;br /&gt;
	return concat(block_names, &amp;quot;\n&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.print_blocks_by_canonical_name(script_name)&lt;br /&gt;
	if type(script_name) ~= &amp;quot;string&amp;quot; then&lt;br /&gt;
		error(&amp;quot;script_name should be a string, not &amp;quot; .. type(script_name) .. &amp;quot;.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local scripts_by_pattern = {}&lt;br /&gt;
	setmetatable(&lt;br /&gt;
		scripts_by_pattern,&lt;br /&gt;
		{&lt;br /&gt;
			__index = function(self, key)&lt;br /&gt;
				if key == nil then&lt;br /&gt;
					return&lt;br /&gt;
				end&lt;br /&gt;
				local val = Array()&lt;br /&gt;
				self[key] = val&lt;br /&gt;
				return val&lt;br /&gt;
			end&lt;br /&gt;
		})&lt;br /&gt;
	&lt;br /&gt;
	local count = 0&lt;br /&gt;
	for code, data in pairs(mw.loadData(&amp;quot;Module:scripts/data&amp;quot;)) do&lt;br /&gt;
		if data[1] == script_name and data.characters then&lt;br /&gt;
			count = count + 1&lt;br /&gt;
			scripts_by_pattern[data.characters]:insert(code)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if not next(scripts_by_pattern) then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local block_arrays_by_scripts = {}&lt;br /&gt;
	local block_count = 0&lt;br /&gt;
	&lt;br /&gt;
	-- Construct arrays of blocks and count the blocks.&lt;br /&gt;
	for pattern, scripts in pairs(scripts_by_pattern) do&lt;br /&gt;
		local array = export.get_block_arrays(pattern)&lt;br /&gt;
		block_arrays_by_scripts[sort_scripts(scripts)] = array&lt;br /&gt;
		block_count = block_count + #array&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	require(&amp;quot;Module:debug&amp;quot;).track{&lt;br /&gt;
		&amp;quot;scriptcatboiler/blocks/&amp;quot; .. count,&lt;br /&gt;
		&amp;quot;scriptcatboiler/blocks/&amp;quot; .. block_count&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if count == 1 and block_count == 1 then&lt;br /&gt;
		local scripts, block_arrays = next(block_arrays_by_scripts)&lt;br /&gt;
		if scripts[2] or block_arrays[2] then&lt;br /&gt;
			error(&amp;quot;More than one script or more than one block. Something is wrong.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		return (&amp;quot;The characters of &amp;lt;code&amp;gt;%s&amp;lt;/code&amp;gt; are found in the Unicode block %s&amp;quot;)&lt;br /&gt;
			:format(scripts[1], format_block_info(block_arrays[1]))&lt;br /&gt;
	else&lt;br /&gt;
		local collapsible1 = &amp;#039;{|\n&amp;#039;&lt;br /&gt;
		local collapsible3 = &amp;#039;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
		&lt;br /&gt;
		return &amp;#039;{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; style=&amp;quot;width: 30em;&amp;quot;\n|+ style=&amp;quot;font-weight: normal;&amp;quot; | &amp;#039; .. &amp;quot;&amp;#039;&amp;#039;&amp;#039;Unicode block&amp;quot;&lt;br /&gt;
			.. (block_count &amp;gt; 1 and &amp;quot;s&amp;quot; or &amp;quot;&amp;quot;) .. &amp;quot; for characters in &amp;quot;&lt;br /&gt;
			.. (count &amp;gt; 1 and &amp;quot;these scripts&amp;quot; or &amp;quot;this script&amp;quot;) .. &amp;quot;&amp;#039;&amp;#039;&amp;#039;\n|\n&amp;quot;&lt;br /&gt;
			.. concat(&lt;br /&gt;
				fun.mapIter(&lt;br /&gt;
					function(block_arrays, scripts)&lt;br /&gt;
						return export.print_blocks(&lt;br /&gt;
							block_arrays,&lt;br /&gt;
							&amp;quot;; Block&amp;quot; .. (block_arrays[2] and &amp;quot;s&amp;quot; or &amp;quot;&amp;quot;) .. &amp;quot; in &amp;quot;&lt;br /&gt;
								.. concat(&lt;br /&gt;
									fun.map(&lt;br /&gt;
										function (script_code)&lt;br /&gt;
											return &amp;quot;&amp;lt;code&amp;gt;&amp;quot; .. script_code .. &amp;quot;&amp;lt;/code&amp;gt;&amp;quot;&lt;br /&gt;
										end,&lt;br /&gt;
										scripts),&lt;br /&gt;
									&amp;quot;, &amp;quot;))&lt;br /&gt;
					end,&lt;br /&gt;
					require(&amp;quot;Module:table&amp;quot;).sortedPairs(&lt;br /&gt;
						block_arrays_by_scripts,&lt;br /&gt;
						function(script_array1, script_array2)&lt;br /&gt;
							return compare_script_codes(script_array1[1], script_array2[1])&lt;br /&gt;
						end)),&lt;br /&gt;
				&amp;quot;\n&amp;quot;)&lt;br /&gt;
			.. &amp;#039;\n|}&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- For testing.&lt;br /&gt;
function export.print_blocks_by_canonical_name_template(frame)&lt;br /&gt;
	return export.print_blocks_by_canonical_name(frame.args[1])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return export&lt;/div&gt;</summary>
		<author><name>Sware</name></author>
	</entry>
</feed>