Jump to content

Module:File parse

From Wikipedia, the free encyclopedia

local p = {};

local function split_pipes(s)
  local tokens = {}
  local buf = {}
  local depth_link, depth_tpl = 0, 0
  local i = 1
  while i <= #s do
    local two = s:sub(i,i+1)
    if two == "[[" then
      depth_link = depth_link + 1
      table.insert(buf, two)
      i = i + 2
    elseif two == "]]" and depth_link > 0 then
      depth_link = depth_link - 1
      table.insert(buf, two)
      i = i + 2
    elseif two == "{{" then
      depth_tpl = depth_tpl + 1
      table.insert(buf, two)
      i = i + 2
    elseif two == "}}" and depth_tpl > 0 then
      depth_tpl = depth_tpl - 1
      table.insert(buf, two)
      i = i + 2
    elseif s:sub(i,i) == "|" and depth_link == 0 and depth_tpl == 0 then
      -- split here
      table.insert(tokens, mw.text.trim(table.concat(buf)))
      buf = {}
      i = i + 1
    else
      table.insert(buf, s:sub(i,i))
      i = i + 1
    end
  end
  if #buf > 0 then
    table.insert(tokens, mw.text.trim(table.concat(buf)))
  end
  return tokens
end

function p.parse(frame)
	local s = frame.args[1]
	local key = frame.args[2]
	
	s = mw.text.trim(s)

	-- Strip outer [[ ]] if present
	if s:match("^%[%[.*%]%]$") then
		s = s:sub(3, -3)	-- from 3rd char to 3rd-from-last char
		s = mw.text.trim(s)
	end

	-- Must start with File: or Image:
	local prefix, rest = s:match("^(File:)(.+)$")
	if not rest then
		prefix, rest = s:match("^(Image:)(.+)$")
	end
	if not rest then
		return nil, "Not a File/Image wikilink"
	end

	rest = mw.text.trim(rest)

	local tokens = split_pipes(rest)

	local name = table.remove(tokens, 1)

	local res = {
		raw = "[[" .. prefix .. rest .. "]]",
		name = name,
		type = nil,
		border = false,
		location = nil,
		alignment = nil,
		size = nil,
		link = nil,
		alt = nil,
		page = nil,
		lang = nil,
		other = {},
		caption = nil,
	}

	-- parse options
	for i, tok in ipairs(tokens) do
		local lowered = tok:lower()

		if lowered == "thumb" or lowered == "thumbnail" or lowered == "frame"
			 or lowered == "framed" or lowered == "frameless" then
			res.type = lowered

		elseif lowered == "border" then
			res.border = true

		elseif lowered == "right" or lowered == "left" or lowered == "center" or lowered == "none" then
			res.location = lowered

		elseif lowered:match("^upright") then
			local factor = lowered:match("^upright=([0-9%.]+)$")
			res.size = { upright = tonumber(factor) or 1 }

		elseif lowered:match("^([0-9]+)px$") then
			res.size = { width = tonumber(lowered:match("^(%d+)px$")), px = true }

		elseif lowered:match("^x([0-9]+)px$") then
			res.size = { height = tonumber(lowered:match("^x(%d+)px$")), px = true }

		elseif lowered:match("^([0-9]+)x([0-9]+)px$") then
			local w,h = lowered:match("^(%d+)x(%d+)px$")
			res.size = { width = tonumber(w), height = tonumber(h), px = true }

		elseif lowered:match("^alt=") then
			res.alt = tok:match("^alt=(.+)$")

		elseif lowered:match("^link=") then
			res.link = tok:match("^link=(.+)$")

		elseif lowered:match("^page=") then
			res.page = tonumber(tok:match("^page=(%d+)$"))

		elseif lowered:match("^lang=") then
			res.lang = tok:match("^lang=(.+)$")

		else
			-- assume caption if it's last, otherwise shove into "other"
			if i == #tokens then
				res.caption = tok
			else
				res.other[#res.other+1] = tok
			end
		end
	end

	if key then
		return res[key]
	else
		return res
	end
end

return p;