• Recognising \end{macrocode}

    From Peter Flynn@21:1/5 to All on Mon Feb 5 00:03:57 2024
    I'm using doc and dox to document a package which includes some XSLT
    code which generates a .dtx file, and therefore includes the strings
    '% \begin{macrocode}' and '% \end{macrocode}' inside the code to
    be documented, eg

    % \begin{macrocode}
    <xsl:text>% \begin{macrocode}&#xa;</xsl:text>
    <xsl:if test="db:constraintdef[db:cmdsynopsis[db:command]]">
    <xsl:for-each select="db:constraintdef/db:cmdsynopsis/db:command">
    <xsl:value-of select="."/>
    <xsl:text>&#xa;</xsl:text>
    </xsl:for-each>
    </xsl:if>
    <xsl:text>% \end{macrocode}&#xa;</xsl:text>
    % \end{macrocode}

    Although the string '% \end{macrocode}' occurs *within* the line, and
    not at the start of the line, it is still being recognised as the end of
    the containing macrocode environment:

    ! Misplaced alignment tab character &.
    l.15885 ... <xsl:text>% \end{macrocode}&
    #xa;</xsl:text>
    I can't figure out why you would want to use a tab mark

    Is there a way to configure doc/dox to recognise the end of the
    environment only when the '% \end{macrocode}' occurs at the beginning
    of a line?

    Peter

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter Flynn@21:1/5 to Peter Flynn on Mon Feb 5 17:03:38 2024
    On 05/02/2024 00:03, Peter Flynn wrote:
    I'm using doc and dox to document a package which includes some XSLT
    code which generates a .dtx file, and therefore includes the
    strings '% \begin{macrocode}' and '% \end{macrocode}' inside
    the code to be documented,
    [...]
    Although the string '% \end{macrocode}' occurs *within* the line,
    and not at the start of the line, it is still being recognised as the
    end of the containing macrocode environment:

    I have managed to create a MWE for this.

    ------------------------------8<------------------------------
    % \iffalse meta-comment
    % A test
    % \fi
    % \iffalse
    %<package>\NeedsTeXFormat{LaTeX2e}[2015/01/01] %<package>\ProvidesPackage{test}[2023/12/30 v1.26
    %<package> Test]
    %<*driver>
    \PassOptionsToPackage{svgnames}{xcolor}
    \documentclass[11pt]{ltxdoc}
    \usepackage{dox}%
    \usepackage{fontspec}%
    \usepackage{xcolor}%
    \usepackage{hypdoc}%
    \hypersetup{linkcolor=DarkGreen,citecolor=DarkRed,
    urlcolor=Blue,colorlinks=true}
    \usepackage{hyperref}%
    \hypersetup{linkcolor=DarkGreen,citecolor=DarkRed,
    urlcolor=Blue,colorlinks=true}
    \hypersetup{pdfauthor={Peter Flynn},
    pdftitle={The test LaTeX2e document package},
    pdfsubject={Testing123},
    pdfkeywords={latex,typesetting},
    pdfproducer={XeLateX with hyperref},
    pdfcreator={Emacs with psgml, ClassPack with Saxon, LaTeX from
    TeX Live}}
    \EnableCrossrefs
    \CodelineIndex
    \RecordChanges
    \begin{document}\raggedright
    \DocInput{test.dtx}
    \end{document}
    %</driver>
    % \fi
    %
    % \CheckSum{7}
    %
    % \CharacterTable
    % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
    % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
    % Digits \0\1\2\3\4\5\6\7\8\9
    % Exclamation \! Double quote \" Hash (number) \#
    % Dollar \$ Percent \% Ampersand \&
    % Acute accent \' Left paren \( Right paren \)
    % Asterisk \* Plus \+ Comma \,
    % Minus \- Point \. Solidus \/
    % Colon \: Semicolon \; Less than \<
    % Equals \= Greater than \> Question mark \?
    % Commercial at \@ Left bracket \[ Backslash \\
    % Right bracket \] Circumflex \^ Underscore \_
    % Grave accent \` Left brace \{ Vertical bar \|
    % Right brace \} Tilde \~}
    %
    % \GetFileInfo{test.dtx}
    % \def\fileversion{1.26}
    % \def\filedate{2023/12/30}
    % \title{The \textsf{test} \LaTeXe\ package\thanks{%
    % This document corresponds to \textsf{test}
    % \textit{v.}\ \fileversion , dated \filedate.}
    % \\[1em]\Large
    % Testing dox/doc
    % \\[1ex]\large
    % on XSLT generating DTX}
    % \author{Peter Flynn}
    % \maketitle
    % \renewcommand{\abstractname}{Summary}\thispagestyle{empty}
    % \begin{abstract}
    % Test
    % \end{abstract}
    % \clearpage
    % \tableofcontents
    % \clearpage
    % \section{Test}
    % Test
    % \clearpage
    % \StopEventually{\label{endcode}%
    % \clearpage
    % \addcontentsline{toc}{section}{Change History}%
    % \label{changehistory}%
    % \PrintChanges
    % \clearpage
    % \label{codeindex}%
    % \addcontentsline{toc}{section}{Index}%
    % \PrintIndex}
    % \iffalse
    %<*package>
    % \fi
    % \clearpage
    % \section{The \textsf{test} macros}
    % \iffalse
    %</package>
    % \fi
    % \iffalse
    %<*testscript>
    % \fi
    % \clearpage
    % \section{The \emph{test.xsl} script}
    % \setcounter{CodelineNo}{0}
    % Now look: this normal usage works fine
    % Identify the file origin, date, time, etc.\par
    % \begin{macrocode}
    <!-- The test.xsl script 24-02-04T21:01:06 -->
    % \end{macrocode}
    % Here we show the XSLT to handle a DocBook <sect1>
    % IMPORTANT: it is supposed to generate the DTX code as-is
    % between <xsl:text> and </xsl:text>
    % \begin{macrocode}
    <xsl:template match="db:sect1">
    <!-- process sect1 content -->
    <xsl:apply-templates/>
    <xsl:if test="@xml:id='options'">
    <xsl:text>% Now invoke the options.\par
    % \iffalse
    %% Now invoke the options.
    % \fi
    % \begin{macrocode}
    \ExecuteOptions{</xsl:text>
    <xsl:value-of
    select="descendant::db:annotation/@xreflabel"/>
    <xsl:text>}
    \ProcessOptions\relax
    % \end{macrocode}&#xa;</xsl:text>
    </xsl:if>
    <xsl:call-template name="checkpackages">
    <xsl:with-param name="pos" select="'after'"/>
    <xsl:with-param name="loc" select="."/>
    </xsl:call-template>
    </xsl:if>
    </xsl:template>
    % \end{macrocode}
    % That's all, folks!
    % \iffalse
    %</db2dtxscript>
    % \fi
    % \Finale
    ------------------------------8<------------------------------

    Cut that out into test.dtx and run through XeLaTeX.

    Peter

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ulrich D i e z@21:1/5 to Peter Flynn on Mon Feb 5 18:55:02 2024
    Peter Flynn wrote:

    I'm using doc and dox to document a package which includes some XSLT code which generates a .dtx file, and therefore includes the strings
    '%    \begin{macrocode}' and '%    \end{macrocode}' inside the code to be documented, eg

    %    \begin{macrocode}
      <xsl:text>%    \begin{macrocode}&#xa;</xsl:text>
       <xsl:if test="db:constraintdef[db:cmdsynopsis[db:command]]">
        <xsl:for-each select="db:constraintdef/db:cmdsynopsis/db:command">       <xsl:value-of select="."/>
          <xsl:text>&#xa;</xsl:text>
        </xsl:for-each>
      </xsl:if>
      <xsl:text>%    \end{macrocode}&#xa;</xsl:text>
    %    \end{macrocode}

    Although the string '%    \end{macrocode}' occurs *within* the line, and not at the start of the line, it is still being recognised as the end of the containing macrocode environment:

    ! Misplaced alignment tab character &.
    l.15885 ...    <xsl:text>%    \end{macrocode}&
                                                      #xa;</xsl:text>
    I can't figure out why you would want to use a tab mark

    Is there a way to configure doc/dox to recognise the end of the environment only when the '%    \end{macrocode}' occurs at the beginning of a line?

    I don't know dox.

    As far as I know, the package doc does not provide facilities for
    configuring such behavior.

    How about patching the environments macrocode and macrocode* of the
    package doc so that you can specify the amount of ending-phrases
    of these environments that should be ignored when scanning for the end
    of an instance of such an environment.

    However, patching these environments is a crucial action as with the development of the package doc the internals of these environments
    may be subject to change so that patching needs to be adapted to those
    changes.

    I assume that the doc package version number v3.0m dated 2022/11/13
    is in use (currently - February 5, 2024 - the most recent one) and
    wrote a patch so that by (re)defining the macro \SkipMacrocodeEndings accordingly you can have these environments ignore as many instances
    of the ending phrase of the environment in question as denoted by \SkipMacrocodeEndings while scanning for the end of that environment.

    Internally this is done by scanning for delimiters
    % \end{macrocode}
    respective
    % \end{macrocode*}
    (tokenized in verbatim catciode-régime with categories of
    spaces and backslashes as determined by the environments)
    and replacing m of category 11(letter) by m of category 12(other)
    so that the delimiter-matching of the mechanism that scans for the
    end of the environment won't match.

    With this patch you can do things like

    % \begingroup
    % \def\SkipMacrocodeEndings{3}
    % \begin{macrocode}
    something
    % \end{macrocode} % 1st ending phrase not considered the end.
    % \end{macrocode} % 2nd ending phrase not considered the end.
    % \end{macrocode} % 3rd ending phrase not considered the end.
    % \end{macrocode} % this ending-phrase is considered the end.
    % \endgroup

    I **think** this patch does not interfere with the indexing-
    and glossary-machineries of the package doc, but be picky anyway
    when checking whether the output is as desired.



    -----[Snip]-Begin of file mytest.tex------------------------------------ %\errorcontextlines=10000

    % Let's create a file myfile.dtx:
    \begin{filecontents*}{myfile.dtx}
    % \begingroup
    % \def\SkipMacrocodeEndings{1}%
    % \begin{macrocode}
    <xsl:text>% \begin{macrocode}&#xa;</xsl:text>
    <xsl:if test="db:constraintdef[db:cmdsynopsis[db:command]]">
    <xsl:for-each select="db:constraintdef/db:cmdsynopsis/db:command">
    <xsl:value-of select="."/>
    <xsl:text>&#xa;</xsl:text>
    </xsl:for-each>
    </xsl:if>
    <xsl:text>% \end{macrocode}&#xa;</xsl:text>
    % \end{macrocode}
    % \endgroup
    \end{filecontents*}

    \documentclass[a4paper]{article}
    \usepackage{doc}

    \makeatletter %=======================================================================
    % \MyReplicate{<amount>}{<tokens>}
    % After triggering two expansion-steps <tokens> are appended to the
    % token stream <amount> times.
    % E.g., \MyReplicate{10}{X} yields XXXXXXXXXX %-----------------------------------------------------------------------
    % Define a TeX-number-quantity of non-positive value \@ifdefinable\MyStopromannumeral{\chardef\MyStopromannumeral=`\^^00}% %-----------------------------------------------------------------------
    % Define Paraphernalia:
    \newcommand\Myfot[2]{#1}%
    \newcommand\Mysot[2]{#2}%
    \newcommand\Myexchg[2]{#2#1}% %-----------------------------------------------------------------------
    % Define the loop:
    \newcommand\MyReplicate[2]{%
    % #1 amount of replications
    % #2 tokens to replicate
    \romannumeral\expandafter\Myexchg
    \expandafter{\romannumeral\number\number#1 000\relax}%
    {\MyReplicateloop{#2}{}}%
    }%
    \newcommand\MyReplicateloop[3]{%
    % #1 tokens to replicate
    % #2 replications gathered so far
    % #3 lowercase letter m or \relax
    \ifx#3\relax\expandafter\Mysot\else\expandafter\Myfot\fi
    {\MyReplicateloop{#1}{#2#1}}%
    {\MyStopromannumeral#2}%
    }%
    %=======================================================================
    % \NeutralizeOneUnstarredEndMacrocode replaces the delimiter
    % % \end{macrocode} by the same but with m of catcode 11 replaced
    % by m of catcode 12. %-----------------------------------------------------------------------
    % \NeutralizeOneStarredEndMacrocode replaces the delimiter
    % % \end{macrocode*} by the same but with m of catcode 11 replaced
    % by m of catcode 12. %----------------------------------------------------------------------- \begingroup
    \catcode`\|=0
    \catcode`\[=1
    \catcode`\]=2
    \catcode`\{=12
    \catcode`\}=12
    \catcode`\%=12
    \catcode`\Y=14
    \catcode`\\=\active
    |def|NeutralizerDefiner#1#2#3#4[Y
    |gdef#1##1%#2#2#2#2\end{macrocode#4}[##1%#2#2#2#2\end{#3acrocode#4}]Y
    ]Y
    |catcode`|m =12Y
    |catcode`| =|active
    |@ifdefinable|NeutralizeOneUnstarredEndMacrocode[Y |NeutralizerDefiner[|NeutralizeOneUnstarredEndMacrocode][ ][m][]Y
    ]Y
    |catcode`| =12Y
    |@ifdefinable|NeutralizeOneStarredEndMacrocode[Y |NeutralizerDefiner[|NeutralizeOneStarredEndMacrocode][ ][m][*]Y
    ]Y
    |endgroup %=======================================================================
    % \NeutralizeInstancesOfUnstarredEndMacrocode{<amount>} replaces
    % <amount> instances of the delimiter % \end{macrocode} by the same
    % but with m of catcode 11 replaced by m of catcode 12. %-----------------------------------------------------------------------
    % \NeutralizeInstancesOfStarredEndMacrocode{<amount>} replaces
    % <amount> instances of the delimiter % \end{macrocode*} by the same
    % but with m of catcode 11 replaced by m of catcode 12. %----------------------------------------------------------------------- \newcommand\NeutralizeInstancesOfUnstarredEndMacrocode[1]{%
    \MyReplicate{#1}{\NeutralizeOneUnstarredEndMacrocode}%
    }%
    \newcommand\NeutralizeInstancesOfStarredEndMacrocode[1]{%
    \MyReplicate{#1}{\NeutralizeOneStarredEndMacrocode}%
    }%
    %=======================================================================
    % Patch the environments macrocode and macrocode* of the package doc
    % so that by redefining the macro \SkipMacrocodeEndings accordingly
    % you can have these environments ignore as many instances of the
    % ending phrase of the environment in question as denoted by
    % \SkipMacrocodeEndings while scanning for the end of that environment. \def\SkipMacrocodeEndings{0}%
    \@namedef{macrocode*}{%
    \macro@code
    \NeutralizeInstancesOfStarredEndMacrocode\SkipMacrocodeEndings
    \sxmacro@code
    }%
    \def\macrocode{%
    \macro@code
    \frenchspacing\@vobeyspaces
    \NeutralizeInstancesOfUnstarredEndMacrocode\SkipMacrocodeEndings
    \xmacro@code
    }%
    \makeatother

    \EnableCrossrefs
    \CodelineIndex

    \begin{document}

    \DocInput{myfile.dtx}

    % Index: makeindex -s gind.ist -o mytest.ind mytest.idx
    % Change-history: makeindex -s gglo.ist -o mytest.gls mytest.glo
    \PrintIndex

    \end{document}
    -----[Snap]-End of file mytest.tex--------------------------------------


    Here you can see an image of the output I get on my system
    when compiling the example above:
    <https://i.stack.imgur.com/azQEv.png>

    Sincerely

    Ulrich

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ulrich D i e z@21:1/5 to Peter Flynn on Mon Feb 5 19:19:42 2024
    Peter Flynn schrieb:

    I have managed to create a MWE for this.
    [...]
    Cut that out into test.dtx and run through XeLaTeX.

    Does the following code do what you want?

    Sincerely

    Ulrich


    % \iffalse meta-comment
    % A test
    % \fi
    % \iffalse
    %<package>\NeedsTeXFormat{LaTeX2e}[2015/01/01] %<package>\ProvidesPackage{test}[2023/12/30 v1.26
    %<package> Test]
    %<*driver>
    \PassOptionsToPackage{svgnames}{xcolor}
    \documentclass[11pt]{ltxdoc}

    \makeatletter %=======================================================================
    % \MyReplicate{<amount>}{<tokens>}
    % After triggering two expansion-steps <tokens> are appended to the
    % token stream <amount> times.
    % E.g., \MyReplicate{10}{X} yields XXXXXXXXXX %-----------------------------------------------------------------------
    % Define a TeX-number-quantity of non-positive value \@ifdefinable\MyStopromannumeral{\chardef\MyStopromannumeral=`\^^00}% %-----------------------------------------------------------------------
    % Define Paraphernalia:
    \newcommand\Myfot[2]{#1}%
    \newcommand\Mysot[2]{#2}%
    \newcommand\Myexchg[2]{#2#1}% %-----------------------------------------------------------------------
    % Define the loop:
    \newcommand\MyReplicate[2]{%
    % #1 amount of replications
    % #2 tokens to replicate
    \romannumeral\expandafter\Myexchg
    \expandafter{\romannumeral\number\number#1 000\relax}%
    {\MyReplicateloop{#2}{}}%
    }%
    \newcommand\MyReplicateloop[3]{%
    % #1 tokens to replicate
    % #2 replications gathered so far
    % #3 lowercase letter m or \relax
    \ifx#3\relax\expandafter\Mysot\else\expandafter\Myfot\fi
    {\MyReplicateloop{#1}{#2#1}}%
    {\MyStopromannumeral#2}%
    }%
    %=======================================================================
    % \NeutralizeOneUnstarredEndMacrocode replaces the delimiter
    % % \end{macrocode} by the same but with m of catcode 11 replaced
    % by m of catcode 12. %-----------------------------------------------------------------------
    % \NeutralizeOneStarredEndMacrocode replaces the delimiter
    % % \end{macrocode*} by the same but with m of catcode 11 replaced
    % by m of catcode 12. %----------------------------------------------------------------------- \begingroup
    \catcode`\|=0
    \catcode`\[=1
    \catcode`\]=2
    \catcode`\{=12
    \catcode`\}=12
    \catcode`\%=12
    \catcode`\Y=14
    \catcode`\\=\active
    |def|NeutralizerDefiner#1#2#3#4[Y
    |gdef#1##1%#2#2#2#2\end{macrocode#4}[##1%#2#2#2#2\end{#3acrocode#4}]Y
    ]Y
    |catcode`|m =12Y
    |catcode`| =|active
    |@ifdefinable|NeutralizeOneUnstarredEndMacrocode[Y |NeutralizerDefiner[|NeutralizeOneUnstarredEndMacrocode][ ][m][]Y
    ]Y
    |catcode`| =12Y
    |@ifdefinable|NeutralizeOneStarredEndMacrocode[Y |NeutralizerDefiner[|NeutralizeOneStarredEndMacrocode][ ][m][*]Y
    ]Y
    |endgroup %=======================================================================
    % \NeutralizeInstancesOfUnstarredEndMacrocode{<amount>} replaces
    % <amount> instances of the delimiter % \end{macrocode} by the same
    % but with m of catcode 11 replaced by m of catcode 12. %-----------------------------------------------------------------------
    % \NeutralizeInstancesOfStarredEndMacrocode{<amount>} replaces
    % <amount> instances of the delimiter % \end{macrocode*} by the same
    % but with m of catcode 11 replaced by m of catcode 12. %----------------------------------------------------------------------- \newcommand\NeutralizeInstancesOfUnstarredEndMacrocode[1]{%
    \MyReplicate{#1}{\NeutralizeOneUnstarredEndMacrocode}%
    }%
    \newcommand\NeutralizeInstancesOfStarredEndMacrocode[1]{%
    \MyReplicate{#1}{\NeutralizeOneStarredEndMacrocode}%
    }%
    %=======================================================================
    % Patch the environments macrocode and macrocode* of the package doc
    % so that by redefining the macro \SkipMacrocodeEndings accordingly
    % you can have these environments ignore as many instances of the
    % ending phrase of the environment in question as denoted by
    % \SkipMacrocodeEndings while scanning for the end of that environment. \def\SkipMacrocodeEndings{0}%
    \@namedef{macrocode*}{%
    \macro@code
    \NeutralizeInstancesOfStarredEndMacrocode\SkipMacrocodeEndings
    \sxmacro@code
    }%
    \def\macrocode{%
    \macro@code
    \frenchspacing\@vobeyspaces
    \NeutralizeInstancesOfUnstarredEndMacrocode\SkipMacrocodeEndings
    \xmacro@code
    }%
    \makeatother

    \usepackage{dox}%
    \usepackage{fontspec}%
    \usepackage{xcolor}%
    \usepackage{hypdoc}%
    \hypersetup{linkcolor=DarkGreen,citecolor=DarkRed,
    urlcolor=Blue,colorlinks=true}
    \usepackage{hyperref}%
    \hypersetup{linkcolor=DarkGreen,citecolor=DarkRed,
    urlcolor=Blue,colorlinks=true}
    \hypersetup{pdfauthor={Peter Flynn},
    pdftitle={The test LaTeX2e document package},
    pdfsubject={Testing123},
    pdfkeywords={latex,typesetting},
    pdfproducer={XeLateX with hyperref},
    pdfcreator={Emacs with psgml, ClassPack with Saxon, LaTeX from TeX Live}}
    \EnableCrossrefs
    \CodelineIndex
    \RecordChanges
    \begin{document}\raggedright
    \DocInput{test.dtx}
    \end{document}
    %</driver>
    % \fi
    %
    % \CheckSum{8}
    %
    % \CharacterTable
    % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
    % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
    % Digits \0\1\2\3\4\5\6\7\8\9
    % Exclamation \! Double quote \" Hash (number) \#
    % Dollar \$ Percent \% Ampersand \&
    % Acute accent \' Left paren \( Right paren \)
    % Asterisk \* Plus \+ Comma \,
    % Minus \- Point \. Solidus \/
    % Colon \: Semicolon \; Less than \<
    % Equals \= Greater than \> Question mark \?
    % Commercial at \@ Left bracket \[ Backslash \\
    % Right bracket \] Circumflex \^ Underscore \_
    % Grave accent \` Left brace \{ Vertical bar \|
    % Right brace \} Tilde \~}
    %
    % \GetFileInfo{test.dtx}
    % \def\fileversion{1.26}
    % \def\filedate{2023/12/30}
    % \title{The \textsf{test} \LaTeXe\ package\thanks{%
    % This document corresponds to \textsf{test}
    % \textit{v.}\ \fileversion , dated \filedate.}
    % \\[1em]\Large
    % Testing dox/doc
    % \\[1ex]\large
    % on XSLT generating DTX}
    % \author{Peter Flynn}
    % \maketitle
    % \renewcommand{\abstractname}{Summary}\thispagestyle{empty}
    % \begin{abstract}
    % Test
    % \end{abstract}
    % \clearpage
    % \tableofcontents
    % \clearpage
    % \section{Test}
    % Test
    % \clearpage
    % \StopEventually{\label{endcode}%
    % \clearpage
    % \addcontentsline{toc}{section}{Change History}%
    % \label{changehistory}%
    % \PrintChanges
    % \clearpage
    % \label{codeindex}%
    % \addcontentsline{toc}{section}{Index}%
    % \PrintIndex}
    % \iffalse
    %<*package>
    % \fi
    % \clearpage
    % \section{The \textsf{test} macros}
    % \iffalse
    %</package>
    % \fi
    % \iffalse
    %<*testscript>
    % \fi
    % \clearpage
    % \section{The \emph{test.xsl} script}
    % \setcounter{CodelineNo}{0}
    % Now look: this normal usage works fine
    % Identify the file origin, date, time, etc.\par
    % \begin{macrocode}
    <!-- The test.xsl script 24-02-04T21:01:06 -->
    % \end{macrocode}
    % Here we show the XSLT to handle a DocBook <sect1>
    % IMPORTANT: it is supposed to generate the DTX code as-is
    % between <xsl:text> and </xsl:text>
    % \begingroup ^^A-----------------------------------------------
    % \def\SkipMacrocodeEndings{1}%
    % \begin{macrocode}
    <xsl:template match="db:sect1">
    <!-- process sect1 content -->
    <xsl:apply-templates/>
    <xsl:if test="@xml:id='options'">
    <xsl:text>% Now invoke the options.\par
    % \iffalse
    %% Now invoke the options.
    % \fi
    % \begin{macrocode}
    \ExecuteOptions{</xsl:text>
    <xsl:value-of
    select="descendant::db:annotation/@xreflabel"/>
    <xsl:text>}
    \ProcessOptions\relax
    % \end{macrocode}&#xa;</xsl:text>
    </xsl:if>
    <xsl:call-template name="checkpackages">
    <xsl:with-param name="pos" select="'after'"/>
    <xsl:with-param name="loc" select="."/>
    </xsl:call-template>
    </xsl:if>
    </xsl:template>
    % \end{macrocode}
    % \endgroup ^^A-------------------------------------------------
    % That's all, folks!
    % \iffalse
    %</db2dtxscript>
    % \fi
    % \Finale

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ulrich D i e z@21:1/5 to Peter Flynn on Mon Feb 5 20:19:45 2024
    [I just realized that the code for macrocode* lacks \relax, so let's fix this:]

    Peter Flynn wrote:

    I'm using doc and dox to document a package which includes some XSLT code which generates a .dtx file, and therefore includes the strings
    '% \begin{macrocode}' and '% \end{macrocode}' inside the code to be documented, eg

    % \begin{macrocode}
    <xsl:text>% \begin{macrocode}&#xa;</xsl:text>
    <xsl:if test="db:constraintdef[db:cmdsynopsis[db:command]]">
    <xsl:for-each select="db:constraintdef/db:cmdsynopsis/db:command">
    <xsl:value-of select="."/>
    <xsl:text>&#xa;</xsl:text>
    </xsl:for-each>
    </xsl:if>
    <xsl:text>% \end{macrocode}&#xa;</xsl:text>
    % \end{macrocode}

    Although the string '% \end{macrocode}' occurs *within* the line, and not at the start of the line, it is still being recognised as the end of the containing macrocode environment:

    ! Misplaced alignment tab character &.
    l.15885 ... <xsl:text>% \end{macrocode}&
    #xa;</xsl:text>
    I can't figure out why you would want to use a tab mark

    Is there a way to configure doc/dox to recognise the end of the environment only when the '% \end{macrocode}' occurs at the beginning of a line?

    I don't know dox.

    As far as I know, the package doc does not provide facilities for
    configuring such behavior.

    How about patching the environments macrocode and macrocode* of the
    package doc so that you can specify the amount of ending-phrases
    of these environments that should be ignored when scanning for the end
    of an instance of such an environment.

    However, patching these environments is a crucial action as with the development of the package doc the internals of these environments
    may be subject to change so that patching needs to be adapted to those
    changes.

    I assume that the doc package version number v3.0m dated 2022/11/13
    is in use (currently - February 5, 2024 - the most recent one) and
    wrote a patch so that by (re)defining the macro \SkipMacrocodeEndings accordingly you can have these environments ignore as many instances
    of the ending phrase of the environment in question as denoted by \SkipMacrocodeEndings while scanning for the end of that environment.

    Internally this is done by scanning for delimiters
    % \end{macrocode}
    respective
    % \end{macrocode*}
    (tokenized in verbatim catciode-régime with categories of
    spaces and backslashes as determined by the environments)
    and replacing m of category 11(letter) by m of category 12(other)
    so that the delimiter-matching of the mechanism that scans for the
    end of the environment won't match.

    With this patch you can do things like

    % \begingroup
    % \def\SkipMacrocodeEndings{3}
    % \begin{macrocode}
    something
    % \end{macrocode} % 1st ending phrase not considered the end.
    % \end{macrocode} % 2nd ending phrase not considered the end.
    % \end{macrocode} % 3rd ending phrase not considered the end.
    % \end{macrocode} % this ending-phrase is considered the end.
    % \endgroup

    I **think** this patch does not interfere with the indexing-
    and glossary-machineries of the package doc, but be picky anyway
    when checking whether the output is as desired.



    -----[Snip]-Begin of file mytest.tex------------------------------------ %\errorcontextlines=10000

    % Let's create a file myfile.dtx:
    \begin{filecontents*}{myfile.dtx}
    % \begingroup
    % \def\SkipMacrocodeEndings{1}%
    % \begin{macrocode}
    <xsl:text>% \begin{macrocode}&#xa;</xsl:text>
    <xsl:if test="db:constraintdef[db:cmdsynopsis[db:command]]">
    <xsl:for-each select="db:constraintdef/db:cmdsynopsis/db:command">
    <xsl:value-of select="."/>
    <xsl:text>&#xa;</xsl:text>
    </xsl:for-each>
    </xsl:if>
    <xsl:text>% \end{macrocode}&#xa;</xsl:text>
    % \end{macrocode}
    % \endgroup
    \end{filecontents*}

    \documentclass[a4paper]{article}
    \usepackage{doc}

    \makeatletter %=======================================================================
    % \MyReplicate{<amount>}{<tokens>}
    % After triggering two expansion-steps <tokens> are appended to the
    % token stream <amount> times.
    % E.g., \MyReplicate{10}{X} yields XXXXXXXXXX %-----------------------------------------------------------------------
    % Define a TeX-number-quantity of non-positive value \@ifdefinable\MyStopromannumeral{\chardef\MyStopromannumeral=`\^^00}% %-----------------------------------------------------------------------
    % Define Paraphernalia:
    \newcommand\Myfot[2]{#1}%
    \newcommand\Mysot[2]{#2}%
    \newcommand\Myexchg[2]{#2#1}% %-----------------------------------------------------------------------
    % Define the loop:
    \newcommand\MyReplicate[2]{%
    % #1 amount of replications
    % #2 tokens to replicate
    \romannumeral\expandafter\Myexchg
    \expandafter{\romannumeral\number\number#1 000\relax}%
    {\MyReplicateloop{#2}{}}%
    }%
    \newcommand\MyReplicateloop[3]{%
    % #1 tokens to replicate
    % #2 replications gathered so far
    % #3 lowercase letter m or \relax
    \ifx#3\relax\expandafter\Mysot\else\expandafter\Myfot\fi
    {\MyReplicateloop{#1}{#2#1}}%
    {\MyStopromannumeral#2}%
    }%
    %=======================================================================
    % \NeutralizeOneUnstarredEndMacrocode replaces the delimiter
    % % \end{macrocode} by the same but with m of catcode 11 replaced
    % by m of catcode 12. %-----------------------------------------------------------------------
    % \NeutralizeOneStarredEndMacrocode replaces the delimiter
    % % \end{macrocode*} by the same but with m of catcode 11 replaced
    % by m of catcode 12. %----------------------------------------------------------------------- \begingroup
    \catcode`\|=0
    \catcode`\[=1
    \catcode`\]=2
    \catcode`\{=12
    \catcode`\}=12
    \catcode`\%=12
    \catcode`\Y=14
    \catcode`\\=\active
    |def|NeutralizerDefiner#1#2#3#4[Y
    |gdef#1##1%#2#2#2#2\end{macrocode#4}[##1%#2#2#2#2\end{#3acrocode#4}]Y
    ]Y
    |catcode`|m =12|relaxY
    |catcode`| =|activeY
    |@ifdefinable|NeutralizeOneUnstarredEndMacrocode[Y |NeutralizerDefiner[|NeutralizeOneUnstarredEndMacrocode][ ][m][]Y
    ]Y
    |catcode`| =12|relaxY
    |@ifdefinable|NeutralizeOneStarredEndMacrocode[Y |NeutralizerDefiner[|NeutralizeOneStarredEndMacrocode][ ][m][*]Y
    ]Y
    |endgroup %=======================================================================
    % \NeutralizeInstancesOfUnstarredEndMacrocode{<amount>} replaces
    % <amount> instances of the delimiter % \end{macrocode} by the same
    % but with m of catcode 11 replaced by m of catcode 12. %-----------------------------------------------------------------------
    % \NeutralizeInstancesOfStarredEndMacrocode{<amount>} replaces
    % <amount> instances of the delimiter % \end{macrocode*} by the same
    % but with m of catcode 11 replaced by m of catcode 12. %----------------------------------------------------------------------- \newcommand\NeutralizeInstancesOfUnstarredEndMacrocode[1]{%
    \MyReplicate{#1}{\NeutralizeOneUnstarredEndMacrocode}%
    }%
    \newcommand\NeutralizeInstancesOfStarredEndMacrocode[1]{%
    \MyReplicate{#1}{\NeutralizeOneStarredEndMacrocode}%
    }%
    %=======================================================================
    % Patch the environments macrocode and macrocode* of the package doc
    % so that by redefining the macro \SkipMacrocodeEndings accordingly
    % you can have these environments ignore as many instances of the
    % ending phrase of the environment in question as denoted by
    % \SkipMacrocodeEndings while scanning for the end of that environment. \def\SkipMacrocodeEndings{0}%
    \@namedef{macrocode*}{%
    \macro@code
    \NeutralizeInstancesOfStarredEndMacrocode\SkipMacrocodeEndings
    \sxmacro@code
    }%
    \def\macrocode{%
    \macro@code
    \frenchspacing\@vobeyspaces
    \NeutralizeInstancesOfUnstarredEndMacrocode\SkipMacrocodeEndings
    \xmacro@code
    }%
    \makeatother

    \EnableCrossrefs
    \CodelineIndex

    \begin{document}

    \DocInput{myfile.dtx}

    % Index: makeindex -s gind.ist -o mytest.ind mytest.idx
    % Change-history: makeindex -s gglo.ist -o mytest.gls mytest.glo
    \PrintIndex

    \end{document}
    -----[Snap]-End of file mytest.tex--------------------------------------


    Here you can see an image of the output I get on my system
    when compiling the example above:
    <https://i.stack.imgur.com/azQEv.png>

    Sincerely

    Ulrich

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ulrich D i e z@21:1/5 to Peter Flynn on Mon Feb 5 20:23:17 2024
    [I just realized that the code for macrocode* lacks \relax, so let's fix this:]

    Peter Flynn wrote:

    I have managed to create a MWE for this.
    [...]
    Cut that out into test.dtx and run through XeLaTeX.

    Does the following code do what you want?

    Sincerely

    Ulrich


    % \iffalse meta-comment
    % A test
    % \fi
    % \iffalse
    %<package>\NeedsTeXFormat{LaTeX2e}[2015/01/01] %<package>\ProvidesPackage{test}[2023/12/30 v1.26
    %<package> Test]
    %<*driver>
    \PassOptionsToPackage{svgnames}{xcolor}
    \documentclass[11pt]{ltxdoc}

    \makeatletter %=======================================================================
    % \MyReplicate{<amount>}{<tokens>}
    % After triggering two expansion-steps <tokens> are appended to the
    % token stream <amount> times.
    % E.g., \MyReplicate{10}{X} yields XXXXXXXXXX %-----------------------------------------------------------------------
    % Define a TeX-number-quantity of non-positive value \@ifdefinable\MyStopromannumeral{\chardef\MyStopromannumeral=`\^^00}% %-----------------------------------------------------------------------
    % Define Paraphernalia:
    \newcommand\Myfot[2]{#1}%
    \newcommand\Mysot[2]{#2}%
    \newcommand\Myexchg[2]{#2#1}% %-----------------------------------------------------------------------
    % Define the loop:
    \newcommand\MyReplicate[2]{%
    % #1 amount of replications
    % #2 tokens to replicate
    \romannumeral\expandafter\Myexchg
    \expandafter{\romannumeral\number\number#1 000\relax}%
    {\MyReplicateloop{#2}{}}%
    }%
    \newcommand\MyReplicateloop[3]{%
    % #1 tokens to replicate
    % #2 replications gathered so far
    % #3 lowercase letter m or \relax
    \ifx#3\relax\expandafter\Mysot\else\expandafter\Myfot\fi
    {\MyReplicateloop{#1}{#2#1}}%
    {\MyStopromannumeral#2}%
    }%
    %=======================================================================
    % \NeutralizeOneUnstarredEndMacrocode replaces the delimiter
    % % \end{macrocode} by the same but with m of catcode 11 replaced
    % by m of catcode 12. %-----------------------------------------------------------------------
    % \NeutralizeOneStarredEndMacrocode replaces the delimiter
    % % \end{macrocode*} by the same but with m of catcode 11 replaced
    % by m of catcode 12. %----------------------------------------------------------------------- \begingroup
    \catcode`\|=0
    \catcode`\[=1
    \catcode`\]=2
    \catcode`\{=12
    \catcode`\}=12
    \catcode`\%=12
    \catcode`\Y=14
    \catcode`\\=\active
    |def|NeutralizerDefiner#1#2#3#4[Y
    |gdef#1##1%#2#2#2#2\end{macrocode#4}[##1%#2#2#2#2\end{#3acrocode#4}]Y
    ]Y
    |catcode`|m =12|relaxY
    |catcode`| =|activeY
    |@ifdefinable|NeutralizeOneUnstarredEndMacrocode[Y |NeutralizerDefiner[|NeutralizeOneUnstarredEndMacrocode][ ][m][]Y
    ]Y
    |catcode`| =12|relaxY
    |@ifdefinable|NeutralizeOneStarredEndMacrocode[Y |NeutralizerDefiner[|NeutralizeOneStarredEndMacrocode][ ][m][*]Y
    ]Y
    |endgroup %=======================================================================
    % \NeutralizeInstancesOfUnstarredEndMacrocode{<amount>} replaces
    % <amount> instances of the delimiter % \end{macrocode} by the same
    % but with m of catcode 11 replaced by m of catcode 12. %-----------------------------------------------------------------------
    % \NeutralizeInstancesOfStarredEndMacrocode{<amount>} replaces
    % <amount> instances of the delimiter % \end{macrocode*} by the same
    % but with m of catcode 11 replaced by m of catcode 12. %----------------------------------------------------------------------- \newcommand\NeutralizeInstancesOfUnstarredEndMacrocode[1]{%
    \MyReplicate{#1}{\NeutralizeOneUnstarredEndMacrocode}%
    }%
    \newcommand\NeutralizeInstancesOfStarredEndMacrocode[1]{%
    \MyReplicate{#1}{\NeutralizeOneStarredEndMacrocode}%
    }%
    %=======================================================================
    % Patch the environments macrocode and macrocode* of the package doc
    % so that by redefining the macro \SkipMacrocodeEndings accordingly
    % you can have these environments ignore as many instances of the
    % ending phrase of the environment in question as denoted by
    % \SkipMacrocodeEndings while scanning for the end of that environment. \def\SkipMacrocodeEndings{0}%
    \@namedef{macrocode*}{%
    \macro@code
    \NeutralizeInstancesOfStarredEndMacrocode\SkipMacrocodeEndings
    \sxmacro@code
    }%
    \def\macrocode{%
    \macro@code
    \frenchspacing\@vobeyspaces
    \NeutralizeInstancesOfUnstarredEndMacrocode\SkipMacrocodeEndings
    \xmacro@code
    }%
    \makeatother

    \usepackage{dox}%
    \usepackage{fontspec}%
    \usepackage{xcolor}%
    \usepackage{hypdoc}%
    \hypersetup{linkcolor=DarkGreen,citecolor=DarkRed,
    urlcolor=Blue,colorlinks=true}
    \usepackage{hyperref}%
    \hypersetup{linkcolor=DarkGreen,citecolor=DarkRed,
    urlcolor=Blue,colorlinks=true}
    \hypersetup{pdfauthor={Peter Flynn},
    pdftitle={The test LaTeX2e document package},
    pdfsubject={Testing123},
    pdfkeywords={latex,typesetting},
    pdfproducer={XeLateX with hyperref},
    pdfcreator={Emacs with psgml, ClassPack with Saxon, LaTeX from TeX Live}}
    \EnableCrossrefs
    \CodelineIndex
    \RecordChanges
    \begin{document}\raggedright
    \DocInput{test.dtx}
    \end{document}
    %</driver>
    % \fi
    %
    % \CheckSum{8}
    %
    % \CharacterTable
    % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
    % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
    % Digits \0\1\2\3\4\5\6\7\8\9
    % Exclamation \! Double quote \" Hash (number) \#
    % Dollar \$ Percent \% Ampersand \&
    % Acute accent \' Left paren \( Right paren \)
    % Asterisk \* Plus \+ Comma \,
    % Minus \- Point \. Solidus \/
    % Colon \: Semicolon \; Less than \<
    % Equals \= Greater than \> Question mark \?
    % Commercial at \@ Left bracket \[ Backslash \\
    % Right bracket \] Circumflex \^ Underscore \_
    % Grave accent \` Left brace \{ Vertical bar \|
    % Right brace \} Tilde \~}
    %
    % \GetFileInfo{test.dtx}
    % \def\fileversion{1.26}
    % \def\filedate{2023/12/30}
    % \title{The \textsf{test} \LaTeXe\ package\thanks{%
    % This document corresponds to \textsf{test}
    % \textit{v.}\ \fileversion , dated \filedate.}
    % \\[1em]\Large
    % Testing dox/doc
    % \\[1ex]\large
    % on XSLT generating DTX}
    % \author{Peter Flynn}
    % \maketitle
    % \renewcommand{\abstractname}{Summary}\thispagestyle{empty}
    % \begin{abstract}
    % Test
    % \end{abstract}
    % \clearpage
    % \tableofcontents
    % \clearpage
    % \section{Test}
    % Test
    % \clearpage
    % \StopEventually{\label{endcode}%
    % \clearpage
    % \addcontentsline{toc}{section}{Change History}%
    % \label{changehistory}%
    % \PrintChanges
    % \clearpage
    % \label{codeindex}%
    % \addcontentsline{toc}{section}{Index}%
    % \PrintIndex}
    % \iffalse
    %<*package>
    % \fi
    % \clearpage
    % \section{The \textsf{test} macros}
    % \iffalse
    %</package>
    % \fi
    % \iffalse
    %<*testscript>
    % \fi
    % \clearpage
    % \section{The \emph{test.xsl} script}
    % \setcounter{CodelineNo}{0}
    % Now look: this normal usage works fine
    % Identify the file origin, date, time, etc.\par
    % \begin{macrocode}
    <!-- The test.xsl script 24-02-04T21:01:06 -->
    % \end{macrocode}
    % Here we show the XSLT to handle a DocBook <sect1>
    % IMPORTANT: it is supposed to generate the DTX code as-is
    % between <xsl:text> and </xsl:text>
    % \begingroup ^^A-----------------------------------------------
    % \def\SkipMacrocodeEndings{1}%
    % \begin{macrocode}
    <xsl:template match="db:sect1">
    <!-- process sect1 content -->
    <xsl:apply-templates/>
    <xsl:if test="@xml:id='options'">
    <xsl:text>% Now invoke the options.\par
    % \iffalse
    %% Now invoke the options.
    % \fi
    % \begin{macrocode}
    \ExecuteOptions{</xsl:text>
    <xsl:value-of
    select="descendant::db:annotation/@xreflabel"/>
    <xsl:text>}
    \ProcessOptions\relax
    % \end{macrocode}&#xa;</xsl:text>
    </xsl:if>
    <xsl:call-template name="checkpackages">
    <xsl:with-param name="pos" select="'after'"/>
    <xsl:with-param name="loc" select="."/>
    </xsl:call-template>
    </xsl:if>
    </xsl:template>
    % \end{macrocode}
    % \endgroup ^^A-------------------------------------------------
    % That's all, folks!
    % \iffalse
    %</db2dtxscript>
    % \fi
    % \Finale

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter Flynn@21:1/5 to Ulrich D i e z on Fri Feb 16 09:43:53 2024
    On 05/02/2024 17:55, Ulrich D i e z wrote:
    Peter Flynn wrote:
    [...]
    Is there a way to configure doc/dox to recognise the end of the environment only when the '%    \end{macrocode}' occurs at the beginning of a line?

    I don't know dox.

    As far as I know, the package doc does not provide facilities for
    configuring such behavior.

    How about patching the environments macrocode and macrocode* of the
    package doc so that you can specify the amount of ending-phrases of
    these environments that should be ignored when scanning for the end
    of an instance of such an environment.

    Thank you for the code, very useful and interesting. In fact there is
    another solution, and that's to change the XSLT code so that it outputs
    percent and four spaces in one xsl:text, and '{macrocode}' in another.
    The result is the same, but it means there is no chance of the code
    being misinterpreted.

    Peter
    "When in doubt, change the data"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)