% !TeX program = lualatex
% =====================================================================
%  scholatex.tex  --  user documentation for the scholatex package
%
%  This is a STANDALONE document: it uses the standard article class and
%  compiles with any LuaLaTeX (or pdfLaTeX) distribution, independently
%  of the scholatex class it documents. It does NOT require any images.
%
%  Compile:  lualatex scholatex.tex   (twice, for the table of contents)
% =====================================================================
\documentclass[11pt,a4paper]{article}

\usepackage[T1]{fontenc}
\usepackage[margin=25mm]{geometry}
\usepackage{xcolor}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{array}
\usepackage{enumitem}
\usepackage{fancyvrb}
\usepackage{titlesec}
\usepackage[colorlinks=true,linkcolor=Navy,urlcolor=Navy]{hyperref}

\definecolor{Navy}{HTML}{1F3A5F}
\definecolor{CodeBg}{HTML}{F4F5F7}
\definecolor{CodeFrame}{HTML}{D7DBE0}
\definecolor{Accent}{HTML}{8A1C1C}

% --- code blocks -----------------------------------------------------
\DefineVerbatimEnvironment{slcode}{Verbatim}{%
  frame=single,
  framerule=0.4pt,
  rulecolor=\color{CodeFrame},
  fontsize=\small,
  xleftmargin=4mm,
  xrightmargin=4mm,
  framesep=3mm,
  formatcom=\color{black!88}}

\newcommand{\tg}[1]{\texttt{#1}}
\newcommand{\opt}[1]{\texttt{\textcolor{Accent}{#1}}}

\titleformat{\section}{\Large\bfseries\color{Navy}}{\thesection}{0.6em}{}
\titleformat{\subsection}{\large\bfseries\color{Navy!85!black}}{\thesubsection}{0.6em}{}
\titlespacing*{\section}{0pt}{1.4em}{0.5em}

\setlength{\parindent}{0pt}
\setlength{\parskip}{0.55em}

\hypersetup{
  pdftitle={scholatex --- user manual},
  pdfauthor={Gerard Dubard},
}

% =====================================================================
\begin{document}

\begin{titlepage}
\centering
\vspace*{3.5cm}
{\Huge\bfseries\color{Navy} scholatex\par}
\vspace{0.8cm}
{\Large Print-ready teaching worksheets, the easy way\par}
\vspace{2.5cm}
{\large A small tag-based language for handouts and exercises,\\[2pt]
built on LuaLaTeX\par}
\vspace{3cm}
{\large Gérard Dubard\par}
\vspace{0.4cm}
{\large Version 1.0\par}
\vfill
{\small Released under the GNU General Public License v3.0\par}
\end{titlepage}

\tableofcontents
\newpage

% =====================================================================
\section{Introduction}
% =====================================================================

\textbf{scholatex} is a small markup language for producing print-ready
teaching materials --- worksheets, exercise sheets, handouts, short
assessments --- without writing LaTeX. It is not a general-purpose
replacement for LaTeX; it is a focused, consistent little language for the
documents a teacher actually makes: a few framed exercises, a table of
results, a couple of simple formulas, an image or two, laid out cleanly on
a page meant to be printed and handed out.

It compiles to LuaLaTeX, so the output has full LaTeX typesetting quality,
but the syntax is meant to be read and edited in minutes by someone who
does not know LaTeX: no \tg{\textbackslash begin\{tabular\}\{|c|c|\}}, no
counting ampersands, no hunting for the package that draws a coloured box. A
single tag syntax covers text, tables, images, simple maths, framed boxes,
lists and full-page named-area layouts --- the building blocks of a
worksheet. The full power of LaTeX stays one escape hatch away (any raw
command still works), but for everyday teaching documents you rarely need
it.

It is built for the people LaTeX usually loses: teachers preparing
classroom materials, and anyone who wants a clean printable sheet without
climbing the LaTeX learning curve.

You write a \tg{.tex} file with a tiny, readable syntax between
\tg{\textbackslash begin\{document\}} and \tg{\textbackslash end\{document\}}.
At compile time the \tg{scholatex} class reads that body, transpiles it to
LaTeX, and typesets it. Nothing to install beyond a LuaLaTeX distribution.

\begin{slcode}
% !TeX program = lualatex
\documentclass[margins=20, size=12, imgdir=IMG]{scholatex}
\begin{document}

<navy b 18pt c>My first scholatex document

This is a normal paragraph. <b>{Bold}, <i>{italic}, <red>{red}.

<box line:Navy fill:AliceBlue radius:3 title:{A framed note}>{
Boxes, tables, images and maths all use the same tag syntax.
}

\end{document}
\end{slcode}

% =====================================================================
\section{The one rule}
% =====================================================================

Everything is a \textbf{tag}: \tg{<attributes>} followed either by
\tg{\{content\}} (inline) or by a line that ends in \tg{\{} (a block).
Attribute words follow a single case convention:

\begin{center}
\begin{tabular}{@{}lll@{}}
\toprule
\textbf{Form} & \textbf{Meaning} & \textbf{Examples} \\
\midrule
\tg{lowercase} & a short keyword or base colour & \tg{b}, \tg{i}, \tg{c}, \tg{red}, \tg{2tab} \\
\tg{CamelCase} & an extended CSS colour (147 of them) & \tg{SteelBlue}, \tg{Crimson} \\
\tg{UPPERCASE} & a font name & \tg{DEJAVU SANS} \\
\bottomrule
\end{tabular}
\end{center}

The order of words inside a tag never matters --- emission is always
normalised (page break, then vertical skips, then alignment, then tabs, then
styles).

% =====================================================================
\section{Class options}
% =====================================================================

Set in \tg{\textbackslash documentclass[...]\{scholatex\}}:

\begin{center}
\small
\begin{longtable}{@{}p{2.4cm}p{2.6cm}p{8.4cm}@{}}
\toprule
\textbf{Option} & \textbf{Default} & \textbf{Meaning} \\
\midrule
\endhead
\opt{margins} & \tg{20} & \tg{N} (all sides) or \tg{\{top,right,bottom,left\}} in mm \\
\opt{font} & \tg{Latin Modern Roman} & main text font \\
\opt{mathfont} & \tg{Latin Modern Math} & math font \\
\opt{size} & \tg{11} & base font size in pt \\
\opt{imgdir} & \tg{img} & folder(s) searched for bare image names; accepts a comma-separated list, e.g. \tg{\{IMG, IMAGES/PNG\}} \\
\opt{tabwidth} & \tg{8} & width of one tab, in mm \\
\opt{lineheight} & \tg{8} & height of one skipped line, in mm \\
\opt{scriptscale} & \tg{100} & scale (\%) of \tg{up}/\tg{down} scripts \\
\opt{padding} & \tg{2} & inner padding (mm) between a box/grid-area frame and its content \\
\opt{lang} & \tg{fr} & decimal separator: \tg{fr} (comma) or \tg{en} (point); affects both literal decimals in maths and interpolated values \\
\opt{untrusted} & \tg{false} & when \tg{true}, runs the document's Lua in a restricted sandbox (see \S\ref{sec:security}) \\
\bottomrule
\end{longtable}
\end{center}

Headings carry no extra vertical space of their own, and no built-in colour:
to style a heading (colour, weight, size, or a line skip before it), fold a
heading keyword into an alias and use it (see \S\ref{sec:aliases}).

% =====================================================================
\section{Text attributes}
% =====================================================================

\textbf{Inline styles} --- \tg{b} bold, \tg{i} italic, \tg{u} underline,
\tg{emph}, \tg{tt} typewriter, \tg{sf} sans-serif, \tg{sc} small caps.

\textbf{Colours} --- short keywords (\tg{red}, \tg{blue}, \tg{green},
\tg{navy}, \tg{orange}, \tg{purple}, \tg{teal}, \tg{brown}, \tg{gray},
\tg{pink}, \dots) or any of the 147 CSS colours in CamelCase (\tg{Tomato},
\tg{SteelBlue}, \tg{ForestGreen}, \dots).

\textbf{Fonts and sizes} --- a font name in CAPITALS
(\tg{<DEJAVU SANS>\{\dots\}}); sizes as \tg{Npt} or \tg{Npx}
(\tg{<14pt>\{\dots\}}).

\textbf{Alignment} --- \tg{l} left, \tg{c} centre, \tg{r} right, \tg{j}
justified (the same letters as table columns).

\textbf{Tabs and skips} (the number is always a prefix) --- \tg{Ntab} indents
the first line by N tabs; vertical skips follow singular/plural agreement:
\tg{line} or \tg{1line} skips one line, \tg{2lines}, \tg{3lines}, \dots\ skip
several. Bare \tg{tab} = \tg{1tab}.

\textbf{Scripts} --- \tg{upN} raises text by N mm (superscript-like),
\tg{downN} lowers it (subscript-like): \tg{x<up4>\{2\}}, \tg{H<down2>\{2\}O}.

\textbf{Page break} --- \tg{nextpage}.

\textbf{Section headings} --- \tg{section}, \tg{subsection},
\tg{subsubsection} give the three heading levels, numbered automatically:

\begin{slcode}
<section>First topic
<subsection>A detail
<subsubsection>A finer point
\end{slcode}

renders as `1 First topic', `1.1 A detail',
`1.1.1 A finer point'. A heading can also be written as a
\textbf{block} carrying a \tg{title:} option, with its body in braces:

\begin{slcode}
<subsection title:{A heading}>{
<tab>This body paragraph is indented on its first line.
}
\end{slcode}

A \textbf{table of contents} is printed with \tg{<tableofcontents>}; give it
a title in braces:

\begin{slcode}
<tableofcontents>{Table of contents}
\end{slcode}

Combine anything in one tag:

\begin{slcode}
<nextpage 2lines 2tab j navy b>{A new page, a two-line skip, a two-tab
indent, justified, navy, bold --- all before the first letter of the text.}
\end{slcode}

% =====================================================================
\section{Aliases and macros --- the factoring tool}\label{sec:aliases}
% =====================================================================

This is what makes scholatex scale. Define a style \textbf{once}, at the top
of the document, then name it everywhere instead of repeating its attributes.
One edit at the definition restyles the whole document.

\begin{slcode}
let title = <navy b 18pt c>          % style alias
let h1    = <navy b section>         % a heading style, reusable
let p     = <tab>                    % a standard indented paragraph
<title>My heading
<h1>First topic
<p>{ A paragraph, indented and justified, named not described. }

let n = 7                            % value, usable in #{...}
Seven squared is #{n*n}.

let greet{name} = Hello #name!       % text macro with parameters
\end{slcode}

Change \tg{let h1 = <navy b section>} to \tg{<ForestGreen b section>} once
and \textbf{every} first-level heading follows --- the single point of
control that keeps a long document consistent.

% =====================================================================
\section{Tables}
% =====================================================================

Columns are declared in brackets, \textbf{one two-letter placement code per
column}. The first letter is vertical (\tg{t} top, \tg{m} middle, \tg{b}
bottom), the second horizontal (\tg{l}, \tg{c}, \tg{r}). So \tg{mc} is
middle-centre, \tg{br} bottom-right. Columns share the page equally; \tg{N:}
before the code fixes a width in mm (\tg{[40:tl, 30:mc]}). Cells are
separated by \tg{|}, rows by line breaks, and \tg{\textbackslash\textbackslash}
breaks a line inside a cell.

\begin{slcode}
<table [mc, tl, br] borders header>{
Figure | Formula | Value
<img 25>{cat.png} | $1/2 + 1/3$ | $5/6$
}
\end{slcode}

\tg{borders} draws rules; \tg{header} bolds the first row. \tg{gap:N} sets
the horizontal spacing between columns, in mm.

A cell may span several columns with \tg{colspan:N}, or several rows with
\tg{rowspan:N} (\tg{N}~$\geq$~2). For a \tg{rowspan}, each cell it covers on
the lines below is marked with a lone \tg{.}.

\begin{slcode}
<table [mc, ml, mc, mc] borders header gap:3>{
<colspan:4 mc>{Term report}
Day | Subject | Mark | Coef.
<rowspan:2 mc>{Monday} | Maths | 15 | 4
. | French | 12 | 3
}
\end{slcode}

Colour options act \textbf{inside} the table, on its cells and rules ---
\tg{fill:} colours every body cell, \tg{line:} the rules, \tg{text:} the text
colour, and \tg{headerfill:} / \tg{headertext:} the header row. These are not
box options: a table has no \tg{radius:}, \tg{title:} or outer frame. To
frame a table, wrap it in a \tg{<box>}.

% =====================================================================
\section{Images}
% =====================================================================

\begin{slcode}
<img>{chat.png}        % fills the available width (the cell or line)
<img 25>{chat.png}     % 25 mm wide
<img 25x15>{chat.png}  % fits a 25x15 mm box, ratio preserved
\end{slcode}

A bare name is searched in each folder of \tg{imgdir} in turn, then at the
project root. An explicit path always works, with or without \tg{./}.

% =====================================================================
\section{Maths}
% =====================================================================

Wrap maths in \Verb|$...$|. A small mini-language keeps it light:

\begin{center}
\begin{tabular}{@{}ll@{}}
\toprule
\textbf{You write} & \textbf{You get} \\
\midrule
\tg{*} & $\times$ \\
\tg{+-} & $\pm$ \\
\tg{<=} \tg{>=} \tg{!=} & $\leq$ \quad $\geq$ \quad $\neq$ \\
\tg{a/b} & fraction (chained \tg{a/b/c} reads as \tg{(a/b)/c}) \\
\tg{x\^{}2} \quad \tg{x\_i} & power / index \\
\tg{sqrt(2)} & $\sqrt{2}$ \\
\tg{sum(i=1, n)} & $\sum$ with bounds \\
\tg{abs(x)} & $|x|$ \\
\tg{norm(v)} & $\|v\|$ \\
\tg{vec(AB)} & $\overrightarrow{AB}$ \\
\tg{lim(x->0)} & limit, \tg{->} becomes the arrow \\
\tg{pi}, \tg{alpha}, \dots & Greek letters \\
\tg{inf} & $\infty$ \\
\bottomrule
\end{tabular}
\end{center}

The helpers nest, so the secondary-school staples come for free:
\tg{norm(vec(AB))} is the norm of a vector,
\tg{vec(AB) + vec(BC) = vec(AC)} is Chasles' relation.

Inject a computed value with \tg{\#\{expr\}} (or \tg{\#name}), including
inside maths: \Verb|$#k^2$|. Decimal numbers follow the \tg{lang} option.

\subsection{Maths blocks}

Matrices and systems are blocks: \textbf{one line is one row}, and inside a
matrix \tg{;} separates the entries.

\begin{slcode}
<matrix>{
1 ; 2 ; 3
4 ; 5 ; 6
}
\end{slcode}

\tg{<matrix>} draws parentheses, \tg{<det>} the vertical bars of a
determinant, \tg{<bmatrix>} square brackets. A single \tg{|} inside a row
draws the separation bar of an \textbf{augmented matrix}, at the column where
you type it; it is allowed on \tg{matrix} and \tg{bmatrix}, never on \tg{det}:

\begin{slcode}
<bmatrix>{
2 ; 1 | 7
1 ; -1 | 1
}
\end{slcode}

A \tg{<system>} stacks equations under a brace and aligns them on the first
relational operator:

\begin{slcode}
<system>{
2x + 3y = 7
x - y = 1
}
\end{slcode}

% =====================================================================
\section{Lists}
% =====================================================================

\tg{<list:STYLE>\{ \dots \}} makes a list; the style is required and comes
right after the name. One item per non-empty line --- no item tag. A
\tg{<list:\dots>} written under an item becomes its sub-list, nested as deep
as you like.

\begin{slcode}
<list:disc>{
Fruits
<list:circle>{
apples
pears
}
Vegetables
}
\end{slcode}

Styles --- bullets: \tg{none} \tg{disc} \tg{circle} \tg{square}; numbered:
\tg{decimal} \tg{alpha} \tg{ALPHA} \tg{roman} \tg{ROMAN} (the case of the
keyword sets the case of the letters); checkboxes: \tg{check}.

% =====================================================================
\section{Boxes}
% =====================================================================

\begin{slcode}
<box line:Crimson fill:MistyRose radius:4 title:{A note}>{
Content here.
}
\end{slcode}

Options: \tg{line:} frame colour, \tg{fill:} background, \tg{text:} text
colour, \tg{radius:N} rounded corners (mm), \tg{width:N} or \tg{width:N\%},
\tg{boxrule:N}, \tg{boxsep:N}, \tg{break:yes} (allow page breaks),
\tg{title:\{\dots\}}, \tg{titlefill:}, \tg{titletext:}. A line containing
only \tg{-{-}-} splits a box into an upper and a lower region.

\tg{<row gap:N>\{ \dots \}} lays its child boxes side by side, with equal
widths and equalised heights. A \tg{row} accepts only \tg{<box>} children.

A box also takes a \textbf{two-letter placement code} (\tg{tl tc tr ml mc mr
bl bc br}, default \tg{tl}) that positions its content; the vertical part
needs a \tg{height:} to have room to act.

% =====================================================================
\section{Grid (named-area layout)}
% =====================================================================

For full-page layouts, \tg{<grid>} borrows CSS Grid's named-area idea. A
\tg{template:[ \dots ]} of quoted rows draws the layout; each word names the
cell at that position. A name repeated \textbf{horizontally} spans columns;
repeated \textbf{vertically} it spans rows. A dot \tg{.} is an empty cell.
Each name must form a solid rectangle.

\begin{slcode}
<grid template:[
  "title  title  logo"
  "intro  info   logo"
  "body   body   body"
] gap:4>{
  <area title>{ <red b 16pt>Maths assessment }
  <area logo >{ <img>{blason.png} }
  <area intro>{ Instructions: no calculator. }
  <area info >{ Name: \\ First name: }
  <area body line:Navy fill:AliceBlue radius:2 title:{Exercise 1}>{
    Solve the equation...
  }
}
\end{slcode}

An area can be framed like a box by giving it the same options
(\tg{line:}, \tg{fill:}, \tg{radius:}, \tg{title:}). An area with no options
stays invisible (a bare cell). The grid itself takes \tg{width:} (a
percentage of the text width or a millimetre value) and \tg{height:} (a
millimetre value fixing the total height).

% =====================================================================
\section{Block aliases}
% =====================================================================

Define a reusable component once; \tg{\#param} placeholders are filled at the
call site, and the call-site body becomes the block content.

\begin{slcode}
let card{title, frame} = <box title:{#title} line:#frame radius:2>

<card First, Crimson>{
Called with two arguments. No box options to repeat.
}
<card Second, Navy>{
Same component, different look.
}
\end{slcode}

% =====================================================================
\section{Control flow}
% =====================================================================

\begin{slcode}
for n in 1..3 {            % numeric range
<c navy b>Sheet #n
}

for f in [chat.png, chien.png] {   % explicit list
<img 16>{#f}
}

if score >= 10 {
<green>Passed.
} else {
<red>Try again.
}
\end{slcode}

Loops and conditions work in the document body, inside boxes, and inside
table bodies. The loop variable interpolates everywhere via \tg{\#}.

% =====================================================================
\section{Escapes}
% =====================================================================

Literal special characters: \tg{\textbackslash<} \tg{\textbackslash>}
\tg{\textbackslash\{} \tg{\textbackslash\}} \tg{\textbackslash\#}. The
characters \tg{\_ \& \% \textasciitilde} are escaped automatically. A double
backslash \tg{\textbackslash\textbackslash} is a line break.

A line whose first non-space character is \tg{\%} is a \textbf{comment} and
is dropped. A bare \tg{\#} not followed by a name or \tg{\{\dots\}} is a
literal \tg{\#}: only \tg{\#name} and \tg{\#\{expr\}} interpolate.

% =====================================================================
\section{Security}\label{sec:security}
% =====================================================================

scholatex evaluates \tg{let name = expr}, \tg{\#\{expr\}} and the conditions
of \tg{for}/\tg{if}/\tg{while} as Lua at compile time, so by default a
document can run arbitrary code --- exactly like \tg{\textbackslash directlua}.

Setting \tg{untrusted=true} runs that Lua in a restricted environment: only
pure, side-effect-free names are visible (the maths the document needs plus
\tg{string}/\tg{table} helpers), while \tg{os}, \tg{io}, \tg{package},
\tg{require}, \tg{load}, \tg{debug} and \tg{setmetatable} are absent. A
blocked access stops the compile with a clear message; a runaway loop is
aborted by an instruction-count ceiling.

\textbf{Scope.} \tg{untrusted} hardens the scholatex expression layer only.
It does \emph{not} sandbox LuaLaTeX as a whole: a hostile \tg{.tex} can still
call \tg{\textbackslash directlua}, \tg{\textbackslash write18} (with
shell-escape), \tg{\textbackslash input}, and so on. To compile a whole
\tg{.tex} you do not trust, run \tg{lualatex} \textbf{without}
\tg{-{-}shell-escape}, ideally inside a container.

% =====================================================================
\section{Examples}
% =====================================================================

The \tg{examples/} folder contains three self-contained, fully commented
documents that together exercise every feature:

\begin{center}
\begin{tabular}{@{}ll@{}}
\toprule
\textbf{File} & \textbf{Covers} \\
\midrule
\tg{01-text-style.tex} & case rule, styles, colours, fonts, sizes, alignment, aliases, TOC \\
\tg{02-containers.tex} & tables, boxes and the named-area grid \\
\tg{03-math.tex} & the inline mini-language, helpers, matrix/system blocks \\
\bottomrule
\end{tabular}
\end{center}

Compile any of them with \tg{lualatex <file>.tex} from the \tg{examples/}
folder. The image folders \tg{IMG/} and \tg{IMAGES/PNG/} ship alongside them;
\tg{02-containers.tex} uses \tg{imgdir=\{IMG, IMAGES/PNG\}} to show that bare
image names are resolved across several directories.

% =====================================================================
\section{Diagnostics}
% =====================================================================

Errors point at the source line, e.g.
\tg{scholatex: line 12: unknown tag attribute: 'xyz'}. Defining an alias
whose name is a built-in (\tg{let section = \dots}, \tg{let tab = \dots})
prints a warning: the built-in always wins, so the alias would be silently
dead --- pick a different name.

\vfill
\begin{center}\small\color{black!55}
scholatex --- Released under the GNU General Public License v3.0.
\end{center}

\end{document}
