-- lx format
--pcall(require, "format.c")

local format = require("core.format")
local cpp_references = require("format.cpp.references")
local quotes = require("core.text.quotes")
local cpp_outline_hook

format.register({
	name = "C++ Source",
	shortname = "C++",
	author = "liqube",

	extensions = {
		"cpp",
		"hpp",
--		"c",
		"h",
		"cc",
		"hh",
		"cxx",
		"hxx",
		"c++",	-- legacy
		"h++",	-- legacy
		"ino",	-- Arduino
		"inl",	-- Inline
		"ixx",	-- C++ module
		"cppm",	-- C++ module
	},

	headers = {
		"#pragma once",
		"#include \"",
		"#include <",
	},

	file_references = cpp_references.new(),
	comment = "//",

	patterns = {
		-- stdc++
		{ pattern = "[%s=,{}](std)(::)", type = { "keyword2", "operator" } },
		{ pattern = "[%s=,{}](boost)(::)", type = { "keyword2", "operator" } },

		-- Highlight long comment separators as function-style headers
		{ pattern = "%s*//%-%-%-%-%-%-%-%-+%s*\n", type = "separator", line_start = true },
		{ pattern = "%s*//========+%s*\n", type = "separator", line_start = true },
		{ pattern = "%s*//////////+%s*\n", type = "separator", line_start = true },
		{ pattern = "//.-\n", type = "comment" },
		{ pattern = { "/%*", "%*/" }, type = "comment" },
		{ pattern = { "#", "[^\\]\n" }, type = "preprocessor" },

		-- Tokenize quote delimiters as operators (same behavior used in JSON)
		{ pattern = { '"', '"', "\\" }, type = "string", delim_type = "operator" },
		{ pattern = { "'", "'", "\\" }, type = "string", delim_type = "operator" },

		-- Consume C++ digit separators as part of numbers before apostrophes can open character strings
		{ pattern = "-?0[xX][%x']+%.[%x']*[pP][%+%-]?[%d']+[fFlL]?", type = "number" },
		{ pattern = "-?0[xX][%x']+[pP][%+%-]?[%d']+[fFlL]?", type = "number" },
		{ pattern = "-?0[xX][%x']+[uUlLzZ]*", type = "number" },
		{ pattern = "-?0[bB][01']+[uUlLzZ]*", type = "number" },
		{ pattern = "-?%d[%d']*%.[%d']*[eE][%+%-]?[%d']+[fFlL]?", type = "number" },
		{ pattern = "-?%.%d[%d']*[eE][%+%-]?[%d']+[fFlL]?", type = "number" },
		{ pattern = "-?%d[%d']*[eE][%+%-]?[%d']+[fFlL]?", type = "number" },
		{ pattern = "-?%d[%d']*%.[%d']*[fFlL]?", type = "number" },
		{ pattern = "-?%.%d[%d']*[fFlL]?", type = "number" },
		{ pattern = "-?%d[%d']*[uUlLzZ]*", type = "number" },

		-- Broader delimiter/operator tokenization for C++ punctuation
		{ pattern = "[%+%-=/%*%^%%<>!~|&%?%:%.,;%(%)%[%]{}]", type = "operator" },
		{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
		{ pattern = "%s*(case)%s*([%a_][%w_]*):", type = { "keyword", "symbol" } },
--		{ pattern = "[%a_][%w_]*", type = "symbol" },
	},

	-- C++ outline points used by doc:outline-next/previous
	outline_patterns = {
		-- Surface template declarations in outline navigation
		{ pattern = "%s*template%s*<.+", line_start = true },
		{ pattern = "%s*namespace%s+[%a_][%w_]*", line_start = true },
		{ pattern = "%s*class%s+[%a_][%w_]*", line_start = true },
		{ pattern = "%s*struct%s+[%a_][%w_]*", line_start = true },
		{ pattern = "%s*enum%s+[%a_][%w_]*", line_start = true },

		-- C++20 exported declarations
		{ pattern = "%s*export%s+template%s*<.+", line_start = true },
		{ pattern = "%s*export%s+namespace%s+[%a_][%w_]*", line_start = true },
		{ pattern = "%s*export%s+class%s+[%a_][%w_]*", line_start = true },
		{ pattern = "%s*export%s+struct%s+[%a_][%w_]*", line_start = true },
		{ pattern = "%s*export%s+enum%s+[%a_][%w_]*", line_start = true },

		-- Preprocessor/module declarations
		{ pattern = "%s*#%s*include%s+.+%s*$", line_start = true, dividers = false, jumps = false },
		{ pattern = "%s*#%s*define%s+.+$", line_start = true, dividers = false, jumps = false },
		{ pattern = "%s*import%s+.-;%s*$", line_start = true, dividers = false, jumps = false },

		-- TODO: functions with const after ()
		-- Function-like declarations/definitions with optional pointer/ref before name
		-- Excludes control-flow starters (if/else/for/while/switch/catch)
		{
			pattern = "%s*[%a_~][%w_:%s%*&<>]-[%*&%s]+[%a_~][%w_:~]*%s*%b()%s*[{;]?%s*$",
			line_start = true,
			line_not_prefix = {
				"if%f[%W]",
				"else%f[%W]",
				"for%f[%W]",
				"while%f[%W]",
				"switch%f[%W]",
				"catch%f[%W]",
			},
		},
		-- TODO: functions with const after ()
		-- Multi-line function headers where arguments continue onto following lines
		{
			pattern = "%s*[%a_~][%w_:%s%*&<>]-[%*&%s]+[%a_~][%w_:~]*%s*%([^%)]*$",
			line_start = true,
			line_not_prefix = {
				"if%f[%W]",
				"else%f[%W]",
				"for%f[%W]",
				"while%f[%W]",
				"switch%f[%W]",
				"catch%f[%W]",
			},
		},
		-- Typed variable initializers ('... name ='), including brace-open on same/next line
		{ pattern = "%s*[%a_~][%w_:%s%*&<>,-]-[%*&%s]+[%a_][%w_]*%s*=%s*{?%s*$", line_start = true },

		-- Broader typed variable initializers without pointer/reference punctuation
		{ pattern = "%s*[%a_][%w_:%s<>,-]*%s+[%a_][%w_]*%s*=%s*{?%s*$", line_start = true },

		-- Access sections inside classes/structs
		{ pattern = "%s*public%s*:%s*$", line_start = true },
		{ pattern = "%s*protected%s*:%s*$", line_start = true },
		{ pattern = "%s*private%s*:%s*$", line_start = true },
	},

	-- Block comment metadata for advanced comment toggling plugin
	block_comment = {
		block_open = "/*",
		block_close = "*/",

		-- Explicit formatting policy (language-agnostic fields)
		block_line_prefix = " * ",
		close_line_prefix = " ",
		open_on_own_line = false,
		close_on_own_line = true,

		-- Tolerant uncommenting for common C/C++ star-line variants
		strip_line_prefix = "^%s*%*%s?",
		allow_nested = false,
	},

	guard_comment = {
		guard_open = { "#if 0", "#if false" },
		guard_close = "#endif",
		guard_align_to_indent = false,
		allow_nested = true,
	},

	outline_hook = function(action, text)
		return cpp_outline_hook(action, text)
	end,

	quotes = {
		primary = "double",
		profiles = {
			double = quotes.profile.c_style_double(),
		},
	},

	symbols = {
		-- Control Flow
		["break"] = "control", -- Exit loop or switch
		["case"] = "keyword2", -- Switch label
		["continue"] = "control", -- Skip to next iteration
		["default"] = "keyword", -- Switch default or defaulted function
		["do"] = "keyword", -- Do-while loop
		["else"] = "keyword", -- If-else branch
		["for"] = "keyword", -- For loop
		["goto"] = "control", -- Jump to label
		["if"] = "keyword", -- Conditional branch
		["return"] = "control", -- Return from function
		["switch"] = "keyword", -- Switch branch
		["while"] = "keyword", -- While loop

		-- Storage and Type
		["auto"] = "keyword", -- Type inference or automatic storage
		["const"] = "keyword", -- Constant qualifier
		["consteval"] = "keyword", -- Immediate function (C++20)
		["constexpr"] = "keyword", -- Compile-time constant expression
		["constinit"] = "keyword", -- Compile-time initialization (C++20)
		["extern"] = "keyword", -- External linkage
		["inline"] = "keyword", -- Inline function hint
		["mutable"] = "keyword", -- Permissive const-member modification
		["register"] = "keyword", -- Storage hint (deprecated/unused)
		["static"] = "keyword", -- Static storage/linkage
		["thread_local"] = "keyword", -- Thread-specific storage
		["volatile"] = "keyword", -- Prevent compiler optimization on object

		-- Type and Structure
		["class"] = "keyword2", -- Class declaration
		["enum"] = "keyword2", -- Enumeration declaration
		["namespace"] = "keyword2", -- Namespace block
		["struct"] = "keyword2", -- Structure declaration
		["typedef"] = "keyword", -- Type alias (C-style)
		["typename"] = "keyword", -- Template type parameter
		["union"] = "keyword", -- Union declaration
		["using"] = "keyword", -- Type alias or namespace usage

		-- Access and Inheritance
		["explicit"] = "keyword", -- Prevent implicit conversions
		["friend"] = "keyword", -- Grant private access
		["private"] = "keyword", -- Private access modifier
		["protected"] = "keyword", -- Protected access modifier
		["public"] = "keyword", -- Public access modifier
		["virtual"] = "keyword", -- Virtual function/inheritance

		-- Templates and Concepts (C++20)
		["concept"] = "keyword", -- Define a concept
		["requires"] = "keyword", -- Constraint requirements
		["template"] = "keyword", -- Template declaration

		-- Coroutines (C++20)
		["co_await"] = "keyword", -- Suspend coroutine
		["co_return"] = "keyword", -- Return from coroutine
		["co_yield"] = "keyword", -- Yield value from coroutine

		-- Error Handling
		["catch"] = "keyword", -- Catch exception
		["noexcept"] = "keyword", -- Exception non-throwing specification
		["throw"] = "keyword", -- Throw exception
		["try"] = "keyword", -- Try block

		-- Casting and RTTI
		["const_cast"] = "keyword", -- Cast away constness
		["dynamic_cast"] = "keyword", -- Polymorphic type cast
		["reinterpret_cast"] = "keyword", -- Low-level bit cast
		["static_cast"] = "keyword", -- Compile-time type cast
		["typeid"] = "keyword", -- Runtime type information

		-- Operators and Memory
		["alignas"] = "keyword", -- Alignment specification
		["alignof"] = "keyword", -- Alignment inquiry
		["and"] = "keyword", -- Operator '&&' alias
		["and_eq"] = "keyword", -- Operator '&=' alias
		["asm"] = "keyword", -- Inline assembly
		["__asm"] = "keyword", -- Inline assembly
		["bitand"] = "keyword", -- Operator '&' alias
		["bitor"] = "keyword", -- Operator '|' alias
		["compl"] = "keyword", -- Operator '~' alias
		["decltype"] = "keyword", -- Query expression type
		["delete"] = "keyword", -- Deallocate memory
		["new"] = "keyword", -- Allocate memory
		["not"] = "keyword", -- Operator '!' alias
		["not_eq"] = "keyword", -- Operator '!=' alias
		["operator"] = "keyword", -- Overloadable operator
		["or"] = "keyword", -- Operator '||' alias
		["or_eq"] = "keyword", -- Operator '|=' alias
		["sizeof"] = "keyword", -- Size of type/object
		["static_assert"] = "keyword", -- Compile-time assertion
		["this"] = "keyword", -- Current object pointer
		["xor"] = "keyword", -- Operator '^' alias
		["xor_eq"] = "keyword", -- Operator '^=' alias

		-- Contextual Keywords
		["final"] = "keyword", -- Prevent inheritance/overriding
		["import"] = "keyword", -- Module import (C++20)
		["module"] = "keyword", -- Module declaration (C++20)
		["override"] = "keyword", -- Explicit virtual override
		["export"] = "keyword", -- Module export

		-- Compiler and Extensions
		["__fastcall"] = "keyword", -- Calling convention
		["__stdcall"] = "keyword", -- Calling convention
		["__declspec"] = "keyword", -- Attribute specification

		-- Fundamental Types
		["bool"] = "keyword2",
		["char"] = "keyword2",
		["char8_t"] = "keyword2", -- UTF-8 character (C++20)
		["char16_t"] = "keyword2", -- UTF-16 character
		["char32_t"] = "keyword2", -- UTF-32 character
		["double"] = "keyword2",
		["float"] = "keyword2",
		["int"] = "keyword2",
		["long"] = "keyword2",
		["short"] = "keyword2",
		["signed"] = "keyword2",
		["unsigned"] = "keyword2",
		["void"] = "keyword2",
		["wchar_t"] = "keyword2",

		-- Standard Library Types
		["int8_t"] = "keyword2",
		["int16_t"] = "keyword2",
		["int32_t"] = "keyword2",
		["int64_t"] = "keyword2",
		["intmax_t"] = "keyword2",
		["intptr_t"] = "keyword2",
		["uint8_t"] = "keyword2",
		["uint16_t"] = "keyword2",
		["uint32_t"] = "keyword2",
		["uint64_t"] = "keyword2",
		["uintmax_t"] = "keyword2",
		["uintptr_t"] = "keyword2",
		["size_t"] = "keyword2",
		["ssize_t"] = "keyword2",
		["ptrdiff_t"] = "keyword2",
		["nullptr"] = "keyword2",

		["string"] = "keyword2",
		["wstring"] = "keyword2",
		["vector"] = "keyword2",
		["bitset"] = "keyword2",
		["dynamic_bitset"] = "keyword2",
		["map"] = "keyword2",
		["set"] = "keyword2",
		["unordered_map"] = "keyword2",
		["unordered_multimap"] = "keyword2",
		["unordered_set"] = "keyword2",
		["unordered_multiset"] = "keyword2",
		["shared_ptr"] = "keyword2",
		["unique_ptr"] = "keyword2",

		-- Literals
		["false"] = "literal",
		["true"] = "literal",
		["NULL"] = "literal",
	},
})

-- Formats outline row text for access-section style markers in class scopes
cpp_outline_hook = function(action, text)
	if action ~= "format" then
		return nil
	end
	if
		text:match("^%s*public")
		or text:match("^%s*private")
		or text:match("^%s*protected")
		or text:match("^%s*__published")
	then
		return "  " .. text
	end
	return text
end
