%
% CoDi: Commutative Diagrams for TeX
% Copyright (c) 2015-2024 Paolo Brasolin <[email protected]>
% SPDX-License-Identifier: MIT
%
% This file is part of CoDi 1.1.2, released on 2024/04/22 under MIT license.
%

% κοινός • (koinós)
%   1. shared
%   2. common
%   3. public

% Koinos implements or aliases commonplace macros.

%==[ catcode manipulation ]=====================================================

\newcount\kDEscapecharCounter

\def\kDEscapecharDisable{\kDEscapecharCounter\escapechar \escapechar=-1}
\def\kDEscapecharEnable{\escapechar\kDEscapecharCounter}

\def\kDStoreCatcodeOf#1%
 {\kDEscapecharDisable
  \expandafter\edef\csname kDRestoreCatcodeOf\string#1\endcsname{\catcode`\string#1=\the\catcode\expandafter`\string#1}%
  % NOTE: setting a default catcode is disabled; might come in handy someday, though.
  % \catcode\expandafter`\string#1=12\relax
  \kDEscapecharEnable}

\def\kDRestoreCatcodeOf#1%
 {\kDEscapecharDisable
  \csname kDRestoreCatcodeOf\string#1\endcsname
  \kDEscapecharEnable}

%==[ forward checks and gobbling ]==============================================

% This macro is the blank space token.
\bgroup
\def\:{\global\let\kDBlankSpace= }\:
\egroup

% Save catcode of @ to restore it later.
\kDStoreCatcodeOf @
\catcode`@=11\relax

% The next two macros both implement token gobbling.

% This "hard" version gobbles any token, ignoring whitespace.
\let\kDGobbleHardTok\pgfutil@gobble

% This "soft" version gobbles only whitespace.
% NOTE: this is just the identity macro. Fun fact.
\def\kDGobbleSoftTok#1{#1}

% The next two macros both implement the following logical condition:
%   if next token is #1 then #2 else #3

% This "hard" version ignores whitespace.
\let\kDIfNextHardCh\pgfutil@ifnextchar

% This "soft" version does not ignore whitespace.
\long\def\kDIfNextSoftCh#1#2#3{%
 \let\kDINCToken= #1% <- MEMO: this space is crucial
 \def\kDINCTrue{#2}\def\kDINCFalse{#3}%
 \futurelet\kDINCTok\kDINC}

\def\kDINC{\ifx\kDINCTok\kDINCToken\let\kDINCFalse\kDINCTrue\fi\kDINCFalse}

% Restore catcode of @.
\kDRestoreCatcodeOf @

%==[ token lists parsing and manipulation ]=====================================

% This macro appends token list #1 to token list #2.
\def\kDAppend#1#2{\edef\kDAct{\noexpand#2={\the#2\the#1}}\kDAct}

% This macro tokenizes the stream into \kDOptTok
% until a group preceeding a ';' character is found;
% then it puts the group into \kDGrpTok and gobbles the ';'.
\def\kDFetchOptAndGrpThen#1%
 {\kDOptTok={}\kDGrpTok={}\kDFetchTilGrpThen{#1}}

\newtoks\kDOptTok
\newtoks\kDGrpTok

\def\kDFetchGrpThen#1#2{%
 \def\kDExit{#1}%
 \def\kDLoop{\kDFetchTilGrpThen{#1}}%
 \kDTmpTok={{#2}}%
 \kDIfNextHardCh;
   {\kDGrpTok\the\kDTmpTok\expandafter\kDExit\kDGobbleHardTok}
   {\kDAppend\kDTmpTok\kDOptTok\kDLoop}}

\newtoks\kDTmpTok

\def\kDFetchTilGrpThen#1#2#{%
 \kDTmpTok={#2}%
 \kDAppend\kDTmpTok\kDOptTok
 \kDFetchGrpThen{#1}}

% This macro removes trailing whitespace from token list #1.
\def\kDTrimTrailingSpace#1{%
 \kDDetectTrailingSpace#1
 \ifkDDTSHasTrail
   \def\kDRTS##1 \kD{#1={##1}}%
   \edef\kDRTSAct{\noexpand\kDRTS\the#1\noexpand\kD}
   \kDRTSAct
 \fi}

\def\kDDetectTrailingSpace#1{%
 \kDDTSPrevSpacefalse
 \edef\kDAct{\noexpand\kDDTSGob\the#1\noexpand\kD}%
 \kDAct}

\newif\ifkDDTSHasTrail

\def\kDDTSGob%
 {\kDIfNextSoftCh\kD
   {\ifkDDTSPrevSpace\kDDTSHasTrailtrue\else\kDDTSHasTrailfalse\fi\kDGobbleHardTok}
   {\kDIfNextSoftCh\kDBlankSpace
     {\kDDTSPrevSpacetrue\expandafter\kDDTSGob\kDGobbleSoftTok}
     {\kDDTSPrevSpacefalse\expandafter\kDDTSGob\kDGobbleHardTok}}}

\newif\ifkDDTSPrevSpace

% This macro removes leading whitespace from token list #1.
\def\kDTrimLeadingSpace#1{%
 \def\kDAct##1\kD{#1={##1}}%
 \expandafter\kDGobbleSpaceThen
 \expandafter\kDAct\the#1\kD}

\def\kDGobbleSpaceThen#1%
 {\kDIfNextHardCh\bgroup
   {\kDGSGroupThen#1}
   {\kDGSOtherThen#1}}

\def\kDGSGroupThen#1#2{#1{#2}}

\def\kDGSOtherThen#1#2{#1#2}

%==[ environment checks ]=======================================================

\newif\ifConTeXt
% Trick stolen from iftex. The second line is expanded inside the group so
% the global scope isn't polluted by \csname defining the token.
\begingroup\expandafter\expandafter\expandafter\endgroup\expandafter
 \ifx\csname starttext\endcsname\relax\ConTeXtfalse\else\ConTeXttrue\fi

%==[ dumping, debugging and testing ]===========================================

% macros for dumping, debugging and testing
% TODO: not sure I want to depend on these being in the sourcecode instead of
%   some external package integrated with a TeX unit testing suite.
%   I'll work in that direction.

\newif\ifkDDumping
\kDDumpingfalse

\newwrite\kDDumpFile

\def\kDDumpOpen%
{\ifkDDumping\immediate\openout\kDDumpFile=\jobname.yml\fi}

\def\kDDump#1%
{\ifkDDumping\immediate\write\kDDumpFile{#1}\fi}

\def\kDDumpClose%
{\ifkDDumping\closeout\kDDumpFile\fi}