% \iffalse
%
%% File: l3galley.dtx
%
% Copyright (C) 1999-2001,2004-2009 Frank Mittelbach
%           (C) 2010-2025 The LaTeX Project
%
% It 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 the file
%
%    https://www.latex-project.org/lppl.txt
%
% This file is part of the "l3experimental bundle" (The Work in LPPL)
% and all files in that bundle must be distributed together.
%
% -----------------------------------------------------------------------
%
% The development version of the bundle can be found at
%
%    https://github.com/latex3/latex3
%
% for those people who are interested.
%
%<*driver|package>
% The version of expl3 required is tested as early as possible, as
% some really old versions do not define \ProvidesExplPackage.
\RequirePackage{expl3}[2018/02/21]
%<package>\@ifpackagelater{expl3}{2018/02/21}
%<package>  {}
%<package>  {%
%<package>    \PackageError{l3galley}{Support package l3kernel too old}
%<package>      {%
%<package>        Please install an up to date version of l3kernel\MessageBreak
%<package>        using your TeX package manager or from CTAN.\MessageBreak
%<package>        \MessageBreak
%<package>        Loading l3galley will abort!%
%<package>      }%
%<package>    \endinput
%<package>  }
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{l3galley} package\\ Galley code^^A
% }
%
% \author{^^A
%  The \LaTeX{} Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released 2025-06-30}
%
% \maketitle
%
% \begin{documentation}
%
% \section{Introduction}
%
% In \LaTeX3 terminology a galley is a rectangular area which receives
% text and other material filling it from top. The vertically extend of
% a galley is normally not restricted: instead certain chunks are taken
% off the top of an already partially filled galley to form columns or
% similar areas on a page. This process is typically asynchronous but
% there are ways to control or change its behavior.
%
% Examples for galleys are \enquote{the main galley}, where the
% continuous document data gets formatted into  and from which columns
% and pages are constructed, and \enquote{vertical box galleys}, such
% as the body of a minipage environment. The latter galleys are
% typically not split after formatting, though there can be exceptions.
%
% \section{Formatting layers}
%
% The present module is mainly concerned with the formatting of text
% in galleys. The mechanism by which this is achieved uses four
% (somewhat) distinct layers, some of which can be addressed using the
% templates provided here.
%
% \subsection{Layer one: external dimensions}
%
% The bottom layer of the system is the external dimensions of the
% galley. Normally only the horizontal dimension is fixed externally,
% while the vertical (filling) dimension is unspecified. The external
% dimensions are fixed when starting a new galley, and are therefore
% not modifiable within the galley.
%
% There are no templates for setting this layer directly, although the
% external values are influenced by other parts of the system (for
% example when creating minipage environments).
%
% \subsection{Layer two: internal dimensions}
%
% The second layer is the internal dimensions of the galley: the
% \emph{measure} used for paragraph text and the position of the
% paragraph relative to the edges of the galley.
%
% This layer is normally accessed by higher-level templates
% \emph{via} the object type \texttt{measure}. Changes made using
% level two templates will often extend for large parts of a document
% (up to and including the entire document).
%
% \subsection{Layer three: paragraph shape}
%
% The third layer defines the paragraph shape within the measure as
% provided by the second layer. In the absence of any specification
% for that layer the paragraph shape used will be that of a
% rectangular area of the width of the current measure.
%
% There are some restrictions imposed on the shape of a paragraph by the
% underlying \TeX{} mechanisms. For example, cut out sections in
% paragraphs can be specified from the top of the paragraph but not from
% the bottom.
%
% \subsection{Layer four: formatting inside the paragraph}
%
% The forth layer deals with the paragraph formatting aspects such as
% hyphenation and justification within the paragraph (this is sometimes
% referred to as \enquote{\texttt{h\&j}} or \enquote{\texttt{hj}}). This
% layer is somewhat distinct from the galley as such, but is handled in
% the same place as there is, internally, interaction between the different
% layers.
%
% \section{Code interfaces}
%
% \subsection{Galley layers}
%
% \begin{variable}{\l_galley_width_dim}
%   The total width of a galley, set either by the page geometry code
%   for the main vertical galley or when creating an independent galley,
%   such as a minipage.
% \end{variable}
%
% \begin{function}{\galley_level:}
%   \begin{syntax}
%     \cs{galley_level:}
%   \end{syntax}
%   Sets up a vertical box to contain a new galley level. The box should
%   include \enquote{wrapper} group (be \enquote{color safe}): this is
%   automatically true for all \LaTeX3 boxes and coffins.
% \end{function}
%
% \subsection{Measure}
%
% \begin{function}
%   {\galley_margins_set_absolute:nn, \galley_margins_set_relative:nn}
%   \begin{syntax}
%     \cs{galley_margins_set_absolute:nn} \Arg{left margin} \Arg{right margin}
%     \cs{galley_margins_set_relative:nn} \Arg{left margin} \Arg{right margin}
%   \end{syntax}
%   Sets the width of the measure to have the \meta{left margin} and
%   \meta{right margin} specified by the arguments, both of which are
%   \meta{dimension expressions}. The \texttt{relative} function will adjust
%   the text width within any existing margins, whereas the \texttt{absolute}
%   measure sets the margins based on the edges of the galley only. One or
%   both of the \meta{margins} may be negative, to specify and outdent.
% \end{function}
%
% \subsection{Between paragraphs}
%
% \begin{variable}{\g_galley_previous_par_lines_int}
%   The number of lines in the preceding conceptual paragraph. This may not
%   correspond to the \TeX{} \tn{prevgraf} primitive value as one conceptual
%   paragraph may contain several \TeX{} \tn{par} primitive tokens.
% \end{variable}
%
% \begin{variable}{\g_galley_restore_running_tl}
%   When galley settings need to be reset at the end of a paragraph, the
%   appropriate detail should be added to this token list. It is inserted
%   immediately before the start of each paragraph, and can therefore be
%   used to clear otherwise global settings. The token list itself is
%   also cleared as part of this process.
% \end{variable}
%
% \begin{variable}{\g_galley_no_break_next_bool}
%   Indicates that no page break should be allowed between the current
%   paragraph and the next paragraph.
% \end{variable}
%
% \begin{function}{\g_galley_omit_next_indent_bool}
%   Indicates that the indent should be omitted from the start of the next
%   paragraph started.
% \end{function}
%
% \begin{variable}{\l_galley_interpar_penalty_int}
%   The \meta{penalty} for a break between paragraphs. The \meta{penalty}
%   should be in the range $-10\,000$ to $10\,000$, where $-10\,000$ forces a
%   page break, $0$ has no effect at all and  $10\,000$ forbids a page break.
%   Note that setting \cs{g_galley_no_break_next_bool} to \texttt{true}
%   will override any setting of \cs{l_galley_interpar_penalty_int}.
% \end{variable}
%
% \begin{variable}{\l_galley_interpar_vspace_skip}
%   Stretchable space to be inserted between paragraphs, set at the design
%   or template level.
% \end{variable}
%
% \begin{function}{\galley_penalty_set_single:n}
%   \begin{syntax}
%     \cs{galley_penalty_set_single:n} \Arg{penalty}
%     \cs{galley_penalty_add_single:n} \Arg{penalty}
%   \end{syntax}
%   Sets the \meta{penalty} for a break between the current and next
%   paragraph on a one-off basis. This function is intended for user-level
%   adjustments to design, and takes precedent over both settings from
%   \cs{l_galley_interpar_penalty_int} and from \cs{galley_no_break_next:}.
%   The \texttt{add} variant adds the penalty to any existing values.
% \end{function}
%
% \begin{function}
%   {
%     \galley_vspace_set_single:n ,
%     \galley_vspace_add_single:n ,
%     \galley_vspace_max_single:n
%   }
%   \begin{syntax}
%     \cs{galley_vspace_set_single:n} \Arg{space}
%   \end{syntax}
%   Sets the \meta{space} to be inserted between the current and next
%   paragraph on a one-off basis. This function is intended for user-level
%   adjustments to design. The \texttt{add} and \texttt{max} variants add
%   to the existing spacing and set to the maximum of the existing value
%   and the argument, respectively.
% \end{function}
%
% \subsection{Paragraph shape}
%
% \begin{function}
%   {
%     \galley_parshape_set_multi:nnnN,
%     \galley_parshape_set_multi:nVVN,
%     \galley_parshape_set_single:nnnN,
%     \galley_parshape_set_single:nVVN
%   }
%   \begin{syntax}
%     \cs{galley_parshape_set_multi:nnnN} \Arg{unaltered lines} \Arg{left indents} \Arg{right indents} \meta{resume flag}
%     \cs{galley_parshape_set_single:nnnN} \Arg{unaltered lines} \Arg{left indents} \Arg{right indents} \meta{resume flag}
%   \end{syntax}
%   Sets the current paragraph shape to create an arbitrary paragraph shape.
%   The paragraph shape is set such that there are \meta{unaltered lines} which
%   have width and indent as set by the measure. The \enquote{altered} lines
%   are then defined by the comma-separated lists of \meta{left indents} and
%   \meta{right indents}. These are both indents from the edge of the measure,
%   and may be negative, and should both contain the same number of items.
%   If the \meta{resume flag} is \texttt{true}, after the last
%   altered line the paragraph shape returns to that of the measure. On the
%   other hand, if the flag is \texttt{false} then the shape of the last line
%   is retained for the rest of the paragraph.
%   For example,
%   \begin{verbatim}
%     \galley_parshape_set_multi:nnnN { 1 }
%       { 2 pt , 4 pt , 6 pt } { 2 pt , 4 pt , 6 pt } \c_true_bool
%   \end{verbatim}
%   would create a paragraph shape in which the first line is the full
%   width of the measure, the second line is indented by $2$\,pt on each side,
%   the third line by $4$\,pt and the fourth line and subsequent lines by
%   $6$\,pt from the edge of the measure on each side.
%
%   The \texttt{single} version applies only to a single paragraph,
%   while the \texttt{multi} function sets the paragraph shape on an
%   ongoing basis within the scope of the current \TeX{} group.
% \end{function}
%
% \begin{function}
%   {
%     \galley_cutout_left:nn,
%     \galley_cutout_right:nn
%   }
%   \begin{syntax}
%     \cs{galley_cutout_left:nn} \Arg{unaltered lines} \Arg{indents}
%     \cs{galley_cutout_right:nn} \Arg{unaltered lines} \Arg{indents}
%   \end{syntax}
%   Adds a cutout section to the active paragraph shape, leaving
%   \meta{unaltered lines} unchanged and then applying the \meta{indents}
%   (a comma list). The cutout will be placed on the left or right as indicated
%   by the function name, and will apply to exactly the number of lines
%   specified (the total of the \meta{unaltered lines} and the number of
%   entries in the \meta{indents} list). Several cutouts may be applied
%   sequentially: these act in an additive sense.
% \end{function}
%
% \subsection{Formatting inside the paragraph}
%
% The settings described here apply \enquote{inside} the paragraph, and so
% are active irrespective of any paragraph shape within the measure.
%
% \begin{variable}{\l_galley_line_left_skip, \l_galley_line_right_skip}
%   Stretchable space added to the appropriate side each line in a paragraph.
% \end{variable}
%
% \begin{variable}{\l_galley_par_begin_skip, \l_galley_par_end_skip}
%   Stretchable space added to the beginning of the first line and end of
%   the last line of a paragraph, respectively.
% \end{variable}
%
% \begin{variable}{\l_galley_par_indent_dim}
%   Fixed space added to the start of each paragraph except for those where
%   \cs{g_galley_omit_next_indent_bool} is \texttt{true}.
% \end{variable}
%
% \begin{variable}{\l_galley_last_line_fit_int}
%   Determines how the inter-word stretch is set for the last line of a
%   paragraph when
%   \begin{enumerate}
%     \item the value of \cs{l_galley_par_end_skip} contains an infinite
%       (\texttt{fil(l)}) component;
%     \item the values of \cs{l_galley_line_left_skip} and
%       \cs{l_galley_line_right_skip} do \emph{not} contain an infinite
%       (\texttt{fil(l)}) component.
%   \end{enumerate}
%   Under these circumstances, \cs{l_galley_last_line_fit_int} is active, and
%   applies as follows:
%   \begin{itemize}
%     \item when set to~$0$, the last line of the paragraph is set with
%       the inter-word spacing at natural width;
%    \item when set to a $1000$ (or above), the inter-word spacing in the last
%      line is stretched by the same factor as that applied to the penultimate
%      line;
%    \item when set to~$n$ between these extremes, the inter-word spacing in
%      the last line is stretched by $n/1000$ times the factor used for the
%      penultimate line.
%   \end{itemize}
% \end{variable}
%
% \begin{function}{\galley_interword_spacing_set:N}
%   \begin{syntax}
%     \cs{galley_interword_spacing_set:N} \meta{fixed spacing bool}
%   \end{syntax}
%   Sets the inter-word spacing used based on the values supplied by the
%   current font. If the \meta{fixed spacing bool} flag is \texttt{true} then
%   no stretch is permitted between words, otherwise the stretch specified by
%   the font designer is used.
% \end{function}
%
% \subsection{Display material}
%
% Material which is set in \enquote{display-style} require additional settings
% to control the relationship with the surrounding material.
%
% \begin{function}{\galley_display_begin:, \galley_display_end:}
%   \begin{syntax}
%     \cs{galley_display_begin:}
%       \ldots
%     \cs{galley_display_end:}
%   \end{syntax}
%   Sets up a group to contain display-style material. Unlike an independent
%   galley level, settings are inherited from the surroundings. However,
%   the interaction of a display block with the paragraphs before and after it
%   can be adjusted independent of the design of text.
% \end{function}
%
% \subsection{Hyphenation}
%
% \begin{variable}{\l_galley_hyphen_left_int}
%   THIS IS A HACK: SEE CODE!
% \end{variable}
%
% \subsection{Line breaking}
%
% \begin{variable}{\l_galley_binop_penalty_int}
%   Penalty charged if an inline math formula is broken at a
%   binary operator.
% \end{variable}
%
% \begin{variable}{\l_galley_double_hyphen_demerits_int}
%   Extra demerit charge of two (or more) lines in succession end
%   in a hyphen.
% \end{variable}
%
% \begin{variable}{\l_galley_emergency_stretch_skip}
%   Additional stretch assumed for each line if no better line breaking
%   can be found without it. This stretch is not actually added to lines,
%   so its use may result in underfull box warnings.
% \end{variable}
%
% \begin{variable}{\l_galley_final_hyphen_demerits_int}
%   Extra demerit charge if the second last line is hyphenated.
% \end{variable}
%
% \begin{variable}{\l_galley_linebreak_badness_int}
%   Boundary that if exceeded will cause \TeX{} to report an
%   underfull line.
% \end{variable}
%
% \begin{variable}{\l_galley_linebreak_fuzz_dim}
%   Boundary below which overfull lines are not reported.
% \end{variable}
%
% \begin{variable}{\l_galley_linebreak_penalty_int}
%   Extra penalty charged per line in the paragraph. By making
%   this penalty higher \TeX{} will try harder to produce compact
%   paragraphs.
% \end{variable}
%
% \begin{variable}{\l_galley_linebreak_pretolerance_int}
%   Maximum tolerance allowed for individual lines to break the
%   paragraph without attempting hyphenation.
% \end{variable}
%
% \begin{variable}{\l_galley_linebreak_tolerance_int}
%   Maximum tolerance allowed for individual lines when breaking a
%   paragraph while attempting hyphenation (if this limit can't be
%   met \cs{l_galley_emergency_stretch_skip} comes into play).
% \end{variable}
%
% \begin{variable}{\l_galley_mismatch_demerits_int}
%   Extra demerit charge if two visually incompatible lines follow
%   each other.
% \end{variable}
%
% \begin{variable}{\l_galley_relation_penalty_int}
%   Penalty charged if an inline math formula is broken at a
%   relational symbol.
% \end{variable}
%
% \begin{function}{\galley_break_line:Nn}
%   \begin{syntax}
%     \cs{galley_break_line:Nn} \meta{boolean} \Arg{dimexpr}
%   \end{syntax}
%   Breaks the current line, filling the remaining space with \texttt{fil}
%   glue. If the \meta{boolean} is \texttt{true} then a page break is possible
%   after the broken line. Vertical space as given by the \meta{dimexpr} will
%   be inserted between the broken line and the next line.
% \end{function}
%
% \subsection{Paragraph breaking}
%
% \begin{variable}{\l_galley_parbreak_badness_int}
%   Boundary that if exceeded will cause \TeX{} to report an
%   underfull vertical box.
% \end{variable}
%
% \begin{variable}{\l_galley_parbreak_fuzz_dim}
%   Boundary below which overfull vertical boxes are not reported.
% \end{variable}
%
% \begin{variable}{\l_galley_broken_penalty_int}
%   Penalty for page breaking after a hyphenated line.
% \end{variable}
%
% \begin{variable}{\l_galley_pre_display_penalty_int}
%   Penalty for breaking between immediately before display math material.
% \end{variable}
%
% \begin{variable}{\l_galley_post_display_penalty_int}
%   Penalty for breaking between immediately after display math material.
% \end{variable}
%
% \begin{function}
%   {
%     \galley_club_penalties_set:n,
%     \galley_club_penalties_set:V,
%     \galley_club_penalties_set:v,
%     \galley_display_club_penalties_set:n,
%     \galley_display_club_penalties_set:V,
%     \galley_display_club_penalties_set:v,
%     \galley_display_widow_penalties_set:n,
%     \galley_display_widow_penalties_set:V,
%     \galley_display_widow_penalties_set:v,
%     \galley_widow_penalties_set:n,
%     \galley_widow_penalties_set:V,
%     \galley_widow_penalties_set:v
%   }
%   \begin{syntax}
%     \cs{galley_club_penalties_set:n} \Arg{penalty list}
%   \end{syntax}
%   Set the penalties for breaking lines at the beginning and end of
%   (partial) paragraphs. In each case, the \meta{penalty list} is a
%   comma-separated list of penalty values. The list applies as follows:
%   \begin{itemize}
%     \item[\texttt{club}] Penalties for breaking after the first, second,
%       third, etc.~line of the paragraph.
%     \item[\texttt{display_club}] Penalties for breaking after the first,
%       second, third, etc.~line after a display math environment.
%     \item[\texttt{display_club}] Penalties for breaking before the last,
%       penultimate, antepenultimate, etc.~line before a display
%       math environment.
%     \item[\texttt{widow}] Penalties for breaking before the last,
%       penultimate, antepenultimate, etc.~line of the paragraph.
%   \end{itemize}
%   In all cases, these penalties apply in addition to the general interline
%   penalty or to any \enquote{special} line penalties.
% \end{function}
%
% \begin{function}{\galley_interline_penalty_set:n}
%   \begin{syntax}
%     \cs{galley_interline_penalty_set:n} \Arg{penalty}
%   \end{syntax}
%   Sets the standard interline penalty applied between lines of a paragraph.
%   This value is added to any (display) club or widow penalty in force.
% \end{function}
%
% \begin{function}
%   {
%     \galley_interline_penalties_set:n,
%     \galley_interline_penalties_set:V
%   }
%   \begin{syntax}
%     \cs{galley_interline_penalties_set:n} \Arg{penalty list}
%   \end{syntax}
%   Sets \enquote{special} interline penalties to be used in place of
%   the standard value, specified as a comma-separated \meta{penalty list}.
%   The \meta{penalties} apply to the first, second, third, etc.~line
%   of the paragraph.
% \end{function}
%
% \begin{function}
%   {
%     \galley_save_club_penalties:N,
%     \galley_save_display_club_penalties:N,
%     \galley_save_display_widow_penalties:N,
%     \galley_save_interline_penalties:N,
%     \galley_save_widow_penalties:N
%   }
%   \begin{syntax}
%     \cs{galley_save_club_penalties:N} \Arg{comma list}
%   \end{syntax}
%   These functions save the current value of the appropriate penalty to the
%   comma list specified, within the current \TeX{} group.
% \end{function}
%
% \begin{function}[EXP]{\galley_interline_penalty:}
%   \begin{syntax}
%     \cs{galley_interline_penalty:}
%   \end{syntax}
%   Expands to the current interline penalty as a \meta{integer denotation}.
% \end{function}
%
% \section{Hooks and insertion points}
%
% \begin{variable}{\g_galley_par_begin_hook_tl}
%   Token list inserted at the beginning of every paragraph in horizontal mode.
%   This is inserted after any paragraph indent but before any other horizontal
%   mode material.
% \end{variable}
%
% \begin{variable}{\g_galley_par_end_hook_tl}
%   Token list inserted at the end of every paragraph in horizontal mode.
% \end{variable}
%
% \begin{variable}{\g_galley_par_reset_hook_tl}
%   Token list inserted after each paragraph. This is used for resetting
%   galley parameters, and is therefore cleared after use. It is inserted
%   in vertical mode and must not contain horizontal mode material.
% \end{variable}
%
% \begin{variable}{\g_galley_whatsit_next_tl}
%   Token list for whatsits to be inserted at the very beginning of the next
%   paragraph started.
% \end{variable}
%
% \begin{variable}{\g_galley_whatsit_previous_tl}
%   Token list for whatsits to be inserted at the very end of the last
%   paragraph started.
% \end{variable}
%
% \section{Paragraphs}
%
% \begin{function}{\galley_par:}
%   \begin{syntax}
%     \cs{galley_par:}
%   \end{syntax}
%   Finalizes the material collected as the last paragraph, inserts tokens
%   at the start of the new paragraph, setting paragraph shape and any
%   special values as required.
% \end{function}
%
% \begin{function}{\galley_par:n}
%   \begin{syntax}
%     \cs{galley_par:n} \Arg{tokens}
%   \end{syntax}
%   Adds the \meta{tokens} to the material collected for the last paragraph
%   before finalizing it in the usual way. This function should
%   therefore be the \emph{first} non-expandable entry used when a function
%   needs to add tokens to the preceding paragraph.
% \end{function}
%
% \section{Information variables}
%
% Some of the variables for the galley mechanism may be of
% interest to the programmer. These should all be treated as read-only
% values and accessed only through the defined interfaces described above.
%
% \begin{variable}{\l_galley_total_left_margin_dim}
%   The total margin between the left side of the galley and the left side of
%   the text block. This may be negative if the measure is set to overlap
%   the text beyond the edge of the galley.
% \end{variable}
%
% \begin{variable}{\l_galley_total_right_margin_dim}
%   The total margin between the right side of the galley and the right side
%   of the text block. This may be negative if the measure is set to overlap
%   the text beyond the edge of the galley.
% \end{variable}
%
% \begin{variable}{\l_galley_text_width_dim}
%   The width of a line of text within the galley, taking account of
%   any margins added. This may be larger than \cs{l_galley_width_dim}
%   if the margins are negative.
% \end{variable}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3galley} implementation}
%
% At the implementation level, there are a number of challenges which
% have to be overcome in order to make the galley easy to use at the
% designer and user levels. Inserting material into the main vertical
% list is in many ways an irreversible operation. Inserting items as
% they appear in the source is therefore not desirable. Instead,
% inserting vertical-mode material needs to be delayed until the start
% of the \enquote{next} paragraph. This is particularly notable for
% invisible items such as whatsits and specials, which will otherwise
% cause changes in spacing. Delaying insertion enables user-supplied
% settings to override design settings in a reliable fashion. This can
% be achieved as the design-level material can be ignored if a user
% value is supplied. There is a need to allow proper nesting of
% galleys, which means that all of the above needs to be set up so that
% it can be saved and restored. All of these manipulations require
% altering the meaning of the \cs{par} token, which is particularly
% awkward as \TeX{} inserts a token \emph{called} \cs{par} rather than
% one with a particular meaning. This makes moving \cs{par} to somewhere
% \enquote{safe} extremely challenging.
%
% Added to all of this complexity, there is a need to deal with
% \enquote{display-like} material. The most obvious example is the way
% lists are handled. These use \cs{par} tokens to achieve the correct
% appearance, but at the same time
% \begin{verbatim}
%   Text
%   \begin{itemize}
%     \item An item
%   \end{itemize}
%   More text
% \end{verbatim}
% should form one visual paragraph while
% \begin{verbatim}
%   Text
%   \begin{itemize}
%     \item An item
%   \end{itemize}
%
%   More text
% \end{verbatim}
% should be shown as two paragraphs. This requires an additional level
% of handling so that the \cs{par} token used to end the list in the
% first case does not start a new paragraph in a visual sense while the
% second does.
%
% Another factor to bear in mind is that \cs{tex_everypar:D} may be
% executed inside a group. For example, a paragraph starting
% \begin{verbatim}
%   {Text} here
% \end{verbatim}
% will insert the tokens such that the current group level is $1$
% higher for \enquote{Text} than for \enquote{here}. The result of this
% is that it's very important to watch how flags are set and reset. This
% can only be done reliably on a global level, which then has a knock-on
% effect on the rest of the implementation.
%
% At a \TeX{} level, settings can only apply to the current paragraph,
% but conceptually there is a need to allow for both single-paragraph
% and \enquote{running} settings. Whenever the code switches galley
% level both of these need to be correctly saved.
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=galley>
%    \end{macrocode}
%
%    \begin{macrocode}
\ProvidesExplPackage{l3galley}{2025-06-30}{}
  {L3 Experimental galley code}
%    \end{macrocode}
%
% \subsection{Scratch variables}
%
% \begin{variable}{\l_@@_tmp_int}
% \begin{variable}{\g_@@_tmpa_seq, \g_@@_tmpb_seq, \l_@@_tmp_seq}
% \begin{variable}{\l_@@_tmp_tl}
%   Used for manipulating cutouts and paragraph shapes.
%    \begin{macrocode}
\int_new:N \l_@@_tmp_int
\seq_new:N \g_@@_tmpa_seq
\seq_new:N \g_@@_tmpb_seq
\seq_new:N \l_@@_tmp_seq
\tl_new:N \l_@@_tmp_tl
%    \end{macrocode}
% \end{variable}
% \end{variable}
% \end{variable}
%
% \subsection{Galley settings}
%
% Settings for application by the galley respect the usual \TeX{} grouping and
% so are all local variables.
%
% \begin{variable}{\g_@@_cutout_active_bool, \g_@@_cutout_active_bool}
%    \begin{macrocode}
\bool_new:N \g_@@_cutout_active_bool
\bool_new:N \l_@@_cutout_active_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {\l_@@_cutout_left_indent_seq, \l_@@_cutout_right_indent_seq}
%   Essentially scratch space, used when setting up a cutout in a paragraph,
%   but named as there is quite a bit to do in that code.
%    \begin{macrocode}
\seq_new:N \l_@@_cutout_left_indent_seq
\seq_new:N \l_@@_cutout_right_indent_seq
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_parshape_multipar_bool}
%   Indicates whether the paragraph shape in use applies to one paragraph
%   only or to more than one.
%    \begin{macrocode}
\bool_new:N \l_@@_parshape_multipar_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {\l_@@_parshape_left_indent_seq, \l_@@_parshape_right_indent_seq}
%   Used to convert user input comma lists into sequences for mapping, and also
%   to keep the information on paragraph shape available for the case where a
%   cutout is also active.
%    \begin{macrocode}
\seq_new:N \l_@@_parshape_left_indent_seq
\seq_new:N \l_@@_parshape_right_indent_seq
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_galley_text_width_dim}
%   The width of the current measure: the \enquote{running} setting can be
%   inherited from \LaTeXe{}.
%    \begin{macrocode}
\cs_new_eq:NN \l_galley_text_width_dim \linewidth
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {\l_galley_total_left_margin_dim, \l_galley_total_right_margin_dim}
%   Margins of the current text within the galley: these plus the galley
%   width are one way to define the measure width. See also the text width,
%   which is an alternative view (and should be in sync with this one!).
%    \begin{macrocode}
\cs_new_eq:NN \l_galley_total_left_margin_dim \@totalleftmargin
\dim_new:N \l_galley_total_right_margin_dim
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {\l_galley_interpar_penalty_int, \l_galley_interpar_vspace_skip}
%   Items between paragraphs at the design level.
%    \begin{macrocode}
\int_new:N \l_galley_interpar_penalty_int
\skip_new:N \l_galley_interpar_vspace_skip
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_galley_width_dim}
%   The external size of a galley is the stored in the \TeX{} primitive
%   \cs{tex_hsize:D}, which is renamed. This will only ever be reset by
%   the code constructing a new galley, for example the start of a
%   minipage. This value will be set for the main galley by the page
%   layout system.
%    \begin{macrocode}
\cs_new_eq:NN \l_galley_width_dim \tex_hsize:D
%    \end{macrocode}
% \end{variable}
%
% \subsection{Galley data structures}
%
% In contrast to settings, the data structures used by the galley are all set
% globally. To allow different galley levels to exist, a local variant is
% defined for each one to save the value when starting a new level.
%
% \begin{variable}{\g_@@_begin_level_bool, \l_@@_begin_level_bool}
%   Indicates that the galley is at the very beginning of the level, and that
%   no material has yet been set. As a result, the global version is set
%   \texttt{true} to begin with.
%    \begin{macrocode}
\bool_new:N \g_@@_begin_level_bool
\bool_new:N \l_@@_begin_level_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {
%     \g_@@_cutout_left_seq,  \l_@@_cutout_left_seq,
%     \g_@@_cutout_right_seq, \l_@@_cutout_right_seq
%   }
%   To apply cutouts across paragraphs, they need to be tracked. The
%   information has to be global, so is handled here.
%    \begin{macrocode}
\seq_new:N \g_@@_cutout_left_seq
\seq_new:N \l_@@_cutout_left_seq
\seq_new:N \g_@@_cutout_right_seq
\seq_new:N \l_@@_cutout_right_seq
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {\g_galley_omit_next_indent_bool, \l_@@_omit_next_indent_bool}
%   A global flag is needed for suppressing indentation of the next
%   paragraph. This does not need a \enquote{running} version since that
%   should be handled using the \texttt{justification} object: the two
%   concepts are related but not identical. The flag here is needed in
%   cases such as the very first paragraph in a galley or immediately
%   following a heading.
%    \begin{macrocode}
\bool_new:N \g_galley_omit_next_indent_bool
\bool_new:N \l_@@_omit_next_indent_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_galley_no_break_next_bool, \l_@@_no_break_next_bool}
%   Dealing with the no-break flag is pretty much the same as the case
%   for the indent: this applies on a single paragraph basis.
%    \begin{macrocode}
\bool_new:N \g_galley_no_break_next_bool
\bool_new:N \l_@@_no_break_next_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {
%     \g_galley_par_begin_hook_tl, \l_@@_par_begin_hook_tl,
%     \g_galley_par_end_hook_tl,   \l_@@_par_end_hook_tl,
%   }
%   Hooks for user-level code: these are not used by the galley itself.
%    \begin{macrocode}
\tl_new:N \g_galley_par_begin_hook_tl
\tl_new:N \l_@@_par_begin_hook_tl
\tl_new:N \g_galley_par_end_hook_tl
\tl_new:N \l_@@_par_end_hook_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {\g_galley_par_reset_hook_tl, \l_@@_par_reset_hook_tl}
%   This one is used by the galley: it happens \enquote{after} the current
%   paragraph, and is used for reset purposes.
%    \begin{macrocode}
\tl_new:N \g_galley_par_reset_hook_tl
\tl_new:N \l_@@_par_reset_hook_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {
%     \g_galley_previous_par_lines_int, \l_@@_previous_par_lines_int,
%     \g_@@_current_par_lines_int, \l_@@_current_par_lines_int
%   }
%   The number of lines in the previous typeset paragraph. This is reset at
%   the start of the paragraph and \emph{added to} when each \cs{tex_par:D}
%   primitive is used: \LaTeX{} uses the primitive in places that do not end
%   a (conceptual) paragraph. There is also a set of variables to deal with
%   the current (conceptual) paragraph, so that the information can be
%   build up correctly.
%    \begin{macrocode}
\int_new:N \g_galley_previous_par_lines_int
\int_new:N \l_@@_previous_par_lines_int
\int_new:N \g_@@_current_par_lines_int
\int_new:N \l_@@_current_par_lines_int
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_galley_restore_running_tl, \l_@@_restore_running_tl}
%   When a parameter is altered from the \enquote{running} value to a
%   different \enquote{current} one, there needs to be a method to restore
%   the \enquote{running} value. This is done by adding the necessary
%   assignment to a token list, which can be executed when needed. At the
%   same time, this information is itself part of the galley parameter
%   structure, and so there has to be a local save version.
%    \begin{macrocode}
\tl_new:N \g_galley_restore_running_tl
\tl_new:N \l_@@_restore_running_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {
%     \g_galley_whatsit_next_tl, \l_@@_whatsit_next_tl,
%     \g_galley_whatsit_previous_tl, \l_@@_whatsit_previous_tl
%   }
%   Whatsits only apply on a per-paragraph basis and so there is no need
%   to differentiate between current and running values. However, there
%   is a need to differentiate between whatsits that attach to the
%   previous (completed) paragraph and those that attach to the next
%   paragraph.
%    \begin{macrocode}
\tl_new:N \g_galley_whatsit_next_tl
\tl_new:N \l_@@_whatsit_next_tl
\tl_new:N \g_galley_whatsit_previous_tl
\tl_new:N \l_@@_whatsit_previous_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {\g_@@_interpar_penalty_user_tl, \l_@@_interpar_penalty_user_tl}
%   The user may want to over-ride the penalty for a break between
%   paragraphs, for example to prevent a break when the overall design
%   allows one. This is handled using an additional penalty.
%    \begin{macrocode}
\tl_new:N \g_@@_interpar_penalty_user_tl
\tl_new:N \l_@@_interpar_penalty_user_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {\g_@@_interpar_vspace_user_tl, \l_@@_interpar_vspace_user_tl}
%   Arbitrary vertical space can be inserted by the user on a one-off
%   basis. This is used in place of any running space between paragraphs.
%    \begin{macrocode}
\tl_new:N \g_@@_interpar_vspace_user_tl
\tl_new:N \l_@@_interpar_vspace_user_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\c_@@_max_penalty_int}
%   \enquote{Infinite} penalty.
%    \begin{macrocode}
\int_const:Nn \c_@@_max_penalty_int { 10000 }
%    \end{macrocode}
% \end{variable}
%
% \subsection{Independent galley levels}
%
% As well as the main vertical list, independent galleys are required
% for items such as minipages and marginal notes. Each of these galleys
% requires an independent set of global data structures. This is
% achieved by storing the data structures in \emph{local} variables. The
% later are only used to save and restore the global value, and so \TeX{}
% grouping will manage the values correctly. This implies that each
% galley level must form a group: galley levels are tied to vertical
% boxes and so this is a reasonable requirements.
%
% \begin{variable}{\l_@@_group_level_int}
%   The top group level for the galley needs to be known to allow
%   some data structures to be reset correctly: they can only be
%   fully cleared at the outer level.
%    \begin{macrocode}
\int_new:N \l_@@_group_level_int
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_initialize_variables:}
%   At the start of a galley level the global variables need to be reset to
%   standard values. For example, the measure is set to the galley width and
%   any paragraph shape is cleared.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_initialize_variables:
  {
    \int_set:Nn \l_@@_group_level_int { \tex_currentgrouplevel:D }
    \bool_gset_true:N \g_@@_begin_level_bool
    \bool_gset_false:N \g_@@_cutout_active_bool
    \seq_gclear:N \g_@@_cutout_left_seq
    \seq_gclear:N \g_@@_cutout_right_seq
    \tl_gclear:N \g_@@_interpar_penalty_user_tl
    \tl_gclear:N \g_@@_interpar_vspace_user_tl
    \bool_gset_true:N \g_galley_omit_next_indent_bool
    \bool_gset_false:N \g_galley_no_break_next_bool
    \tl_gclear:N \g_galley_par_begin_hook_tl
    \tl_gclear:N \g_galley_par_end_hook_tl
    \tl_gclear:N \g_galley_par_reset_hook_tl
    \int_gzero:N \g_@@_current_par_lines_int
    \int_gzero:N \g_galley_previous_par_lines_int
    \tl_gclear:N \g_galley_restore_running_tl
    \tl_gclear:N \g_galley_whatsit_previous_tl
    \tl_gclear:N \g_galley_whatsit_next_tl
  }
\@@_initialize_variables:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_initialize_settings:}
%   This sets the local values of the various galley settings. The
%   flag \cs{l_@@_parshape_multipar_bool} is set \texttt{true} here
%   as it allows an efficiency saving in parshape setting: only
%   when it is actively set \texttt{false} is action needed.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_initialize_settings:
  {
    \bool_set_true:N \l_@@_parshape_multipar_bool
    \seq_clear:N \l_@@_parshape_left_indent_seq
    \seq_clear:N \l_@@_parshape_right_indent_seq
    \dim_set_eq:NN \l_galley_text_width_dim \l_galley_width_dim
    \dim_zero:N \l_galley_total_left_margin_dim
    \dim_zero:N \l_galley_total_right_margin_dim
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_save_parameters:, \@@_restore_parameters:}
%   Saving and restoring parameters is carried out by a series of copy
%   functions.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_save_parameters:
  {
    \bool_set_eq:NN \l_@@_begin_level_bool
      \g_@@_begin_level_bool
    \bool_set_eq:NN \l_@@_cutout_active_bool
      \g_@@_cutout_active_bool
    \seq_set_eq:NN \l_@@_cutout_left_seq
      \g_@@_cutout_left_seq
    \seq_set_eq:NN \l_@@_cutout_right_seq
      \g_@@_cutout_right_seq
    \tl_set_eq:NN \l_@@_interpar_penalty_user_tl
      \g_@@_interpar_penalty_user_tl
    \tl_set_eq:NN \l_@@_interpar_vspace_user_tl
      \g_@@_interpar_vspace_user_tl
    \bool_set_eq:NN \l_@@_omit_next_indent_bool
      \g_galley_omit_next_indent_bool
    \bool_set_eq:NN \l_@@_no_break_next_bool
      \g_galley_no_break_next_bool
    \tl_set_eq:NN \l_@@_par_begin_hook_tl
      \g_galley_par_begin_hook_tl
    \tl_set_eq:NN \l_@@_par_end_hook_tl
      \g_galley_par_end_hook_tl
    \tl_set_eq:NN \l_@@_par_reset_hook_tl
      \g_galley_par_reset_hook_tl
    \int_set_eq:NN \l_@@_current_par_lines_int
      \g_@@_current_par_lines_int
    \int_set_eq:NN \l_@@_previous_par_lines_int
      \g_galley_previous_par_lines_int
    \tl_set_eq:NN \l_@@_restore_running_tl
      \g_galley_restore_running_tl
    \tl_set_eq:NN \l_@@_whatsit_previous_tl
      \g_galley_whatsit_previous_tl
    \tl_set_eq:NN \l_@@_whatsit_next_tl
      \g_galley_whatsit_next_tl
  }
\cs_new_protected:Npn \@@_restore_parameters:
  {
    \bool_gset_eq:NN \g_@@_begin_level_bool
      \l_@@_begin_level_bool
    \bool_gset_eq:NN \g_@@_cutout_active_bool
      \l_@@_cutout_active_bool
    \seq_gset_eq:NN \g_@@_cutout_left_seq
      \l_@@_cutout_left_seq
    \seq_gset_eq:NN \g_@@_cutout_right_seq
      \l_@@_cutout_right_seq
    \tl_gset_eq:NN \g_@@_interpar_penalty_user_tl
      \l_@@_interpar_penalty_user_tl
    \tl_gset_eq:NN \g_@@_interpar_vspace_user_tl
      \l_@@_interpar_vspace_user_tl
    \bool_gset_eq:NN \g_galley_omit_next_indent_bool
      \l_@@_omit_next_indent_bool
    \bool_gset_eq:NN \g_galley_no_break_next_bool
      \l_@@_no_break_next_bool
    \tl_gset_eq:NN \g_galley_par_begin_hook_tl
      \l_@@_par_begin_hook_tl
    \tl_gset_eq:NN \g_galley_par_end_hook_tl
      \l_@@_par_end_hook_tl
    \tl_gset_eq:NN \g_galley_par_reset_hook_tl
      \l_@@_par_reset_hook_tl
    \int_gset_eq:NN \g_@@_current_par_lines_int
      \l_@@_current_par_lines_int
    \int_gset_eq:NN \g_galley_previous_par_lines_int
      \l_@@_previous_par_lines_int
    \tl_gset_eq:NN \g_galley_restore_running_tl
      \l_@@_restore_running_tl
    \tl_gset_eq:NN \g_galley_whatsit_previous_tl
      \l_@@_whatsit_previous_tl
    \tl_gset_eq:NN \g_galley_whatsit_next_tl
      \l_@@_whatsit_next_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\galley_level:}
% \begin{macro}{\@@_level_end:}
%   Galley levels are created by saving all of the current global
%   settings, starting a group then initializing both the local and global
%   variables.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_level:
  {
    \@@_save_parameters:
    \group_begin:
      \@@_initialize_variables:
      \@@_initialize_settings:
      \group_insert_after:N \@@_level_end:
  }
%    \end{macrocode}
%   At the end of the level, the global values are restored using the
%   saved \emph{local} versions, hence the position of the close-of-group
%   instruction. As this code can be inserted automatically, at the point
%   of use only the start of a galley level needs to be marked up: the end
%   must come in a fixed location. All of this relies on the
%   \enquote{color safe} group used inside a box.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_level_end:
  {
      \par
      \@@_restore_parameters:
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{The \cs{par} token}
%
% \begin{variable}{\s_@@_par_omit}
%   Used to indicate that a paragraph should be omitted.
%    \begin{macrocode}
\scan_new:N \s_@@_par_omit
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\galley_par:}
% \begin{macro}{\@@_par_auxi:, \@@_par_auxii:, \@@_par_auxiii:}
% \begin{macro}{\@@_par_aux:N}
% \begin{macro}{\@@_par_update_cutout:}
%   The idea here is to expand the next token in exactly the same way as \TeX{}
%   would do anyway. The \texttt{f}-type expansion will ignore any protection,
%   but will stop at a scan marker. Thus the code can test for an
%   \enquote{omit paragraph} marker.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_par:
  {
    \s_@@_par_omit
    \exp_after:wN \@@_par_auxi: \exp:w \exp_end_continue_f:w
  }
\cs_new_protected:Npn \@@_par_auxi:
  {
    \peek_meaning:NTF \s_@@_par_omit
      { \@@_par_aux:N }
      { \@@_par_auxii: }
  }
\cs_new_protected:Npn \@@_par_aux:N #1
  {
    \str_if_eq:nnF {#1} { \s_@@_par_omit }
      {
        \@@_par_auxii:
        #1
      }
  }
%    \end{macrocode}
%   No marker, so really insert a paragraph: the \cs{tex_par:D} is inside a
%   group to preserve some dynamic settings (for example
%   \cs{tex_interlinepenalties:D}). In vertical mode, that means just
%   inserting the primitive.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_par_auxii:
  {
    \mode_if_vertical:TF
      {
        \group_begin:
          \tex_par:D
        \group_end:
      }
%    \end{macrocode}
%   In horizontal mode, after the end-of-paragraph hook we check if there
%   is a cutout active. If there is, the paragraph shape has to be set.
%   Inserting \cs{tex_par:D} will then carry out the typesetting
%   operation. Once the paragraph has been typeset, the number of lines is
%   added to the running total. It's possible that the conceptual paragraph
%   contains display-like material, and simply setting the number of lines
%   equal to \cs{tex_prevgraf:D} would lose these.
%    \begin{macrocode}
      {
        \g_galley_par_end_hook_tl
        \bool_if:NT \g_@@_cutout_active_bool
          { \@@_parshape_set: }
        \group_begin:
          \tex_par:D
        \group_end:
        \int_gset:Nn \g_galley_previous_par_lines_int
          { \tex_prevgraf:D + \g_@@_current_par_lines_int }
        \int_gzero:N \g_@@_current_par_lines_int
        \bool_if:NF \l_@@_parshape_multipar_bool
          {
            \seq_clear:N \l_@@_parshape_left_indent_seq
            \seq_clear:N \l_@@_parshape_right_indent_seq
            \bool_set_true:N \l_@@_parshape_multipar_bool
            \@@_parshape_set:
          }
        \@@_par_update_cutout:
      }
    \g_galley_par_reset_hook_tl
    \tl_gclear:N \g_galley_par_reset_hook_tl
%    \end{macrocode}
%   The non-breaking penalty is needed here as within the \cs{tex_everypar:D}
%   hook there is an additional \cs{tex_par:D}. This leads to an extra
%   \cs{tex_parskip:D}, which will leave an unwanted break-point here
%   otherwise.
%    \begin{macrocode}
    \tex_penalty:D \c_@@_max_penalty_int
  }
%    \end{macrocode}
%   Once a cutout has been set, properly tidying up needs some work. The
%   cutout is applied \enquote{just in time} at the start of each paragraph
%   (see above). After the paragraph, the consumed lines are removed from
%   the tracking sequences and the paragraph shape is reset. The latter step
%   is required as we do not set the paragraph shape for every paragraph.
%   Once the two sequences are empty, there is no cutout to apply. However,
%   it can still be \enquote{active}. If a cutout is started then we have a
%   group, it is possible for the cutout to be entirely applied before the
%   end of the group. At that point, the two sequences show there is nothing
%   to do \emph{but} the active paragraph shape still has some lines indented.
%   As we avoid setting the \tn{parshape} primitive for every paragraph,
%   the result of only checking the sequences would be that the cutout would
%   reappear after the group! Instead, we use a boolean and only set it
%   false once the group level is that of the galley itself. (There is a slight
%   inefficiency here in that we thus do set the paragraph shape for each
%   paragraph after a cutout until we reach the top group level of the galley.
%   That should be an acceptable hit given the extra work needed to track
%   reset-in-this-group as well.)
%    \begin{macrocode}
\cs_new_protected:Npn \@@_par_update_cutout:
  {
    \bool_lazy_and:nnF
      { \seq_if_empty_p:N \g_@@_cutout_left_seq }
      { \seq_if_empty_p:N \g_@@_cutout_right_seq }
      {
        \prg_replicate:nn \tex_prevgraf:D
          {
            \seq_gpop_left:NN \g_@@_cutout_left_seq  \l_@@_tmp_tl
            \seq_gpop_left:NN \g_@@_cutout_right_seq \l_@@_tmp_tl
          }
        \@@_parshape_set:
      }
    \int_compare:nNnT \l_@@_group_level_int = \tex_currentgrouplevel:D
      {
        \bool_lazy_and:nnT
          { \seq_if_empty_p:N \g_@@_cutout_left_seq }
          { \seq_if_empty_p:N \g_@@_cutout_right_seq }
          { \bool_gset_false:N \g_@@_cutout_active_bool }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\galley_par:n}
%   Inserts tokens such that they are appended to the end of the last
%   paragraph, using the paragraph-omitting system.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_par:n #1
  {
    \s_@@_par_omit
    \bool_if:NF \g_@@_begin_level_bool
      {
        #1
        \galley_par:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\par}
%   The meaning of the token \cs{par} itself starts off as a standard
%   paragraph.
%    \begin{macrocode}
\cs_set_protected:Npn \par { \galley_par: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@par}
%   \LaTeXe{} requires a \enquote{long term} version of \cs{par}, which is
%   stored as \cs{@par}. Things are done a bit differently by \LaTeX3 and
%   so this will only be needed in package mode.
%    \begin{macrocode}
%<*package>
\tl_set:Nn \@par { \galley_par: }
%</package>
%    \end{macrocode}
% \end{macro}
%
% \subsection{Display levels}
%
% \begin{macro}{\galley_display_begin:, \galley_display_end:}
% \begin{macro}{\@@_display_penalty:N, \@@_display_vspace:N}
% \begin{macro}{\@@_display_par_setup:, \@@_display_par:}
%   Display items within the galley are a bit like galley levels: they
%   may have different paragraph settings to the main part of the galley.
%   On the other hand, unlike independent galleys they should inherit the
%   settings from the surrounding material. They may also start and end with
%   special spacing values.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_display_begin:
  {
    \group_begin:
      \@@_save_parameters:
      \mode_if_vertical:TF
        {
          \@@_display_penalty:N \l_galley_display_begin_par_penalty_tl
          \@@_display_vspace:N  \l_galley_display_begin_par_vspace_tl
        }
        {
          \@@_display_penalty:N \l_galley_display_begin_penalty_tl
          \@@_display_vspace:N  \l_galley_display_begin_vspace_tl
        }
      \par
  }
%    \end{macrocode}
%   Two short-cuts for setting up any special penalty or vertical space.
%   The idea is that the standard value is saved to the \enquote{restore}
%   token list, before setting up the value to the special value needed
%   in this one case.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_display_penalty:N #1
  {
    \tl_if_empty:NF #1
      {
        \tl_gput_right:Ne \g_galley_restore_running_tl
          {
            \int_gset:Nn \exp_not:N \g_galley_penalty_int
              { \int_use:N \g_galley_penalty_int }
          }
        \int_gset:Nn \g_galley_penalty_int {#1}
      }
  }
\cs_new_protected:Npn \@@_display_vspace:N #1
  {
    \tl_if_empty:NF #1
      {
        \tl_gput_right:Ne \g_galley_restore_running_tl
          {
            \skip_gset:Nn \exp_not:N \g_galley_vspace_skip
              { \skip_use:N \g_galley_vspace_skip }
          }
        \skip_gset:Nn \g_galley_vspace_int {#1}
      }
  }
%    \end{macrocode}
%   The \cs{par} token at the end of the display needs to go in at the same
%   group level as the text, hence this function cannot be placed using
%   \cs{group_insert_after:N}. Resetting the meaning of the \cs{par} token
%   needs to be carried out after the group used for the environment.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_display_end:
  {
      \par
      \@@_restore_parameters:
    \group_end:
    \group_insert_after:N \@@_display_par_setup:
  }
%    \end{macrocode}
%   The method used here is to assume that the next piece of horizontal
%   mode material will follow on from the displayed output without an
%   intervening \cs{par} token (probably a blank line). The meaning of the
%   \cs{par} token is then altered so that a check can be made to see if
%   this assumption was correct.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_display_par_setup:
  {
    \bool_gset_false:N \g_galley_omit_next_indent_bool
    \cs_set_eq:NN \par \@@_display_par:
  }
%    \end{macrocode}
%   The \enquote{special} meaning of the paragraph token starts by putting
%   things back to normal: there should never need to be more than one
%   special paragraph marker in one group. If \TeX{} is in vertical mode,
%   then there has been a paragraph token inserted, most likely by a
%   blank line. Thus the next piece of material is a separate conceptual
%   paragraph from the display. In that case, the assumption from above is
%   undone and the indent is turned back on. On the other hand, for the
%   case where \TeX{} is in horizontal mode then a \cs{tex_par:D} primitive
%   is required in the same way as in \cs{galley_standard_par:}. Most of
%   the settings for a conceptual paragraph will carry over there but any
%   cutout will have to be updated as it depends on the number of lines
%   \TeX{} has typeset.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_display_par:
  {
    \cs_set_eq:NN \par \galley_par:
    \mode_if_vertical:TF
      {
        \par
        \bool_gset_false:N \g_galley_omit_next_indent_bool
        \@@_display_penalty:N \l_galley_display_end_par_penalty_tl
        \@@_display_vspace:N  \l_galley_display_end_par_vspace_tl
      }
      {
        \@@_par_set_cutout:
        \group_begin:
          \tex_par:D
        \group_end:
        \int_gadd:Nn \g_@@_current_par_lines_int \tex_prevgraf:D
        \bool_set_false:N \l_@@_tmp_bool
        \@@_par_update_cutout:
        \@@_display_penalty:N \l_galley_display_end_penalty_tl
        \@@_display_vspace:N  \l_galley_display_end_vspace_tl
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Insertions using \cs{tex_everypar:D}}
%
% The key to the entire galley mechanism is hooking into the
% \cs{tex_everypar:D} token register. This requires that the original
% is moved out of the way, with appropriate hooks left attached for
% further modification by other modules and by the user. This is all
% done such that there is no danger of accidentally deactivating the
% galley mechanism.
%
% \begin{macro}{\everypar}
%   When used on top of \LaTeXe{} the original primitive name needs to be
%   available without the risk of completely overwriting the new
%   mechanism. This is implemented as a token register in case low-level
%   \TeX{} is used. The \TeX{} primitive is set here as otherwise the
%   \LaTeXe{} \cs{@nodocument} is never removed from the register.
%   This precaution is not be needed for a stand-alone format.
%    \begin{macrocode}
\cs_undefine:N \everypar
\newtoks \everypar
\cs_if_exist:NTF \AtBeginDocument
  { \AtBeginDocument }
  { \use:n }
  {
    \tex_everypar:D
      {
        \bool_if:NTF \g_@@_begin_level_bool
          { \@@_start_paragraph_first: }
          { \@@_start_paragraph_std: }
        \tex_the:D \everypar
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{The galley mechanism}
%
% \begin{variable}{\g_@@_last_box}
%   A temporary box to hold the box inserted by \TeX{} when a paragraph
%   is inserted with an indent. The galley actually inserts the space
%   (i.e., \cs{tex_parindent:D} is globally zero), but there is
%   still an empty box to test for.
%    \begin{macrocode}
\box_new:N \g_@@_last_box
%    \end{macrocode}
% \end{variable}
%
% The \enquote{start of paragraph} routines are fired by \cs{tex_everypar:D}.
% This can take place within a group in a construction such as
% \begin{verbatim}
%   ... end of last par.
%
%   {\Large Start} of par
% \end{verbatim}
% and so anything applied here must be done globally.
%
% \begin{macro}{\@@_start_paragraph_common:N}
%   Share some code between all types of paragraph start.
%   The routine at the start of a paragraph starts by removing any
%   (empty) indent box from the vertical list. As there may be vertical
%   mode items still to insert (|#1|), a \cs{tex_par:D} primitive is used to
%   get back into vertical mode before they are tidied up. To get back
%   again to horizontal mode, \cs{tex_noindent:D} can be used. To avoid
%   an infinite loop, \cs{tex_everypar:D} is locally cleared before doing
%   that.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_start_paragraph_common:N #1
  {
    \group_begin:
      \box_gset_to_last:N \g_@@_last_box
      \tex_par:D
      #1
      \tex_everypar:D { }
      \tex_noindent:D
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_start_paragraph_std:}
%   After dealing with the common items, the horizontal mode items can be
%   tidied up before sorting out any items which have been set on a
%   single-paragraph basis.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_start_paragraph_std:
  {
    \@@_start_paragraph_common:N \@@_insert_vertical_items:
    \@@_insert_horizontal_items:
    \@@_restore_running_parameters:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_start_paragraph_first:}
% \begin{macro}{\@@_insert_vspace_first:}
%   For the very first paragraph in a galley, the code needs to avoid
%   adding any unnecessary vertical items at the top as it will interfere with
%   vertical positioning in \cs{tex_vtop:D}. That requirement also means we
%   must not add any vertical space as the start of the box unless there
%   is a user space to insert.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_start_paragraph_first:
  {
    \bool_gset_false:N \g_@@_begin_level_bool
    \mode_if_horizontal:TF
      { \@@_start_paragraph_common:N \@@_insert_vspace_first: }
      { \@@_insert_vspace_first: }
    \@@_insert_horizontal_items:
    \@@_restore_running_parameters:
  }
\cs_new_protected:Npn \@@_insert_vspace_first:
  {
    \tl_if_empty:NF \g_@@_interpar_vspace_user_tl
      { \skip_vertical:n { \g_@@_interpar_vspace_user_tl } }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_insert_vertical_items}
%   The aim here is to insert the vertical items such that they attach to
%   the correct place. This function is used as part of the \cs{tex_everypar:D}
%   mechanism, meaning that the immediately-preceding item on the vertical
%   list is the \cs{tex_parskip:D}, always zero-length but an implicit
%   penalty. So any whatsits \enquote{attached} to the previous paragraph
%   should stay glued on.  After the whatsits, a penalty for
%   breaking will be inserted. This will be the user penalty if supplied,
%   or the running penalty unless the no-break flag is set. Finally,
%   the inter-paragraph space is applied: only one space is ever added
%   there.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_insert_vertical_items:
  {
    \g_galley_whatsit_previous_tl
    \tl_gclear:N \g_galley_whatsit_previous_tl
    \tl_if_empty:NTF \g_@@_interpar_penalty_user_tl
      {
        \bool_if:NTF \g_galley_no_break_next_bool
          { \tex_penalty:D \c_@@_max_penalty_int }
          { \tex_penalty:D \l_galley_interpar_penalty_int }
      }
      {
        \tex_penalty:D
          \int_eval:n { \g_@@_interpar_penalty_user_tl } \exp_stop_f:
        \tl_gclear:N \g_@@_interpar_penalty_user_tl
      }
    \bool_gset_false:N \g_galley_no_break_next_bool
    \tl_if_empty:NTF \g_@@_interpar_vspace_user_tl
      { \skip_vertical:N \l_galley_interpar_vspace_skip }
      {
        \skip_vertical:n { \g_@@_interpar_vspace_user_tl }
        \tl_gclear:N \g_@@_interpar_vspace_user_tl
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_insert_horizontal_items:}
%   Horizontal mode objects start with the whatsits for the next paragraph. An
%   indent is then included if the removed box was not void.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_insert_horizontal_items:
  {
    \g_galley_whatsit_next_tl
    \tl_gclear:N \g_galley_whatsit_next_tl
    \bool_if:NF \g_galley_omit_next_indent_bool
      {
        \box_if_empty:NF \g_@@_last_box
          { \hbox_to_wd:nn \l_galley_par_indent_dim { } }
      }
    \skip_horizontal:N \l_galley_par_begin_skip
    \g_galley_par_begin_hook_tl
    \bool_gset_false:N \g_galley_omit_next_indent_bool
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_restore_running_parameters:}
%   Restoring the ongoing parameters just means using the token list
%   variable in which the appropriate assignments are stored. The
%   list can then be cleared.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_restore_running_parameters:
  {
    \g_galley_restore_running_tl
    \tl_gclear:N \g_galley_restore_running_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Measure}
%
% \begin{variable}{\l_@@_total_left_margin_dim, \l_@@_total_right_margin_dim}
%   Used to set the measure, first by providing a place to save the existing
%   values, then allowing calculation of the difference between old and new
%   settings.
%    \begin{macrocode}
\dim_new:N \l_@@_total_left_margin_dim
\dim_new:N \l_@@_total_right_margin_dim
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}
%   {\galley_margins_set_absolute:nn, \galley_margins_set_relative:nn}
%   Setting the measure is just a question of adjusting margins, either
%   in a relative or absolute sense. One the settings are sorted, the
%   paragraph shape can be reset.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_margins_set_absolute:nn #1#2
  {
    \dim_set:Nn \l_galley_total_left_margin_dim  {#1}
    \dim_set:Nn \l_galley_total_right_margin_dim {#2}
    \dim_set:Nn \l_galley_text_width_dim
      {
          \l_galley_width_dim
        - \l_galley_total_left_margin_dim
        - \l_galley_total_right_margin_dim
      }
    \@@_parshape_set:
  }
\cs_new_protected:Npn \galley_margins_set_relative:nn #1#2
  {
    \dim_add:Nn \l_galley_total_left_margin_dim  {#1}
    \dim_add:Nn \l_galley_total_right_margin_dim {#2}
    \dim_set:Nn \l_galley_text_width_dim
      {
          \l_galley_width_dim
        - \l_galley_total_left_margin_dim
        - \l_galley_total_right_margin_dim
      }
    \@@_parshape_set:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Paragraph shape}
%
% \begin{macro}
%   {
%     \galley_parshape_set_multi:nnnN,
%     \galley_parshape_set_multi:nVVN,
%     \galley_parshape_set_single:nnnN,
%     \galley_parshape_set_single:nVVN
%   }
%   Setting the paragraph shape is mainly a question of converting the input.
%   First, though, a flag is set.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_parshape_set_multi:nnnN
  {
    \bool_set_true:N \l_@@_parshape_multipar_bool
    \@@_parshape_set:nnnN
  }
\cs_new_protected:Npn \galley_parshape_set_single:nnnN
  {
    \bool_set_false:N \l_@@_parshape_multipar_bool
    \@@_parshape_set:nnnN
  }
\cs_generate_variant:Nn \galley_parshape_set_multi:nnnN  { nVV }
\cs_generate_variant:Nn \galley_parshape_set_single:nnnN { nVV }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parshape_set:nnnN}
%   Setting the paragraph shape starts by converting the two input lists into
%   sequences. The shape is then set using a mapping with allowance for the
%   unaltered lines and the possibility of resuming the measure. The unaltered
%   lines are added to the sequences as this information may be needed
%   elsewhere (if a cutout is active), and this is the most convenient way to
%   deal with it. Everything ends up stored in the two sequences for possible
%   re-application if there are cutouts.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parshape_set:nnnN #1#2#3#4
  {
    \seq_set_from_clist:Nn \l_@@_parshape_left_indent_seq {#2}
    \seq_set_from_clist:Nn \l_@@_parshape_right_indent_seq {#3}
    \prg_replicate:nn {#1}
      {
        \seq_put_left:Nn \l_@@_parshape_left_indent_seq { 0pt }
        \seq_put_left:Nn \l_@@_parshape_right_indent_seq { 0pt }
      }
    \bool_if:NT #4
      {
        \seq_put_right:Nn \l_@@_parshape_left_indent_seq { 0pt }
        \seq_put_right:Nn \l_@@_parshape_right_indent_seq { 0pt }
      }
    \@@_parshape_set:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Cutouts}
%
% Cutouts are another way of looking at paragraph shapes, but apply to
% a fixed number of lines within a galley. As such, they require separate
% handling from the measure and shape.
%
% \begin{macro}{\galley_cutout_left:nn, \galley_cutout_right:nn}
% \begin{macro}{\@@_cutout:nnn}
% \begin{macro}{\@@_cutout:NN, \@@_cutout:cN, \@@_cutout:Nc}
%   Setting up cutouts on the two sides of the paragraph is more or less
%   the same idea with one or two very specific points of difference. As such,
%   the two interface functions both use the same implementation.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_cutout_left:nn
  { \@@_cutout:nnn { left } }
\cs_new_protected:Npn \galley_cutout_right:nn
  { \@@_cutout:nnn { right } }
%    \end{macrocode}
%   The cutout information needs to be saved in the appropriate sequence.
%   First, the input is converted to a (temporary) sequence. If there is
%   no existing cutout defined, this is simply stored. On the other hand,
%   if there is a cutout already active, the new one needs to be added to
%   it. To achieve that, we iterate over whichever sequence is longer
%   (so that every relevant line is covered). At the end of this process,
%   the paragraph shape needs to be activated. Notice here that we use
%   a global temporary sequence: this allows the auxiliary \cs{@@_cutout:NN}
%   to apply \cs{seq_gpop_left:NNF } with whichever sequence is shorter.
%   The parshape is not set at this stage as cutouts need handling
%   on a per-paragraph level.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_cutout:nnn #1#2#3
  {
    \seq_gset_from_clist:Nn \g_@@_tmpa_seq {#3}
    \prg_replicate:nn {#2}
      { \seq_gput_left:Nn \g_@@_tmpa_seq { 0pt } }
    \seq_if_empty:cTF { g_@@_cutout_ #1 _seq }
      { \seq_gset_eq:cN { g_@@_cutout_ #1 _seq } \g_@@_tmpa_seq }
      {
        \int_compare:nNnTF
          { \seq_count:c { g_@@_cutout_ #1 _seq } } >
            { \seq_count:N \g_@@_tmpa_seq }
          { \@@_cutout:cN { g_@@_cutout_ #1 _seq } \g_@@_tmpa_seq }
          { \@@_cutout:Nc \g_@@_tmpa_seq { g_@@_cutout_ #1 _seq } }
        \seq_gset_eq:cN { g_@@_cutout_ #1 _seq } \l_@@_tmp_seq
      }
    \seq_if_empty:cF { g_@@_cutout_ #1 _seq }
      { \bool_gset_true:N \g_@@_cutout_active_bool }
  }
\cs_new_protected:Npn \@@_cutout:NN #1#2
  {
    \seq_clear:N \l_@@_tmp_seq
    \seq_map_inline:Nn #1
      {
        \seq_gpop_left:NNF #2 \l_@@_tmp_tl
          { \tl_set:Nn \l_@@_tmp_tl { 0pt } }
        \seq_put_right:Ne \l_@@_tmp_seq
          { \dim_eval:n { ##1 + \l_@@_tmp_tl } }
      }
  }
\cs_generate_variant:Nn \@@_cutout:NN { c , Nc }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Setting the primitive paragraph shape}
%
% \begin{macro}{\@@_parshape_set:}
% \begin{macro}
%   {
%     \@@_parshape_set_margins:,
%     \@@_parshape_set_indents:,
%     \@@_parshape_set_cutouts:
%   }
% \begin{macro}{\@@_parshape_set_indents:NN}
% \begin{macro}[rEXP]{\@@_parshape_set_indents:nn}
% \begin{macro}{\@@_parshape_set_cutouts:n}
% \begin{macro}{\@@_parshape_set_cutouts:N}
%   The real paragraph shape (\cs{tex_parshape:D}) is set whenever any
%   of the conceptual elements (margins, measure, cutouts) are set and
%   potentially at the end of a paragraph in the cases where a single-paragraph
%   measure or a cutout was active. Rather than try to track different
%   combinations of the elements, as was done in earlier versions of this
%   code, the approach taken here is always to reset the entire shape. This
%   is done in three stages, one for each conceptual element.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parshape_set:
  {
    \@@_parshape_set_margins:
    \@@_parshape_set_indents:
    \@@_parshape_set_cutouts:
  }
%    \end{macrocode}
%   Setting the margins is simple. Either they are zero, using the full measure,
%   or they are not. This is always set even if there are other elements to
%   apply as these settings are very fast, so it is not worth doing a check
%   at this stage for further parts to apply.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parshape_set_margins:
  {
    \bool_lazy_and:nnTF
      { \dim_compare_p:nNn \l_galley_total_left_margin_dim  = \c_zero_dim }
      { \dim_compare_p:nNn \l_galley_total_right_margin_dim = \c_zero_dim }
      { \tex_parshape:D \c_zero_int }
      {
        \tex_parshape:D
          \c_one_int
          \l_galley_total_left_margin_dim
          \l_galley_text_width_dim
      }
  }
%    \end{macrocode}
%   If there is a measure (indent) to apply this simply overwrites the
%   settings for the margins. As there are two sequences to use it is
%   convenient to use a thread mapping, which means that the shorter sequence
%   will always apply. The margins are reapplied at this stage as part of
%   the auxiliary for the calculation of indentation.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parshape_set_indents:
  {
    \bool_lazy_and:nnF
      { \seq_if_empty_p:N \l_@@_parshape_left_indent_seq }
      { \seq_if_empty_p:N \l_@@_parshape_right_indent_seq }
      {
        \@@_parshape_set_indents:NN
          \l_@@_parshape_left_indent_seq
          \l_@@_parshape_right_indent_seq
      }
  }
\cs_new_protected:Npn \@@_parshape_set_indents:NN #1#2
  {
    \tex_parshape:D
      \int_min:nn { \seq_count:N #1 } { \seq_count:N #2 }
      \exp_stop_f:
      \seq_map_pairwise_function:NNN #1 #2
        \@@_parshape_set_indents:nn
  }
\cs_new:Npn \@@_parshape_set_indents:nn #1#2
  {
    \dim_eval:n { \l_galley_total_left_margin_dim + #1 } \exp_stop_f:
    \dim_eval:n { \l_galley_text_width_dim - ( #1 + #2 ) } \exp_stop_f:
  }
%    \end{macrocode}
%   Calculating cutouts is by far the most complex operation here. The
%   first step is to establish if this needs to be done at all. If so,
%   the cutout list and the matching measure (indent) are stored in two
%   temporary sequences so that they can safely be \enquote{chomped} by
%   \cs{@@_cutout:NN}. We then construct the overall list of indents required
%   and store them in dedicated temporary storage. That is necessary as to get
%   the indents correct on both sides is to use a thread mapping. That also
%   means that the two sequences need to be of the same length.  That is
%   done by finding the length difference then applying an auxiliary to
%   the shorter sequence.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parshape_set_cutouts:
  {
    \bool_lazy_and:nnF
      { \seq_if_empty_p:N \g_@@_cutout_left_seq }
      { \seq_if_empty_p:N \g_@@_cutout_right_seq }
      {
        \@@_parshape_set_cutouts:n { left }
        \@@_parshape_set_cutouts:n { right }
        \int_set:Nn \l_@@_tmp_int
          {
              \seq_count:N \l_@@_cutout_left_indent_seq
            - \seq_count:N \l_@@_cutout_right_indent_seq
          }
        \int_compare:nNnTF \l_@@_tmp_int > 0
          { \@@_parshape_set_cutouts:N \l_@@_cutout_right_indent_seq }
          { \@@_parshape_set_cutouts:N \l_@@_cutout_left_indent_seq }
        \@@_parshape_set_indents:NN
          \l_@@_cutout_left_indent_seq
          \l_@@_cutout_right_indent_seq
      }
  }
%    \end{macrocode}
%   To work out the offsets for a cutout, we first check that there is
%   anything to do at all. If there is, we need to ensure that there
%   are more entries in the measure list than in the cutout list, so that
%   any lines omitted by the cutout are correct and so that the normal measure
%   will resume after the cutout. That is done in a global temporary sequence,
%   which allows code sharing with the earlier path.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parshape_set_cutouts:n #1
  {
    \seq_if_empty:cTF { g_@@_cutout_ #1 _seq }
      {
        \seq_set_eq:cc { l_@@_cutout_ #1 _indent_seq }
          { l_@@_parshape_ #1 _indent_seq }
      }
      {
        \seq_gset_eq:Nc \g_@@_tmpa_seq { g_@@_cutout_ #1 _seq }
        \seq_gset_eq:Nc \g_@@_tmpb_seq { l_@@_parshape_ #1 _indent_seq }
        \seq_get_right:NNF \g_@@_tmpb_seq \l_@@_tmp_tl
          { \tl_clear:N \l_@@_tmp_tl }
        \tl_if_empty:NT \l_@@_tmp_tl
          { \tl_set:Nn \l_@@_tmp_tl { 0pt } }
        \int_set:Nn \l_@@_tmp_int
          {
              \seq_count:N \g_@@_tmpa_seq
            - \seq_count:N \g_@@_tmpb_seq
            + 1
          }
        \int_compare:nNnT \l_@@_tmp_int > 0
          {
            \prg_replicate:nn
              { \l_@@_tmp_int }
              { \seq_gput_right:NV \g_@@_tmpb_seq \l_@@_tmp_tl }
          }
        \@@_cutout:NN \g_@@_tmpb_seq \g_@@_tmpa_seq
        \seq_set_eq:cN { l_@@_cutout_ #1 _indent_seq } \l_@@_tmp_seq
      }
  }
%    \end{macrocode}
%   Grab the last entry of the shorter sequence and repeat it to match
%   the length of the longer.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parshape_set_cutouts:N #1
  {
    \seq_get_right:NNF #1 \l_@@_tmp_tl
      { \tl_clear:N \l_@@_tmp_tl }
    \tl_if_empty:NT \l_@@_tmp_tl
      { \tl_set:Nn \l_@@_tmp_tl { 0pt } }
    \prg_replicate:nn { \int_abs:n \l_@@_tmp_int }
      { \seq_put_right:NV #1 \l_@@_tmp_tl }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Between paragraphs}
%
% \begin{macro}
%   {
%     \galley_penalty_set_single:n,
%     \galley_penalty_add_single:n,
%     \galley_vspace_set_single:n,
%     \galley_vspace_add_single:n,
%     \galley_vspace_max_single:n
%   }
%   User supplied penalties and spaces only apply for a single paragraph.
%   In both cases, the input values need to be checked for the correct
%   form but are stored as token lists. The \texttt{x}-type expansion
%   deals with this nicely.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_penalty_set_single:n #1
  { \tl_gset:Ne \g_@@_interpar_penalty_user_tl { \int_eval:n {#1} } }
\cs_new_protected:Npn \galley_penalty_add_single:n #1
  {
    \tl_gset:Ne \g_@@_interpar_penalty_user_tl
      {
        \int_eval:n
          {
            \tl_if_empty:NF \g_@@_interpar_penalty_user_tl
              { \g_@@_interpar_penalty_user_tl + }
            #1
          }
      }
  }
\cs_new_protected:Npn \galley_vspace_set_single:n #1
  { \tl_gset:Ne \g_@@_interpar_vspace_user_tl { \skip_eval:n {#1} } }
\cs_new_protected:Npn \galley_vspace_add_single:n #1
  {
    \tl_gset:Ne \g_@@_interpar_vspace_user_tl
      {
        \skip_eval:n
          {
            \tl_if_empty:NF \g_@@_interpar_vspace_user_tl
              { \g_@@_interpar_vspace_user_tl + }
            #1
          }
      }
  }
\cs_new_protected:Npn \galley_vspace_max_single:n #1
  {
    \tl_if_empty:NTF \g_@@_interpar_vspace_user_tl
      { \galley_vspace_set_single:n {#1} }
      {
        \dim_compare:nNnT
          { \tex_glueexpr:D \g_@@_interpar_vspace_user_tl }
            < { \tex_glueexpr:D (#1) \scan_stop: }
          { \galley_vspace_set_single:n {#1} }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\parskip}
%   For the package, the \cs{parskip} primitive is moved out of the
%   way as the code above is handling things.
%    \begin{macrocode}
%<*package>
\dim_set:Nn \parskip \c_zero_dim
\cs_undefine:N \parskip
\skip_new:N \parskip
%</package>
%    \end{macrocode}
% \end{macro}
%
% \subsection{Formatting inside the paragraph}
%
% Justification is more complex than is necessarily desirable as the various
% \TeX{} parameters here interact in ways which mean that clear separation
% between different areas is not so easy.
%
% \begin{variable}
%   {
%     \l_galley_line_left_skip,
%     \l_galley_line_right_skip,
%     \l_galley_par_begin_skip,
%     \l_galley_par_end_skip,
%     \l_galley_par_indent_dim
%   }
%   The variables for setting paragraph shape: essentially, these are
%   the \TeX{} set.
%    \begin{macrocode}
\cs_new_eq:NN \l_galley_line_left_skip  \tex_leftskip:D
\cs_new_eq:NN \l_galley_line_right_skip \tex_rightskip:D
\dim_new:N \l_galley_par_begin_skip
\cs_new_eq:NN \l_galley_par_end_skip   \tex_parfillskip:D
\cs_new_eq:NN \l_galley_par_indent_dim \tex_parindent:D
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_galley_last_line_fit_int}
%   One from \eTeX{}.
%    \begin{macrocode}
\cs_new_eq:NN \l_galley_last_line_fit_int \tex_lastlinefit:D
%    \end{macrocode}
% \end{variable}
%
% \subsection{Inter-word spacing}
%
% Setting the spacing between words and between sentences is important
% for achieving the correct output from ragged and centered output. At
% the same time, as far as possible the aim is to retain the spacing
% specified by the font designer and not to use arbitrary values
% (\emph{cf.}~the approach in \emph{The \TeX{}book}, p.~101).
%
% \begin{macro}{\galley_interword_spacing_set:N}
%   The approach taken to setting a fixed space is to use the information
%   from the current font to set the spacing. This means that only
%   \cs{tex_spacefactor:D} needs to be set, while \cs{tex_xspacefactor:D}
%   is left alone. However, this is only necessary for fonts which have
%   a stretch component to the inter-word spacing in the first place,
%   i.e., monospaced fonts require no changes. The code therefore
%   checks whether there is any stretch, and if there is uses the fixed
%   component to set \cs{tex_spaceskip:D}. If there is a stretch component
%   (non-zero \cs{tex_fontdimen:D} \texttt{3}), then the \cs{teX_spaceskip:D}
%   is set to the fixed component from the font.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_interword_spacing_set:N #1
  {
    \bool_if:NTF #1
      { % TODO Hook for font changes required!
        \dim_compare:nNnTF { \tex_fontdimen:D 3 \tex_font:D }
          = \c_zero_dim
          { \tex_spaceskip:D \c_zero_dim }
          { \tex_spaceskip:D \tex_fontdimen:D 2 \tex_font:D }
      }
      { \tex_spaceskip:D \c_zero_dim }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Hyphenation}
%
% \begin{variable}{\l_galley_hyphen_left_int}
%   Currently something of a hack: this links in with language and fonts,
%   so is not so straight-forward to handle.
%    \begin{macrocode}
\int_new:N \l_galley_hyphen_left_int
%<*package>
\int_set:Nn \l_galley_hyphen_left_int { \tex_lefthyphenmin:D }
%</package>
%    \end{macrocode}
% \end{variable}
%
% \subsection{Line breaking}
%
% \begin{variable}
%   {
%     \l_galley_binop_penalty_int,
%     \l_galley_double_hyphen_demerits_int,
%     \l_galley_emergency_stretch_skip,
%     \l_galley_final_hyphen_demerits_int,
%     \l_galley_linebreak_badness_int,
%     \l_galley_linebreak_fuzz_dim,
%     \l_galley_linebreak_penalty_int,
%     \l_galley_linebreak_pretolerance_int,
%     \l_galley_linebreak_tolerance_int,
%     \l_galley_mismatch_demerits_int,
%     \l_galley_relation_penalty_int
%   }
%   All \TeX{} primitives renamed.
%    \begin{macrocode}
\cs_new_eq:NN \l_galley_binop_penalty_int          \tex_binoppenalty:D
\cs_new_eq:NN \l_galley_double_hyphen_demerits_int \tex_doublehyphendemerits:D
\cs_new_eq:NN \l_galley_emergency_stretch_skip     \tex_emergencystretch:D
\cs_new_eq:NN \l_galley_final_hyphen_demerits_int  \tex_finalhyphendemerits:D
\cs_new_eq:NN \l_galley_linebreak_badness_int      \tex_hbadness:D
\cs_new_eq:NN \l_galley_linebreak_fuzz_dim         \tex_hfuzz:D
\cs_new_eq:NN \l_galley_linebreak_penalty_int      \tex_linepenalty:D
\cs_new_eq:NN \l_galley_linebreak_pretolerance_int \tex_pretolerance:D
\cs_new_eq:NN \l_galley_mismatch_demerits_int      \tex_adjdemerits:D
\cs_new_eq:NN \l_galley_relation_penalty_int       \tex_relpenalty:D
\cs_new_eq:NN \l_galley_linebreak_tolerance_int    \tex_tolerance:D
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\galley_break_line:Nn}
%   Terminating a line early without a new paragraph requires a few steps.
%   First, any skips are removed, then any additional space to add is
%   places on the surrounding vertical list. Finally, the current line
%   is ended, using a penalty to prevents an overfull line ending |\\| giving
%   a totally-blank one in the output. The boolean argument is used to indicate
%   that a break is allowed after the blank line.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_break_line:Nn #1#2
  {
    \mode_if_vertical:TF
      { \msg_error:nn { galley } { no-line-to-end } }
      {
        \tex_unskip:D
        \bool_if:NF #1
          { \tex_vadjust:D { \tex_penalty:D \c_@@_max_penalty_int } }
        \dim_compare:nNnF {#2} = \c_zero_dim
          { \tex_vadjust:D { \skip_vertical:n {#2} } }
        \tex_penalty:D \c_@@_max_penalty_int
        \tex_hfil:D
        \tex_penalty:D - \c_@@_max_penalty_int
      }
  }
%    \end{macrocode}
%\end{macro}
%
% \subsection{Paragraph breaking}
%
% \begin{variable}
%   {
%     \l_galley_broken_penalty_int,
%     \l_galley_interline_penalty_int,
%     \l_galley_parbreak_badness_int,
%     \l_galley_parbreak_fuzz_dim,
%     \l_galley_post_display_penalty_int,
%     \l_galley_pre_display_penalty_int
%
%   }
%   \TeX{} primitives renamed cover \emph{some} of this.
%    \begin{macrocode}
\cs_new_eq:NN \l_galley_broken_penalty_int       \tex_brokenpenalty:D
\cs_new_eq:NN \l_galley_interline_penalty_int    \tex_interlinepenalty:D
\cs_new_eq:NN \l_galley_parbreak_badness_int     \tex_vbadness:D
\cs_new_eq:NN \l_galley_parbreak_fuzz_dim        \tex_vfuzz:D
\cs_new_eq:NN \l_galley_post_display_penalty_int \tex_postdisplaypenalty:D
\cs_new_eq:NN \l_galley_pre_display_penalty_int  \tex_predisplaypenalty:D
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\l_galley_club_penalties_clist, \l_galley_line_penalties_clist}
%   These are used to keep a track of information which cannot be
%   extracted out of the primitives due to the overlapping nature of
%   the meanings.
%    \begin{macrocode}
\clist_new:N \l_galley_club_penalties_clist
\clist_new:N \l_galley_line_penalties_clist
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \galley_display_widow_penalties_set:n,
%     \galley_display_widow_penalties_set:V,
%     \galley_display_widow_penalties_set:v,
%     \galley_widow_penalties_set:n,
%     \galley_widow_penalties_set:V,
%     \galley_widow_penalties_set:v
%   }
% \begin{macro}{\@@_set_aux:n}
%   By far the easiest penalties to deal with are those for widows. These
%   work exactly as the names imply, with the display version only used
%   immediately before display math, and the standard penalty used at the end
%   of a paragraph. Thus there is only the need to convert the argument into
%   the correct form, and add a $0$ penalty at the end to nullify the effect of
%   repeating the last value.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_display_widow_penalties_set:n #1
  {
    \tex_displaywidowpenalties:D
      \int_eval:n { \clist_count:n {#1} + 1 } \exp_stop_f:
      \clist_map_function:nN {#1} \@@_set_aux:n
      \c_zero_int
  }
\cs_generate_variant:Nn \galley_display_widow_penalties_set:n { V , v }
\cs_new_protected:Npn \galley_widow_penalties_set:n #1
  {
    \tex_widowpenalties:D
      \int_eval:n { \clist_count:n {#1} + 1 } \exp_stop_f:
      \clist_map_function:nN {#1} \@@_set_aux:n
      \c_zero_int
  }
\cs_generate_variant:Nn \galley_widow_penalties_set:n { V , v }
\cs_new:Npn \@@_set_aux:n #1 { \int_eval:n {#1} ~ }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \galley_club_penalties_set:n,
%     \galley_club_penalties_set:V,
%     \galley_club_penalties_set:v,
%     \galley_interline_penalties_set:n,
%     \galley_interline_penalties_set:V,
%     \galley_interline_penalties_set:v
%   }
%   Setting club or special line penalties is easy, as these are handled
%   mainly by the interline set up function. The two concepts are essentially
%   the same, but having two takes makes some special effects easier to
%   carry out.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_club_penalties_set:n #1
  {
    \clist_set:Nn \l_galley_club_penalties_clist {#1}
    \@@_calc_interline_penalties:
  }
\cs_generate_variant:Nn \galley_club_penalties_set:n { V , v }
\cs_new_protected:Npn \galley_interline_penalties_set:n #1
  {
    \clist_set:Nn \l_galley_line_penalties_clist {#1}
    \@@_calc_interline_penalties:
  }
\cs_generate_variant:Nn \galley_interline_penalties_set:n { V , v }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \galley_display_club_penalties_set:n,
%     \galley_display_club_penalties_set:V,
%     \galley_display_club_penalties_set:v
%   }
%   Setting the display club penalties means first setting the primitive,
%   then recalculating the interline array to allow for these new values.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_display_club_penalties_set:n #1
  {
    \tex_clubpenalties:D
      \int_eval:n { \clist_count:n {#1} + 1 } \exp_stop_f:
      \clist_map_function:nN {#1} \@@_set_aux:n
      \c_zero_int
    \@@_calc_interline_penalties:
  }
\cs_generate_variant:Nn \galley_display_club_penalties_set:n { V , v }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\galley_interline_penalty_set:n}
% \begin{macro}{\@@_set_interline_penalty:nn}
% \begin{macro}
%   {
%     \@@_set_interline_penalty_auxi:n,
%     \@@_set_interline_penalty_auxii:n
%   }
%   Dealing with the general interline penalty is handled in one shot.
%   The idea is that for lines with no special penalty, the old general
%   penalty is removed and the new one is added. If there is currently
%   no shape set, then after adding the general interline value the
%   generic build system is invoked (in case the
%   \cs{tex_interlinepenalties:D} has accidentally been cleared).
%    \begin{macrocode}
\cs_new_protected:Npn \galley_interline_penalty_set:n #1
  {
    \int_compare:nNnTF { \tex_interlinepenalties:D 0 } = 0
      {
        \tex_interlinepenalties:D 1 = \int_eval:n {#1} \exp_stop_f:
        \@@_calc_interline_penalties:
      }
      {
        \cs_set:Npn \@@_set_interline_penalty_auxii:n ##1
          {
            \int_eval:n
              {
                \tex_interlinepenalties:D ##1
                - \tex_interlinepenalties:D \tex_interlinepenalties:D 0
                + #1
              }
              \exp_stop_f:
          }
        \exp_args:Nf \@@_set_interline_penalty:nn
          { \clist_count:N \l_galley_line_penalties_clist } {#1}
      }
  }
\cs_new_protected:Npn \@@_set_interline_penalty:nn #1#2
  {
    \tex_interlinepenalties:D
      \tex_interlinepenalties:D \c_zero_int
      \int_step_function:nN {#1}
        \@@_set_interline_penalty_auxi:n
      \int_step_function:nnN { #1 + 1 } { \tex_interlinepenalties:D 0 - 1 }
        \@@_set_interline_penalty_auxii:n
      \int_eval:n {#2} \exp_stop_f:
  }
\cs_new:Npn \@@_set_interline_penalty_auxi:n #1
  { \tex_interlinepenalties:D \int_eval:n {#1} \exp_stop_f: }
\cs_new:Npn \@@_set_interline_penalty_auxii:n #1 { }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_calc_interline_penalties:}
% \begin{macro}{\@@_calc_interline_penalties:nn}
% \begin{macro}
%   {
%     \@@_calc_interline_penalties_auxi:n,
%     \@@_calc_interline_penalties_auxii:n
%   }
%   The underlying interline penalty array has to deal with club penalties,
%   display club penalties and any special line penalties, and include
%   the general interline penalty. These requirements lead to a rather
%   complex requirement on how many lines to deal with. This is needed twice,
%   so an \texttt{f}-type expansion is used to make life a little less
%   complex.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_calc_interline_penalties:
  {
    \exp_args:Nff \@@_calc_interline_penalties:nn
      {
        \int_max:nn
          { \clist_count:N \l_galley_club_penalties_clist + 1 }
          {
            \int_max:nn
              { \clist_count:N \l_galley_line_penalties_clist + 1 }
              { \tex_clubpenalties:D 0 }
          }
      }
      { \clist_count:N \l_galley_line_penalties_clist }
  }
%    \end{macrocode}
%   The idea is now to calculate the correct penalties. Two auxiliary functions
%   are used: one for any \enquote{special penalty} lines and a second for
%   normal lines. At the end of the process, the standard interline
%   penalty is always included.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_calc_interline_penalties:nn #1#2
  {
    \tex_interlinepenalties:D #1 ~
      \int_step_function:nN {#2}
        \@@_calc_interline_penalties_auxi:n
      \int_step_function:nnN { #2 + 1 } { #1 - 1 }
        \@@_calc_interline_penalties_auxii:n
      \tex_interlinepenalties:D \tex_interlinepenalties:D \c_zero_int
  }
\cs_new:Npn \@@_calc_interline_penalties_auxi:n #1
  {
    \int_eval:n
      {
        \clist_item:Nn \l_galley_line_penalties_clist {#1}
        + 0 \clist_item:Nn \l_galley_club_penalties_clist {#1}
        - \tex_clubpenalties:D #1 ~
      }
      \exp_stop_f:
  }
\cs_new:Npn \@@_calc_interline_penalties_auxii:n #1
  {
    \int_eval:n
      {
        \tex_interlinepenalties:D \tex_interlinepenalties:D \c_zero_int
        + 0 \clist_item:Nn \l_galley_club_penalties_clist {#1}
        - \tex_clubpenalties:D #1 ~
      }
      \exp_stop_f:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \galley_save_club_penalties:N,
%     \galley_save_interline_penalties:N,
%     \galley_save_display_club_penalties:N,
%     \galley_save_display_widow_penalties:N,
%     \galley_save_widow_penalties:N
%   }
% \begin{macro}
%   {
%     \@@_save_display_club_penalties:n,
%     \@@_save_display_widow_penalties:n,
%     \@@_save_widow_penalties:n
%   }
% \begin{macro}{\galley_interline_penalty:}
%   Saving the array penalties varies in complexity depending on how they are
%   stored internally. The first two are easy: these are simply copies.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_save_club_penalties:N #1
  { \clist_set_eq:NN #1 \l_galley_club_penalties_clist }
\cs_new_protected:Npn \galley_save_interline_penalties:N #1
  { \clist_set_eq:NN #1 \l_galley_line_penalties_clist }
%    \end{macrocode}
%   These all require appropriate mappings, using the fact that
%   \cs{clist_set:Ne} will tidy up the excess comma.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_save_display_club_penalties:N #1
  {
    \clist_set:Ne #1
      {
        \int_step_function:nN { \tex_clubpenalties:D 0 - 1 }
          \@@_save_display_club_penalties:n
      }
  }
\cs_new:Npn \@@_save_display_club_penalties:n #1
  { \int_value:w \tex_clubpenalties:D \int_eval:n {#1} , }
\cs_new_protected:Npn \galley_save_display_widow_penalties:N #1
  {
    \clist_set:Ne #1
      {
        \int_step_function:nN { \tex_displaywidowpenalties:D 0 - 1 }
          \@@_save_display_widow_penalties:n
      }
  }
\cs_new:Npn \@@_save_display_widow_penalties:n #1
  {
    \int_value:w \tex_displaywidowpenalties:D
      \int_eval:n {#1} ,
  }
\cs_new_protected:Npn \galley_save_widow_penalties:N #1
  {
    \clist_set:Ne #1
      {
        \int_step_function:nN { \tex_widowpenalties:D 0 - 1 }
          \@@_save_widow_penalties:n
      }
  }
\cs_new:Npn \@@_save_widow_penalties:n #1
  { \int_value:w \tex_widowpenalties:D \int_eval:n {#1} , }
%    \end{macrocode}
%   This one is not an array, but is stored in a primitive, so there is
%   a simple conversion. The general interline penalty is always the
%   last value in the primitive array.
%    \begin{macrocode}
\cs_new_protected:Npn \galley_interline_penalty:
  { \int_value:w \tex_interlinepenalties:D \tex_interlinepenalties:D \c_zero_int }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Messages}
%
%    \begin{macrocode}
\msg_new:nnn { galley } { no-line-to-end }
  { There's~no~line~here~to~end. }
%    \end{macrocode}
%
% \subsection{\LaTeXe{} functions}
%
% \begin{macro}{\clearpage}
%   The \tn{clearpage} macro needs to place material into the correct
%   structures rather than directly onto the main vertical list. Other
%   than that it is the same as the \LaTeXe{} version.
%    \begin{macrocode}
\cs_set_protected:Npn \clearpage
  {
    \mode_if_vertical:T
      {
        \int_compare:nNnT \@dbltopnum = { -1 }
          {
            \dim_compare:nNnT \tex_pagetotal:D < \topskip
              { \tex_hbox:D { } }
          }
      }
    \newpage
%    \end{macrocode}
%  The reason for the following is explained in the \LaTeXe{} source: it
%  handled any dangling writes. We need to use the primitive for \tn{write} as
%  \LaTeXe{} has some last-minute code that may redefine \cs{iow_shipout:Nn}.
%  Everything is otherwise a copy from the \LaTeXe{} version.
%    \begin{macrocode}
    \tex_write:D \m@ne { }
    \vbox { }
    \penalty -\@Mi
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\nobreak}
% \begin{macro}{\noindent}
% \begin{macro}{\vspace}
% In package mode, some of \LaTeXe{}'s functions are re-implemented using
% the galley system. Not all of the optional arguments currently work!
%    \begin{macrocode}
\cs_set_protected:Npn \nobreak
  { \bool_gset_true:N \g_galley_no_break_next_bool }
%    \end{macrocode}
%  The \tn{noindent} primitive will causes problems, as it is used by
%  \LaTeXe{} documents to implicitly leave vertical mode as well as to
%  prevent indentation. Rather than patch \emph{every} place where we
%  need leave vertical mode, at the moment we stick with the primitive as
%  well as setting the galley flag.
%    \begin{macrocode}
\cs_set_protected:Npn \noindent
  {
    \tex_noindent:D
    \bool_gset_false:N \g_galley_omit_next_indent_bool
  }
%    \begin{macrocode}
%   At present we don't have a proper handling for the starred version
%   of \tn{vspace}: just ignore it for the moment!
%    \begin{macrocode}
\DeclareRobustCommand \vspace
  {
    \@ifstar
      \@vspace
      \@vspace
  }
\cs_set:Npn \@vspace #1 { \galley_vspace_add_single:n {#1} }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\\}
% \begin{macro}{\newline}
%   These functions pass their arguments straight through to the internal
%   implementation (which is currently just the \LaTeXe{} one recoded).
%    \begin{macrocode}
\DeclareRobustCommand \\
  {
    \@ifstar
      { \cs_set_eq:NN \reserved@e \c_true_bool }
      { \cs_set_eq:NN \reserved@e \c_false_bool }
    \@xnewline
  }
\cs_set:Npn \@xnewline
  {
    \@ifnextchar [ % ]
      { \@newline }
      { \@newline [ 0pt ] }
  }
\cs_set:Npn \@newline [ #1 ]
  { \galley_break_line:Nn \reserved@e {#1} }
\DeclareRobustCommand \newline
  { \galley_break_line:Nn \c_true_bool { 0pt } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{\LaTeXe{} fixes}
%
% Purely for testing, some internal \LaTeXe{} functions are altered to work
% with the mechanism here. This material is not comprehensive: additions are
% made as-needed for test purposes.
%
% \begin{macro}{\@@par}
%   The primitive is moved as otherwise the clever skipping code will fail.
%    \begin{macrocode}
\cs_set_eq:NN \@@@@par \galley_par:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\addpenalty, \addvspace}
%   The mechanism here is entirely different, but at least this works!
%    \begin{macrocode}
\cs_set_protected:Npn \addpenalty { \galley_penalty_add_single:n }
\cs_set_protected:Npn \addvspace  { \galley_vspace_max_single:n }
%    \end{macrocode}
%\end{macro}
%
% \begin{macro}{\@afterheading}
%   Set some flags and hope for the best!
%    \begin{macrocode}
\cs_set_protected:Npn \@afterheading
  {
    \bool_gset_true:N \g_galley_no_break_next_bool
    \if@afterindent
    \else
      \bool_gset_true:N \g_galley_omit_next_indent_bool
    \fi
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@hangfrom}
%   The \cs{tex_hangindent:D} primitive is no longer used, so the paragraph
%   shape is set in a different way. As a result, the label is part of the
%   same paragraph as the main body, hence the need to leave vertical mode.
%    \begin{macrocode}
\cs_set_protected:Npn \@hangfrom #1
  {
    \bool_gset_true:N \g_galley_omit_next_indent_bool
    \leavevmode
    \setbox \@tempboxa = \hbox { {#1} }
    \galley_parshape_set_single:nnnN
      { 1 }
      { \box_wd:N \@tempboxa }
      \c_zero_dim
      \c_false_bool
    \bool_gset_true:N \g_galley_no_break_next_bool
    \bool_gset_true:N \g_galley_omit_next_indent_bool
    \box \@tempboxa
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@normalcr}
%   This is needed as \cs{@parboxrestore} sets |\\| equal to \cs{@normalcr},
%   and the new definition must be used
%    \begin{macrocode}
\cs_set_eq:Nc \@normalcr { \cs_to_str:N \\ }
%    \end{macrocode}
%\end{macro}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
