-- lx format
local format = require("core.format")
local lua_references = require("format.lua.references")
local quotes = require("core.text.quotes")

local function pick_lualong_level(text)
	local s = tostring(text or "")
	local level = 0
	while true do
		local close = "]" .. string.rep("=", level) .. "]"
		if not s:find(close, 1, true) then
			return level
		end
		level = level + 1
	end
end

local function lualong_quote_profile()
	local function wrap_lua(text)
		local s = tostring(text or "")
		local level = pick_lualong_level(s)
		local eq = string.rep("=", level)
		return "[" .. eq .. "[" .. s .. "]" .. eq .. "]", nil
	end
	local function unwrap_lua(text)
		local s = tostring(text or "")
		local eq, body = s:match("^%[(=*)%[(.*)%]%1%]$")
		if eq == nil then
			return nil, "wrapper mismatch"
		end
		return body, nil
	end
	return {
		input_multiline = true,
		output_multiline = true,
		wrap = wrap_lua,
		unwrap = unwrap_lua,
	}
end

format.register({
	name = "Lua Script",
	shortname = "Lua",
	extensions = {
		"lua",
		"rockspec",
	},
	filenames = {
		".luacheckrc",
	},
	headers = "^#!.*[ /]lua",

	file_references = lua_references.new(),

	comment = "--",

	patterns = {
		{ pattern = { '"', '"', "\\" }, type = "string" },
		{ pattern = { "'", "'", "\\" }, type = "string" },
		{ pattern = "%s*([%w_%.]+)(:)([%w_]+)", type = { "symbol", "operator", "function" } }, -- Object:function
		{ pattern = { "%[%[", "%]%]" }, type = "string" },
		{ pattern = { "%-%-%[%[", "%]%]" }, type = "comment" },
		{ pattern = "%-%-.-\n", type = "comment" },
		{ pattern = "-?0x%x+", type = "number" },
		{ pattern = "-?%d+[%d%.eE]*", type = "number" },
		{ pattern = "-?%.?%d+", type = "number" },
		{ pattern = "<%a+>", type = "keyword2" },
		{ pattern = "%.%.%.?", type = "operator" },
		{ pattern = "%=%=", type = "bold" }, -- highlight not equals
		{ pattern = "[%+%-%*%/%^]", type = "normal" },
		{ pattern = "%~%=", type = "bold" }, -- highlight equals
		{ pattern = "[<>~=]=", type = "operator" },
		{ pattern = "[%+%-=/%*%^%%<>%(%)%,]", type = "operator" },
		{ pattern = "[%[%]]", type = "normal" }, -- brackets
		{ pattern = "[%{%}]", type = "label" }, -- braces
		{ pattern = "#", type = "function" },
		{ pattern = '[%a_][%w_]*%s*%f[("{]', type = "function" },
--		{ pattern = "[%a_][%w_]*", type = "symbol" },
		{ pattern = "::[%a_][%w_]*::", type = "function" },
	},

	outline_patterns = {
		{ pattern = "%s*local%s+function%s+[%a_][%w_]*%s*%b()", line_start = true },
		{ pattern = "%s*function%s+[%a_][%w_%.:]*%s*%b()", line_start = true },

		-- Outline line-start callback literals like 'something(function(...)'
		{ pattern = "%s*[%a_][%w_%.:]*%s*%(%s*function%s*%b()", line_start = true },

		-- Outline line-start function assignments like 'something = function(...)'
		{ pattern = "%s*[%a_][%w_%.:]*%s*=%s*function%s*%b()", line_start = true },
	},

	block_comment = {
		block_open = "--[[",
		block_close = "]]",
		block_line_prefix = "",
		close_line_prefix = "",
		open_on_own_line = false,
		close_on_own_line = false,
		strip_line_prefix = "",
	},

	quotes = {
		primary = "double",
		secondary = "single",
		profiles = {
			double = quotes.profile.c_style_double(),
			single = quotes.profile.c_style_single(),
			lualong = lualong_quote_profile(),
		},
	},

	symbols = {
		["and"] = "keyword",
		["do"] = "keyword",
		["else"] = "keyword",
		["elseif"] = "keyword",
		["end"] = "keyword",
		["for"] = "keyword",
		["function"] = "keyword",
		["if"] = "keyword",
		["in"] = "keyword",
		["local"] = "keyword",
		["not"] = "keyword",
		["or"] = "keyword",
		["repeat"] = "keyword",
		["then"] = "keyword",
		["until"] = "keyword",
		["while"] = "keyword",

		["break"] = "control",
		["goto"] = "control",
		["return"] = "control",

		["_G"] = "keyword2",
		["ipairs"] = "keyword2",
		["next"] = "keyword2",
		["pairs"] = "keyword2",
		["print"] = "keyword2",
		["rawequal"] = "keyword2",
		["rawget"] = "keyword2",
		["rawlen"] = "keyword2",
		["rawset"] = "keyword2",
		["require"] = "keyword2",
		["self"] = "keyword2",
		["select"] = "keyword2",
		["tonumber"] = "keyword2",
		["tostring"] = "keyword2",
		["type"] = "keyword2",
		["pcall"] = "exception",
		["xpcall"] = "exception",

		["false"] = "literal",
		["nil"] = "literal",
		["true"] = "literal",
	},
})
