-- Categorizes content and display them.
-- Improvements are welcomed.
-- requires
-- forward declarations
local index;
local build_keys;
local build_values;
local as_key_content_function;
local as_value_content_function;
local as_fold_function;
local escape_replacement;
local adapt_magic_word_pattern;
-- exposed: categorizes content and display them
-- 'folder', 'table_*', 'content'
index = function(frame)
local args = build_args(frame)
local folder = as_fold_function(args.folder)
local keys = build_keys(args)
local values = build_values(args.content)
local result = ""
for category, key in pairs(keys) do
local value = values[category]
if value == nil then
value = function(category)
return ""
end
end
result = folder(result,
key(
value(category)
)
)
end
return result
end
-- builds arguments
-- reads parent frame
build_args = function(frame)
local result = {}
local pframe = frame:getParent()
for key, value in pairs(frame.args) do
result[key] = value
end
for key, value in pairs(pframe.args) do
result[key] = value
end
return result
end
-- builds key mapping
-- reads 'table_*'
build_keys = function(args)
local result = {}
for arg_k, arg_v in pairs(args) do
local arg_k_trim = mw.text.trim(arg_k)
if arg_k_trim:match("^table_") then
local key = arg_k_trim:gsub("table_", "", 1)
result[key] = as_key_content_function(mw.text.trim(arg_v))
end
end
return result
end
-- builds values mapping
-- magic words: '__M_INDEX__'
-- syntax: '__M_INDEX__ [category1] [category2] ... [categoryN]'
build_values = function(text)
-- need cleanup
local result = {}
local context = {}
local content = ""
for line_number, line in ipairs(mw.text.split(text, "\n", true)) do -- is \n sufficient
if line:match("^__M_INDEX__") then
-- finish result
for index, category in ipairs(context) do
local sub_result = result[category]
if sub_result == nil then
result[category] = content
else
result[category] = sub_result .. content
end
end
content = ""
-- change context
context = {}
for category in line:gmatch("%[([^%]]*)%]") do
table.insert(context, category)
end
else
-- append content
content = content .. line .. "\n"
end
end
-- one more round of finishing result
for index, category in ipairs(context) do
local sub_result = result[category]
if sub_result == nil then
result[category] = content
else
result[category] = sub_result .. content
end
end
-- turn into content function
for key, value in pairs(result) do
result[key] = as_value_content_function(value)
end
return result
end
-- converts text to key content function
-- magic words: '__M_CONTENT__'
as_key_content_function = function(text)
local function func(content)
return text:gsub(adapt_magic_word_pattern("__M_CONTENT__"), escape_replacement(content))
end
return func
end
-- converts text to value content function
-- magic words: '__M_CATEGORY__'
as_value_content_function = function(text)
local function func(category)
return text:gsub(adapt_magic_word_pattern("__M_CATEGORY__"), escape_replacement(category))
end
return func
end
-- converts text to folding function
-- magic words: '__M_LEFT__', '__M_RIGHT__'
as_fold_function = function(text)
local function func(left, right)
-- some improvements could be made here
return text:gsub(adapt_magic_word_pattern("__M_LEFT__"), escape_replacement(left)):gsub(adapt_magic_word_pattern("__M_RIGHT__"), escape_replacement(right))
end
return func
end
-- adapt magic word pattern for un-escaped and escaped underscore
adapt_magic_word_pattern = function(text)
return text:gsub("_", "[_(_)]")
end
return {index = index}