% \iffalse
%<*driver>
\documentclass{ltxdoc}
\usepackage{fontspec}
\AtBeginDocument{\RequirePackage{luabreakurl}}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
  \DocInput{luabreakurl.dtx}
\end{document}
%</driver>
% \fi
%
% \GetFileInfo{luabreakurl.sty}
%
% \title{\textsf{luabreakurl}: Breakable URLs with visible continuation marks}
% \author{Klaus Rindfrey}
% \date{Version \fileversion\ (\filedate)}
%
% \maketitle
%
% \begin{abstract}
% The \textsf{luabreakurl} package typesets long, clickable URLs and URIs with
% flexible line breaking under Lua\LaTeX. It keeps the URI scheme intact and
% can display a configurable continuation mark whenever a URL is continued on
% the following line.
% \end{abstract}
%
% \tableofcontents
%
% \section{Introduction}
%
% Long URLs can cause overfull lines, especially in narrow columns, footnotes,
% bibliographies, and technical documentation. The standard \cs{url} command
% and packages such as \textsf{xurl} provide useful line-breaking facilities.
%
% The particular aim of \textsf{luabreakurl} is to combine very frequent break
% opportunities with a visible indication that the URL continues on the next
% line.
%
% The package follows a deliberately simple approach:
%
% \begin{itemize}
%   \item it inserts a possible break after almost every character;
%   \item it keeps the URI scheme and a following |//| together;
%   \item it preserves the URL as a clickable hyperlink;
%   \item it prints a continuation mark only when a break is actually taken;
%   \item it does not change the hyphenation of ordinary text.
% \end{itemize}
%
% \section{Requirements}
%
% The package is intended for Lua\LaTeX. It loads \textsf{hyperref}, which is
% used to create the clickable hyperlink.
%
% \section{Installation}
%
% For a local installation, run
%
% \begin{verbatim}
% lualatex luabreakurl.ins
% \end{verbatim}
%
% This extracts |luabreakurl.sty| from the documented source. Place the
% generated file in the same directory as your document or in a directory
% searched by \TeX.
%
% Once the package is distributed through \TeX\ Live or MiK\TeX, it can be
% installed with the package manager of the respective distribution.
%
% \section{Quick start}
%
% Load the package in the document preamble:
%
% \begin{verbatim}
% \usepackage{luabreakurl}
% \end{verbatim}
%
% Then use \cs{breakurl} for a URL or URI:
%
% \begin{verbatim}
% \breakurl{https://www.example.org/a/very/long/url}
% \end{verbatim}
%
% The result is typeset in a typewriter font and remains clickable.
%
% \section{User interface}
%
% \subsection{\cs{breakurl}}
%
% \DescribeMacro{\breakurl}
% The command
%
% \begin{verbatim}
% \breakurl{<URL or URI>}
% \end{verbatim}
%
% typesets its argument as a clickable hyperlink and inserts line-break
% opportunities after almost every character.
%
% The argument is read verbatim, so characters such as |_| may be used without
% escaping.
%
% The URI scheme is protected. For example, \texttt{https://},
% \texttt{mailto:}, and \texttt{git+ssh://} are kept together at the beginning
% of the URI.
%
% \subsection{\cs{luabreakurlsetup}}
%
% \DescribeMacro{\luabreakurlsetup}
% Package settings are changed with
%
% \begin{verbatim}
% \luabreakurlsetup{
%   continuation={\tiny$\Rightarrow$}
% }
% \end{verbatim}
%
% The only setting currently available is |continuation|. Its default value is
% |\tiny$\hookrightarrow$|. The value is printed only when a line break is
% actually taken.
%
% To disable the continuation mark, use an empty value:
%
% \begin{verbatim}
% \luabreakurlsetup{
%   continuation={}
% }
% \end{verbatim}
%
% Settings obey normal \TeX\ grouping. A temporary setting can therefore be
% limited to a group:
%
% \begin{verbatim}
% \begingroup
%   \luabreakurlsetup{
%     continuation={\tiny$\Rightarrow$}
%   }
%   \breakurl{https://www.example.org/a/very/long/url}
% \endgroup
% \end{verbatim}
%
% \section{Examples}
%
% The following narrow block deliberately forces line breaks:
%
% \begin{center}
% \begin{minipage}{0.48\linewidth}
% \breakurl{https://www.example.org/documentation/releases/2026/07/20/a/very/long/path/with/query/parameters?language=en&format=pdf&download=true}
% \end{minipage}
% \end{center}
%
% A different continuation mark can be selected:
%
% \begingroup
% \luabreakurlsetup{
%   continuation={\tiny$\Rightarrow$}
% }
% \begin{center}
% \begin{minipage}{0.48\linewidth}
% \breakurl{git+ssh://git.example.org/repositories/latex/luabreakurl/branches/feature/documentation/index.html}
% \end{minipage}
% \end{center}
% \endgroup
%
% Other URI schemes work in the same way:
%
% \begin{center}
% \begin{minipage}{0.48\linewidth}
% \breakurl{mailto:someone.with.a.very.long.name+latex-package@example.org?subject=Question-about-luabreakurl}
%
% \medskip
%
% \breakurl{doi:10.1000/abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ}
% \end{minipage}
% \end{center}
%
% \section{URI scheme recognition}
%
% A URI scheme is recognized according to the RFC~3986 form
%
% \begin{verbatim}
% ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) ":"
% \end{verbatim}
%
% If the colon is followed immediately by |//|, the two slashes are protected
% as part of the prefix. Consequently prefixes such as |https://|, |ftp://|,
% |file://|, |git+ssh://|, |mailto:|, and |doi:| remain intact.
%
% \section{Comparison with other packages}
%
% The standard \cs{url} command and the \textsf{xurl} package are suitable for
% many documents and provide established URL-breaking behaviour.
%
% \textsf{luabreakurl} is intended for the more specific case in which breaks
% should be permitted after almost every character and a visible continuation
% mark is desired.
%
% It is therefore not intended as a general replacement for \textsf{xurl}.
%
% \section{Limitations}
%
% \begin{itemize}
%   \item The package is intended for Lua\LaTeX.
%   \item \cs{breakurl} is intended for URLs and URIs, not for arbitrary text.
%   \item The command takes a verbatim argument and therefore cannot be used in
%         every moving argument.
%   \item Break opportunities are intentionally very frequent. Applications
%         requiring conventional URL-breaking rules may prefer \textsf{xurl}.
% \end{itemize}
%
% \section{Building the package and documentation}
%
% A complete build of the package documentation is simply:
%
% \begin{verbatim}
% make
% \end{verbatim}
%
% To build the documentation and the demonstration document, run:
%
% \begin{verbatim}
% make check
% \end{verbatim}
%
% Internally, the documentation build performs the following steps:
%
% \begin{verbatim}
% lualatex luabreakurl.dtx
% makeindex -s gind.ist -o luabreakurl.ind luabreakurl.idx
% makeindex -s gglo.ist -o luabreakurl.gls luabreakurl.glo
% lualatex luabreakurl.dtx
% lualatex luabreakurl.dtx
% \end{verbatim}
%
% The resulting |luabreakurl.pdf| serves both as the user manual and as the
% documented implementation.
%
% \section{License}
%
% The package is distributed under the MIT License.
%
% \section{Change history}
%
% \changes{v0.01}{2026-07-01}{Initial implementation.}
% \changes{v0.02}{2026-07-10}{Internal improvements.}
% \changes{v0.03}{2026-07-18}{General URI scheme detection and configurable
% continuation mark.}
% \changes{v1.0}{2026-07-20}{Renamed the package to
% \textsf{luabreakurl} and prepared the first public release.}
%
% \StopEventually{
%   \clearpage
%   \PrintChanges
%   \clearpage
%   \PrintIndex
% }
%
% \section{Implementation}
%
% \subsection{Package declaration}
%
%    \begin{macrocode}
%<*package>
\NeedsTeXFormat{LaTeX2e}
\ProvidesExplPackage
  {luabreakurl}
  {2026-07-19}
  {1.00}
  {Breakable URLs with visible continuation marks}

\RequirePackage{hyperref}

\ExplSyntaxOn
%    \end{macrocode}
%
% \subsection{Variables}
%
%    \begin{macrocode}
\tl_new:N  \l_luabreakurl_url_tl
\tl_new:N  \l_luabreakurl_continuation_tl
\seq_new:N \l_luabreakurl_scheme_match_seq

\int_new:N \l_luabreakurl_url_len_int
\int_new:N \l_luabreakurl_scheme_len_int
\int_new:N \l_luabreakurl_position_int
%    \end{macrocode}
%
% \subsection{Configuration}
%
%    \begin{macrocode}
\keys_define:nn
  { luabreakurl }
  {
    continuation .tl_set:N =
      \l_luabreakurl_continuation_tl,

    continuation .initial:n =
      {
        \tiny
        $\hookrightarrow$
      }
  }
%    \end{macrocode}
%
% \subsection{URI scheme detection}
%
% Determine the length of the initial URI scheme, including a following |//|.
%    \begin{macrocode}
\cs_new_protected:Npn \luabreakurl_set_scheme_length:n #1
  {
    \int_zero:N \l_luabreakurl_scheme_len_int
    \seq_clear:N \l_luabreakurl_scheme_match_seq

    \regex_extract_once:nnNT
      { \A [A-Za-z] [-A-Za-z0-9+.]* : (//)? }
      { #1 }
      \l_luabreakurl_scheme_match_seq
      {
        \int_set:Nn
          \l_luabreakurl_scheme_len_int
          {
            \tl_count:e
              {
                \seq_item:Nn
                  \l_luabreakurl_scheme_match_seq
                  { 1 }
              }
          }
      }
  }
%    \end{macrocode}
%
% \subsection{Insertion of a break point}
%
%    \begin{macrocode}
\cs_new_protected:Npn \luabreakurl_insert_breakpoint:
  {
    \nobreak
    \hskip 0pt plus .5pt

    \discretionary
      {
        \hbox to 0pt
          {
            \tl_use:N \l_luabreakurl_continuation_tl
            \hss
          }
      }
      { }
      { }
  }
%    \end{macrocode}
%
% \subsection{Typesetting}
%
%    \begin{macrocode}
\cs_new_protected:Npn \luabreakurl_typeset:n #1
  {
    \group_begin:
      \ttfamily

      \tl_set:Nn \l_luabreakurl_url_tl { #1 }

      \int_set:Nn
        \l_luabreakurl_url_len_int
        { \tl_count:N \l_luabreakurl_url_tl }

      \luabreakurl_set_scheme_length:n { #1 }

      \href{#1}
        {
          \int_zero:N \l_luabreakurl_position_int

          \tl_map_inline:Nn
            \l_luabreakurl_url_tl
            {
              \int_incr:N \l_luabreakurl_position_int

              ##1

              \int_compare:nNnT
                { \l_luabreakurl_position_int }
                >
                { 1 }
                {
                  \int_compare:nT
                    {
                      \l_luabreakurl_position_int
                      >=
                      \l_luabreakurl_scheme_len_int
                    }
                    {
                      \int_compare:nNnT
                        { \l_luabreakurl_position_int }
                        <
                        { \l_luabreakurl_url_len_int - 1 }
                        {
                          \luabreakurl_insert_breakpoint:
                        }
                    }
                }
            }
        }

    \group_end:
  }
%    \end{macrocode}
%
% \subsection{Public commands}
%
%    \begin{macrocode}
\NewDocumentCommand
  \luabreakurlsetup
  { m }
  {
    \keys_set:nn
      { luabreakurl }
      { #1 }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\NewDocumentCommand
  \breakurl
  { v }
  {
    \luabreakurl_typeset:n { #1 }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOff
%</package>
%    \end{macrocode}
%
% \Finale
