-- lx format
local format = require("core.format")
local rust_references = require("format.rust.references")

format.register({
	name = "Rust Source",
	shortname = "Rust",
	author = "liqube",
	extensions = "rs",
	comment = "//",

	file_references = rust_references.new(),

	patterns = {
		-- Doc comments (outer and inner)
		{ pattern = "///.-\n", type = "comment2" },
		{ pattern = "//!.-\n", type = "comment2" },

		-- Line comments
		{ pattern = "//.-\n", type = "comment" },

		-- Block comments (nested is handled by block_comment config below)
		{ pattern = { "/%*", "%*/" }, type = "comment" },

		-- Attributes
		{ pattern = "#%!?%[", type = "operator" }, -- #[ or #![
		{ pattern = "%]", type = "operator" },

		-- Character literals must win before lifetimes and embedded double quotes
		-- Pattern breakdown: optional 'b', quoted Unicode escape, and hexadecimal code point
		{ pattern = "b?'[\\]u%{[%x_]+%}'", type = "string" },
		-- Pattern breakdown: optional 'b', quoted hexadecimal byte escape with two digits
		{ pattern = "b?'[\\]x%x%x'", type = "string" },
		-- Pattern breakdown: optional 'b', quoted backslash escape with one escaped character
		{ pattern = "b?'[\\].'", type = "string" },
		-- Pattern breakdown: optional 'b', one UTF-8 character, and its closing quote
		{ pattern = "b?'[^'\\\n][\128-\191]*'", type = "string" },

		-- Lifetimes and labels: 'a, 'static, 'label:
		{ pattern = "'[%a_][%w_]*%f[^%w_]", type = "keyword2" },
		{ pattern = "'[%a_][%w_]*%s*:", type = "keyword2" },

		-- Raw strings: r"..." or r#"..."# or r##"..."##
		{ pattern = "r#+%b\"\"#+", type = "string" },
		{ pattern = "r%b\"\"", type = "string" },

		-- Byte and raw byte strings: b"..." or br"..." or br#"..."#
		{ pattern = "br#+%b\"\"#+", type = "string" },
		{ pattern = "br%b\"\"", type = "string" },
		{ pattern = "b%b\"\"", type = "string" },

		-- Normal strings
		{ pattern = { '"', '"', "\\" }, type = "string" },

		-- Numbers (Rust allows '_' separators and type suffixes)
		-- Hex, octal, and binary
		{ pattern = "0x[%da-fA-F_]+[%a%d_]*", type = "hex" },
		{ pattern = "0o[0-7_]+[%a%d_]*", type = "number" },
		{ pattern = "0b[01_]+[%a%d_]*", type = "number" },

		-- Floats such as 1.0 or 1. or .5 or 1e10 or 1.2e-3 with optional suffix
		{ pattern = "%d+%.%d*([eE][%+%-]?%d+)?[%a%d_]*", type = "number" },
		{ pattern = "%.%d+([eE][%+%-]?%d+)?[%a%d_]*", type = "number" },
		{ pattern = "%d+[eE][%+%-]?%d+[%a%d_]*", type = "number" },

		-- Decimal integers with optional suffix such as u8 or i32
		{ pattern = "%d[%d_]*[%a%d_]*", type = "number" },

		-- Paths and namespace separators
		{ pattern = "::", type = "operator" },

		-- Common multi character operators, longest first
		{ pattern = "%.%.%.", type = "operator" }, -- ..
		{ pattern = "%.%.=", type = "operator" },  -- ..=
		{ pattern = "%.%.", type = "operator" },   -- .
		{ pattern = "=>", type = "operator" },
		{ pattern = "%->", type = "operator" },
		{ pattern = "<<=", type = "operator" },
		{ pattern = ">>=", type = "operator" },
		{ pattern = "==", type = "operator" },
		{ pattern = "!=", type = "operator" },
		{ pattern = "<=", type = "operator" },
		{ pattern = ">=", type = "operator" },
		{ pattern = "&&", type = "operator" },
		{ pattern = "%|%|", type = "operator" },
		{ pattern = "<<", type = "operator" },
		{ pattern = ">>", type = "operator" },
		{ pattern = "%+=", type = "operator" },
		{ pattern = "%-=", type = "operator" },
		{ pattern = "%*=", type = "operator" },
		{ pattern = "/=", type = "operator" },
		{ pattern = "%%=", type = "operator" },
		{ pattern = "%^=", type = "operator" },
		{ pattern = "&=", type = "operator" },
		{ pattern = "%|=", type = "operator" },

		-- Single character operators and punctuation that matter
		{ pattern = "[%+%-%*/%^%%=<>!~|&?:;,%.%(%)%[%]{}@#]", type = "operator" },

		-- Macro invocations: ident!(...) or ident!{...} or ident![...]
		{ pattern = "[%a_][%w_]*%f[!]", type = "function" },
		{ pattern = "!", type = "operator" },

		-- Function calls: ident(
		{ pattern = "[%a_][%w_]*%f[(]", type = "function" },

		-- Symbols
		{ pattern = "[%a_][%w_]*", type = "symbol" },
	},

	block_comment = {
		block_open = "/*",
		block_close = "*/",
		block_line_prefix = " * ",
		close_line_prefix = " ",
		open_on_own_line = false,
		close_on_own_line = true,
		strip_line_prefix = "^%s*%*%s?",

		-- Rust supports nested block comments
		allow_nested = true,
	},

	guard_comment = {
		guard_open = "#[cfg(any())]\n{",
		guard_close = "}",
		guard_body_prefix = "auto",
		guard_align_to_indent = true,
		allow_nested = true,
	},

	-- Jump points for outline and symbol list
	outline_patterns = {
		{ pattern = "^%s*fn%s+[%a_][%w_]*", type = "function" },
		{ pattern = "^%s*(pub%s+)?struct%s+[%a_][%w_]*", type = "keyword" },
		{ pattern = "^%s*(pub%s+)?enum%s+[%a_][%w_]*", type = "keyword" },
		{ pattern = "^%s*(pub%s+)?trait%s+[%a_][%w_]*", type = "keyword" },
		{ pattern = "^%s*impl%s+[%w_<>,:%s]*%f[{]", type = "keyword" },
		{ pattern = "^%s*mod%s+[%a_][%w_]*", type = "keyword" },
	},

	symbols = {
		-- Control and structure
		["as"] = "keyword",
		["const"] = "keyword",
		["crate"] = "keyword",
		["else"] = "keyword",
		["enum"] = "keyword",
		["extern"] = "keyword",
		["fn"] = "keyword",
		["for"] = "keyword",
		["if"] = "keyword",
		["impl"] = "keyword",
		["in"] = "keyword",
		["let"] = "keyword",
		["loop"] = "keyword",
		["match"] = "keyword",
		["mod"] = "keyword",
		["move"] = "keyword",
		["mut"] = "keyword",
		["pub"] = "keyword",
		["ref"] = "keyword",
		["static"] = "keyword",
		["struct"] = "keyword",
		["super"] = "keyword",
		["trait"] = "keyword",
		["type"] = "keyword",
		["unsafe"] = "keyword",
		["use"] = "keyword",
		["where"] = "keyword",
		["while"] = "keyword",
		["break"] = "control",
		["continue"] = "control",
		["return"] = "control",

		-- Async and await
		["async"] = "keyword",
		["await"] = "keyword",

		-- Self identifiers
		["self"] = "keyword",
		["Self"] = "keyword",

		-- Literals and built ins
		["true"] = "literal",
		["false"] = "literal",
		["None"] = "literal",
		["Some"] = "literal",
		["Ok"] = "literal",
		["Err"] = "literal",

		-- Common prelude types
		["Option"] = "keyword2",
		["Result"] = "keyword2",
		["String"] = "keyword2",
		["str"] = "keyword2",
		["bool"] = "keyword2",
		["char"] = "keyword2",

		-- Integers and floats
		["i8"] = "keyword2",
		["i16"] = "keyword2",
		["i32"] = "keyword2",
		["i64"] = "keyword2",
		["i128"] = "keyword2",
		["u8"] = "keyword2",
		["u16"] = "keyword2",
		["u32"] = "keyword2",
		["u64"] = "keyword2",
		["u128"] = "keyword2",
		["isize"] = "keyword2",
		["usize"] = "keyword2",
		["f32"] = "keyword2",
		["f64"] = "keyword2",

		-- Unit type spelling appears frequently
		["()"] = "keyword2",
	},
})
