% \iffalse meta-comment
% A LaTeX Class and Package for OMDoc Document Structures
% Copyright (c) 2019 Michael Kohlhase, all rights reserved
%               this file is released under the
%               LaTeX Project Public License (LPPL)
%
% The original of this file is in the public repository at 
% http://github.com/sLaTeX/sTeX/
%
%
%<*driver>
\def\libfolder#1{../../lib/#1}
\input{../../doc/stex-docheader}

\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{document-structure: Semantic Markup for Open Mathematical Documents in {\LaTeX}
% 	\thanks{Version {\fileversion} (last revised {\filedate})} 
% }
%
% \author{Michael Kohlhase, Dennis Müller\\
% 	FAU Erlangen-Nürnberg\\
% 	\url{http://kwarc.info/}
% }
%
% \maketitle
%
% \ifinfulldoc\else
% \begin{abstract}
%   This is the documentation for the \pkg{document-structure} package from \sTeX
%   collection, a version of {\TeX/\LaTeX} that allows to markup {\TeX/\LaTeX} documents
%   semantically without leaving the document format, essentially turning {\TeX/\LaTeX}
%   into a document format for mathematical knowledge management (MKM).
%
%   For a more high-level introduction, see \href{\basedocurl/manual.pdf}{the \sTeX
%   Manual} or the \href{\basedocurl/stex.pdf}{full \sTeX documentation}.
% \end{abstract}
%
% \tableofcontents
% 
% \begin{documentation}\label{pkg:documentstructure:doc}
% \begin{sfragment}{The User Interface}
% \input{../../doc/packages/stex-document-structure}
% \end{sfragment}
% \end{documentation}
%
% \fi
%
% \begin{implementation}\label{pkg:documentstructure:impl}
%
% \begin{sfragment}{document-structure.sty Implementation}
%
%    \begin{macrocode}
%<*package>
%<@@=document_structure>
\ProvidesExplPackage{document-structure}{2022/09/14}{3.2.0}{Modular Document Structure}
\RequirePackage{l3keys2e}
%    \end{macrocode}
%
% \begin{sfragment}[id=sec:impl:options]{Package Options}
%
%   We declare some switches which will modify the behavior according to the package
%   options. Generally, an option |xxx| will just set the appropriate switches to true
%   (otherwise they stay false).
%
%
%    \begin{macrocode}

\keys_define:nn{ document-structure }{
  class       .str_set_x:N  = \c_document_structure_class_str,
  topsect     .str_set_x:N  = \c_document_structure_topsect_str,
  unknown     .code:n       = {
    \PassOptionsToClass{\CurrentOption}{stex}
    \PassOptionsToClass{\CurrentOption}{tikzinput}
  }
%  showignores .bool_set:N   = \c_document_structure_showignores_bool,
}
\ProcessKeysOptions{ document-structure }
\str_if_empty:NT \c_document_structure_class_str {
  \str_set:Nn \c_document_structure_class_str {article}
}
\str_if_empty:NT \c_document_structure_topsect_str {
  \str_set:Nn \c_document_structure_topsect_str {section}
}
%    \end{macrocode}
%
% Then we need to set up the packages by requiring the |sref| package to be loaded,
% and set up triggers for other languages
%
%    \begin{macrocode}
\RequirePackage{xspace}
\RequirePackage{comment}
\RequirePackage{stex}
\AddToHook{begindocument}{
	\ltx@ifpackageloaded{babel}{
    \clist_set:Nx \l_tmpa_clist {\bbl@loaded}
    \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\detokenize{ngerman}}{
      \makeatletter\input{document-structure-ngerman.ldf}\makeatother
    }
  }{}
}
%    \end{macrocode}
%
% Finally, we set the \DescribeMacro{\section@level}|\section@level| macro that governs
% sectioning. The default is two (corresponding to the |article| class), then we set the
% defaults for the standard classes |book| and |report| and then we take care of the
% levels passed in via the |topsect| option.
%
%    \begin{macrocode}
\int_new:N \l_document_structure_section_level_int
\str_case:VnF \c_document_structure_topsect_str {
  {part}{
    \int_set:Nn \l_document_structure_section_level_int {0}
  }
  {chapter}{
    \int_set:Nn \l_document_structure_section_level_int {1}
  }
}{
  \str_case:VnF \c_document_structure_class_str {
    {book}{
      \int_set:Nn \l_document_structure_section_level_int {0}
    }
    {report}{
      \int_set:Nn \l_document_structure_section_level_int {0}
    }
  }{
    \int_set:Nn \l_document_structure_section_level_int {2}
  }
}
%    \end{macrocode}
%
% \end{sfragment}
% 
% \begin{sfragment}[id=sec:impl:struct]{Document Structure}
% 
%   The structure of the document is given by the |sfragment| environment. The hierarchy
%   is adjusted automatically according to the {\LaTeX} class in effect.
% \begin{macro}{\currentsectionlevel}
%   For the |\currentsectionlevel| and |\Currentsectionlevel| macros we use an internal
%   macro |\current@section@level| that only contains the keyword (no markup). We
%   initialize it with ``document'' as a default. In the generated OMDoc, we only generate
%   a text element of class |omdoc_currentsectionlevel|, wich will be instantiated by CSS
%   later.\ednote{MK: we may have to experiment with the more powerful uppercasing macro
%   from \texttt{mfirstuc.sty} once we internationalize.}
%    \begin{macrocode}
\def\current@section@level{document}%
\newcommand\currentsectionlevel{\lowercase\expandafter{\current@section@level}\xspace}%
\newcommand\Currentsectionlevel{\expandafter\MakeUppercase\current@section@level\xspace}%
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\skipfragment}
%    \begin{macrocode}
\cs_new_protected:Npn \skipfragment {
  \ifcase\l_document_structure_section_level_int
  \or\stepcounter{part}
  \or\stepcounter{chapter}
  \or\stepcounter{section}
  \or\stepcounter{subsection}
  \or\stepcounter{subsubsection}
  \or\stepcounter{paragraph}
  \or\stepcounter{subparagraph}
  \fi
}
%    \end{macrocode}
% \end{macro}
%
% \begin{environment}{blindfragment}
%    \begin{macrocode}
\newcommand\at@begin@blindsfragment[1]{}
\newenvironment{blindfragment}
{
  \int_incr:N\l_document_structure_section_level_int
  \at@begin@blindsfragment\l_document_structure_section_level_int
}{}
%    \end{macrocode}
% \end{environment}
%
% \begin{macro}{\sfragment@nonum}
%   convenience macro: |\sfragment@nonum{|\meta{level}|}{|\meta{title}|}| makes an unnumbered
%   sectioning with title \meta{title} at level \meta{level}.
%    \begin{macrocode}
\newcommand\sfragment@nonum[2]{
  \ifx\hyper@anchor\@undefined\else\phantomsection\fi
  \addcontentsline{toc}{#1}{#2}\@nameuse{#1}*{#2}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\sfragment@num}
%   convenience macro: |\sfragment@nonum{|\meta{level}|}{|\meta{title}|}| makes numbered
%   sectioning with title \meta{title} at level \meta{level}. We have to check the |short|
%   key was given in the |sfragment| environment and -- if it is use it. But how to do that
%   depends on whether the |rdfmeta| package has been loaded. In the end we call
%   |\sref@label@id| to enable crossreferencing.
%    \begin{macrocode}
\newcommand\sfragment@num[2]{
  \tl_if_empty:NTF \l_@@_sfragment_short_tl {
    \@nameuse{#1}{#2}
  }{
    \cs_if_exist:NTF\rdfmeta@sectioning{
      \@nameuse{rdfmeta@#1@old}[\l_@@_sfragment_short_tl]{#2}
    }{
      \@nameuse{#1}[\l_@@_sfragment_short_tl]{#2}
    }
  }
%\sref@label@id@arg{\omdoc@sect@name~\@nameuse{the#1}}\sfragment@id
}
%    \end{macrocode}
% \end{macro}
%
% \begin{environment}{sfragment}
%    \begin{macrocode}
\keys_define:nn { document-structure / sfragment }{
  id            .str_set_x:N = \l_@@_sfragment_id_str,
  date          .str_set_x:N = \l_@@_sfragment_date_str,
  creators      .clist_set:N = \l_@@_sfragment_creators_clist,
  contributors  .clist_set:N = \l_@@_sfragment_contributors_clist,
  srccite       .tl_set:N    = \l_@@_sfragment_srccite_tl,
  type          .tl_set:N    = \l_@@_sfragment_type_tl,
  short         .tl_set:N    = \l_@@_sfragment_short_tl,
  intro         .tl_set:N    = \l_@@_sfragment_intro_tl,
  imports       .tl_set:N    = \l_@@_sfragment_imports_tl,
  loadmodules   .bool_set:N  = \l_@@_sfragment_loadmodules_bool
}
\cs_new_protected:Nn \_@@_sfragment_args:n {
  \str_clear:N \l_@@_sfragment_id_str
  \str_clear:N \l_@@_sfragment_date_str
  \clist_clear:N \l_@@_sfragment_creators_clist
  \clist_clear:N \l_@@_sfragment_contributors_clist
  \tl_clear:N \l_@@_sfragment_srccite_tl
  \tl_clear:N \l_@@_sfragment_type_tl
  \tl_clear:N \l_@@_sfragment_short_tl
  \tl_clear:N \l_@@_sfragment_imports_tl
  \tl_clear:N \l_@@_sfragment_intro_tl
  \bool_set_false:N \l_@@_sfragment_loadmodules_bool
  \keys_set:nn { document-structure / sfragment } { #1 }
}
%    \end{macrocode}
% we define a switch for numbering lines and a hook for the beginning of groups: The
% \DescribeMacro{\at@begin@sfragment}|\at@begin@sfragment| macro allows customization. It is
% run at the beginning of the |sfragment|, i.e. after the section heading.
%    \begin{macrocode}
\newif\if@mainmatter\@mainmattertrue
\newcommand\at@begin@sfragment[3][]{}
%    \end{macrocode}
%
% Then we define a helper macro that takes care of the sectioning magic. It comes with its
% own key/value interface for customization.
%
%    \begin{macrocode}
\keys_define:nn { document-structure / sectioning }{
  name    .str_set_x:N  = \l_@@_sect_name_str   ,
  ref     .str_set_x:N  = \l_@@_sect_ref_str    ,
  clear   .bool_set:N   = \l_@@_sect_clear_bool ,
  clear   .default:n    = {true}                ,
  num     .bool_set:N   = \l_@@_sect_num_bool   ,
  num     .default:n    = {true}
}
\cs_new_protected:Nn \_@@_sect_args:n {
  \str_clear:N \l_@@_sect_name_str
  \str_clear:N \l_@@_sect_ref_str
  \bool_set_false:N \l_@@_sect_clear_bool
  \bool_set_false:N \l_@@_sect_num_bool
  \keys_set:nn { document-structure / sectioning } { #1 }
}
\newcommand\omdoc@sectioning[3][]{
  \_@@_sect_args:n {#1 }
  \let\omdoc@sect@name\l_@@_sect_name_str
  \bool_if:NT \l_@@_sect_clear_bool { \cleardoublepage }
  \if@mainmatter% numbering not overridden by frontmatter, etc.
    \bool_if:NTF \l_@@_sect_num_bool {
      \sfragment@num{#2}{#3}
    }{
      \sfragment@nonum{#2}{#3}
    }
    \def\current@section@level{\omdoc@sect@name}
  \else
    \sfragment@nonum{#2}{#3}
  \fi
}% if@mainmatter
%    \end{macrocode}
% and another one, if redefines the |\addtocontentsline| macro of {\LaTeX} to import the
% respective macros. It takes as an argument a list of module names.
%    \begin{macrocode}
\newcommand\sfragment@redefine@addtocontents[1]{%
%\edef\@@import{#1}%
%\@for\@I:=\@@import\do{%
%\edef\@path{\csname module@\@I  @path\endcsname}%
%\@ifundefined{tf@toc}\relax%
%     {\protected@write\tf@toc{}{\string\@requiremodules{\@path}}}}
%\ifx\hyper@anchor\@undefined% hyperref.sty loaded?
%\def\addcontentsline##1##2##3{%
%\addtocontents{##1}{\protect\contentsline{##2}{\string\withusedmodules{#1}{##3}}{\thepage}}}
%\else% hyperref.sty not loaded
%\def\addcontentsline##1##2##3{%
%\addtocontents{##1}{\protect\contentsline{##2}{\string\withusedmodules{#1}{##3}}{\thepage}{\@currentHref}}}%
%\fi
}% hypreref.sty loaded?
%    \end{macrocode}
% now the |sfragment| environment itself. This takes care of the table of contents via the
% helper macro above and then selects the appropriate sectioning command from
% |article.cls|. It also registeres the current level of sfragments in the |\sfragment@level|
% counter. 
%    \begin{macrocode}
\newenvironment{sfragment}[2][]% keys, title
{
  \_@@_sfragment_args:n { #1 }%\sref@target%
%    \end{macrocode}
% If the |loadmodules| key is set on |\begin{sfragment}|, we redefine the |\addcontetsline|
%   macro that determines how the sectioning commands below construct the entries for the
%   table of contents.
%    \begin{macrocode}
  \stex_csl_to_imports:No \usemodule \l_@@_sfragment_imports_tl

  \bool_if:NT \l_@@_sfragment_loadmodules_bool {
    \sfragment@redefine@addtocontents{
      %\@ifundefined{module@id}\used@modules%
      %{\@ifundefined{module@\module@id @path}{\used@modules}\module@id}
    }
  }
%    \end{macrocode}
% now we only need to construct the right sectioning depending on the value of
% |\section@level|.
%    \begin{macrocode}

  \stex_document_title:n { #2 }
  
  \int_incr:N\l_document_structure_section_level_int
  \ifcase\l_document_structure_section_level_int
    \or\omdoc@sectioning[name=\omdoc@part@kw,clear,num]{part}{#2}
    \or\omdoc@sectioning[name=\omdoc@chapter@kw,clear,num]{chapter}{#2}
    \or\omdoc@sectioning[name=\omdoc@section@kw,num]{section}{#2}
    \or\omdoc@sectioning[name=\omdoc@subsection@kw,num]{subsection}{#2}
    \or\omdoc@sectioning[name=\omdoc@subsubsection@kw,num]{subsubsection}{#2}
    \or\omdoc@sectioning[name=\omdoc@paragraph@kw,ref=this \omdoc@paragraph@kw]{paragraph}{#2}
    \or\omdoc@sectioning[name=\omdoc@subparagraph@kw,ref=this \omdoc@subparagraph@kw]{paragraph}{#2}
  \fi
  \at@begin@sfragment[#1]\l_document_structure_section_level_int{#2}
  \str_if_empty:NF \l_@@_sfragment_id_str {
    \stex_ref_new_doc_target:n\l_@@_sfragment_id_str
  }
}% for customization
{}
%    \end{macrocode}
% \end{environment}
%
% and finally, we localize the sections
%    \begin{macrocode}
\newcommand\omdoc@part@kw{Part}
\newcommand\omdoc@chapter@kw{Chapter}
\newcommand\omdoc@section@kw{Section}
\newcommand\omdoc@subsection@kw{Subsection}
\newcommand\omdoc@subsubsection@kw{Subsubsection}
\newcommand\omdoc@paragraph@kw{paragraph}
\newcommand\omdoc@subparagraph@kw{subparagraph}
%    \end{macrocode}
%
% \end{sfragment}
%
% \begin{sfragment}[id=sec:user:docmatter]{Front and Backmatter}
% 
%   Index markup is provided by the |omtext| package~\cite{Kohlhase:smmtf:git}, so in the
%   |document-structure| package we only need to supply the corresponding |\printindex| command, if it
%   is not already defined
% \begin{macro}{\printindex}
%    \begin{macrocode}
\providecommand\printindex{\IfFileExists{\jobname.ind}{\input{\jobname.ind}}{}}
%    \end{macrocode}
% \end{macro}
% 
% some classes (e.g. |book.cls|) already have |\frontmatter|, |\mainmatter|, and
% |\backmatter| macros. As we want to define |frontmatter| and |backmatter| environments,
% we save their behavior (possibly defining it) in |orig@*matter| macros and make them
% undefined (so that we can define the environments).
%    \begin{macrocode}
\cs_if_exist:NTF\frontmatter{
  \let\_@@_orig_frontmatter\frontmatter
  \let\frontmatter\relax
}{
  \tl_set:Nn\_@@_orig_frontmatter{
    \clearpage
    \@mainmatterfalse
    \pagenumbering{roman}
  }
}
\cs_if_exist:NTF\backmatter{
  \let\_@@_orig_backmatter\backmatter
  \let\backmatter\relax
}{
  \tl_set:Nn\_@@_orig_backmatter{
    \clearpage
    \@mainmatterfalse
    \pagenumbering{roman}
  }
}
%    \end{macrocode}
%
% Using these, we can now define the |frontmatter| and |backmatter| environments
% 
% \begin{environment}{frontmatter}
%  we use the |\orig@frontmatter| macro defined above and |\mainmatter| if it exists,
%  otherwise we define it.  
%    \begin{macrocode}
\newenvironment{frontmatter}{
  \_@@_orig_frontmatter
}{
  \cs_if_exist:NTF\mainmatter{
    \mainmatter
  }{
    \clearpage
    \@mainmattertrue
    \pagenumbering{arabic}
  }
}
%    \end{macrocode}
% \end{environment}
%
% \begin{environment}{backmatter}
%   As backmatter is at the end of the document, we do nothing for |\endbackmatter|. 
%    \begin{macrocode}
\newenvironment{backmatter}{
  \_@@_orig_backmatter
}{
  \cs_if_exist:NTF\mainmatter{
    \mainmatter
  }{
    \clearpage
    \@mainmattertrue
    \pagenumbering{arabic}
  }
}
%    \end{macrocode}
%
% finally, we make sure that page numbering is arabic and we have main matter as the default
%
%    \begin{macrocode}
\@mainmattertrue\pagenumbering{arabic}
%    \end{macrocode}
% \end{environment}
% \end{sfragment}
%
% \begin{macro}{\prematurestop}
%   We initialize |\afterprematurestop|, and provide 
%   |\prematurestop@endsfragment| which looks up |\sfragment@level| and recursively ends
%   enough |{sfragment}|s. 
%    \begin{macrocode}
\def \c_@@_document_str{document} 
\newcommand\afterprematurestop{}
\def\prematurestop@endsfragment{
  \unless\ifx\@currenvir\c_@@_document_str
    \expandafter\expandafter\expandafter\end\expandafter\expandafter\expandafter{\expandafter\@currenvir\expandafter}
    \expandafter\prematurestop@endsfragment
  \fi
}
\providecommand\prematurestop{
  \message{Stopping~sTeX~processing~prematurely}
  \prematurestop@endsfragment
  \afterprematurestop
  \end{document}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{sfragment}[id=sec:impl:gvars]{Global Variables}
%
% \begin{macro}{\setSGvar}
%   set a global variable
%    \begin{macrocode}
\RequirePackage{etoolbox}
\newcommand\setSGvar[1]{\@namedef{sTeX@Gvar@#1}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\useSGvar}
%   use a global variable
%    \begin{macrocode}
\newrobustcmd\useSGvar[1]{%
  \@ifundefined{sTeX@Gvar@#1}
  {\PackageError{document-structure}
    {The sTeX Global variable #1 is undefined}
    {set it with \protect\setSGvar}}
\@nameuse{sTeX@Gvar@#1}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ifSGvar}
%   execute something conditionally based on the state of the global variable. 
%    \begin{macrocode}
\newrobustcmd\ifSGvar[3]{\def\@test{#2}%
  \@ifundefined{sTeX@Gvar@#1}
  {\PackageError{document-structure}
    {The sTeX Global variable #1 is undefined}
    {set it with \protect\setSGvar}}
  {\expandafter\ifx\csname sTeX@Gvar@#1\endcsname\@test #3\fi}}
%    \end{macrocode}
% \end{macro}
%
% \end{sfragment}
% \end{sfragment}
%
% \end{implementation}
% \ifinfulldoc\else\printbibliography\fi
\endinput

%%% Local Variables: 
%%% mode: doctex
%%% TeX-master: t
%%% End: 
