Mô đun:Ancient Greek/typing

local p = {}
local sparse_concat = require("Module:TableTools").sparseConcat
local U = mw.ustring.char
local UTF8_char = "%z\1-\127\194-\244\128-\191*" -- roughly equivalent to "." in Ustring patterns
local one_UTF8_char_or_none = "%z\1-\127\194-\244?\128-\191*" -- roughly equivalent to ".?" in Ustring patterns
local subscript = U(0x345) -- iota subscript (ypogegrammeni)
local macron = U(0x304) -- macron
local spacing_macron = U(0xAF)
local modifier_macron = U(0x2C9) -- modifier letter macron
local breve = U(0x306) -- breve
local spacing_breve = "˘" -- spacing breve
local diaeresis = U(0x308) -- diaeresis
local rough = U(0x314) -- rough breathing (reversed comma)
local smooth = U(0x313) -- smooth breathing (comma)
local acute = U(0x301) -- acute
local grave = U(0x300) -- grave
local circumflex = U(0x342) -- Greek circumflex (perispomeni)
local question_mark = U(0x37E) -- Greek question mark
local spacing_rough = "῾" -- spacing rough breathing
local spacing_smooth = "᾿" -- spacing smooth breathing
local combining_diacritic = table.concat{
	"",
	macron, breve,
	rough, smooth, diaeresis,
	acute, grave, circumflex,
	subscript,
	"",
}
-- The numbers are used to sort series of diacritics.
local diacritic_position = {
	macron = 1,
	breve = 2,
	rough = 3,
	smooth = 3,
	diaeresis = 3,
	acute = 4,
	grave = 4,
	circumflex = 4,
	subscript = 5,
}
-- Perform a function on each Unicode character in a string.
local function for_each(str, func)
	for char in string.gmatch(str, UTF8_char) do
		func(char)
	end
end
--=	This function arranges diacritics in the following order:
			1. macron or breve
			2. breathings or diaeresis
			3. acute, circumflex, or grave
			4. iota subscript
		Used by Module:typing-aids.
		
		Returns an error if a sequence of diacritics contains more than one
		of each category.
**
local function get_relative_position(diacritic1, diacritic2)
	return diacritic_positiondiacritic1 < diacritic_positiondiacritic2
end
local function chars_to_table(chars)
	local t = {}
	local i = 0
	for char in string.gmatch(chars, "%z\1-\127\194-\244\128-\191*") do
		i = i + 1
		ti = char
	end
	return t
end
local function reorder_diacritic_sequence(diacritics)
	diacritics = chars_to_table(diacritics)
	table.sort(diacritics, get_relative_position)
	return table.concat(diacritics)
end
function p.reorder_diacritics(text)
	return (mw.ustring.gsub(mw.ustring.toNFD(text),
		combining_diacritic .. combining_diacritic .. "+",
		reorder_diacritic_sequence))
end
local multiple = {
	"_i" = subscript,
}
local single = {
	"a" = "α", "A" = "Α",
	"b" = "β", "B" = "Β",
	"c" = "ξ", "C" = "Ξ",
	"d" = "δ", "D" = "Δ",
	"e" = "ε", "E" = "Ε",
	"f" = "φ", "F" = "Φ",
	"g" = "γ", "G" = "Γ",
	"h" = "η", "H" = "Η",
	"i" = "ι", "I" = "Ι",
	"k" = "κ", "K" = "Κ",
	"l" = "λ", "L" = "Λ",
	"m" = "μ", "M" = "Μ",
	"n" = "ν", "N" = "Ν",
	"o" = "ο", "O" = "Ο",
	"p" = "π", "P" = "Π",
	"q" = "θ", "Q" = "Θ",
	"r" = "ρ", "R" = "Ρ",
	"s" = "σ", "S" = "Σ",
	"t" = "τ", "T" = "Τ",
	"u" = "υ", "U" = "Υ",
	"v" = "ϝ", "V" = "Ϝ",
	"w" = "ω", "W" = "Ω",
	"x" = "χ", "X" = "Χ",
	"y" = "ψ", "Y" = "Ψ",
	"z" = "ζ", "Z" = "Ζ",
	
	-- vowel length
	"_" = macron, spacing_macron = macron, modifier_macron = macron,
	"^" = breve, spacing_breve = breve,
	
	-- diaeresis and breathings
	"+" = diaeresis, "(" = rough, ")" = smooth,
	
	-- accents
	"/" = acute, "\\" = grave,
	"=" = circumflex, "" = circumflex, "~" = circumflex,
	
	-- punctuation
	"'" = "’",
	"?" = question_mark,
	";" = "·",
	"*" = "", -- place after s to prevent it from turning into final sigma
	
	-- pipe
	"!" = "|",
}
local function convert_s_to_sigma(text)
	text = string.gsub(text,
		"s(" .. one_UTF8_char_or_none .. ")",
		function (following)
			return ((following == ""
				or following ~= "*" and following ~= "-" and mw.ustring.find(following, "%s%p"))
				and  "ς"
				or "σ") .. following
		end)
	return text
end
local function combining_to_spacing(text)
	for _, accents in ipairs{ { rough, spacing_rough }, { smooth, spacing_smooth } } do
		local combining, spacing = unpack(accents)
		text = string.gsub(text,
			"(" .. one_UTF8_char_or_none .. ")" .. combining,
			function (preceding)
				if preceding == "" then
					return spacing
				else
					return preceding .. combining
				end
			end)
	end
	
	return text
end
function p.to_Greek(text)
	if type(text) ~= "string" then
		error("first argument to to_greek should be string, not " .. type(text))
	end
	
	text = convert_s_to_sigma(text)
	for k, v in pairs(multiple) do
		text = string.gsub(text, k, v)
	end
	text = string.gsub(text, UTF8_char, single)
	text = combining_to_spacing(text)
	return p.reorder_diacritics(text)
end
function p.to_Greek_t(frame)
	local args = {}
	for k, v in pairs(frame:getParent().args) do
		if k == 1 then
			v = mw.text.trim(v)
			if v == "" then
				v = nil
			end
			argsk = v
		end
	end
	
	if not args1 then
		if mw.title.getCurrentTitle().nsText == "Template" then
			args1 = "le/cis"
		else
			error("Parameter 1 is required.")
		end
	end
	
	return p.to_Greek(args1)
end
local function process(char)
	if char == "" then
		return char
	end
	local entity = ("&#x%X;"):format(mw.ustring.codepoint(char))
	if diacritic_positionchar then
		return "◌" .. entity
	else
		return entity
	end
end
function p.show_shortcuts(frame)
	local output = { )
	
	return table.concat(output, '\n')	
end
return p