Module:HighlightPHP

From Soyjak Wiki, the free ensoyclopedia
Jump to navigationJump to search

local p = {}
local colors = {
	keyword = "#0077aa",
	variable = "#dd1144",
	string = "#228822",
	comment = "#888888",
	number = "#aa7700",
	tag = "#999999"
}
local keywords = {
	["abstract"]=true, ["and"]=true, ["array"]=true, ["as"]=true, ["break"]=true,
	["callable"]=true, ["case"]=true, ["catch"]=true, ["class"]=true, ["clone"]=true,
	["const"]=true, ["continue"]=true, ["declare"]=true, ["default"]=true,
	["do"]=true, ["echo"]=true, ["else"]=true, ["elseif"]=true, ["enddeclare"]=true,
	["endfor"]=true, ["endforeach"]=true, ["endif"]=true, ["endswitch"]=true,
	["endwhile"]=true, ["extends"]=true, ["final"]=true, ["finally"]=true, ["for"]=true, ["foreach"]=true,
	["function"]=true, ["global"]=true, ["goto"]=true, ["if"]=true, ["implements"]=true,
	["include"]=true, ["include_once"]=true, ["instanceof"]=true, ["insteadof"]=true,
	["interface"]=true, ["namespace"]=true, ["new"]=true, ["or"]=true, ["private"]=true,
	["protected"]=true, ["public"]=true, ["require"]=true, ["require_once"]=true,
	["return"]=true, ["static"]=true, ["switch"]=true, ["throw"]=true,
	["trait"]=true, ["try"]=true, ["use"]=true, ["var"]=true, ["while"]=true,
	["xor"]=true, ["yield"]=true
}

local function escapeHTML(t)
	return t:gsub("&", "&amp;"):gsub("<", "&lt;"):gsub(">", "&gt;")
end

function p.highlight(frame)
	local code = frame.args[1] or ""
	code = escapeHTML(code)
	local spans = {}
	local function mark(html)
		table.insert(spans, html)
		return "\x00SPAN" .. #spans .. "\x00"
	end
	
	-- PHP tags
	code = code:gsub("(&lt;%?php)", function(c) return mark('<span style="color:'..colors.tag..';">'..c..'</span>') end)
	code = code:gsub("(&lt;%?)", function(c) return mark('<span style="color:'..colors.tag..';">'..c..'</span>') end)
	code = code:gsub("(%?&gt;)", function(c) return mark('<span style="color:'..colors.tag..';">'..c..'</span>') end)
	
	-- Multi-line comments (before single-line to handle /* inside //)
	code = code:gsub("(%/%*.-%*%/)", function(c) return mark('<span style="color:'..colors.comment..';">'..c..'</span>') end)
	
	-- Single-line comments
	code = code:gsub("(//.-)(\n)", function(c, nl) return mark('<span style="color:'..colors.comment..';">'..c..'</span>')..nl end)
	code = code:gsub("(//.-)", function(c) return mark('<span style="color:'..colors.comment..';">'..c..'</span>') end)
	code = code:gsub("(#.-)(\n)", function(c, nl) return mark('<span style="color:'..colors.comment..';">'..c..'</span>')..nl end)
	code = code:gsub("(#.-)", function(c) return mark('<span style="color:'..colors.comment..';">'..c..'</span>') end)
	
	-- Strings (with escaped quotes handled)
	code = code:gsub('(".-[^\\]")', function(s) return mark('<span style="color:'..colors.string..';">'..s..'</span>') end)
	code = code:gsub("('.-[^\\]')", function(s) return mark('<span style="color:'..colors.string..';">'..s..'</span>') end)
	-- Empty strings
	code = code:gsub('("")', function(s) return mark('<span style="color:'..colors.string..';">'..s..'</span>') end)
	code = code:gsub("('')", function(s) return mark('<span style="color:'..colors.string..';">'..s..'</span>') end)
	
	-- Variables
	code = code:gsub("(%$[%a_][%w_]*)", function(v) return mark('<span style="color:'..colors.variable..';">'..v..'</span>') end)
	
	-- Numbers
	code = code:gsub("([^%w_])(%d+%.?%d*)([^%w_])", function(before, n, after) 
		return before .. mark('<span style="color:'..colors.number..';">'..n..'</span>') .. after 
	end)
	code = code:gsub("^(%d+%.?%d*)([^%w_])", function(n, after)
		return mark('<span style="color:'..colors.number..';">'..n..'</span>') .. after
	end)
	code = code:gsub("([^%w_])(%d+%.?%d*)$", function(before, n)
		return before .. mark('<span style="color:'..colors.number..';">'..n..'</span>')
	end)
	
	-- Keywords
	code = code:gsub("([^%w_])([%a_][%w_]*)([^%w_])", function(before, word, after)
		if keywords[word:lower()] then
			return before .. mark('<span style="color:'..colors.keyword..'; font-weight:bold;">'..word..'</span>') .. after
		else
			return before .. word .. after
		end
	end)
	code = code:gsub("^([%a_][%w_]*)([^%w_])", function(word, after)
		if keywords[word:lower()] then
			return mark('<span style="color:'..colors.keyword..'; font-weight:bold;">'..word..'</span>') .. after
		else
			return word .. after
		end
	end)
	code = code:gsub("([^%w_])([%a_][%w_]*)$", function(before, word)
		if keywords[word:lower()] then
			return before .. mark('<span style="color:'..colors.keyword..'; font-weight:bold;">'..word..'</span>')
		else
			return before .. word
		end
	end)
	
	-- Replace placeholders
	code = code:gsub("\x00SPAN(%d+)\x00", function(i) return spans[tonumber(i)] or "" end)
	
	return '<pre style="background:#f8f8f8; padding:0.5em; border:1px solid #ddd; overflow-x:auto;">'
		.. code ..
		'</pre>'
end

return p