%
% CoDi: Commutative Diagrams for TeX
% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
% SPDX-License-Identifier: MIT
%
% This file is part of CoDi 1.0.1, released on 2020/06/11 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
    {\message{A}\ifkDDTSPrevSpace\kDDTSHasTrailtrue\else\kDDTSHasTrailfalse\fi\kDGobbleHardTok}
    {\message{B}\kDIfNextSoftCh\kDBlankSpace
      {\message{Y}\kDDTSPrevSpacetrue\expandafter\kDDTSGob\kDGobbleSoftTok}
      {\message{N}\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}
