% \iffalse meta-comment
%
% Copyright (C) 2011-2015 by Raphaël Pinson <raphink@gmail.com>
% ---------------------------------------------------------------------------
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Raphaël Pinson.
%
% This work consists of the files impnattypo.dtx and impnattypo.ins
% and the derived filebase impnattypo.sty.
%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{impnattypo.dtx}
%</driver>
%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
%<package>\ProvidesPackage{impnattypo}
%<*package>
    [2019/03/04 1.5 Typographic utilities inspired by the French Imprimerie Nationale]
%</package>
%
%<*driver>
\expandafter\ifx\csname ifenglish\endcsname\relax
    \expandafter\newif\csname ifenglish\endcsname
    \englishtrue
\fi
\documentclass{ltxdoc}
\ifenglish
\usepackage[english]{babel}
\else
\usepackage[french]{babel}
\fi
\usepackage{fontspec}
\usepackage[svgnames]{xcolor}
\setmainfont{Linux Libertine O}
\usepackage{metalogo}
\usepackage[draft,hyphenation,nosingleletter,parindent,lastparline,homeoarchy,rivers]{impnattypo}[2018/06/04]
\usepackage[all]{nowidow}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
  \DocInput{impnattypo.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \CheckSum{121}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
%
% \changes{1.5}{2019/03/04}{Fix support for TexLive 2016 (new luatex
% compatibility). Thanks to Michal Hoftich}
% \changes{1.4}{2015/02/25}{Fix release date}
% \changes{1.3}{2015/02/25}{Fix French documentation}
% \changes{1.2}{2013/06/18}{Fix French documentation}
% \changes{1.1}{2013/06/17}{Fix French documentation}
% \changes{1.0}{2011/09/20}{Improve documentation, simplify internal variables}
% \changes{0.9}{2011/09/20}{River detection returns false by default}
% \changes{0.8}{2011/09/20}{Add river detection}
% \changes{0.7}{2011/09/20}{Add homoioteleuton detection}
% \changes{0.6}{2011/09/19}{Words contain at least one character}
% \changes{0.5}{2011/09/19}{Add homeoarchy detection}
% \changes{0.4}{2011/09/15}{Add draft mode}
% \changes{0.3}{2011/09/13}{Add parindent and lastparline options}
% \changes{0.2}{2011/09/13}{Add nosingleletter option}
% \changes{0.1}{2011/09/11}{First version}
%
% \DoNotIndex{\newcommand,\newenvironment}
%
% \providecommand*{\url}{\texttt}
% \GetFileInfo{impnattypo.dtx}
% \ifenglish
% \title{The \textsf{impnattypo} package}
% \else
% \title{Le paquet \textsf{impnattypo}}
% \fi
% \author{Raphaël Pinson \\ \url{raphink@gmail.com}}
% \ifenglish
% \date{\fileversion~from \filedate}
% \else
% \date{\fileversion~en date du \filedate}
% \fi
%
% \maketitle
%
% \section{Introduction}
%
% \ifenglish
% When it comes to French typography,
% the \emph{Lexique des règles typographiques en usage à l'Imprimerie Nationale}
% is a definite reference.
%
% While the majority of the recommendations of this book has been implemented
% in the \textsf{frenchb} module for \textsf{babel},
% other recommendations still deserve to be automatized in order to be
% implemented in \LaTeX.
%
% Such is the original goal of this package, initiated by a question on the
% tex.stackexchange.com\footnote{\url{http://tex.stackexchange.com/questions/20493/french-typography-recommendations}} website,
% and which implements several of the rules listed in this booklet
% so as to make them more easily applicable to texts edited with \LaTeX.
%
% As this package grew, functionalities were added, including some
% that were not directly related to the booklet, but improved
% the typographic quality of documents.
% \else
% En matière de typographie française,
% le \emph{Lexique des règles typographiques en usage à l'Imprimerie Nationale}
% est une référence incontournable.
%
% Si la majorité des recommandations de cet ouvrage est implémentée dans
% le module \textsf{frenchb} pour \textsf{babel},
% certaines autres recommandations méritent encore d'être automatisées pour être
% implémentées en \LaTeX.
%
% C'est le but original de ce paquet, initié par une question sur le site
% tex.stackexchange.com\footnote{\url{http://tex.stackexchange.com/questions/20493/french-typography-recommendations}},
% et qui implémente plusieurs règles édictées dans ce lexique
% afin de les rendre plus facilement applicables aux textes édités avec \LaTeX.
%
% Au fur et à mesure que ce paquet a grandi, des fonctionnalités sont venues
% s'ajouter, dont certaines ne sont pas directement liées au lexique,
% mais améliorent la qualité typographique des documents.
% \fi
%
% \ifenglish
% \section{Usage}
% \else
% \section{Utilisation}
% \fi
%
% \ifenglish
% In order to use the \texttt{impnattypo} package, use the following line:
% \else
% Pour utiliser le paquet \texttt{impnattypo}, entrez la ligne:
% \fi
%
% \begin{verbatim}
%    \usepackage[<options>]{impnattypo}
% \end{verbatim}
%
% \ifenglish
% The package options are described in the following sections.
% \else
% Les options du paquet sont décrites dans les sections suivantes.
% \fi
%
% \ifenglish
% \subsection{Hyphenation}
%
% \DescribeMacro{hyphenation}
% Besides the general hyphenation rules, the booklet indicates
% that we should ``prevent hyphenation of words on more
% than two consecutive lines.''
%
% In order to simplify the code, the suggested implementation
% strongly discourages hyphenation at the end of pages, as well
% as hyphenation on two consecutive lines.
%
% To active this functionality, use the \texttt{hyphenation} option:
% \else
% \subsection{Césures}
%
% \DescribeMacro{hyphenation}
% En dehors des règles générales de coupure des mots, le lexique indique
% qu'il faut \og [éviter] les coupures de mots sur plus de trois lignes
% consécutives. \fg{}
%
% Afin de simplifier le code, l'implémentation proposée décourage fortement
% les césures en fin de page, ainsi que les césures sur deux lignes
% consécutives.
%
% Pour activer cette fonctionnalité, utilisez l'option \texttt{hyphenation}:
% \fi
%
% \begin{verbatim}
%    \usepackage[hyphenation]{impnattypo}
% \end{verbatim}
%
%
% \ifenglish
% \subsection{Paragraph formatting}
%
% \DescribeMacro{parindent}
% The booklet advises to indent paragraphs by 1em.
% This |\parindent| setting can be achieved by using
% the \texttt{parindent} option:
% \else
% \subsection{Formatage des paragraphes}
%
% \DescribeMacro{parindent}
% Le lexique conseille une indentation des paragraphes de 1em.
% Ce réglage de |\parindent| peut être obtenu par l'utilisation
% de l'option \texttt{parindent}:
% \fi
%
% \begin{verbatim}
%    \usepackage[parindent]{impnattypo}
% \end{verbatim}
%
% \DescribeMacro{lastparline}
% \ifenglish
% Moreover, it is indicated in the ``Hyphenation'' section
% that ``the last line of a paragraph must contain a word or
% the end of a word of a width at least equal to the double
% of the indent of the next paragraph.'' Since implementing
% this solution exactly is quite tricky, the \texttt{lastparline}
% option ensures that the last line of a paragraph is at least
% as long as the double value of |\parindent|.\footnote{\url{http://tex.stackexchange.com/questions/28357/ensure-minimal-length-of-last-line}}
%
% When \LuaTeX{} is used, the solution provided by Patrick Gundlach\footnote{\url{http://tex.stackexchange.com/questions/28357/ensure-minimal-length-of-last-line/28361\#28361}}
% is used. With other rendering engines, it is the native solution provided by
% Enrico Gregorio\footnote{\url{http://tex.stackexchange.com/questions/28357/ensure-minimal-length-of-last-line/28358\#28358}}
% that serves as an implementation:
% \else
% De plus, il est indiqué dans la section \og Coupure des mots \fg{}
% que \og la dernière ligne d'un alinéa doit comporter un mot ou
% une fin de mot de longueur au moins égale au double du renfoncement
% de l'alinéa suivant. \fg{} À défaut d'implémenter exactement cette
% solution, l'option \texttt{lastparline} s'assure que la dernière
% ligne d'un alinéa est au moins aussi longue que le double
% de la valeur de |\parindent|.\footnote{\url{http://tex.stackexchange.com/questions/28357/ensure-minimal-length-of-last-line}}
%
% Lorsque \LuaTeX{} est utilisé, la solution de Patrick Gundlach\footnote{\url{http://tex.stackexchange.com/questions/28357/ensure-minimal-length-of-last-line/28361\#28361}}
% est utilisée. Avec les autres moteurs de rendu, c'est la solution native de
% Enrico Gregorio\footnote{\url{http://tex.stackexchange.com/questions/28357/ensure-minimal-length-of-last-line/28358\#28358}}
% qui fait office d'implémentation:
% \fi
%
% \begin{verbatim}
%    \usepackage[lastparline]{impnattypo}
% \end{verbatim}
%
% \ifenglish
% When the \texttt{draft} option is activated and \LuaTeX{} is used,
% the inserted ties are colored in
% {\color{\intlastparlinecolor}\intlastparlinecolor}.
% The color can be tuned with the \texttt{lastparlinecolor} option.
% \else
% Lorsque l'option \texttt{draft} est activée et que \LuaTeX{} est utilisé,
% les espaces insécables insérés sont colorés en
% {\color{\intlastparlinecolor}\intlastparlinecolor}.
% La couleur utilisée peut être ajustée par l'option \texttt{lastparlinecolor}.
% \fi
%
% \DescribeMacro{nosingleletter}
% \ifenglish
% It is also recommended to avoid hyphenation points that would isolate a single letter.
% The solution proposed by Patrick Gundlach\footnote{\url{http://tex.stackexchange.com/questions/27780/one-letter-word-at-the-end-of-line}}
% allows to fix this by using \LuaTeX. To activate this functionality,
% you can use the \texttt{nosingleletter} option:
% \else
% Il est également recommandé d'éviter les coupures isolant une lettre.
% La solution proposée par Patrick Gundlach\footnote{\url{http://tex.stackexchange.com/questions/27780/one-letter-word-at-the-end-of-line}}
% permet de remédier à cela en utilisant \LuaTeX. Pour activer cette
% fonctionalité, il faut utiliser l'option \texttt{nosingleletter}:
% \fi
%
% \begin{verbatim}
%    \usepackage[nosingleletter]{impnattypo}
% \end{verbatim}
%
% \ifenglish
% When this option is activated, only \LuaTeX{} (with the |lualatex| command)
% can render the document.
%
% When the \texttt{draft} option is activated,
% the inserted ties are colored in
% {\color{\intnosinglelettercolor}\intnosinglelettercolor}.
% The color can be tuned by setting the \texttt{nosinglelettercolor} option.
% \else
% Lorsque cette option est activée, seul \LuaTeX{} (via la commande |lualatex|)
% pourra effectuer le rendu du document.
%
% Lorsque l'option \texttt{draft} est activée,
% les espaces insécables insérés sont colorés en
% {\color{\intnosinglelettercolor}\intnosinglelettercolor}.
% La couleur utilisée peut être ajustée par l'option \texttt{nosinglelettercolor}.
% \fi
%
% \DescribeMacro{homeoarchy}
% \ifenglish
% When two consecutive lines begin (homeoarchy) or end (homoioteleuton)
% with the same word or series of letters,
% it can confuse the reader, so this has to be avoided.
%
% Fixing this problem automatically is very complex
% and generally not a good idea.\footnote{\url{http://tex.stackexchange.com/questions/27588/repetition-of-a-word-on-two-lines}}
% For this reason, the \texttt{homeoarchy} option in this package
% only detects and highlights them. Fixing them will usually
% be a matter of introducing ties in the paragraph:
% \else
% Lorsque deux lignes consécutives commencent ou finissent
% par le même mot ou la même série de lettres,
% cela peut induire le lecteur en erreur et cela est donc à éviter.
%
% La correction automatique de ce phénomène est très complexe
% et en général non souhaitable.\footnote{\url{http://tex.stackexchange.com/questions/27588/repetition-of-a-word-on-two-lines}}
% C'est pourquoi l'option
% \texttt{homeoarchy} de ce paquet se contente
% de les détecter et de les afficher. Leur correction
% consistera en général en l'introduction d'une
% espace insécable dans le paragraphe:
% \fi
%
% \begin{verbatim}
%    \usepackage[homeoarchy]{impnattypo}
% \end{verbatim}
%
% \ifenglish
% When this option is activated, only \LuaTeX{} (with the |lualatex| command)
% can render the document.
%
% This option is only effective if the \texttt{draft} option is activated.
%
% The inserted ties are colored with two colors:
% \begin{itemize}
% \item Entire words are colored in
% {\color{\inthomeoarchywordcolor}\inthomeoarchywordcolor}
% and this color can be set with the \texttt{homeoarchywordcolor} option;
% \item Partial words are colored in
% {\color{\inthomeoarchycharcolor}\inthomeoarchycharcolor}
% and this color can be set by means of the \texttt{homeoarchycharcolor} option;
% \end{itemize}
%
% A glyph sequence is considered problematic when:
%
% \begin{itemize}
%   \item The number of entire matching words is greater than \inthomeoarchymaxwords.
%         This parameter can be tuned with the \texttt{homeoarchymaxwords} option;
%   \item The number of matching characters is greaterr than \inthomeoarchymaxchars.
%         This parameter can be tuned with the \texttt{homeoarchymaxchars} option;
% \end{itemize}
% \else
% Lorsque cette option est activée, seul \LuaTeX{} (via la commande |lualatex|)
% pourra effectuer le rendu du document.
%
% Cette option n'est effective que si l'option \texttt{draft} est activée.
%
% Les espaces insécables insérées sont colorées de deux couleurs:
%
% \begin{itemize}
% \item Les mots entiers sont colorés en
% {\color{\inthomeoarchywordcolor}\inthomeoarchywordcolor}
% et cette couleur peut être ajustée par l'option \texttt{homeoarchywordcolor};
% \item Les mots partiels sont colorés en
% {\color{\inthomeoarchycharcolor}\inthomeoarchycharcolor}
% et cette couleur peut être ajustée par l'option \texttt{homeoarchycharcolor};
% \end{itemize}
%
% Une séquence de glyphes est considérée comme problématique si:
%
% \begin{itemize}
%   \item Le nombre de mots entiers trouvés dans les deux lignes consécutives est supérieur à \inthomeoarchymaxwords.
%         Ce paramètre peut être ajusté par l'option \texttt{homeoarchymaxwords};
%   \item Le nombre de caractères trouvés dans les deux lignes consécutives est supérieur à \inthomeoarchymaxchars.
%         Ce paramètre peut être ajusté par l'option \texttt{homeoarchymaxchars};
% \end{itemize}
% \fi
%
%
% \DescribeMacro{rivers}
% \ifenglish
% A river is a vertical alignment of spaces in a paragraph.
% The \texttt{rivers} option allows to color rivers so as to
% identify them. This option does not fix the detected rivers:
% \else
% Une lézarde est un alignement vertical d'espaces dans un paragraphe.
% L'option \texttt{rivers} permet de colorer les lézardes afin de les
% identifier. Cette option ne corrige pas les lézardes détectées:
% \fi
%
% \begin{verbatim}
%    \usepackage[rivers]{impnattypo}
% \end{verbatim}
%
% \ifenglish
% When this option is activated, only \LuaTeX{} (with the |lualatex| command)
% can render the document.
%
% This option is only effective if the \texttt{draft} option is activated.
%
% The inserted ties are colored in
% {\color{\intriverscolor}\intriverscolor}.
% This color can be tuned by means of the \texttt{riverscolor} option.
% \else
% Lorsque cette option est activée, seul \LuaTeX{} (via la commande |lualatex|)
% pourra effectuer le rendu du document.
%
% Cette option n'est effective que si l'option \texttt{draft} est activée.
%
% Les espaces insécables insérées sont colorées en
% {\color{\intriverscolor}\intriverscolor}.
% Cette couleur peut être ajustée par l'option \texttt{riverscolor}.
% \fi
%
% \ifenglish
% \subsection{Chapter numbering}
% \else
% \subsection{Numérotation des chapitres}
% \fi
%
% \DescribeMacro{frenchchapters}
% \ifenglish
% When it comes to chapter numbering, the booklet indicates:
% ``In a title, chapter numbers are typeset in roman capital numbers,
% except for the ordinal `premier' written in letters in spite
% of the current fashion to write it in the cardinal form Chapter I.''
%
% The \texttt{frenchchapters} option of the package implements
% this recommendation:
% \else
% Concernant la numérotation des chapitres, le lexique indique:
% \og Dans un titre, on compose en chiffres romains grandes capitales
% les numéros de chapitres, à l'exception de l'ordinal \og premier \fg{}
% en toutes lettres malgré la tendance actuelle qui tend à lui substituer
% la forme cardinale Chapitre I. \fg{}
%
% L'option \texttt{frenchchapters} du paquet implémente cette recommandation:
% \fi
%
% \begin{verbatim}
%    \usepackage[frenchchapters]{impnattypo}
% \end{verbatim}
%
% \ifenglish
% Should you wish to use the ordinal form `premier'
% without using roman numbers for chapter numbering,
% you can redefine the \texttt{frenchchapter} macro, for example:
%
% \begin{verbatim}
%    \let\frenchchapter\arabic % use arabic numbers
%    \let\frenchchapter\babylonian % use babylonian numbers
% \end{verbatim}
% \else
% Si vous souhaitez bénéficier de la forme ordinale \og premier \fg{}
% sans pour autant utiliser une numérotation des chapitres en chiffres romains,
% il est possible de redéfinir la macro \texttt{frenchchapter}, par exemple:
%
% \begin{verbatim}
%    \let\frenchchapter\arabic % numérotation en chiffres arabes
%    \let\frenchchapter\babylonian % numérotation en chiffres babyloniens
% \end{verbatim}
% \fi
%
%
% \ifenglish
% \subsection{Widows and Orphans}
%
% It is recommended not to leave widows and orphans in a document.
% For this reason, we recommend you use the |nowidow| package:
% \else
% \subsection{Lignes orphelines et veuves}
%
% Il est fortement recommandé de ne pas laisser de lignes orphelines
% dans un document. Pour cela, nous vous conseillons d'utiliser le paquet
% |nowidow|:
% \fi
%
% \begin{verbatim}
%    \usepackage[all]{nowidow}
% \end{verbatim}
%
% \ifenglish
% See the package documentation for more options.
% \else
% Voir la documentation de ce paquet pour plus d'options.
% \fi
%
%
% \ifenglish
% \subsection{Draft mode}
% The \textsf{impnattypo} package features a draft mode
% allowing to visualize the penalties (ties) inserted by the
% \texttt{nosingleletter} and \texttt{lastparline} options,
% as well as the information added by the \texttt{homeoarchy}
% and \texttt{rivers} options. In draft mode,
% places where ties were inserted are indicated
% by colored squares.
%
% To activate the draft mode, use the \texttt{draft} option,
% for example:
% \else
% \subsection{Mode brouillon}
%
% \DescribeMacro{draft}
% Le paquet \textsf{impnattypo} dispose d'un mode brouillon
% permettant de visualiser les pénalités (espaces insécables)
% ajoutés par les options \texttt{nosingleletter} et
% \texttt{lastparline}, ainsi que les informations
% ajoutées par les options \texttt{homeoarchy}
% et \texttt{rivers}. En mode brouillon,
% les emplacements des espaces insécables insérés
% sont marqués par des rectangles de couleur.
%
% Pour activer le mode brouillon, utilisez l'option \texttt{draft},
% par exemple:
% \fi
%
% \begin{verbatim}
%    \usepackage[draft,lastparline]{impnattypo}
% \end{verbatim}
%
% \ifenglish
% This document is generated with the \texttt{draft} option on
% in order to demonstrate its effects.
% \else
% Cet document est générée avec l'option \texttt{draft} afin d'en
% montrer les effets.
% \fi
%
%
% \StopEventually{}
%
% \section{Implementation}
%
% \iffalse
%<*package>
% \fi
%
%    \begin{macrocode}
\ProvidesPackage{impnattypo}
\RequirePackage{ifluatex}
\RequirePackage{kvoptions}
\SetupKeyvalOptions{
   family=impnattypo,
   prefix=int,
}
\DeclareBoolOption{draft}
\DeclareBoolOption{frenchchapters}
\DeclareBoolOption{hyphenation}
\DeclareBoolOption{nosingleletter}
\DeclareBoolOption{parindent}
\DeclareBoolOption{lastparline}
\DeclareBoolOption{homeoarchy}
\DeclareBoolOption{rivers}
\DeclareStringOption[red]{homeoarchywordcolor}
\DeclareStringOption[orange]{homeoarchycharcolor}
\DeclareStringOption[brown]{nosinglelettercolor}
\DeclareStringOption[teal]{lastparlinecolor}
\DeclareStringOption[lime]{riverscolor}
\DeclareStringOption[1]{homeoarchymaxwords}
\DeclareStringOption[3]{homeoarchymaxchars}
\ProcessKeyvalOptions*
\RequirePackage{xcolor}
\def\usecolor#1{\csname\string\color@#1\endcsname\space}
%    \end{macrocode}
%
% \marginpar{No page finishes with an hyphenated word}
%
%    \begin{macrocode}
\ifinthyphenation
   \brokenpenalty=10000
%    \end{macrocode}
% \marginpar{Discourage hyphenation on two lines in a row}
%    \begin{macrocode}
   \doublehyphendemerits=1000000000
\fi
%    \end{macrocode}
%
% \marginpar{Number chapters}
%
%    \begin{macrocode}
\ifintfrenchchapters
   \let\frenchchapter\Roman
   \renewcommand{\thechapter}{%
     \ifnum\value{chapter}=1
       premier%
     \else
       \frenchchapter{chapter}%
     \fi
   }
\fi
%    \end{macrocode}
%
% \marginpar{No single letter}
%
%    \begin{macrocode}
\ifintnosingleletter
   \ifluatex
      \RequirePackage{luatexbase,luacode}
      \begin{luacode}
      local glyph_id = node.id "glyph"
      local glue_id  = node.id "glue"
      local hlist_id = node.id "hlist"

      local prevent_single_letter = function (head)
        while head do
          if head.id == glyph_id then                                             -- glyph
            if unicode.utf8.match(unicode.utf8.char(head.char),"%a") then   -- some kind of letter
               if head.prev.id == glue_id and head.next.id == glue_id then            -- only if we are at a one letter word

                 local p = node.new("penalty")
                 p.penalty = 10000

                 \ifintdraft
                    local w = node.new("whatsit","pdf_literal")
                    w.data = "q \usecolor{\intnosinglelettercolor} 0 0 m 0 5 l 2 5 l 2 0 l b Q"

                    node.insert_after(head,head,w)
                    node.insert_after(head,w,p)
                 \else
                    node.insert_after(head,head,p)
                 \fi
               end
            end
          end
          head = head.next
        end
        return true
      end

      luatexbase.add_to_callback("pre_linebreak_filter",prevent_single_letter,"~")
      \end{luacode}
   \else
      \PackageError{The nosingleletter option only works with LuaTeX}
   \fi
\fi
%    \end{macrocode}
%
% \marginpar{Paragraph indentation}
%
%    \begin{macrocode}
\ifintparindent
\setlength{\parindent}{1em}
\fi
%    \end{macrocode}
%
% \marginpar{Last line of paragraph}
%
%    \begin{macrocode}
\ifintlastparline
   \ifluatex
      \RequirePackage{luatexbase,luacode}
      \begin{luacode}
      local glyph_id = node.id "glyph"
      local glue_id  = node.id "glue"
      local hlist_id = node.id "hlist"

      last_line_twice_parindent = function (head)
        while head do
          local _w,_h,_d = node.dimensions(head)
          if head.id == glue_id and head.subtype ~= 15 and (_w < 2 * tex.parindent) then

              -- we are at a glue and have less then 2*\parindent to go
              local p = node.new("penalty")
              p.penalty = 10000

              \ifintdraft
                 local w = node.new("whatsit","pdf_literal")
                 w.data = "q \usecolor{\intlastparlinecolor} 0 0 m 0 5 l 2 5 l 2 0 l b Q"

                 node.insert_after(head,head.prev,w)
                 node.insert_after(head,w,p)
              \else
                 node.insert_after(head,head.prev,p)
              \fi
          end

          head = head.next
        end
        return true
      end

      luatexbase.add_to_callback("pre_linebreak_filter",last_line_twice_parindent,"lastparline")
      \end{luacode}
   \else
      \setlength{\parfillskip}{0pt plus\dimexpr\textwidth-2\parindent}
   \fi
\fi
%    \end{macrocode}
%
% \marginpar{Detect homeoarchies}
%
%    \begin{macrocode}
\ifinthomeoarchy
 \ifintdraft
   \ifluatex
      \RequirePackage{luatexbase,luacode}
      \begin{luacode}
      local glyph_id = node.id "glyph"
      local glue_id  = node.id "glue"
      local hlist_id = node.id "hlist"

      compare_lines = function (line1,line2)
        local head1 = line1.head
        local head2 = line2.head

        local char_count = 0
        local word_count = 0

        while head1 and head2 do
           if (head1.id == glyph_id and head2.id == glyph_id
                  and head1.char == head2.char)          -- identical glyph
              or (head1.id == glue_id and head2.id == glue_id) then  -- glue

              if head1.id == glyph_id then -- glyph
                 char_count = char_count + 1
              elseif char_count > 0 and head1.id == glue_id then -- glue
                 word_count = word_count + 1
              end
              head1 = head1.next
              head2 = head2.next
           elseif (head1.id == 0 or head2.id == 0) then -- end of line
              break
           elseif (head1.id ~= glyph_id and head1.id ~= glue_id) then -- some other kind of node
              head1 = head1.next
           elseif (head2.id ~= glyph_id and head2.id ~= glue_id) then -- some other kind of node
              head2 = head2.next
           else -- no match, no special node
              break
           end
        end
        -- analyze last non-matching node, check for punctuation
        if ((head1 and head1.id == glyph_id and head1.char > 49)
             or (head2 and head2.id == glyph_id and head2.char > 49)) then
           -- not a word
        elseif char_count > 0 then
           word_count = word_count + 1
        end
        return char_count,word_count,head1,head2
      end

      compare_lines_reverse = function (line1,line2)
        local head1 = node.tail(line1.head)
        local head2 = node.tail(line2.head)

        local char_count = 0
        local word_count = 0

        while head1 and head2 do
           if (head1.id == glyph_id and head2.id == glyph_id
                  and head1.char == head2.char)          -- identical glyph
              or (head1.id == glue_id and head2.id == glue_id) then  -- glue

              if head1.id == glyph_id then -- glyph
                 char_count = char_count + 1
              elseif char_count > 0 and head1.id == glue_id then -- glue
                 word_count = word_count + 1
              end
              head1 = head1.prev
              head2 = head2.prev
           elseif (head1.id == 0 or head2.id == 0) then -- start of line
              break
           elseif (head1.id ~= glyph_id and head1.id ~= glue_id) then -- some other kind of node
              head1 = head1.prev
           elseif (head2.id ~= glyph_id and head2.id ~= glue_id) then -- some other kind of node
              head2 = head2.prev
           elseif (head1.id == glyph_id and head1.char < 48) then -- punctuation
              head1 = head1.prev
           elseif (head2.id == glyph_id and head2.char < 48) then -- punctuation
              head2 = head2.prev
           else -- no match, no special node
              break
           end
        end
        -- analyze last non-matching node, check for punctuation
        if ((head1 and head1.id == glyph_id and head1.char > 49)
             or (head2 and head2.id == glyph_id and head2.char > 49)) then
           -- not a word
        elseif char_count > 0 then
           word_count = word_count + 1
        end
        return char_count,word_count,head1,head2
      end

      highlight = function (line,nend,color)
         local n = node.new("whatsit","pdf_literal")

         -- get dimensions
         local w,h,d = node.dimensions(line.head,nend)
         local w_pts = w/65536 -- scaled points to points

         -- set data
         n.data = "q " .. color .. " 0 0 m 0 5 l " .. w_pts .. " 5 l " .. w_pts .. " 0 l b Q"

         -- insert node
         n.next = line.head
         line.head = n
         node.slide(line.head)
      end

      highlight_reverse = function (nstart,line,color)
         local n = node.new("whatsit","pdf_literal")


         -- get dimensions
         local w,h,d = node.dimensions(nstart,node.tail(line.head))
         local w_pts = w/65536 -- scaled points to points

         -- set data
         n.data = "q " .. color .. " 0 0 m 0 5 l " .. w_pts .. " 5 l " .. w_pts .. " 0 l b Q"

         -- insert node
         node.insert_after(line.head,nstart,n)
      end

      homeoarchy = function (head)
        local cur_line = head
        local prev_line -- initiate prev_line

        local max_char = tonumber(\inthomeoarchymaxchars)
        local max_word = tonumber(\inthomeoarchymaxwords)

        while head do
          if head.id == hlist_id then -- new line
            prev_line = cur_line
            cur_line = head
            if prev_line.id == hlist_id then
               -- homeoarchy
               char_count,word_count,prev_head,cur_head = compare_lines(prev_line,cur_line)
               if char_count >= max_char or word_count >= max_word then
                  local color
                  if word_count >= max_word then
                     color = "q \usecolor{\inthomeoarchywordcolor}"
                  else
                     color = "q \usecolor{\inthomeoarchycharcolor}"
                  end

                  -- highlight both lines
                  highlight(prev_line,prev_head,color)
                  highlight(cur_line,cur_head,color)
               end
            end
          end
          head = head.next
        end
        return true
      end

      luatexbase.add_to_callback("post_linebreak_filter",homeoarchy,"homeoarchy")

      homoioteleuton = function (head)
        local cur_line = head
        local prev_line -- initiate prev_line

        local max_char = tonumber(\inthomeoarchymaxchars)
        local max_word = tonumber(\inthomeoarchymaxwords)

        local linecounter = 0

        while head do
          if head.id == hlist_id then -- new line
            linecounter = linecounter + 1
            if linecounter > 1 then
               prev_line = cur_line
               cur_line = head
               if prev_line.id == hlist_id then
                  -- homoioteleuton
                  char_count,word_count,prev_head,cur_head = compare_lines_reverse(prev_line,cur_line)
                  if char_count >= max_char or word_count >= max_word then
                     local color
                     if word_count >= max_word then
                        color = "q \usecolor{\inthomeoarchywordcolor}"
                     else
                        color = "q \usecolor{\inthomeoarchycharcolor}"
                     end

                     -- highlight both lines
                     highlight_reverse(prev_head,prev_line,color)
                     highlight_reverse(cur_head,cur_line,color)
                  end
               end
            end
          end
          head = head.next
        end

        return true
      end

      luatexbase.add_to_callback("post_linebreak_filter",homoioteleuton,"homoioteleuton")
      \end{luacode}
   \else
      \PackageError{The homeoarchy option only works with LuaTeX}
   \fi
 \fi
\fi
%    \end{macrocode}
%
% \marginpar{Detect rivers}
%
%    \begin{macrocode}
\ifintrivers
 \ifintdraft
   \ifluatex
      \RequirePackage{luatexbase,luacode}
      \begin{luacode}
local glyph_id = node.id "glyph"
local glue_id  = node.id "glue"
local hlist_id = node.id "hlist"

river_analyze_line = function(line,dim1,dim2,precision)
   local head = line.head

   while head do
      if head.id == glue_id then  -- glue node
         local w1,h1,d1 = node.dimensions(line.glue_set,line.glue_sign,line.glue_order,line.head,head.prev)
         local w2,h2,d2 = node.dimensions(line.glue_set,line.glue_sign,line.glue_order,line.head,head)
         --print("dim1:"..dim1.."; dim2:"..dim2.."; w1:"..w1.."; w2:"..w2)
         if w1 > dim2 + precision then  -- out of range
            return false,head
         elseif w1 < (dim2 + precision) and w2 > (dim1 - precision) then -- found
            return true,head
         end
      end
      head = head.next
   end

   return false,head
end

rivers = function (head)
   local prev_prev_line
   local prev_line
   local cur_line = head
   local cur_node
   local char_count

   local linecounter = 0

   while head do
      if head.id == hlist_id then -- new line
         linecounter = linecounter + 1
         prev_prev_line = prev_line
         prev_line = cur_line
         cur_line = head
         if linecounter > 2 then
            cur_node = cur_line.head
            char_count = 0

            while cur_node do
               if cur_node.id == glyph_id then  -- glyph
                  char_count = char_count + 1
               elseif cur_node.id == glue_id and char_count > 0 and cur_node.next then  -- glue node
                  -- prev_line
                  local w1,h1,d1 = node.dimensions(head.glue_set,head.glue_sign,head.glue_order,head.head,cur_node.prev)
                  local w2,h2,d2 = node.dimensions(head.glue_set,head.glue_sign,head.glue_order,head.head,cur_node)
                  -- if we allow up to 45° diagonal rivers, then there can be up to + or - line height between spaces
                  local w_p,h_p,d_p = node.dimensions(prev_line.head,cur_line.head) -- calculate line height
                  found_p,head_p = river_analyze_line(prev_line,w1,w2,h_p)

                  if found_p then
                     -- prev_prev_line
                     local w1,h1,d1 = node.dimensions(prev_line.glue_set,prev_line.glue_sign,prev_line.glue_order,prev_line.head,head_p.prev)
                     local w2,h2,d2 = node.dimensions(prev_line.glue_set,prev_line.glue_sign,prev_line.glue_order,prev_line.head,head_p)
                     -- if we allow up to 45° diagonal rivers, then there can be up to + or - line height between spaces
                     local w_p,h_p,d_p = node.dimensions(prev_prev_line.head,prev_line.head) -- calculate line height
                     found_pp,head_pp = river_analyze_line(prev_prev_line,w1,w2,h_p)

                     if found_pp then
                        local n_pp = node.new("whatsit","pdf_literal")
                        n_pp.data = "q \usecolor{\intriverscolor} 0 0 m 0 5 l 5 5 l 5 0 l b Q"
                        node.insert_after(prev_prev_line,head_pp.prev,n_pp)

                        local n_p = node.new("whatsit","pdf_literal")
                        n_p.data = "q \usecolor{\intriverscolor} 0 0 m 0 5 l 5 5 l 5 0 l b Q"
                        node.insert_after(prev_line,head_p.prev,n_p)

                        local n_c = node.new("whatsit","pdf_literal")
                        n_c.data = "q \usecolor{\intriverscolor} 0 0 m 0 5 l 5 5 l 5 0 l b Q"
                        node.insert_after(cur_line,cur_node.prev,n_c)
                     end
                  end
               end
               cur_node = cur_node.next
            end
         end
      end
      head = head.next
   end

   return true

end


luatexbase.add_to_callback("post_linebreak_filter",rivers,"rivers")
      \end{luacode}
   \else
      \PackageError{The homeoarchy option only works with LuaTeX}
   \fi
 \fi
\fi
%    \end{macrocode}
%
% \iffalse
%</package>
%<*fr>
%% Set language to French
\expandafter\newif\csname ifenglish\endcsname
\englishfalse
\input{impnattypo.dtx}
%</fr>
% \fi
%
% \Finale
\endinput
