\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{scholatex}[2026-06-18 v1.0 A tag-based language for print-ready teaching worksheets]
% scholatex --- a lightweight tag-based markup language for LuaLaTeX
% Copyright (C) 2026 Gerard Dubard
%
% This program is free software: you can redistribute it and/or modify it
% under the terms of the GNU General Public License version 3 as published
% by the Free Software Foundation. This program is distributed WITHOUT ANY
% WARRANTY. See the LICENSE file or <https://www.gnu.org/licenses/> for
% the full text of the license.
%
\RequirePackage{kvoptions}
\SetupKeyvalOptions{family=scholatex, prefix=scholatex@}
\DeclareStringOption[20]{margins}
\DeclareStringOption[Latin Modern Roman]{font}
\DeclareStringOption[11]{size}
\DeclareStringOption[Latin Modern Math]{mathfont}
\DeclareStringOption[img]{imgdir}
\DeclareStringOption[8]{tabwidth}
\DeclareStringOption[8]{lineheight}
\DeclareStringOption[100]{scriptscale}
\DeclareStringOption[2]{padding}
\DeclareStringOption[fr]{lang}
\DeclareBoolOption[false]{untrusted}
\DeclareDefaultOption{\PassOptionsToClass{\CurrentOption}{extarticle}}
\ProcessKeyvalOptions*
\LoadClass[\scholatex@size pt, a4paper]{extarticle}
\RequirePackage{amsmath}
\RequirePackage{array}
\RequirePackage{graphicx}
\RequirePackage[export]{adjustbox}
\RequirePackage{xstring}
\IfEndWith{\scholatex@imgdir}{/}{%
	\edef\scholatex@imgpath{\scholatex@imgdir}%
}{%
	\edef\scholatex@imgpath{\scholatex@imgdir/}%
}
\def\scholatex@graphicspaths{{./}}
\@for\scholatex@dir:=\scholatex@imgdir\do{%
	\StrDel{\scholatex@dir}{ }[\scholatex@dir]%
	\IfEndWith{\scholatex@dir}{/}{%
		\edef\scholatex@graphicspaths{\scholatex@graphicspaths{\scholatex@dir}}%
	}{%
		\edef\scholatex@graphicspaths{\scholatex@graphicspaths{\scholatex@dir/}}%
	}%
}
\expandafter\graphicspath\expandafter{\scholatex@graphicspaths}
\RequirePackage{tabularx}
\RequirePackage{tabularray}
\RequirePackage{multirow}
\RequirePackage[svgnames]{xcolor}
\RequirePackage{colortbl}
\RequirePackage{enumitem}
\RequirePackage{amssymb}
\RequirePackage{ragged2e}
\RequirePackage{needspace}
\RequirePackage[skins,breakable,raster]{tcolorbox}
\tcbuselibrary{poster}
\setlength{\JustifyingParindent}{0pt}
\newlength{\scholatextab}
\setlength{\scholatextab}{\scholatex@tabwidth mm}
\newlength{\scholatexline}
\setlength{\scholatexline}{\scholatex@lineheight mm}
% Headings carry no extra space above or below: only the normal interline
% spacing separates them from surrounding text, identical for every level.
% Their appearance (colour, size, a preceding line skip) is set per document
% with a style alias, e.g. let s1 = <line navy b section>.
\RequirePackage{titlesec}
\titlespacing*{\section}      {0pt}{0pt}{0pt}
\titlespacing*{\subsection}   {0pt}{0pt}{0pt}
\titlespacing*{\subsubsection}{0pt}{0pt}{0pt}
\edef\scholatex@scriptfactor{\strip@pt\dimexpr\scholatex@scriptscale pt/100\relax}
\newcommand{\scholatexscript}[2]{\raisebox{#1}{\scalebox{\scholatex@scriptfactor}{#2}}}
\RequirePackage{fontspec}
\RequirePackage{unicode-math}
\RequirePackage{geometry}
\StrCount{\scholatex@margins}{,}[\scholatex@ncommas]
\ifnum\scholatex@ncommas>0\relax
\StrCut{\scholatex@margins}{,}\scholatex@mt\scholatex@mrest
\StrCut{\scholatex@mrest}{,}\scholatex@mr\scholatex@mrest
\StrCut{\scholatex@mrest}{,}\scholatex@mb\scholatex@ml
\geometry{top=\scholatex@mt mm, right=\scholatex@mr mm, bottom=\scholatex@mb mm, left=\scholatex@ml mm}%
\else
\geometry{margin=\scholatex@margins mm}%
\fi
% Short lowercase colour keywords: aliases to the CamelCase svgnames
\colorlet{navy}{Navy}
\colorlet{blue}{Blue}
\colorlet{red}{Red}
\colorlet{green}{Green}
\colorlet{gray}{Gray}
\colorlet{grey}{Grey}
\colorlet{violet}{Violet}
\colorlet{orange}{Orange}
\colorlet{purple}{Purple}
\colorlet{teal}{Teal}
\colorlet{brown}{Brown}
\colorlet{yellow}{Yellow}
\colorlet{black}{Black}
\colorlet{white}{White}
\colorlet{pink}{Pink}
\colorlet{olive}{Olive}
\colorlet{lime}{Lime}
\colorlet{aqua}{Aqua}
\colorlet{cyan}{Cyan}
\colorlet{magenta}{Magenta}
\colorlet{silver}{Silver}
\colorlet{maroon}{Maroon}
\directlua{scholatex = require("scholatex")}
\directlua{scholatex.config = scholatex.config or {}; scholatex.config.padding = "\scholatex@padding"; scholatex.config.lang = "\scholatex@lang"}
\ifscholatex@untrusted
  \directlua{scholatex.config.untrusted = true}
\else
  \directlua{scholatex.config.untrusted = false}
\fi
\IfFontExistsTF{\scholatex@font}{%
	\setmainfont{\scholatex@font}%
}{%
	\directlua{scholatex.respace("scholatex@font")}%
	\IfFontExistsTF{\scholatex@font}{%
		\setmainfont{\scholatex@font}%
	}{%
		\ClassWarningNoLine{scholatex}{Font '\scholatex@font' not found, falling back to Latin Modern Roman}%
		\setmainfont{Latin Modern Roman}%
	}%
}
\IfFontExistsTF{\scholatex@mathfont}{%
	\setmathfont{\scholatex@mathfont}%
}{%
	\directlua{scholatex.respace("scholatex@mathfont")}%
	\IfFontExistsTF{\scholatex@mathfont}{%
		\setmathfont{\scholatex@mathfont}%
	}{%
		\ClassWarningNoLine{scholatex}{Math font '\scholatex@mathfont' not found, falling back to Latin Modern Math}%
		\setmathfont{Latin Modern Math}%
	}%
}
\setlength{\parindent}{0pt}
\setlength{\parskip}{0.5em}
\AtBeginDocument{%
	\directlua{
	local f = io.open(tex.jobname .. ".tex", "r")
	local whole = f:read("*a"); f:close()
	local body = whole:match("\string\\begin{document}(.-)\string\\end{document}")
	if not body then
	tex.error("scholatex.cls: begin/end document not found")
	else
	scholatex.inject(body)
	end
}%
\end{document}%
}