-- lx format
local format = require("core.format")
local gnumake_references = require("format.gnumake.references")

format.register({
	name = "GNU Makefile",
	shortname = "Make",
	author = "liqube",

	extensions = { "mk" },

	filenames = {
		"Makefile",
		"makefile",
		"GNUmakefile",
	},
	filename_patterns = {
		"^Makefile.+$",
	},
	comment = "#",

	file_references = gnumake_references.new(),

	line_patterns = {
		-- Recipe prefix with command modifiers
		{
			pattern = "(\t)([@%-%+]+)",
			type = { "meta", "operator" },
		},

		-- Recipe prefix
		{ pattern = "\t", type = "meta" },
	},

	patterns = {
		-- Escaped comment marker
		{ pattern = "\\#", type = "normal" },

		-- Comments
		{ pattern = "#[^\r\n]*", type = "comment", not_preceded_by = "\\" },

		-- Same-line double quoted text
		{ pattern = "\"[^\"\r\n]*\"", type = "string" },

		-- Same-line single quoted text
		{ pattern = "'[^'\r\n]*'", type = "string" },

		-- Same-line backtick shell command
		{ pattern = "`[^`\r\n]*`", type = "meta" },

		-- Line continuation backslash
		{ pattern = "[ \t]*(\\)[ \t]*\n", type = { "meta" } },

		-- Override assignment
		{
			pattern = " *(override)(%s+)([^%s:=#][^:=#\r\n]-)(%s*)([:%+%?%!]*=)",
			type = { "keyword", "normal", "variable", "normal", "operator" },
			line_start = true,
		},

		-- Export assignment
		{
			pattern = " *(export)(%s+)([^%s:=#][^:=#\r\n]-)(%s*)([:%+%?%!]*=)",
			type = { "keyword", "normal", "variable", "normal", "operator" },
			line_start = true,
		},

		-- Private assignment
		{
			pattern = " *(private)(%s+)([^%s:=#][^:=#\r\n]-)(%s*)([:%+%?%!]*=)",
			type = { "keyword", "normal", "variable", "normal", "operator" },
			line_start = true,
		},

		-- Plain variable assignment
		{
			pattern = " *([^%s:=#][^:=#\r\n]-)(%s*)([:%+%?%!]*=)",
			type = { "variable", "normal", "operator" },
			line_start = true,
		},

		-- Define directive with variable name
		{
			pattern = " *(define)(%s+)([^%s#:=]+)",
			type = { "keyword", "normal", "variable" },
			line_start = true,
		},

		-- Undefine directive with variable name
		{
			pattern = " *(undefine)(%s+)([^%s#:=]+)",
			type = { "keyword", "normal", "variable" },
			line_start = true,
		},

		-- Include directive
		{ pattern = " *(include)%s+", type = { "keyword" }, line_start = true },

		-- Optional include directive
		{ pattern = " *(%-include)%s+", type = { "keyword" }, line_start = true },

		-- Silent include directive
		{ pattern = " *(sinclude)%s+", type = { "keyword" }, line_start = true },

		-- Conditional directives
		{ pattern = " *(ifeq)%f[%s%(\"']", type = { "keyword" }, line_start = true },
		{ pattern = " *(ifneq)%f[%s%(\"']", type = { "keyword" }, line_start = true },
		{ pattern = " *(ifdef)%s+", type = { "keyword" }, line_start = true },
		{ pattern = " *(ifndef)%s+", type = { "keyword" }, line_start = true },
		{ pattern = " *(else)%f[%s\r\n]", type = { "keyword" }, line_start = true },
		{ pattern = " *(endif)%f[%s\r\n]", type = { "keyword" }, line_start = true },

		-- Other top-level directives
		{ pattern = " *(endef)%f[%s\r\n]", type = { "keyword" }, line_start = true },
		{ pattern = " *(export)%f[%s\r\n]", type = { "keyword" }, line_start = true },
		{ pattern = " *(unexport)%f[%s\r\n]", type = { "keyword" }, line_start = true },
		{ pattern = " *(override)%s+", type = { "keyword" }, line_start = true },
		{ pattern = " *(private)%s+", type = { "keyword" }, line_start = true },
		{ pattern = " *(vpath)%f[%s\r\n]", type = { "keyword" }, line_start = true },

		-- Special target
		{
			pattern = " *(%.[%a_][%w_%.%-]*)(%s*&?::?)",
			type = { "keyword2", "operator" },
			line_start = true,
			not_followed_by = "=",
		},

		-- Rule target
		{
			pattern = " *([^#%s:=][^#:=\r\n]-)(%s*&?::?)",
			type = { "function", "operator" },
			line_start = true,
			not_followed_by = "=",
		},

		-- Make function head with parentheses
		{
			pattern = "(%$%()([%a_][%w_%-]*)(%s+)",
			type = { "operator", "function", "normal" },
		},

		-- Make function head with braces
		{
			pattern = "(%${)([%a_][%w_%-]*)(%s+)",
			type = { "operator", "function", "normal" },
		},

		-- Automatic variable with directory or file suffix
		{
			pattern = "(%$%()([@%%<%?%^%+%*%|][DF])(%))",
			type = { "operator", "variable", "operator" },
		},

		-- Parenthesized Make variable reference
		{
			pattern = "(%$%()([^%s%)%(,]+)(%))",
			type = { "operator", "variable", "operator" },
		},

		-- Braced Make variable reference
		{
			pattern = "(%${)([^}%s,]+)(})",
			type = { "operator", "variable", "operator" },
		},

		-- Escaped dollar for shell pass-through
		{ pattern = "%$%$", type = "operator" },

		-- Automatic variables
		{ pattern = "%$[@%%<%?%^%+%*%|]", type = "variable" },

		-- Single-character Make variable
		{ pattern = "%$[%a%d]", type = "variable" },

		-- Command line option
		{ pattern = "%f[%S]%-[%w%-_%.=,/]+", type = "function" },

		-- Decimal number
		{ pattern = "%f[%w_]%d+%.?%d*%f[^%w_]", type = "number" },

		-- Rule and assignment operators
		{ pattern = "&::", type = "operator" },
		{ pattern = "&:", type = "operator" },
		{ pattern = ":::", type = "operator" },
		{ pattern = "::", type = "operator" },
		{ pattern = "[:%+%?%!]*=", type = "operator" },

		-- Pattern wildcard
		{ pattern = "%%", type = "operator" },

		-- Make and shell punctuation
		{ pattern = "[%(%){},;:@|&<>%*%+%-=%%%!%?%^%[%]]", type = "operator" },

		-- Plain words
		{ pattern = "[%.%a_][%w_%.%-]*", type = "normal" },
	},

	outline_patterns = {
		{ pattern = " *[^%s:=#][^:=#\r\n]-[:%+%?%!]*=", line_start = true }, -- Variable assignment
		{ pattern = " *[^#%s:=][^#:=\r\n]-%s*&?::?", line_start = true }, -- Rule target
		{ pattern = " *include%s+", line_start = true }, -- Include directive
		{ pattern = " *%-include%s+", line_start = true }, -- Optional include directive
		{ pattern = " *sinclude%s+", line_start = true }, -- Silent include directive
		{ pattern = " *define%s+", line_start = true }, -- Multi-line variable
		{ pattern = " *ifeq%f[%s%(\"']", line_start = true }, -- Equal conditional
		{ pattern = " *ifneq%f[%s%(\"']", line_start = true }, -- Not-equal conditional
		{ pattern = " *ifdef%s+", line_start = true }, -- Defined conditional
		{ pattern = " *ifndef%s+", line_start = true }, -- Undefined conditional
	},

	symbols = {
		-- Directive keywords
		["include"] = "keyword",
		["-include"] = "keyword",
		["sinclude"] = "keyword",
		["define"] = "keyword",
		["endef"] = "keyword",
		["undefine"] = "keyword",
		["override"] = "keyword",
		["export"] = "keyword",
		["unexport"] = "keyword",
		["private"] = "keyword",
		["vpath"] = "keyword",

		-- Conditional keywords
		["ifeq"] = "keyword",
		["ifneq"] = "keyword",
		["ifdef"] = "keyword",
		["ifndef"] = "keyword",
		["else"] = "keyword",
		["endif"] = "keyword",

		-- Common special targets
		[".PHONY"] = "keyword2",
		[".SUFFIXES"] = "keyword2",
		[".DEFAULT"] = "keyword2",
		[".PRECIOUS"] = "keyword2",
		[".INTERMEDIATE"] = "keyword2",
		[".SECONDARY"] = "keyword2",
		[".SECONDEXPANSION"] = "keyword2",
		[".DELETE_ON_ERROR"] = "keyword2",
		[".IGNORE"] = "keyword2",
		[".LOW_RESOLUTION_TIME"] = "keyword2",
		[".SILENT"] = "keyword2",
		[".EXPORT_ALL_VARIABLES"] = "keyword2",
		[".NOTPARALLEL"] = "keyword2",
		[".ONESHELL"] = "keyword2",
		[".POSIX"] = "keyword2",
		[".RECIPEPREFIX"] = "keyword2",
		[".DEFAULT_GOAL"] = "keyword2",

		-- GNU Make built-in functions
		["subst"] = "function",
		["patsubst"] = "function",
		["strip"] = "function",
		["findstring"] = "function",
		["filter"] = "function",
		["filter-out"] = "function",
		["sort"] = "function",
		["word"] = "function",
		["wordlist"] = "function",
		["words"] = "function",
		["firstword"] = "function",
		["lastword"] = "function",
		["dir"] = "function",
		["notdir"] = "function",
		["suffix"] = "function",
		["basename"] = "function",
		["addsuffix"] = "function",
		["addprefix"] = "function",
		["join"] = "function",
		["wildcard"] = "function",
		["realpath"] = "function",
		["abspath"] = "function",
		["foreach"] = "function",
		["if"] = "function",
		["or"] = "function",
		["and"] = "function",
		["call"] = "function",
		["value"] = "function",
		["eval"] = "function",
		["origin"] = "function",
		["flavor"] = "function",
		["let"] = "function",
		["shell"] = "function",
		["file"] = "function",
		["guile"] = "function",
		["info"] = "function",
		["warning"] = "warning",
		["error"] = "error",

		-- Common built-in variables
		["MAKE"] = "variable",
		["MAKEFLAGS"] = "variable",
		["MAKEFILE_LIST"] = "variable",
		["MAKECMDGOALS"] = "variable",
		["CURDIR"] = "variable",
		["SHELL"] = "variable",
		["VPATH"] = "variable",
		["CC"] = "variable",
		["CXX"] = "variable",
		["CPP"] = "variable",
		["AR"] = "variable",
		["LD"] = "variable",
		["RM"] = "variable",
		["CFLAGS"] = "variable",
		["CPPFLAGS"] = "variable",
		["CXXFLAGS"] = "variable",
		["LDFLAGS"] = "variable",
		["LDLIBS"] = "variable",
	},

	defaults = {
		word_wrap = false,
	},
})
