%% setbuilder.sty %% Smart set-builder notation for LaTeX. %% %% \set{x \in \mathbb{R} \given x^2 < 2} %% %% produces { x ∈ ℝ | x² < 2 } with correctly spaced and, on demand, %% correctly scaled braces and separator bar. No more %% \left\{ ... \,\middle|\, ... \right\}. %% %% Commands: %% \set{...} canonical command: braces and bar at normal size %% \set*{...} braces and bar auto-scale (\left/\middle/\right) %% \set[\Big]{...} braces and bar at a fixed size %% \given the separator, usable only inside \set %% \suchthat alias for \given %% %% Package options (key-value): %% bar (default) separator is a vertical bar { x | ... } %% colon separator is a colon { x : ... } %% pad= space just inside the braces of a set given by %% a condition, { x | x>0 } (default: \, ). %% pad=none disables it. A set written as a %% plain enumeration, {1, 2, 3}, never gets it. %% synonym= additionally define \ as a full copy of %% \set (with all its * and [\Big] variants). %% If \set is already taken by another package, %% setbuilder leaves it untouched, and the synonym %% becomes the way to access the functionality: %% \usepackage[synonym=mkset]{setbuilder} %% %% Requires LaTeX kernel 2022-06-01 or newer (for key-value options). %% %% Copyright (c) 2026 Vseslav Sekorin %% License: MIT (see LICENSE file or https://opensource.org/licenses/MIT) %% \NeedsTeXFormat{LaTeX2e}[2022/06/01] \ProvidesPackage{setbuilder}[2026/07/28 v0.2.0 Smart set-builder notation] \RequirePackage{mathtools} %% --------------------------------------------------------------- %% Key-value options %% --------------------------------------------------------------- \newif\ifsetbuilder@colon \newcommand*\setbuilder@synonym{} \newcommand*\setbuilder@pad{} %% The default padding inside the braces: one line to change it. \newcommand*\setbuilder@defaultpad{\,} \DeclareKeys[setbuilder]{ bar.code = {\setbuilder@colonfalse}, colon.code = {\setbuilder@colontrue}, synonym.store = \setbuilder@synonym, synonym.usage = load, pad.store = \setbuilder@pad, pad.usage = load, } \ProcessKeyOptions[setbuilder] %% pad= | none | (unset => \setbuilder@defaultpad). %% \nonscript is part of the stored value, so that pad=none leaves no %% stray \nonscript to swallow whatever glue happens to come next. \newcommand*\setbuilder@none{none} \newcommand*\setbuilder@padamount{} \ifx\setbuilder@pad\@empty \renewcommand*\setbuilder@padamount{\nonscript\setbuilder@defaultpad} \else\ifx\setbuilder@pad\setbuilder@none % pad=none: no space at all \else \renewcommand*\setbuilder@padamount{\nonscript\mskip\setbuilder@pad\relax} \fi\fi %% --------------------------------------------------------------- %% The separator %% --------------------------------------------------------------- %% \setbuilder@sep[] typesets the separator with correct spacing: %% - \nonscript\: adds a medium-thin space that vanishes in sub/superscripts; %% - \allowbreak permits a line break after the bar in inline formulas; %% - \mathopen{} makes what follows behave as if freshly opened, so %% unary minus etc. after the bar are spaced correctly. %% The bar scales with the braces (it receives \delimsize / \middle); %% a colon never needs to scale, so the size argument is ignored there. \ifsetbuilder@colon \newcommand\setbuilder@sep[1][]{% \nonscript\:{\mathord{:}}\allowbreak\nonscript\:\mathopen{}} \else \newcommand\setbuilder@sep[1][]{% \nonscript\:#1\vert\allowbreak\nonscript\:\mathopen{}} \fi %% Outside \set the separator commands raise a descriptive error. \DeclareRobustCommand\given{% \PackageError{setbuilder}% {\string\given\space may only be used inside \string\set}% {Write e.g. \string\set{x \string\given\space x>0}.}} \DeclareRobustCommand\suchthat{% \PackageError{setbuilder}% {\string\suchthat\space may only be used inside \string\set}% {Write e.g. \string\set{x \string\suchthat\space x>0}.}} %% --------------------------------------------------------------- %% The command itself (internal master copy) %% --------------------------------------------------------------- %% \DeclarePairedDelimiterX gives us the *, [\Big] and plain variants %% for free; inside the body we locally redefine \given so that it %% knows the current delimiter size (\delimsize is \middle in the %% starred version and the chosen \big/\Big/... otherwise). %% \setbuilder@ifsep{} emits the padding, but only if %% really is a set given by a condition, i.e. contains a separator at %% brace level 0. Knuth's rule (TeXbook): {\,x \mid x>0\,} but %% {1, 2, \dots, n}. Both spellings of the separator must be looked %% for, and the test is redone before the closing brace rather than %% remembered in a flag: a nested \set in the body would clobber %% \ifin@ in between. \newcommand\setbuilder@ifsep[1]{% \in@{\given}{#1}% \ifin@\else\in@{\suchthat}{#1}\fi \ifin@\setbuilder@padamount\fi} \DeclarePairedDelimiterX\setbuilder@cmd[1]\{\}{% \renewcommand\given{\setbuilder@sep[\delimsize]}% \let\suchthat\given \setbuilder@ifsep{#1}% #1 \setbuilder@ifsep{#1}} %% --------------------------------------------------------------- %% Canonical name \set + optional synonym %% --------------------------------------------------------------- %% \NewCommandCopy makes a faithful copy of the robust paired-delimiter %% command, so the copy supports \set, \set* and \set[\Big] alike. \ifdefined\set \ifx\setbuilder@synonym\@empty \PackageWarning{setbuilder}{% \string\set\space is already defined by another package and is\MessageBreak left untouched. Load setbuilder with a synonym to access\MessageBreak its functionality, e.g.\MessageBreak \space\space\string\usepackage[synonym=mkset]{setbuilder}}% \else \PackageInfo{setbuilder}{% \string\set\space is already defined elsewhere and is left\MessageBreak untouched; using the requested synonym instead}% \fi \else \NewCommandCopy\set\setbuilder@cmd \fi \ifx\setbuilder@synonym\@empty\else \ifcsname \setbuilder@synonym\endcsname \PackageError{setbuilder}% {Cannot create synonym \expandafter\string \csname\setbuilder@synonym\endcsname: this name is already defined}% {Choose another name in the synonym=... option.}% \else \expandafter\NewCommandCopy \csname\setbuilder@synonym\endcsname \setbuilder@cmd \fi \fi \endinput