% \iffalse meta-comment
%
% File: docext.dtx
% -----------------------------------------------------------------------
%   Copyright (C) 2026 by Mingyu Xia <myhsia@outlook.com>               *
% -----------------------------------------------------------------------
%   This work may be distributed and/or modified under the conditions   *
%   of the LaTeX Project Public License (LPPL), either version 1.3c of  *
%   this license or (at your option) any later version.                 *
%   The latest version of this license is in                            *
%                                                                       *
%       http://www.latex-project.org/lppl.txt                           *
%                                                                       *
%   and version 1.3c or later is part of all distributions of LaTeX     *
%   version 2008 or later.                                              *
%                                                                       *
%   This work has the LPPL maintenance status `maintained'.             *
%                                                                       *
%   The Current Maintainer of this work is Mingyu Xia.                  *
% -----------------------------------------------------------------------
%   This work consists of the files docext.dtx,                         *
%                                   docext.ins,                         *
%                 the derived files docext.sty,                         *
%           the documentation files docext.pdf,                         *
%                               and README.md.                          *
% -----------------------------------------------------------------------
%                                                                       *
%   Any modification of this file should ensure that the copyright and  *
%   license information is placed in the derived files.                 *
%                                                                       *
% -----------------------------------------------------------------------
%
%<*internal>
\iffalse
%</internal>
%
%<*readme>
[![CTAN Version](https://img.shields.io/ctan/v/docext)](https://ctan.org/pkg/docext)
[![GitHub Release](https://img.shields.io/github/v/release/myhsia/docext)](https://github.com/myhsia/docext/releases/latest)
[![GitHub Last Commit](https://img.shields.io/github/last-commit/myhsia/docext)](https://github.com/myhsia/docext/commits)
[![Actions Status](https://github.com/myhsia/docext/actions/workflows/test.yaml/badge.svg?branch=main)](https://github.com/myhsia/docext/actions)
[![GitHub Repo stars](https://img.shields.io/github/stars/myhsia/docext)](https://github.com/myhsia/docext)

The `docext` Package
====================

The `docext` package is an extension for documenting LaTeX source files.

It provides
- An elegant way to typeset the `key-value` list.
- The `codedemo` enviornment for typesetting the code within a `verbatim` and a
`demo` environment at the same time.

It fixes the drawbacks of the `doc` package under
- The engines: `pTeX` and `upTeX`.
- The classes: `book` and `report` (or any class uses the `titlepage`
environment in `\maketitle`)

In the `l3doc` class, it resets the counter of `section` at the beginning of the
`documentation` environment to support the bilingual manuals.

This package is based on the `doc` package and works smoothly under the `l3doc`,
`ltxdoc`, and `article` classes.

Overview
--------

To load this template, write the line

    \usepackage[<options>]{docext}

See `docext.pdf` for more. Happy TeXing!

Issues
------

The issue tracker for `docext` is currently located
[on GitHub](https://github.com/myhsia/docext/issues).

Build status
------------

This project uses [GitHub Actions](https://github.com/features/actions) as a
hosted continuous integration service. For each commit, the build status is
tested using the current release of TeX Live.

_Current build status:_
![build status](https://github.com/myhsia/docext/actions/workflows/test.yaml/badge.svg?branch=main)

Copyright and License
---------------------

Copyright (C) 2026 by Mingyu Xia
[`<myhsia@outlook.com>`](mailto:myhsia@outlook.com)

This work may be distributed and/or modified under the conditions
of the LaTeX Project Public License (LPPL), either version 1.3c of
this license or (at your option) any later version.
The latest version of this license is in

    http://www.latex-project.org/lppl.txt

and version 1.3c or later is part of all distributions of LaTeX
version 2008 or later.

This work has the LPPL maintenance status `maintained`.

The Current Maintainer of this work is **Mingyu Xia**.
%</readme>
%
%<*internal>
\fi
%</internal>
%
%<*package>
%<+!driver>\GetIdInfo $Id: docext.dtx v0.2A 2026-06-13 myhsia<myhsia@outlook.com>$
%<package>  {Extension for documenting the LaTeX source files}
%<package>\ProvidesExplPackage {\ExplFileName}
%<!driver>  {\ExplFileDate} {\ExplFileVersion} {\ExplFileDescription}
%<package>\edef \DocFileDate        {\ExplFileDate}
%<package>\edef \DocFileVersion     {\ExplFileVersion}
%<package>\edef \DocFileDescription {\ExplFileDescription}
%<package>\tl_greplace_all:Nnn \DocFileDate { / } { - }
%</package>
%<*driver>
\documentclass[11pt, letterpaper, cs-break = true]{l3doc}
\usepackage[color = 00498F, ratio = .625]{docext}
\usepackage{microtype, zref-clever}
\usepackage[osf, mono = false]{libertine}
\newcommand \mail[1] {\href{mailto:#1}{\ttfamily #1}}
\makeindex
\begin{document}
  \DocInput{\jobname.dtx}
  \clearpage
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \begin{documentation}
%
% \title{\bfseries
%   The \pkg{docext} Package\thanks{^^A
%     \url{https://ctan.org/pkg/docext},\
%     \url{https://github.com/myhsia/docext}^^A
%   }^^A
% }
% \author{Mingyu Xia\thanks{\mail{xiamingyu@westlake.edu.cn}}}
% \date{Released \DocFileDate\quad \texttt{\DocFileVersion}}
% \maketitle
% \begin{abstract}
%   The \pkg{docext} package is an extension for documenting the \LaTeX\
%   source files. It is based on the \pkg{doc} package and works smoothly under
%   the \cls{l3doc}, \cls{ltxdoc}, and~\cls{article} classes.
% \end{abstract}
%
% \section{Loading \& Configuring the Package}
%
% Write the line in the preamble
% \begin{quote}
%   "\usepackage[options]{docext}"
% \end{quote}
% while the package \meta{options} accepts the following keys\label{pkgopt}
% \begin{keyval}
%   \item [\keys{color}] \val{l3color, HTML}:
%   The color of keys (Default: |black|).
%   \item [\keys{font}] \val{font macros}: Font of the keys.
%   \item [\keys{delimiter}] \val{string}: Delimiter between the keys.
%   \item [\keys{ratio}] \val{fp num}: Ratio of the boxes' widths
%   in~\env{codemo} environment (Default: |0.625|).
% \end{keyval}
% Apart from configuring the package with the package options, users can
% also use the \tn{docextset} function within the preamble and the context.
% \begin{function}[added = 2026-06-07]{\docextset}
%   \begin{syntax}
%     \tn{docextset} \marg{options}
%   \end{syntax}
%   The functions used in this package \emph{after} \tn{docextset} will be
%   influenced.\\
%   The \meta{options} accepts the same keys above.
% \end{function}
%
% \section{User's Interfaces}
%
% \begin{function}[added = 2026-06-07, updated = 2026-06-13]{\keys}
%   \begin{syntax}
%     \tn{keys} \oarg{options} \marg{comma list}
%   \end{syntax}
%   Typeset the keys with specific format.
%   The \meta{options} accepts the \keys{delimiter, font, color} keys referred
%   in~\zcref{pkgopt} and another \keys{emph} key to assign \# of the key will
%   be emphasised.\\
%   The initial value of the \keys{delimiter} key is |,\,\allowbreak| in this
%   function.
% \iffalse
%<*example>
% \fi
\begin{codemo}
  \keys [font = \sl] {keya, keyb, keyc}\\
  \keys [emph = 2, delimiter = \textbar]
        {true, false, not given}
\end{codemo}
% \iffalse
%</example>
% \fi
% \end{function}
% \begin{function}[added = 2026-06-13]{\val}
%   \begin{syntax}
%     \tn{val} \oarg{options} \marg{comma list}
%   \end{syntax}
%   Typeset the value with specific format and surround with \tn{meta}.
%   The \meta{options} accepts the \keys{delimiter, font, color} keys referred
%   in~\zcref{pkgopt}.\\
%   The initial value of the \keys{delimiter} key is \tn{textbar} in this
%   function.
% \end{function}
% \docextset{ratio = .375}
% \begin{function}[added = 2026-06-07]{\TF}
%   Shortcut for typeset Boolean-choice value.
% \iffalse
%<*example>
% \fi
\begin{codemo}
  \TF, \TTF, \TFF.
\end{codemo}
% \iffalse
%</example>
% \fi
% \end{function}
% \begin{function}[added = 2026-06-13]{\ttwd}
% \begin{syntax}
%   \cs{hspace} \cs{\meta{fontsize}ttwd}
% \end{syntax}
% Output the dimension of the width of one typewriter letter.
% The \meta{fontsize} prefix can be chosen as~\keys[emph = 5]{^^A
%   tiny,  scriptsize, footnotesize, small, normalsize,
%   large, Large,      LARGE,        huge,  Huge}.
% \end{function}
% \docextset{ratio = .625}
% \noindent \DescribeEnv{codemo, codemo*}
% Typeset the code on the left hand side and then execute the code in the right
% hand side, while the star version will put the code above the demo.
% \begin{quote}
%  |\begin{codemo(*)}|\\
%  |  Code needs to be typeset in verbatim and demoed|\\
%  |\end{codemo(*)}|
% \end{quote}
% The effect is the same as the demos in the introductions of the functions
% above.
% \noindent \DescribeEnv{keyval}
% Itemize-type environment for typesetting the keys.
% \begin{quote}
% |\begin{keyval}|\\
% |  \item [\keys{keya, keyb, keyc}]\meta{foo}|\\
% |\end{keyval}|
% \end{quote}
% The effect is the same as the package options introduction of~\zcref{pkgopt}
% in this manual.
%
% \end{documentation}
%
% \StopEventually{\PrintIndex}
% \clearpage \appendix
%
% \begin{implementation}
% \section{The source code}
% Using |codedoc| as the namespace.
%    \begin{macrocode}
%<@@=codedoc>
%    \end{macrocode}
% Start the optionlist |package| for \pkg{l3docstrip}.
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
% \begin{variable}
%   {
%     \l__color_named_docolor_prop,
%     \g_@@_keys_font_tl,
%     \g_@@_keys_delimiter_tl,
%     \g_@@_codemo_ratio_fp
%   }
% Key–value definitions of the package options, separate the keys into two
% groups. The first one, |@@ / pkgopt / keys|, is also used in \tn{keys}.
%    \begin{macrocode}
\keys_define:nn { @@ / pkgopt / keys }
  {
    color       .code:n    =
      {
        \color_if_exist:nTF {#1}
          { \color_set:nn  { docolor }          {#1} }
          { \color_set:nnn { docolor } { HTML } {#1} }
      },
      color     .initial:n = { black },
    font        .tl_set:N  = \g_@@_keys_font_tl,
    delimiter   .tl_set:N  = \g_@@_keys_delimiter_tl,
  }
\keys_define:nn { @@ / pkgopt / codemo }
  {
    ratio       .fp_set:N  = \g_@@_codemo_ratio_fp,
      ratio     .initial:n = { .625 },
  }
%    \end{macrocode}
% \end{variable}
% Process the class options.
%    \begin{macrocode}
\ProcessKeyOptions [ @@ / pkgopt / keys,
                     @@ / pkgopt / codemo ]
%    \end{macrocode}
% \begin{macro}{\docextset}
% To control the variables.
%    \begin{macrocode}
\DeclareDocumentCommand \docextset { m }
  {
    \keys_set_known:nn { @@ / pkgopt / keys   } {#1}
    \keys_set_known:nn { @@ / pkgopt / codemo } {#1}
  }
%    \end{macrocode}
% \end{macro}
% Load the dependencies.
%    \begin{macrocode}
\RequirePackage { xcolor, enumitem, verbatim }
%    \end{macrocode}
% Overwrite \tn{prepare@family@series@update} again under \hologo{pLaTeX} and
% \hologo{upLaTeX} to resolve the error raised by |\settowidth \MacroIndent| in
% the \pkg{doc} package.
%    \begin{macrocode}
\bool_lazy_or:nnT { \sys_if_engine_ptex_p: } { \sys_if_engine_uptex_p: }
  {
    \def\prepare@family@series@update#1#2{%
      \def\@currentmetafamily{#1}%
      \if@forced@series
        \fontfamily#2%
      \else
        \expand@font@defaults
        \let\target@series@value\@empty
        \expandafter\edef\csname ??def@ult\endcsname{\f@family}%
        \let\@elt\update@series@target@value
            \@meta@family@list
            \@elt{??}%
        \let\@elt\relax
        \fontfamily#2%
        \ifx\target@series@value\@empty
        \else
          \ifx \f@series\target@series@value
          \else
            \maybe@load@fontshape
            \series@maybe@drop@one@m\target@series@value\f@series
          \fi
        \fi
      \fi
    }
  }
%    \end{macrocode}
% Patch the font of the \env{macrocode} environment.
%    \begin{macrocode}
\hook_gput_code:nnn { cmd / macro@font / after } { . } { \ttfamily }
%    \end{macrocode}
% Patch the macro \tn{meta} in the \cls{l3doc} class and the \pkg{doc} package.
% Since the \cls{l3doc} package has already loaded the \pkg{doc} package,
% a branch is required.
%    \begin{macrocode}
\cs_if_exist:cTF { ver@l3doc.cls }
%    \end{macrocode}
% Under the \cls{l3doc} class, surround \cs{hbox:n} to the argument of the
% kernel function \cs{__codedoc_meta_original:n} of the \tn{meta} macro.
% Suppress the warning raised by \cls{l3doc} (checking l3syntax), and reset the
% counter: |section| at the beginning of the \env{documentation} environment.
%    \begin{macrocode}
  {
    \cs_set_eq:NN \@@_meta_patch:n \@@_meta_original:n
    \cs_set_protected:Npn \@@_meta_original:n #1
      { \@@_meta_patch:n { \hbox:n {#1} } }
    \msg_redirect_module:nnn { l3doc } { warning } { none }
    \hook_gput_code:nnn { env / documentation / before } { . }
      { \setcounter { section } { 0 } }
  }
%    \end{macrocode}
% Under other classes, load the \cls{doc} package then take the same trick as in
% the \cls{l3doc} class.
%    \begin{macrocode}
  {
    \RequirePackage { doc }
    \cs_set_eq:NN \@@_meta_patch:n \meta
    \DeclareDocumentCommand \meta { m }
      { \@@_meta_patch:n { \hbox:n {#1} } }
  }
%    \end{macrocode}
% \begin{macro}{\keys}
% \hologo{LaTeX2e} user's interface for input keys quickly.
%    \begin{macrocode}
\DeclareDocumentCommand \keys { O {} m }
  {
    \group_begin:
      \keys_set_known:nn { @@ / pkgopt / keys }
        { delimiter = { ,\,\allowbreak }, #1 }
      \keys_set_known:nn { @@ / keys          } {#1}
      \@@_keys_aux:nnnnn {#2}
        { \l_@@_keys_emph_int             }
        { \textup \g_@@_keys_delimiter_tl }
        { \g_@@_keys_font_tl \ttfamily    }
        { docolor                         }
      \tl_if_eq:NnT \@currenvir    { keyval }
        { \g_@@_keys_font_tl \ttfamily \, = \, }
    \group_end:
  }
%    \end{macrocode}
% \begin{variable}{\l_@@_keys_emph_int}
% Key–value definitions special for the \tn{keys} macro.
%    \begin{macrocode}
\keys_define:nn { @@ / keys }
  { emph        .int_set:N = \l_@@_keys_emph_int }
%    \end{macrocode}
% \end{variable}
% \end{macro}
% \begin{macro}{\val}
% \hologo{LaTeX2e} user's interface for input value quickly.
%    \begin{macrocode}
\DeclareDocumentCommand \val { O {} m }
  {
    \group_begin:
      \keys_set_known:nn { @@ / pkgopt / keys }
        { delimiter = { \g_@@_vbar_tl \allowbreak }, #1 }
      \meta
        {
          \@@_keys_aux:nnnnn {#2}
            { 0                               }
            { \textup \g_@@_keys_delimiter_tl }
            { \g_@@_keys_font_tl \ttfamily    }
            { docolor                         }
        }
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_keys_aux:nnnnn, \@@_keys_emph:n}
% Auxiliary commands of the \tn{keys} macro.
% \begin{multicols}{2}
% \begin{arguments}
%   \item comma list,
%   \item \# of the element to be emphasised,
%   \item delimiter,
%   \item font,
%   \item color (works only for the key),
% \end{arguments}
% \end{multicols}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_keys_aux:nnnnn #1#2#3#4#5
  {
    \group_begin:
      \seq_set_from_clist:Nn \l_tmpa_seq {#1}
      \int_if_zero:nF {#2}
        {
          \seq_gset_item:Nnn \l_tmpa_seq {#2}
            { \@@_keys_emph:n { \clist_item:nn {#1} {#2} } }
        }
      \seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq
        {
          \color_group_begin:
            \exp_args:No \color_select:n {#5} ##1
          \color_group_end:
        }
      #4 \seq_use:Nn \l_tmpb_seq {#3}
    \group_end:
  }
\cs_new_protected_nopar:Npn \@@_keys_emph:n #1
  {
    \group_begin:
      \upshape \bfseries \exp_args:No \color_select:n { red } #1
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\TF, \TTF, \TFF}
% \hologo{LaTeX2e} user's interface for input Boolean-choice value quickly.
%    \begin{macrocode}
\DeclareDocumentCommand \TF  {} { \@@_keys_TF_aux:n { 0 } }
\DeclareDocumentCommand \TTF {} { \@@_keys_TF_aux:n { 1 } }
\DeclareDocumentCommand \TFF {} { \@@_keys_TF_aux:n { 2 } }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_keys_TF_aux:n}
% Auxiliary commands of the \tn{TF}, \tn{TTF}, \tn{TFF} macros.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_keys_TF_aux:n #1
  {
    \@@_keys_aux:nnnnn
      { \g_@@_true_tl,       \g_@@_false_tl } {#1}
      { \textup \g_@@_vbar_tl } { \ttfamily } { docolor }
  }
%    \end{macrocode}
% \begin{variable}{\g_@@_true_tl, \g_@@_false_tl, \g_@@_vbar_tl}
% Constant variables used in \cs{@@_keys_TF_aux:n}.
%    \begin{macrocode}
\tl_const:Nn \g_@@_true_tl  { true  }
\tl_const:Nn \g_@@_false_tl { false }
\tl_const:Nn \g_@@_vbar_tl
  { \sys_if_engine_opentype:TF { \textbar } { | } }
%    \end{macrocode}
% \end{variable}
% \end{macro}
% \noindent \DescribeEnv{keyval}
% Itemize-type environment for typesetting the keys. Using the interfaces
% provided by the \pkg{enumitem} package.
%    \begin{macrocode}
\newlist{keyval}{itemize}{10}
\setlist[keyval]{leftmargin = 0pt, labelsep = 0pt}
%    \end{macrocode}
% \noindent \DescribeEnv{codemo, codemo*}
% Environment for typesetting the code within a |verbatim| and a |demo|
% environment at the same time.
%    \begin{macrocode}
\DeclareDocumentEnvironment { codemo  } { } { \@@_codemo_start: }
  {
    \@@_codemo_end:Nn \c_false_bool
      { \g_@@_codemo_ratio_fp }
  }
\DeclareDocumentEnvironment { codemo* } { } { \@@_codemo_start: }
  {
    \@@_codemo_end:Nn \c_true_bool
      { \g_@@_codemo_ratio_fp }
  }
%    \end{macrocode}
% \begin{macro}{\@@_codemo_start:, \@@_codemo_end:Nn}
% Auxiliary commands of the \env{codemo} environment.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_codemo_start:
  {
%    \end{macrocode}
% The I/O streams part\footnote{By modifying \href
%   {https://github.com/AlphaZTX/physics2/blob/main/doc/phy2docdef.tex}^^A
%   {@AlphaZTX's \file{phy2docdef.tex}} magically using LaTeX3.}.
%    \begin{macrocode}
    \group_begin:
      \@bsphack
      \iow_open:Nn \l_@@_codemo_iow { \l_@@_codemo_name_tl }
      \let \do \char_set_catcode_other:N
      \dospecials \char_set_catcode_active:N \^^M
      \cs_set:Npn \verbatim@processline
        {
          \exp_args:NNo \iow_now:Nn
            \l_@@_codemo_iow { \int_use:N \verbatim@line }
        }
      \verbatim@start
  }
\cs_new_protected:Npn \@@_codemo_end:Nn #1#2
  {
      \iow_close:N \l_@@_codemo_iow
      \@esphack
    \group_end:
    \char_set_catcode_comment:N \%
    \ior_open:Nn \l_@@_codemo_ior { \l_@@_codemo_name_tl }
    \int_zero:N \l_@@_codemo_int
    \ior_map_inline:Nn \l_@@_codemo_ior
      { \int_incr:N \l_@@_codemo_int }
%    \end{macrocode}
% The typeset part.
%    \begin{macrocode}
    \par \smallskip
    \group_begin:
      \dim_set:Nn \parindent { \c_zero_skip }
      \fbox
        {
          \bool_if:NT #1 { \null \skip_horizontal:n { 2\ttwd } }
          \parbox [ c ] [ \l_@@_codemo_int \baselineskip + .48ex ]
            {
              \fp_eval:n { \bool_if:NTF #1 { 1 } {#2} * .96 }
              \linewidth \bool_if:NT #1 { -.8pt }
            } { \small \verbatiminput \l_@@_codemo_name_tl }
        }
      \bool_if:NTF #1
        { \par \skip_vertical:n { -1.5pt } } { \hfill }
      \fbox
        {
          \null \skip_horizontal:n { 2\ttwd }
          \parbox [ c ] [ \l_@@_codemo_int \baselineskip + .48ex ]
            {
              \fp_eval:n { \bool_if:NTF #1 { 1 } { (1 - #2) } * .96 }
              \linewidth \bool_if:NTF #1 { -.8pt } { - 2\ttwd }
            } { \file_input:n  { \l_@@_codemo_name_tl }    }
        }
      \par \smallskip
    \group_end:
    \char_set_catcode_ignore:N \%
  }
%    \end{macrocode}
% \begin{variable}
%   {
%     \l_@@_codemo_iow,
%     \l_@@_codemo_ior,
%     \l_@@_codemo_int,
%     \l_@@_codemo_name_tl
%   }
% Variables used in \cs{@@_codemo_start:} and \cs{@@_codemo_end:Nn}.
%    \begin{macrocode}
\iow_new:N   \l_@@_codemo_iow
\ior_new:N   \l_@@_codemo_ior
\int_new:N   \l_@@_codemo_int
\tl_const:Nn \l_@@_codemo_name_tl {\jobname.codemo.vrb}
%    \end{macrocode}
% \end{variable}
% \end{macro}
% \begin{macro}{\ttwd}
% Dimensions of the width of one typewriter letter under different fontsizes.
% \begin{variable}{\l_@@_ttwd_box}
% Box for saving one typewriter letter temporally.
%    \begin{macrocode}
\box_new:N \l_@@_ttwd_box
%    \end{macrocode}
% \end{variable}
%    \begin{macrocode}
\clist_map_inline:nn
  {
    tiny,  scriptsize, footnotesize, small, \@empty,
    large, Large,      LARGE,        huge,  Huge
  }
  {
    \dim_new:c { #1 ttwd }
    \cs_new_protected_nopar:cpn { update#1ttwd }
      {
        \hbox_set:Nn \l_@@_ttwd_box { \use:c {#1} \ttfamily x }
        \dim_gset:cn { #1 ttwd } { \box_wd:N \l_@@_ttwd_box }
      }
    \hook_gput_code:nnn { begindocument / before } { . }
      { \use:c { update#1ttwd } }
  }
%    \end{macrocode}
% \end{macro}
% End\hskip\ttwd the optionlist |package| for \pkg{l3docstrip}.
%    \begin{macrocode}
%</package>
%    \end{macrocode}
% Restore the namespace.
%    \begin{macrocode}
%<@@=>
%    \end{macrocode}
% \iffalse
%<*package>
%<!driver>\file_input_stop:
%</package>
% \fi
% \end{implementation}
