模組:PlatformMap
local p = {}
---@overload fun(x: any): boolean?
local yesno = require('Module:Yesno')
---@type { [string]: { set: string, subset: string } }
local alias_map = {
['SS'] = { set = 'lr\\lr', subset = 'a\\\\\\e' },
['SIS'] = { set = 'lr\\\\lr', subset = 'a\\\\ae\\\\e' },
['I'] = { set = 'lr\\\\\\lr', subset = 'e\\a' }
}
---@param frame frame
---@return string
function p.main(frame)
local args = frame:getParent().args
---@module 'PlatformMapShared'
local util = require('Module:PlatformMap/Shared')
---@module "PlatformMapStrings"
local strs = require('Module:PlatformMap/Strings')
-- Import set inst
local set = args[1]
local subset = args[2]
if not set then
return '~~ ~~' .. strs.err_nil_arg_set
end
if alias_map[set] then
subset = alias_map[set].subset
set = alias_map[set].set
end
---@type { subsets: { [string]: string[][] }, rows: { tracks: integer[], [integer]: { continue: ('left'|'right')?, to: ('left'|'right')?, trimmable: boolean? } }, switches: { both: { [string]: string[][] }, left: { [string]: string[][] }, right: { [string]: string[][] } } }
local meta = require('Module:PlatformMap/' .. set)
-- Init
local inst
if meta.subsets[subset] then
inst = meta.subsets[subset]
else
local rows = mw.text.split(subset, ' ')
if #rows > 1 then
inst = {}
for r, row in ipairs(rows) do
inst[r] = mw.text.split(row, '\\')
end
else
return '~~ ~~' .. mw.ustring.format(strs.err_unknown_subset, set, subset)
end
end
local stats = {
custom_subset = false, -- TODO
custom_switches = false, -- TODO
unknown_switches = {}
}
-- Override track connections
for t, r in ipairs(meta.rows.tracks) do
if args['continue' .. t] then
meta.rows[r].continue = args['continue' .. t]
end
end
local i
-- Left switches
i = 1
while (true) do
local name = args['switchL' .. i]
if not name then
break
end
local switch = meta.switches.both[name] or meta.switches.left[name]
if switch then
util.matrix.prepend(inst, switch)
else
local rows = mw.text.split(name, ' ')
if #rows == #inst then -- direct input
switch = {}
for r, row in ipairs(rows) do
switch[r] = mw.text.split(row, '\\')
end
util.matrix.prepend(inst, switch)
elseif mw.ustring.sub(name, 1, 3) == 'STR' and mw.ustring.sub(name, -1, -1) == '#' then
local pad = tonumber(mw.ustring.sub(name, 4, -2))
for r = 1, #inst do
local info = meta.rows[r]
if info and info.to and info.continue ~= 'right' then
for _ = 1, pad do
table.insert(inst[r], 1, 'uSTRq')
end
else
for _ = 1, pad do
table.insert(inst[r], 1, '')
end
end
end
else
table.insert(stats.unknown_switches, name)
end
end
i = i + 1
end
-- Right switches
i = 1
while (true) do
local name = args['switchR' .. i]
if not name then
break
end
local switch = meta.switches.both[name] or meta.switches.right[name]
if switch then
util.matrix.append(inst, switch)
else
local rows = mw.text.split(name, ' ')
if #rows == #inst then -- direct input
switch = {}
for r, row in ipairs(rows) do
switch[r] = mw.text.split(row, '\\')
end
util.matrix.append(inst, switch)
elseif mw.ustring.sub(name, 1, 3) == 'STR' and mw.ustring.sub(name, -1, -1) == '#' then
local pad = tonumber(mw.ustring.sub(name, 4, -2))
for r = 1, #inst do
local info = meta.rows[r]
if info and info.to and info.continue ~= 'left' then
for _ = 1, pad do
table.insert(inst[r], 'uSTRq')
end
else
for _ = 1, pad do
table.insert(inst[r], '')
end
end
end
else
table.insert(stats.unknown_switches, name)
end
end
i = i + 1
end
-- Tracks (round I)
local replace_l = true
local replace_r = true
for t, r in ipairs(meta.rows.tracks) do
-- override orientions
if args['to' .. t] then meta.rows[r].to = args['to' .. t] end
-- track end detection
local row = inst[r]
local info = meta.rows[r]
if info.continue ~= 'right' then
local bound = args['bound' .. t .. 'L'] or args['boundL']
if info.to == 'right' or (bound ~= nil and bound ~= '') then
if not util.icon.map[row[1]] then
replace_l = false
end
else
if string.find(row[1], 'BS') then
replace_l = false
end
end
end
if info.continue ~= 'left' then
local bound = args['bound' .. t .. 'R'] or args['boundR']
if info.to == 'left' or (bound ~= nil and bound ~= '') then
if not util.icon.map[row[#row]] then
replace_r = false
end
else
if string.find(row[#row], 'BS') then
replace_r = false
end
end
end
-- outbound text (overrided by manual)
local nxt = args['next' .. t]
if nxt then
local system = args['system' .. t] or args.system
local line = args['line' .. t] or args.line
local typ = args['type' .. t] or args.type
local inverse = yesno(args['inverse' .. t]) or false
if meta.rows[r].to == 'left' then
row.textL = util.text.adjacent
{ system = system, line = line, type = typ, next = nxt, left = true, inverse = inverse } .. '~~'
else
row.textR = '~~' ..
util.text.adjacent
{ system = system, line = line, type = typ, next = nxt, left = false, inverse = inverse }
end
end
end
-- Manual texts
for r, row in ipairs(inst) do
-- Manual text
if args['textL' .. r] then
row.textL = args['textL' .. r]
end
if args['textR' .. r] then
row.textR = args['textR' .. r]
end
end
-- Tracks (round II)
local noextend_l = (args['boundL'] == 'hard')
local noextend_r = (args['boundR'] == 'hard')
for t, r in ipairs(meta.rows.tracks) do
-- track ends
local row = inst[r]
local info = meta.rows[r]
-- left
if info.continue ~= 'right' then
local bound = args['bound' .. t .. 'L'] or args['boundL']
if bound == 'hard' then
if replace_l then
row[1] = util.icon.map[row[1]].hard.on_left
else
table.insert(row, 1, util.icon.map['uSTRq'].hard.on_left)
end
if not noextend_l then
table.insert(row, 1, '')
end
elseif bound == 'soft' then
if replace_l then
row[1] = util.icon.map[row[1]].soft.on_left
else
table.insert(row, 1, util.icon.map['uSTRq'].soft.on_left)
end
table.insert(row, 1, util.icon.map['uexCONTgq'][info.to])
else
if replace_l then
if util.icon.map[row[1]] then
row[1] = util.icon.map[row[1]].open.on_left
end
else
table.insert(row, 1, util.icon.map['uSTRq'].open.on_left)
end
table.insert(row, 1, util.icon.map['uCONTgq'][info.to])
end
else
if not replace_l then
table.insert(row, 1, '')
end
if not noextend_l then
table.insert(row, 1, '')
end
end
-- right
if info.continue ~= 'left' then
local bound = args['bound' .. t .. 'R'] or args['boundR']
if bound == 'hard' then
if replace_r then
row[#row] = util.icon.map[row[#row]].hard.on_right
else
table.insert(row, util.icon.map['uSTRq'].hard.on_right)
end
if not noextend_r then
table.insert(row, '')
end
elseif bound == 'soft' then
if replace_r then
row[#row] = util.icon.map[row[#row]].soft.on_right
else
table.insert(row, util.icon.map['uSTRq'].soft.on_right)
end
table.insert(row, util.icon.map['uexCONTfq'][info.to])
else
if replace_r then
if util.icon.map[row[#row]] then
row[#row] = util.icon.map[row[#row]].open.on_right
end
else
table.insert(row, util.icon.map['uSTRq'].open.on_right)
end
table.insert(row, util.icon.map['uCONTfq'][info.to])
end
else
if not replace_r then
table.insert(row, '')
end
if not noextend_r then
table.insert(row, '')
end
end
end
-- Fix align
local nontrack_pad = 0
if replace_r then nontrack_pad = nontrack_pad - 1 end
if replace_l then nontrack_pad = nontrack_pad + 1 end
if noextend_r then nontrack_pad = nontrack_pad - 1 end
if noextend_l then nontrack_pad = nontrack_pad + 1 end
if nontrack_pad ~= 0 then
for r, row in ipairs(inst) do
local info = meta.rows[r]
if not info or not info.to then
if nontrack_pad == -2 then
table.insert(row, 1, '')
table.insert(row, 1, '')
elseif nontrack_pad == -1 then
table.insert(row, 1, '')
elseif nontrack_pad == 1 then
table.insert(row, '')
elseif nontrack_pad == 2 then
table.insert(row, '')
table.insert(row, '')
end
end
end
end
-- Trim unused rows
for r = #inst, 1, -1 do
local row = inst[r]
local info = meta.rows[r]
if info and info.trimmable then
local trim = true
for c = 1, #row do
if row[c] ~= '' then
trim = false
break
end
end
if trim then table.remove(inst, r) end
end
end
-- Padding
if args.pad then
local pad = tonumber(args.pad)
if pad < 0 then
for r = 1, #inst do
for _ = 1, -pad do
table.insert(inst[r], 1, '')
end
end
elseif pad > 0 then
for r = 1, #inst do
for _ = 1, pad do
table.insert(inst[r], '')
end
end
end
end
-- Error
if #stats.unknown_switches > 0 then
local row = inst[#inst]
row.textR = table.concat {
mw.ustring.format(strs.err_unknown_switches, table.concat(stats.unknown_switches, ', ')),
row.textR
}
end
-- Output
local lines = {}
for r, row in ipairs(inst) do
lines[r] = table.concat(row, '\\')
---@diagnostic disable-next-line: undefined-field
if row.textL then lines[r] = mw.ustring.format('%s! !%s', row.textL, lines[r]) end
---@diagnostic disable-next-line: undefined-field
if row.textR then lines[r] = mw.ustring.format('%s~~%s', lines[r], row.textR) end
end
return table.concat(lines, '\n')
end
---@param frame frame
---@return string
function p.switch(frame)
local args = frame.args
local set = args[1]
set = require('Module:PlatformMap/' .. set)
local switch = args[2]
local side = args[3] or 'both'
switch = set.switches[side][switch]
local lines = {}
for l = 1, #switch do
lines[l] = table.concat(switch[l], '\\') .. '~~' .. l .. '~~'
end
return table.concat(lines, '\n')
end
return p