-- lx format
local format = require("core.format")
local sh_references = require("format.sh.references")

format.register({
	name = "Shell Script",
	shortname = "Shell",
	author = "liqube",

	extensions = {
		"sh",
		"bash",
		"zsh",
		"fish",
		"ash",
	},

	filenames = {
		".bashrc",
		".bash_profile",
		".profile",
	},

	headers = {
		"^#!/bin/sh",
		"^#!/bin/bash",
		"^#!/usr/bin/env%s+sh",
	},
	comment = "#",

	file_references = sh_references.new(),

	patterns = {
		-- Highlight shebang line (e.g. #!/bin/bash) as meta
		{ pattern = "%s*#!.*", type = "meta", line_start = true },
		{ pattern = "#.*\n", type = "comment" },

		{ pattern = [[\.]], type = "normal" },

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

		-- Single quotes do not use backslash escapes in sh
		{ pattern = { "'", "'" }, type = "string" },

		-- Backticks
		{ pattern = { "`", "`", "\\" }, type = "meta" },

		-- Line continuation backslash with surrounding spaces
		{ pattern = "%s*(\\)%s*\n", type = { "meta" } },

		{ pattern = "%f[%w_][%d%.]+%f[^%w_]", type = "number" },
		{ pattern = "[!<>|&%[%]=*]", type = "operator" },
		{ pattern = "%f[%S]%-[%w%-_]+", type = "function" },

		-- Non-greedy ${...} so it does not span too far
		{ pattern = "%${[^}]-}", type = "variable" }, -- ${VAR}

		-- Variables
		{ pattern = "%$[%a_][%w_]*", type = "variable" }, -- $var
		{ pattern = "%$[%d]+", type = "variable" }, -- $1, $2, etc
		{ pattern = "%$[%@%*%#%?%-%!%$]", type = "variable" }, -- $@ $* $# $? $- $! $$

		-- Command substitution
		{ pattern = "(%$)(%b())", type = { "operator", "symbol" } }, -- $(...)

		-- Variable assignment
		{ pattern = "%s*([%a_][%w_]*)(=)", type = { "variable", "operator" }, line_start = true },

		-- Fallback identifiers so symbols table can apply
--		{ pattern = "[%a_][%w_]*", type = "symbol" },
	},

	symbols = {
		-- Control Flow
		["case"] = "keyword", -- Start case pattern match block
		["do"] = "keyword", -- Begin loop body
		["done"] = "keyword", -- End loop body
		["elif"] = "keyword", -- Else-if branch
		["else"] = "keyword", -- Else branch
		["esac"] = "keyword", -- End case block
		["fi"] = "keyword", -- End if block
		["for"] = "keyword", -- For loop
		["function"] = "keyword", -- Declare a function
		["if"] = "keyword", -- Conditional branch
		["in"] = "keyword", -- Used in for and case
		["select"] = "keyword", -- Select loop (menu loop)
		["then"] = "keyword", -- Then branch of if
		["time"] = "keyword", -- Measure execution time
		["until"] = "keyword", -- Until loop
		["while"] = "keyword", -- While loop

		-- Builtins and Shell Commands
		["alias"] = "keyword2", -- Define or list command aliases
		["builtin"] = "keyword2", -- Execute a shell builtin
		["cd"] = "keyword2", -- Change directory
		["declare"] = "keyword2", -- Declare variables and attributes
		["echo"] = "keyword2", -- Print text to stdout
		["eval"] = "keyword2", -- Evaluate constructed command
		["exec"] = "keyword2", -- Replace shell or redirect FDs
		["exit"] = "keyword2", -- Exit the shell or script
		["export"] = "keyword2", -- Export variable to environment
		["local"] = "keyword2", -- Declare local variable (bash and zsh)
		["printf"] = "keyword2", -- Formatted output
		["readonly"] = "keyword2", -- Mark variable as read-only
		["set"] = "keyword2", -- Set shell options or positional params
		["shift"] = "keyword2", -- Shift positional parameters
		["source"] = "keyword2", -- Execute script in current shell
		["test"] = "keyword2", -- Evaluate conditional expression
		["trap"] = "keyword2", -- Set signal or exit traps
		["typeset"] = "keyword2", -- Declare typed variables (ksh and bash)
		["ulimit"] = "keyword2", -- Set resource limits
		["umask"] = "keyword2", -- Set file creation mask
		["unalias"] = "keyword2", -- Remove aliases
		["unset"] = "keyword2", -- Unset variables or functions

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