Module:Link list

From Wikisource
Jump to navigation Jump to search

require('strict')
local p = {} --p stands for package

-- make a "set" from a list for easy membership testing
local function make_set(list)
  local set = {}
  for _, l in ipairs(list) do
  	set[l] = true
  end
  return set
end

--[=[
Format a list of links for a given range
 Arg 1: The link target format pattern
 Arg 2: The link name format pattern
 Arg 3: The range start
 Arg 4: The range end
 Arg rowlen: Break rows after this many entries
]=]
function p._link_list(args)

	local out = ""
	
	local rowlen = tonumber(args["rowlen"] or "0")
	local start = tonumber(args[3])
	local endi = tonumber(args[4])
	
	local alt_indexes = {}

	-- collect any targetN_when lists as sets, along with their patterns into
	-- a table that holds the patterns and sets
	local alt_n = 2
	while args[ 'target' .. alt_n ] ~= nil and args[ 'target' .. alt_n .. '_when' ] ~= nil do
		local when_arg = 'target' .. alt_n .. '_when'
		local pattern_arg = 'target' .. alt_n
		table.insert( alt_indexes, {
			whenSet = make_set( mw.text.split( args[ when_arg ], ',', true ) ),
			pattern = args[ pattern_arg ]
		} )
		alt_n = alt_n + 1
	end

    for idx = start, endi do 
    	local fsp = " "
    	local display = string.format(args[2], idx)
    	-- replace spaces in the display string with figure spaces which don't collapse in HTML

    	-- replace spaces before number with a figure space, but keep normal spaces after words
    	display = display:gsub("([^ ] |%d)( *)(%d)", function(p, s, n) return p .. s:gsub(" ", " ") .. n  end)
        --  and spaces before leading numbers
    	display = display:gsub("^( +)(%d)", function(s, n) return s:gsub(" ", " ") .. n  end)
    	
    	local target = args[1]
    	
    	-- for every target set, check that there a matching patter
    	for _, altTarget in pairs( alt_indexes ) do
    		if altTarget.whenSet[ tostring( idx ) ]	then
    			target = altTarget.pattern
    		end
    	end
    	
    	-- interpolate the index in to the string
    	target = string.format(target, idx)

    	out = out .. "* [[" .. target .. "|" .. display .. "]]\n"
    	
    	-- add an extra line break after "rowlen" items, if rowlen is set
    	if rowlen > 0 and ((idx - start + 1) % rowlen == 0) and idx ~= endi then
    		out = out .. "\n"
    	end
    end

	return out
end

function p.link_list(frame)
	local getArgs = require('Module:Arguments').getArgs
	return p._link_list(getArgs(frame))
end

return p