%%%%% \iffalse meta-comment % %% File: unicodefonttable.dtx (C) Copyright 2019-2024 Frank Mittelbach % % 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 % % % The development version of the bundle can be found below % % https://github.com/FrankMittelbach/fmitex/ % % for those people who are interested or want to report an issue. % \def\unicodefonttabledate {2024/03/01} \def\unicodefonttableversion{1.0h} %<*driver> \documentclass{l3doc-TUB} % some fixes local to this documentation \ExplSyntaxOn \cs_new:Npn\IfImplementationShownTF {\bool_if:NTF \g__codedoc_typeset_implementation_bool} \ExplSyntaxOff \makeatletter \def\meta@font@select{\normalfont\itshape} \IndexPrologue{% \IfImplementationShownTF{\section*{Index}% Numbers written in italic refer to the page where the corresponding entry is described or mentioned. Numbers underlined refer to the code line of the definition; numbers in Roman refer to the code lines where the entry is used.}% {\section{Index}% Numbers written in italic refer to the page where the corresponding entry is described or mentioned.}} \makeatother \usepackage{graphicx,unicodefonttable} \EnableCrossrefs \CodelineIndex \begin{document} \DocInput{unicodefonttable.dtx} \advance\signaturewidth by 40pt \makesignature \end{document} % % % \fi % % \tracinglostchars=3 % % \newcommand\key [1]{\texttt{#1}} % \newcommand\kval[1]{\texttt{#1}} % % \newcommand\keysetup[1]{\noindent\marginpar{\raggedleft Key setup: #1}\ignorespaces} % \renewcommand\keysetup[1]{\paragraph*{\hspace*{-8pc}Key setup (#1)}} % % % \title{The \texttt{unicodefonttable} package\thanks{This is % version \unicodefonttableversion\ of the package, dated % \unicodefonttabledate; the license is LPPL.}} % \author{Frank Mittelbach} % \address{Mainz, Germany} % \netaddress{https://www.latex-project.org} % \personalURL{https://ctan.org/pkg/unicodefonttable} % \raggedbottom % % \maketitle % % % \begin{abstract} % A package for typesetting font tables for larger fonts, e.g., % TrueType or OpenType Unicode fonts. % To produce a one-off table, a standalone version is available as well. % \end{abstract} % % \vspace*{\medskipamount} % % \tableofcontents % % \vspace*{\bigskipamount} % % \section{Introduction} % % When I started to write a new chapter for the third edition of % \emph{The \LaTeX{} Companion} on modern fonts available for % different \LaTeX{} engines, I was a bit surprised that I couldn't % find a way to easily typeset tables showing the glyphs available in % TrueType or OpenType fonts. The \pkg{nfssfont} package available % with \LaTeX{} only supports fonts from the 8-bit world, but % modern fonts that can be used with \XeTeX{} or \LuaTeX{} can % contain thousands of glyphs and having a method to display what % is available in them was important for me. % % I therefore set out to write my own little package and what % started as an afternoon exercise ended up being this package, % offering plenty of bells and whistles for typesetting such % font tables. % % As there can be many glyphs in such fonts a tabular % representation of them might run for several pages, so the % package internally uses the \pkg{longtable} package to handle % that. % % In most cases the glyphs inside the fonts are indexed by their % Unicode numbers so it is natural to display them sorted by their % position in the Unicode character set. % % Unicode is organized in named blocks such as ``Basic Latin'', % ``Latin-1~Supplement'', etc., typically consisting of 265 % characters each.\footnote{Some blocks are smaller, while those % containing the Asian ideographs are much larger.} It is therefore % helpful to use these block names as subtitles within the table, % to more easily find the information one is looking for. % % A common way to represent the number of a single Unicode % character is \texttt{U+} followed by four (or more) % hexadecimal digits. For example, \texttt{U+0041} represents the letter % ``A'' and \texttt{U+20AC} the Euro currency symbol ``\texteuro''. % We use this convention by showing a Unicode range of sixteen % characters at the left of each table row, % e.g., \texttt{U+0040 - % 004F}, followed by the sixteen glyphs in the range. Thus that % \IfImplementationShownTF{}{\pagebreak}\ignorespaces % particular table row from the ``Basic Latin'' block would show % something like % % \displayfonttable*[noheader,range-start=0040, range-end=004F, % color=black!50]{Latin Modern Sans} % % If a Unicode character has no glyph representation in a given % font then this is indicated by a special symbol (by default a % colored hyphen). By default some color is used, but we've grayscaled % the output for \TUB. % % In order to easily locate any Unicode character the table shows by % default sixteen hex digits as a column heading. For example, to find % Euro currency symbol (\texttt{U+20AC}) one first finds the % right row, which is the range \texttt{U+20A0 - 20AF}, and then % the \texttt{C} column in that row, and the glyph is there (or an % indication that the font is missing that glyph; % the line shows that for some of the other slots). % % \displayfonttable*[noheader,range-start=20A0, range-end=20AF, % color=black!50]{Latin Modern Sans} % % It can be useful to compare two fonts with each other by % filling the table with glyphs from a secondary font if the % primary font is missing them. For example, the next display shows % two rows of Latin Modern Math (black glyphs) and instead of showing % a missing glyph symbol in most slots, we use the glyphs from New % Computer Modern Math, which has a much larger glyph set % (normally red glyphs with gray background but again, grayscaled for % \TUB). % % % \displayfonttable[noheader,nostatistics,display-block=none, % compare-with=NewCMMath-Regular.otf,range-start=2A00,range-end=2A1F, % color=black!50,compare-color=none] % {latinmodern-math.otf} % % % \section{The user interface} % % The package offers one command to typeset a font table. The % appearance of the table can be customized by specifying key/value % pairs. % % \begin{function}{\displayfonttable} % \begin{syntax} % \cs{displayfonttable} \texttt{*} \oarg{key/value-list} \Arg{font-name} \oarg{font-features} % \end{syntax} % The \meta{font-name} is the font to be displayed. This and the % \meta{font-features} argument are passed to \pkg{fontspec}, thus they % should follow the conventions of that package for specifying a % font. The \meta{key/value-list} offers customization % possibilities discussed below. % % The \cs{displayfonttable*} is a variant of the command, intended % for use with 8-bit legacy fonts. It presets some keys, but % otherwise behaves identically. The preset values are: %\begin{verbatim} % nostatistics, display-block=none, hex-digits=head, range-end=FF %\end{verbatim} % For details see the next section. % \end{function} % % % % \begin{function}{\fonttablesetup} % \begin{syntax} % \cs{fonttablesetup} \Arg{key/value-list} % \end{syntax} % Instead of or in addition to specifying key/values to % \cs{displayfonttable} it is possible to set them up as % defaults. Inside \cs{displayfonttable} the defaults are applied first, % so one can still overwrite their values for an individual table. % \end{function} % % % \begin{function}{\fonttableglyphcount} % \begin{syntax} % \cs{fonttableglyphcount} % \end{syntax} % While typesetting a font table the package keeps track of the % number of glyphs it finds in the font. After the table has finished, % this value is available in \cs{fonttableglyphcount} and it is, for % example, used when statistics are produced. At the start of the % next table it is reset to zero. % \end{function} % % % % % \subsection{Keys and their values} % % Several of the available keys are booleans accepting \texttt{true} % or \texttt{false}. They usually exist in pairs so that one can % specify the desired behavior without needing to provide a value, % e.g., specifying \key{header} is equivalent to specifying % \key{header}\texttt{=true} or \key{noheader}\texttt{=false}, etc. % In the lists below the default settings are indicated by an % underline. % % \begin{variable}{ % header, noheader, % title-format, title-format-cont, % } % The first set of keys is concerned with the overall look and % feel of the generated table. % \begin{description} % \item[\underline{\key{header}}, \key{noheader}] % These keys determine whether a header to the table is % produced. % % \item[\key{title-format}, \key{title-format-cont}] % These keys define what is provided as a header title or % continuation title if the table consists of several pages. % They expect code as their value. This code can contain \verb=#1= % and \verb=#2= to denote the \meta{font-name} and % \meta{font-features} arguments, respectively. % % By default a title using the \cs{caption} command is produced; on % continuation titles, the \meta{font-features} are not shown. % This is typeset as a \env{longtable} header row, so you either need to use % \cs{multicolumn} or a \cs{caption} command\Dash otherwise everything % ends up in the first column. % % \end{description} % % \end{variable} % % % \begin{variable}{ % display-block, % hex-digits, hex-digits-font,hex-digits-row-format, % color, % } % These keys handle the inner parts of the table. % % \begin{description} % \item[\key{display-block}] % The Unicode dataset is organized in named blocks that are typically 128 or % 256 characters, though some are noticeably larger and a few are % smaller. With the \key{display-block} key it is % possible to specify if and how such blocks should be made visible. % The following values are supported: % \begin{description} % \item[\underline{\kval{titles}}] % Above each display block that contains glyphs the Unicode title % of the block is displayed. % % \item[\kval{rules}] % Display blocks are indicated only by a \cs{midrule}. % % \item[\kval{none}] % Display blocks are not indicated at all. % \end{description} % % \item[\key{hex-digits}] % To ease reading the table, rows of hex digits are added to % it. Where or if this happens is controlled by this key. Allowed % values for it are the following: % \begin{description} % \item[\kval{block}] % A row of hex digits is placed at the beginning of each Unicode % block containing glyphs in the displayed font. % % \item[\kval{foot}] % A row is added to the foot of each table page. % % \item[\underline{\kval{head}}] % A row is added to the top of each table page. % % \item[\kval{head+foot}] % A row is added to the top and the foot of each table page. % % \item[\kval{none}] % All hex digit rows are suppressed. % \end{description}% % % \item[\key{hex-digits-font}] % The font to use for the hex digits, by default % \underline{\cs{ttfamily}\cs{scriptsize}}.{\hfuzz=2.7pt\par} % % \item[\key{hex-digits-row-format}] % This key defines the format for the hex digits shown on the left % of each row. It accepts one argument hold the hex values for the % row except for the last digit, e.g, \texttt{0A3} for the values % from \texttt{0A30} to \texttt{0A3F}. The default formatting is % \underline{\ttfamily U+\#10\cs{,}-\cs{,}\#1F} and without further % adjustments it is automaticaly set % in \cs{ttfamily}\cs{footnotesize} and in the color % specified by the \key{color} key. % A suitable value that takes up less space would be \texttt{U+\#1x}. % % % % \item[\key{color}] % This key determines the color for parts of the table (hex digits % and Unicode ranges). It can be either \kval{none} or a color % specification as understood by the \cs{color} command. % The default is \underline{\texttt{blue}}. % % \end{description} % % \end{variable} % % % \begin{variable}{ % statistics, nostatistics, % statistics-font,statistics-format, % } % The next set of keys allows altering the statistics that are produced. % \begin{description} % % \item[\underline{\key{statistics}}, \key{nostatistics}] % These keys determine whether some statistics are listed at % the end of the table. % % \item[\key{statistics-font}] % The font used to typeset the statistics; the default is\\ % \underline{\cs{normalfont}\cs{small}}. % % % \item[\key{statistics-format}] % Code (text) to specify what should be typeset in the % statistics. One can use \verb=#1= for the \meta{font-name} and % \verb=#2= for the glyph count. % The material is typeset on a single line at the end of the % table. If several lines are needed you need to use \cs{parbox} % or a similar construct. % \end{description} % \end{variable} % % % % \begin{variable}{ % glyph-width, % missing-glyph, missing-glyph-font, missing-glyph-color, % } % Another set of keys deals with customization on the glyph level. % \begin{description} % \item[\key{glyph-width}] % All glyphs are typeset in a box with the same width, the default % value is \underline{\texttt{6pt}} which is suitable for most 10pt % fonts % and make the table fit comfortably into the text width of % a typical document. % % \item[\key{missing-glyph}] % If a slot in a row doesn't have a glyph in the font you may still % want display something to indicate this state. By giving the key % a value any arbitrary glyph or material can be typeset. The % default is to typeset a \kval{-} (hyphen) in a special color. % % Rows that contain no glyph whatsoever are not displayed at % all. Instead a small vertical space is added to indicate the one % or more rows are omitted. % % \item[\key{missing-glyph-font}] % % The font used for the missing glyphs (the default value is % \underline{\cs{ttfamily}\cs{scriptsize}}). % % \item[\key{missing-glyph-color}] % If not specified it uses the value specified with the \key{color} % key. If you want a different color, e.g., \texttt{red}, you can % use a color value or you can specify \kval{none} to use no coloring. % % \end{description} % % \end{variable} % % % \begin{variable}{ % compare-with,compare-color, compare-bgcolor,statistics-compare-format % } % % You can make comparisons between two fonts, which is useful, for % example when dealing with incomplete math fonts and you need to % see how well the symbols from one font blend with the supplementary % symbols from another font. % % \begin{description} % \item[\key{compare-with}] % % If given, the value is a \meta{comparison-font-name} that is used % to supply missing glyphs. This means that if the \meta{font-name} % to be displayed is missing a glyph in a slot, then the % \meta{comparison-font-name} is checked, and if that font has the % glyph in question, it will be displayed instead of showing a % missing glyph indicator. % % \item[\key{compare-color}, \key{compare-bgcolor}] % % To distinguish real glyphs from missing but substituted glyphs, % they can be colored specially (default \underline{\texttt{red}}) % and/or you can have their background colored (default is % \underline{\texttt{black!10}}, i.e., a light gray). % % \item[\key{statistics-compare-format}] % % Code (text) to specify what should be typeset in the statistics % when comparing two fonts. One can use \verb=#1= for the % \meta{font-name} and \verb=#2= for its glyph count, \verb=#3= is % the name of the comparison font, \verb=#4= its glyph count, % \verb=#5= for the number of glyphs missing in this font and % \verb=#6= the number of extra glyphs in it. This code is used % instead of \key{statistics-format} when comparisons are made. % % The material is typeset on a single line at the end of the % table. If several lines are needed you need to use \cs{parbox} % or a similar construct. % % \end{description} % \end{variable} % % % \begin{variable}{ % range-start, range-end, % } % Finally there are two keys for restricting the display range. % \begin{description} % \item[\key{range-start}, \key{range-end}] % The full Unicode set of characters is huge and checking every % slot to see if the current font contains a glyph in the slot % takes a long time. If you know that font contains only a % certain subset then you can speed up the table generation % considerably by limiting the search (and consequently the output % generation). % The \key{range-start} specifies where to start with the search % (default \underline{\texttt{0000}}) and \key{range-end} gives % the last slot that is tested (default % \underline{\texttt{FFFF}}). % % Thus, by default we restrict the display to slots below % \texttt{10000}, because text fonts seldom contain glyphs in the % higher planes. But if you want to see everything of the font (as % far as supported by this package) and are prepared to wait for % the higher % planes to be scanned, you can go up to a value of \texttt{FFFFF}. % % However, please note that the \LuaTeX{} fontloader uses the % \enquote{Supplementary Private Use Area-A}, which starts at % \texttt{F0000}, as its own playground and places remapping into % it, so by default you see random data instead of font data there. You % either have to use the \XeTeX{} engine or load the font with % \texttt{Renderer=HarfBuzz} in \LuaTeX{}. % % These keys are also quite useful in combination with the previous % \key{compare-with} key, to display only, for example, the Greek % letters and see how glyphs from two fonts blend with each other. % \end{description} % \end{variable} % % % % \subsection{A standalone interactive version} % % If you want to quickly display a single font, you can run % \texttt{unicodefont.tex} through \LaTeX{} using \LuaTeX{} (or \XeTeX{}) % as the engine. Similar to % \texttt{nfssfont.tex} (which is for 8-bit fonts with \pdfTeX) it % asks you a few questions and then generates the font table for % you. There are fewer configuration options available, % but this workflow saves you writing a document to get a % one-off table. % % Most font tables need several runs due to the use of % \pkg{longtable}, which has to find the right width for the columns % across several pages. The \texttt{unicodefont} file therefore % remembers your selection from the previous run and asks you if % you want to reapply it to speed up the process. % % % % \section{Notes on the table data} % % If you look at some parts of a Unicode font table you see a number of slots that % do not show a \enquote{missing glyph} sign, but nonetheless appear % to be empty. For example: % % \displayfonttable[noheader,nostatistics,display-block=none, % range-start=0020,range-end=00BF, % color=black!50] % {TeX Gyre Pagella} % % % The reason is that Unicode contains a lot of special % spaces or otherwise invisible characters, e.g., \texttt{U+0020} % is the normal space, \texttt{U+00A0} is a non-breaking space, % \texttt{U+00AD} is a soft-hyphen (what \LaTeX{} users would % indicate with \cs{-}), and so forth. Especially the row % \texttt{U+2000-200F} in Table~6 looks strange as it appears to be totally % empty, but in fact most of its slots contain spaces of different % width. % %\displayfonttable[noheader,nostatistics,hex-digits=foot, % range-start=2000,range-end=202F, % color=black!50] % {latinmodern-math.otf} % % % Another somewhat surprising area is the \enquote{Mathematical % Alphanumeric Symbols} block in math fonts, starting at \texttt{U+1D400}. % There you see a number of missing characters, the first two being % \texttt{U+1D455} (math italic small h) and \texttt{U+1D49D} (math % script B). % % \displayfonttable[noheader,nostatistics,hex-digits=foot, % range-start=1D400,range-end=1D4AF, % color=black!50] % {latinmodern-math.otf} % % In this case the reason is \emph{not} that the font % fails to implement the characters, but that these characters have % already been defined in earlier revisions of the Unicode standard in the % lower Unicode plane. For example, the \enquote{h} is the % Planck constant \texttt{U+210E} and \texttt{U+212C} is % the script capital B, etc. The Unicode Consortium decided not % to encode the \emph{same} character twice, hence the apparent % holes. % % % \IfImplementationShownTF{} % {\appendix % \def\theHsection{Appendix.\thesection} % \addtocontents{toc}{\smallskip} % \setlength\IndexMin{200pt} % \PrintIndex % } % % % \section{Examples} % % In this section we show the results of a few calls to % \cs{displayfonttable}. % The tables are a bit easier to navigate if they use color in some % places, but for \TUB{} this is not practical, so we % use black and gray. % % Please note that this documentation was produced with % \LuaTeX{}. If you reuse the examples with \XeTeX{}, you may have % to specify the font names differently (i.e., following to the % \pkg{fontspec} documentation for this engine). % % % % \subsection{Computer Modern Sans --- 7-bit font} % % Our first example is the original Computer Modern Sans, with % character codes $\le 127$. % % Command used: \begin{verbatim} % \displayfonttable*[color=none, range-end=7F]{cmss10} % \end{verbatim} % % \displayfonttable*[color=none, range-end=7F]{cmss10} % % % \iftrue % %\subsection{\TeX\ Gyre Heros --- 8-bit font} % % This example shows the \TeX\ Gyre Heros 8-bit font, % in the T1 encoding, with character codes $\le 255$. % We used \key{hex-digits-row-format} to shorten the row titles on % the left: %\begin{verbatim} % \displayfonttable*[color=none,hex-digits-row-format=U+#1]{ec-qhvr} %\end{verbatim} % %\displayfonttable*[color=none,hex-digits-row-format=U+#1]{ec-qhvr} % % \fi % % % \iftrue %\subsection{Latin Modern Math --- 8-bit fonts} % % The traditional Latin Modern Math Italic, Symbol and Extension fonts. % The symbol font (\texttt{lmsy10}) has two characters added to the % Computer Modern symbol repertoire, seen in the last row of the table. % Commands used: % %\begin{verbatim} % \displayfonttable*[color=none]{lmmi10} % \displayfonttable*[color=none]{lmsy10} % \displayfonttable*[color=none]{lmex10} %\end{verbatim} % %\displayfonttable*[color=none]{lmmi10} %\displayfonttable*[color=none]{lmsy10} %\displayfonttable*[color=none]{lmex10} % % \fi % % % \iffalse % 5pp % %\subsection{\TeX{} Gyre Pagella (Palatino) oldstyle figures --- OTF font} % % This example shows Pagella with oldstyle numerals. % Command used: %\begin{verbatim} %\displayfonttable{TeX Gyre Pagella}[Numbers=OldStyle] %\end{verbatim} % %\displayfonttable{TeX Gyre Pagella}[Numbers=OldStyle] % % \fi % % % ^^A \IfImplementationShownTF{}{\newpage} % % \subsection{Latin Modern Math compared to New Computer Modern Math} % % This example shows the extra symbols available in New Computer % Modern Math in comparison to Latin Modern Math as the base font. % We use the following setup (including settings for the % grayscaled \TUB\ output, as an example of color overrides): %\begin{verbatim} % \displayfonttable[hex-digits=head+foot, range-end=1FFFF, % compare-with=New Computer Modern Math, % title-format=\caption{Latin Modern Math compared to % New Computer Modern Math}, % title-format-cont=\caption{LM Math vs.\ NewCM Math, % \emph{cont.}}, % compare-color=black, compare-bgcolor=black!5, % missing-glyph-color=black!50, color=black!75] % {Latin Modern Math} %\end{verbatim} % That is, glyphs only in \texttt{NewCM} are shown with a light gray % background. % % We also extended the range to cover \texttt{U+10000} to % \texttt{U+1FFFF} in order to include the Unicode Math alphabets. % % \displayfonttable[hex-digits=head+foot, range-end=1FFFF, % compare-with=New Computer Modern Math, % title-format=\caption{Latin Modern Math compared to % New Computer Modern Math}, % title-format-cont=\caption{LM Math vs.\ NewCM Math, % \emph{cont.}}, % compare-color=black, compare-bgcolor=black!5, % missing-glyph-color=black!50, color=black!75] % {Latin Modern Math} % % %\subsection{Garamond Libre's Byzantine Musical Symbols} % % As a final example we exhibit the Byzantine Musical Symbols as provided by % Garamond Libre. % Command used: %\begin{verbatim} % \displayfonttable[range-start=1D000, range-end=1D0FF, % hex-digits=block, % missing-glyph-color=black!50, color=black!75, % statistics-format=Total number of glyphs in % this block of #1 is #2] % {Garamond Libre} %\end{verbatim} % % Note that we have altered the text produced by the statistics, % because the default is somewhat misleading if only a portion of % the font is displayed. This produces the following table: % % \displayfonttable[range-start=1D000, range-end=1D0FF, % hex-digits=foot, % missing-glyph-color=black!50, color=black!75, % statistics-format=Total number of glyphs in % this block of #1 is #2] % {Garamond Libre} % % % % \IfImplementationShownTF % {\StopEventually{\setlength\IndexMin{200pt} \PrintIndex }} % {\StopEventually{}} % % % % \section{The package implementation} % % \hfuzz=10pt ^^A lots of slightly overfull tt lines % % \begin{macrocode} %<*package> % \end{macrocode} % % By default the package uses coloring to improve the table % appearance and therefore requires a color package. % \begin{macrocode} \RequirePackage{xcolor} % \end{macrocode} % % \begin{macrocode} %<@@=fmuft> % \end{macrocode} % % We need the package \pkg{xparse} for specifying the document-level % interface commands and \pkg{l3keys2e} to use the \pkg{expl3} key % value methods within \LaTeXe{}. These packages automatically % require \pkg{expl3} so there is no need to load that explicitly. % Actually, \pkg{expl3}, \pkg{l3keys2e} and the \pkg{xparse} % functionality is now all part of the \LaTeX{} kernel so the next % line is actually not needed at all with a current \LaTeX{} kernel, but % in order to support older installations we keep it for now. % % \begin{macrocode} \RequirePackage{xparse,l3keys2e} % \end{macrocode} % % Here we introduce the package and specify its version number: % \begin{macrocode} \ProvidesExplPackage{unicodefonttable} {\unicodefonttabledate} {\unicodefonttableversion} {Producing font tables for Unicode and other fonts} % \end{macrocode} % % \newcommand\hex[1]{$\langle\textit{hex}_{#1}\rangle$} % % % % % % \subsection{User interface commands} % % % Throughout the implementation we will define a number of keys (and % their allowed values). We introduce them at the point where they are % used, so they are sprinkled throughout the code.\footnote{This fits % with the way this package was developed. I first implemented a % single rigid table layout without configuration possibilities and % then thought about which parts I wanted to have flexible. I then % replaced the rigid code with code that is affected by setting % key/value pairs.} % \begin{macro}{\fonttablesetup} % To set up user defaults for the keys we provide a standard % interface. The command \cs{unicodefonttabletablesetup} expects a % key/value list and can be called as often as necessary. % \begin{macrocode} \NewDocumentCommand \fonttablesetup { m } { \keys_set:nn {@@} {#1} \ignorespaces } % \end{macrocode} % \end{macro} % % % % \begin{macro}{\displayfonttable} % The document-level command for generating a font table. % \begin{macrocode} \NewDocumentCommand\displayfonttable {s O{} m o}{% \IfBooleanTF #1 { % \end{macrocode} % For the starred form we preset a number of keys with values % suitable when displaying 8-bit legacy fonts. % With such fonts Unicode block headers make little % sense (as the fonts do not conform to the Unicode layout and % since they have at most 265 glyphs). It is therefore also unnecessary to % loop over the whole Unicode range of the first plane. % If necessary all of them can still be overwritten in the optional argument. % \begin{macrocode} \@@_display_fonttable:nnn {nostatistics,display-block=none,hex-digits=head,range-end=FF,#2} {#3}{#4} } { \@@_display_fonttable:nnn {#2}{#3}{#4} } } % \end{macrocode} % \end{macro} % % % \begin{macro}{\@@_display_fonttable:nnn} % This command is the main workhorse of the % package. It produces a \texttt{longtable} containing all font % glyphs with 16 glyphs per row. The first optional argument is % used to configure the table through key/value pairs, the % mandatory argument is the font name to display (in % \texttt{fontspec} conventions) and the final optional argument is % the font feature list if any. If the latter is not provided it % will get a special value (\texttt{--NoValue--}) assigned by % \texttt{xparse}, which is something that can be tested for. % \begin{macrocode} \cs_new:Npn \@@_display_fonttable:nnn #1#2#3 { \group_begin: % \end{macrocode} % First initialize the font that should be displayed (perhaps with a % feature list) and then update the key/value list using \verb=#1=. % \begin{macrocode} \fontspec{#2}[#3] \keys_set:nn{@@}{#1} % \end{macrocode} % If the \LuaTeX{} engine is used without HarfBuzz and the display % range includes code points above \texttt{U+EFFFF} the output shows % remappings and not what is in the font, so we issue a warning. % \changes{v1.0g}{2022/11/12}{Test for luatex without harfbuzz and % private area A and warn (gh/8)} % \begin{macrocode} \bool_lazy_and:nnT { \sys_if_engine_luatex_p: } { \int_compare_p:nNn { "EFFFF } < { "\l_@@_range_end_tl } } { \directlua{token.put_next(token.create(font.getfont(font.current()).hb~ and~ 'use_none:n'~ or~ 'use:n'))} { \msg_warning:nn {unicodefonttable}{noharfbuzz} } } % \end{macrocode} % If the user has asked for a comparsion to some other font we need to set this up: % \begin{macrocode} \tl_if_empty:NTF \l_@@_compare_with_tl { \tl_clear:N \l_@@_compare_font_tl } { \setfontface \l_@@_compare_font_tl {\l_@@_compare_with_tl}[] \cs_set_eq:NN \@@_handle_missing_glyph:n \@@_handle_missing_glyph_compare:n } % \end{macrocode} % Typesetting the font tables in twocolumn mode makes little sense % due to their width, and if \env{longtable} is used it will % complain. However there is one case where it should work: in a % page-wide float. To make this happen we claim that we are not in % twocolumn mode if the display is inside a vertical box. % \changes{v1.0g}{2022/11/12}{Support use in twocolumn mode if inside % a table* float (gh/7)} % \begin{macrocode} \if_mode_vertical: \if_mode_inner: \@twocolumnfalse \fi: \fi: % \end{macrocode} % Then we start the table with 17 columns. We use \texttt{longtable} % if we produce a caption and \texttt{longtable*} if not (so that % the table number is not increased, which would look odd if you % have other tables in your document). % \begin{macrocode} \begin{longtable\bool_if:NF\l_@@_display_header_bool{*}} {@{}r@{\quad}*{16}{c}@{}} % \end{macrocode} % Special headers and footers are set up first: % \begin{macrocode} \@@_setup_header_footer:nn{#2}{#3} % \end{macrocode} % Then we produce all table rows with the glyphs. % \begin{macrocode} \@@_produce_table_rows: % \end{macrocode} % At the very end we may typeset some statistics. This can't be % done in the table footer, because the data is dynamic (e.g., % number of glyphs processed) and the table footers are static and % do not change based on the table content. % \begin{macrocode} \@@_handle_table_ending:n {#2} \end{longtable\bool_if:NF\l_@@_display_header_bool{*}} \group_end: } % \end{macrocode} % \end{macro} % % % \begin{macrocode} \msg_new:nnn {unicodefonttable}{noharfbuzz} { You~ asked~ for~ displaying~ glyphs~ with~ code \iow_newline: points~ above~ U+EFFFF~ \msg_line_context: ,~ i.e.,~ from~ the~ 'Supplementary~ Private~ Use~ Area-A'\iow_newline: without~ specifying~ '[Renderer=Harfbuzz]'~ when~ loading~ the~ font. \iow_newline:\iow_newline: With~ LuaLaTeX,~ this~ Unicode~ region~ is~ used~ for~ remappings~ (if~ the~ HarfBuzz~ engine~ is~ not~ used).~ Thus,~ the~ results~ shown~ do~ not~ reflect~ what~ is~ in~ the~ font! } % \end{macrocode} % % % % \begin{macro}{\fonttableglyphcount} % \begin{macro}{\g_@@_glyph_int,\g_@@_glyph_only_B_int,\g_@@_glyph_also_B_int} % While generating the font table we count the number of glyphs we % see (and typeset). The total is available in the command % \cs{fonttableglyphcount} after the table got finished and will be reset to % zero when the next table starts. % \begin{macrocode} \DeclareDocumentCommand \fonttableglyphcount {} { \int_use:N \g_@@_glyph_int } % \end{macrocode} % % \begin{macrocode} \int_new:N \g_@@_glyph_int % \end{macrocode} % When comparing fonts we also record data for the second font: the % number of glyphs in both and the number of glyphs only in the % second one. % \begin{macrocode} \int_new:N \g_@@_glyph_only_B_int \int_new:N \g_@@_glyph_also_B_int % \end{macrocode} % \end{macro} % \end{macro} % \subsection{The overall table layout} % % % \begin{macro}{\@@_setup_header_footer:nn} % Setting up header and footer lines of the table. % This macro receives the \textit{font name} and the \textit{font % features} specified by the user as its arguments. % \begin{macrocode} \cs_new:Npn \@@_setup_header_footer:nn #1#2{ % \end{macrocode} % On the first page of the table the header may show a caption or % some other sort of title based on the value of % \cs{l_@@_display_header_bool}. The formatting is handled by % \cs{@@_format_table_title:nn} which can be customized through the % key \key{title-format}. % \begin{macrocode} \bool_if:NT \l_@@_display_header_bool { \@@_format_table_title:nn{#1}{#2} \@@_debug_nl:n{T}\\*[6pt] } % \end{macrocode} % We may also want to display a line of hex digits. This is % controlled through the key \key{hex-digits} that accepts different % values: \kval{head}, \kval{foot}, \kval{head+foo}, \kval{block} % (after a block title) or \kval{none}. % \begin{macrocode} \bool_if:NT \l_@@_header_hex_digits_bool { \@@_display_row_of_hex_digits: \@@_debug_nl:n{H}\\* } \endfirsthead % \end{macrocode} % Headers for later table pages have a continuation title and % maybe a row of hex digits. % \begin{macrocode} \bool_if:NT \l_@@_display_header_bool { \@@_format_table_cont:nn{#1}{#2} \@@_debug_nl:n{T}\\*[6pt] } \bool_if:NT \l_@@_header_hex_digits_bool { \@@_display_row_of_hex_digits: \@@_debug_nl:n{H}\\* } \endhead % \end{macrocode} % Footers of the table are either empty or show a row of hex digits. % \begin{macrocode} \bool_if:NT \l_@@_footer_hex_digits_bool { \@@_display_row_of_hex_digits: \@@_debug_nl:n{H}\\* } \endfoot % \end{macrocode} % The footer of the last page of the table will always be % empty. Any special row, such as a row of hex digits, will be % provided in the table body. The reason is that we may want to % display statistics at the very end of the table and those can't be % placed into a static footer. % \begin{macrocode} \endlastfoot } % \end{macrocode} % \end{macro} % % \begin{macro}{\l_@@_header_hex_digits_bool} % \begin{macro}{\l_@@_footer_hex_digits_bool} % \begin{macro}{\l_@@_blockwise_hex_digits_bool} % Here are the booleans we use in the code. % \begin{macrocode} \bool_new:N \l_@@_header_hex_digits_bool \bool_new:N \l_@@_footer_hex_digits_bool \bool_new:N \l_@@_blockwise_hex_digits_bool % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\@@_display_row_of_hex_digits:} % \begin{macro}{\@@_format_hex_digit:n} % Producing a row of hex digits is simple. % \begin{macrocode} \cs_new:Npn \@@_display_row_of_hex_digits: { & \@@_format_hex_digit:n{0} & \@@_format_hex_digit:n{1} & \@@_format_hex_digit:n{2} & \@@_format_hex_digit:n{3} & \@@_format_hex_digit:n{4} & \@@_format_hex_digit:n{5} & \@@_format_hex_digit:n{6} & \@@_format_hex_digit:n{7} & \@@_format_hex_digit:n{8} & \@@_format_hex_digit:n{9} & \@@_format_hex_digit:n{A} & \@@_format_hex_digit:n{B} & \@@_format_hex_digit:n{C} & \@@_format_hex_digit:n{D} & \@@_format_hex_digit:n{E} & \@@_format_hex_digit:n{F} } % \end{macrocode} % Each digit is typeset in typewriter and in script size. We offer % font and color % customizations. Note that it is important to set an explicit % family. Otherwise the hex digits are formatted using the current % table font (which may or may not work at all). % \begin{macrocode} \cs_new:Npn \@@_format_hex_digit:n #1 { \l_@@_hex_digits_font_tl \l_@@_color_tl #1 } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\l_@@_color_tl} % The token list to hold definition if set up. % \begin{macrocode} \tl_new:N \l_@@_color_tl % \end{macrocode} % \end{macro} % % % \keysetup{overall table} % Here are the definitions for the keys used in the code above: % \begin{macrocode} \keys_define:nn {@@} { % \end{macrocode} % The \key{header} key is a boolean that determines if a header % title should be produced (default) % \begin{macrocode} ,header .bool_set:N = \l_@@_display_header_bool ,header .default:n = true ,header .initial:n = true % \end{macrocode} % To ease the setup we also support the key \key{noheader} which is % a short form for \texttt{header=false}. % \begin{macrocode} ,noheader .bool_set_inverse:N = \l_@@_display_header_bool ,noheader .default:n = true % \end{macrocode} % The default for the \key{title-format} key is to produce a % \cs{caption} listing the font name and any features (if % given). Note the \cs{IfValueTF} command (provided by % \texttt{xparse}) that checks if the second argument got any value % or has the special \texttt{--NoValue--} value. % \begin{macrocode} ,title-format .cs_set:Np = \@@_format_table_title:nn #1#2 ,title-format .initial:n = \IfValueTF{#2} { \caption{ #1~ (features:~ \texttt{\small#2}) } } { \caption{ #1 } } % \end{macrocode} % The default continuation title ignores the given features, so the % formatting is somewhat simpler. It uses \verb=\caption[]{...}= to % make a caption that doesn't alter the table number. % \changes{v1.0f}{2021/10/29}{Make documentation and code match: % it should be \texttt{title-format-cont}} % \begin{macrocode} ,title-format-cont .cs_set:Np = \@@_format_table_cont:nn #1#2 ,title-format-cont .initial:n = \caption[]{#1~ \emph{cont.}} % \end{macrocode} % The key \key{hex-digits} is implemented as a choice, where each % allowed value sets different booleans that are then used in the code. % \begin{macrocode} ,hex-digits .choice: ,hex-digits / block .code:n = \bool_set_true:N \l_@@_blockwise_hex_digits_bool \bool_set_false:N \l_@@_header_hex_digits_bool \bool_set_false:N \l_@@_footer_hex_digits_bool ,hex-digits / foot .code:n = \bool_set_true:N \l_@@_footer_hex_digits_bool \bool_set_false:N \l_@@_header_hex_digits_bool \bool_set_false:N \l_@@_blockwise_hex_digits_bool ,hex-digits / head .code:n = \bool_set_true:N \l_@@_header_hex_digits_bool \bool_set_false:N \l_@@_footer_hex_digits_bool \bool_set_false:N \l_@@_blockwise_hex_digits_bool ,hex-digits / head+foot .code:n = \bool_set_true:N \l_@@_header_hex_digits_bool \bool_set_true:N \l_@@_footer_hex_digits_bool \bool_set_false:N \l_@@_blockwise_hex_digits_bool ,hex-digits / none .code:n = \bool_set_false:N \l_@@_header_hex_digits_bool \bool_set_false:N \l_@@_footer_hex_digits_bool \bool_set_false:N \l_@@_blockwise_hex_digits_bool ,hex-digits .initial:n = head % \end{macrocode} % The font for hex digits are set with \key{hex-digits-font}. % \begin{macrocode} ,hex-digits-font .tl_set:N = \l_@@_hex_digits_font_tl ,hex-digits-font .initial:n = \ttfamily \scriptsize % \end{macrocode} % Customizing the row header (on the left) can be done with this % key. Defaults for font, fontsize, and color is set on the outside, but can, of % course, be overwritten inside if that is desired. % \changes{v1.0g}{2022/11/12}{Add key hex-digits-row-format to allow % customizing the row title on the left (gh/3)} % \begin{macrocode} ,hex-digits-row-format .cs_set:Np = \@@_format_row_hex_digits:n #1 ,hex-digits-row-format .initial:n = U+#1 0 \, - \, #1 F % \end{macrocode} % The \key{color} key is used in most places that get colored; some % have their own key but default to the main color. % \begin{macrocode} ,color .choice: ,color / none .code:n = \tl_clear:N \l_@@_color_tl ,color / unknown .code:n = \tl_set:Nn \l_@@_color_tl { \color {#1} } ,color .initial:n = blue } % \end{macrocode} % % % % % \begin{macro}{\@@_handle_table_ending:n} % At the end of the table we may want to display a final row of % hex digits and perhaps some statistics, i.e., the number of % typeset glyphs. % \begin{macrocode} \cs_new:Npn \@@_handle_table_ending:n #1 { % \end{macrocode} % % \begin{macrocode} \@@_debug_nl:n{H} \\* \bool_if:NT \l_@@_footer_hex_digits_bool { \@@_display_row_of_hex_digits: \@@_debug_nl:n{H} \\* } \bool_if:NT \l_@@_display_statistics_bool { \\*[2pt] \multicolumn{17}{l}{ \l_@@_stats_font_tl % \end{macrocode} % If we do font comparison, we use a different command for % displaying statistics and pass more data to it. % \begin{macrocode} \tl_if_empty:NTF \l_@@_compare_with_tl { \@@_format_stats:nn{#1}{\fonttableglyphcount} } { \@@_format_compare_stats:nnnnnn{#1}{\fonttableglyphcount} { \l_@@_compare_with_tl } % \end{macrocode} % The extra arguments are total glyph number in second font, glyphs % missing in second font and glyphs only in second font. % \begin{macrocode} { \int_eval:n { \int_use:N\g_@@_glyph_also_B_int + \int_use:N\g_@@_glyph_only_B_int } } { \int_eval:n { \fonttableglyphcount - \int_use:N\g_@@_glyph_also_B_int } } { \int_use:N\g_@@_glyph_only_B_int } } % \end{macrocode} % We don't know exactly how wide the table is (and nor does the % user) but one may need to use \cs{parbox} when formatting % the statistic line(s). So we back up a bit (rather random) which % allows us to use \verb=\parbox{\linewidth}{...= in the key % without thinking too much about it. % \begin{macrocode} \hspace*{-3cm} } } } % \end{macrocode} % % \keysetup{for statistics} % Here are the keys used above. By default we produce statistics. % \begin{macrocode} \keys_define:nn {@@} { ,statistics .bool_set:N = \l_@@_display_statistics_bool ,statistics .default:n = true ,statistics .initial:n = true % \end{macrocode} % the key \key{nostatistics} is just short for \texttt{statistics=false}: % \begin{macrocode} ,nostatistics .bool_set_inverse:N = \l_@@_display_statistics_bool ,nostatistics .default:n = true % \end{macrocode} % The default font we use is \cs{normalfont}. Again we need to % supply a family to avoid getting the font used in the table body. % \begin{macrocode} ,statistics-font .tl_set:N = \l_@@_stats_font_tl ,statistics-font .initial:n = \normalfont\small % \end{macrocode} % And here we have the default text. There is only space for a % single line. If more text is needed one needs to provide some % explicit \cs{parbox}. % \changes{v1.0g}{2022/11/12}{Change default text so that it makes % more sense if only a portion of the font is displayed (gh/4)} % \begin{macrocode} ,statistics-format .cs_set:Np = \@@_format_stats:nn #1#2 ,statistics-format .initial:n = Total~ number~ of~ glyphs~ shown~ from~ #1:~#2 } % \end{macrocode} % \end{macro} % % % % % % \begin{macro}{\@@_debug_nl:n} % While developing the code I had a bit of trouble getting the line % endings correct, so I added a little macro that made them visible % (displaying its argument in the table margin when the key % \key{debug} is used. By default it does nothing. % \begin{macrocode} \cs_new:Npn \@@_debug_nl:n #1 {} % \end{macrocode} % % \keysetup{debugging} % This key is really internal and is therefore not documented above % (and its behavior may changes over time). % \begin{macrocode} \keys_define:nn {@@} { debug .code:n = \cs_set:Npn \@@_debug_nl:n ##1 {\rlap{\normalfont\scriptsize \qquad ##1}} } % \end{macrocode} % \end{macro} % % % % % % % % \subsection{The producing the table content} % % % The body of the table consists of rows with sixteen glyphs each % and to produce it we loop through all possible Unicode points % starting at \texttt{U+0000} and ending with \texttt{U+FFFF}. % % This is implemented with a four-level nested loop that runs through the % values \texttt{0}, \texttt{1}, \ldots, \texttt{F} with the % current hex value in each of the four positions stored in some variable. % \begin{macro}{\g_@@_hex_H_tl,\g_@@_hex_A_tl, % \g_@@_hex_B_tl,\g_@@_hex_C_tl} % \cs{g_@@_hex_H_tl} is a bit special because, it is initially not % zero, but empty, so that slots in the lower plane are denoted by 4 % hex digits. % We really only need three further variables, as the value in the % innermost loop can used directly. % \begin{macrocode} \tl_new:N \g_@@_hex_H_tl % higher plane \tl_new:N \g_@@_hex_A_tl \tl_new:N \g_@@_hex_B_tl \tl_new:N \g_@@_hex_C_tl % \end{macrocode} % \end{macro} % % % \begin{macro}{\c_@@_hex_digits_clist} % Here is the sequence we loop through on each level, except the % one for the outer level. % \begin{macrocode} \clist_const:Nn\c_@@_hex_digits_clist{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F} % \end{macrocode} % \end{macro} % % % % \begin{macro}{\@@_produce_table_rows:,\@@_handle_hex_H:n, % \@@_handle_hex_A:n,\@@_handle_hex_B:n, % \@@_handle_hex_C:n,\@@_handle_hex_D:n} % The overall code layout is then fairly simply: % \begin{macrocode} \cs_new:Npn \@@_produce_table_rows: { % \end{macrocode} % First to some general initialization % \begin{macrocode} \@@_initialize_table_rows: % \end{macrocode} % and then loop we start the loop. The outer level is a bit special % as currently Unicode has only slots allocated in plane 0, 1, 2 % and E (well, and F, but that is a private area) so we loop only % over those and instead of \texttt{0} we use an empty value. % Not covered is the whole of plane 16 which too is now a % private area. % % \begin{macrocode} \clist_map_function:nN { { } , 1, 2, E, F } \@@_handle_hex_H:n } % \end{macrocode} % % Most fonts do not have glyphs in the higher planes, which is why % by default we don't loop using a nonempty \cs{@@_handle_hex_H:n}. % But if the user wants to scan and display the higher slots they % can by setting \key{range-end} appropriatly. % % So after setting \cs{@@_handle_hex_H:n} we loop over % \cs{c_@@_hex_digits_clist} for the next % hex digit (which we call \enquote{A}). % \begin{macrocode} \cs_new:Npn \@@_handle_hex_H:n #1 { \tl_gset:Nn\g_@@_hex_H_tl{#1} \clist_map_function:NN \c_@@_hex_digits_clist \@@_handle_hex_A:n } % \end{macrocode} % % Handling \enquote{A} means storing its value for later use and % then start a loop for setting the second (or third on higher planes) hex digits: % \begin{macrocode} \cs_new:Npn \@@_handle_hex_A:n #1 { \tl_gset:Nn\g_@@_hex_A_tl{#1} \clist_map_function:NN \c_@@_hex_digits_clist \@@_handle_hex_B:n } % \end{macrocode} % % Same game for \enquote{B} and \enquote{C}\footnote{Actually this % is a white lie. In reality we do a lot of extra stuff when % handling \enquote{C} so later one we give a second definition for % \cs{@@_handle_hex_C:n} but for understanding the overall picture % the simpler one shown here is better.}: % \begin{macrocode} \cs_new:Npn \@@_handle_hex_B:n #1 { \tl_gset:Nn\g_@@_hex_B_tl{#1} \clist_map_function:NN \c_@@_hex_digits_clist \@@_handle_hex_C:n } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_handle_hex_C:n #1 { \tl_gset:Nn\g_@@_hex_C_tl{#1} \clist_map_function:NN \c_@@_hex_digits_clist \@@_handle_hex_D:n } % \end{macrocode} % In the innermost loop we now have the full Unicode number % available, so there we have to decide what to do with it. This is % done by \cs{@@_handle_hex_D:n} that receives the full number, % e.g., \texttt{1A7C} or \texttt{1AD00}, as its argument. % \begin{macrocode} \cs_new:Npn \@@_handle_hex_D:n #1 { \@@_handle_slot:x { " \g_@@_hex_H_tl \g_@@_hex_A_tl \g_@@_hex_B_tl \g_@@_hex_C_tl #1 } } % \end{macrocode} % \end{macro} % % \begin{macro}{\g_@@_row_tl} % We first collect the glyphs for a whole row before deciding to % typeset it, because if the row is entirely empty we want to omit % it. The data for the row is collected slot by slot and the typesetting % information (the glyph or the indication for a missing glyph is % appended to \cs{g_@@_row_tl}. % \begin{macrocode} \tl_new:N \g_@@_row_tl % \end{macrocode} % \end{macro} % \begin{macro}{\@@_handle_slot:n,\@@_handle_slot:x} % If the current slot number under inspection contains a glyph in % our font we want to typeset it. But we don't do this immediately, % instead we build up the whole row and typeset it later. We % therefore append a \verb=&= and the glyph (including the necessary % formatting) to the token list \cs{g_@@_row_tl}. % \begin{macrocode} \cs_new:Npn \@@_handle_slot:n #1 { \@@_if_uchar_exists:nTF { #1 } { \tl_gput_right:Nn \g_@@_row_tl { & \@@_format_glyph:n { \symbol{#1} } } % \end{macrocode} % We then increment the overall glyph count and record that we have % seen at least one glyph in the current row. There is not much % point in displaying rows that are completely empty; indeed, % we'd end up with extremely large tables which are % mostly empty. % \begin{macrocode} \int_gincr:N\g_@@_glyph_int \bool_gset_true:N \g_@@_glyph_seen_bool % \end{macrocode} % If we do font comparison we also check if the glyph is in the % second font and if so record that fact. % \begin{macrocode} \tl_if_empty:NF \l_@@_compare_font_tl { \group_begin: \l_@@_compare_font_tl \@@_if_uchar_exists:nT { #1 } { \int_gincr:N \g_@@_glyph_also_B_int } \group_end: } } % \end{macrocode} % If the current slot has no glyph in the font we also add a % \verb=&= followed by something that indicates the glyph is % missing. If we do font comparison, it may show the glyph from % the other font (if it exists there) in some special way to indicate which glyph % should be in this slot. % \begin{macrocode} { \@@_handle_missing_glyph:n {#1} } } % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn \@@_handle_slot:n {x} % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_handle_missing_glyph:n, % \@@_handle_missing_glyph_std:n, % \@@_handle_missing_glyph_compare:n} % % In the standard case we typeset a special symbol to indicate that the glyph is missing. % For this case we provide some customization through keys: % \cs{l_@@_missing_glyph_tl} holds the symbol for a missing glyph % (default: a hyphen). It is typeset in a specific color and we allow for % setting it in a special font. The actual symbol number in % \verb=#1= is not needed in this scenario. % \begin{macrocode} \cs_new:Npn \@@_handle_missing_glyph_std:n #1 { \tl_gput_right:Nn \g_@@_row_tl { & \@@_format_glyph:n { % \colorbox{black!30} % <--- povide interface {\l_@@_missing_glyph_color_tl \l_@@_missing_glyph_font_tl \l_@@_missing_glyph_tl } } } } % \end{macrocode} % % \keysetup{missing glyphs} % Here are the keys for customizing the missing glyph representation. % \begin{macrocode} \keys_define:nn {@@} { missing-glyph-color .choice: ,missing-glyph-color / none .code:n = \tl_clear:N \l_@@_missing_glyph_color_tl ,missing-glyph-color / unknown .code:n = \tl_set:Nn \l_@@_missing_glyph_color_tl { \color {#1} } % ,missing-glyph-font .tl_set:N = \l_@@_missing_glyph_font_tl ,missing-glyph-font .initial:n = \ttfamily \scriptsize ,missing-glyph .tl_set:N = \l_@@_missing_glyph_tl ,missing-glyph .initial:n = - } % \end{macrocode} % % % The default definition for the color is to use the same as the % one specified by the \key{color} key. We therefore define the % default outside of the \pkg{l3keys} method. % \begin{macrocode} \tl_new:N \l_@@_missing_glyph_color_tl \tl_set:Nn \l_@@_missing_glyph_color_tl {\l_@@_color_tl} % \end{macrocode} % % This is the version that handles a missing glyph by checking % the \key{compare-with} font to see if that font contains the % glyph. % If yes, the substitute glyph will be typeset, otherwise the missing % glyph symbol is shown by calling \cs{@@_handle_missing_glyph_std:n}. % \begin{macrocode} \cs_new:Npn \@@_handle_missing_glyph_compare:n #1 { \group_begin: % \end{macrocode} % Locally switch to the other font, then check for the glyph: % \begin{macrocode} \l_@@_compare_font_tl \@@_if_uchar_exists:nTF { #1 } { % \end{macrocode} % If available, format it (together with the \texttt{\&}) but use a % special color and perhaps a background color. % \begin{macrocode} \tl_gput_right:Nn \g_@@_row_tl { & \@@_format_glyph:n { \l_@@_compare_bgcolor_tl { \l_@@_compare_color_tl \l_@@_compare_font_tl \symbol {#1} } } } % \end{macrocode} % Having seen a glyph only in the second font we record this fact. % \begin{macrocode} \int_gincr:N \g_@@_glyph_only_B_int % \end{macrocode} % Also tell the algorithm that we have seen a glyph to typeset. If % we don't do this then a row consisting of only substitute glyphs is not % typeset. However, we don't update the glyph count, because this % is not a glyph from the main font we display. % \begin{macrocode} \bool_gset_true:N \g_@@_glyph_seen_bool } % \end{macrocode} % If the alternate font doesn't have the glyph either we % typeset the missing glyph symbol. % \begin{macrocode} { \@@_handle_missing_glyph_std:n {} } \group_end: } % \end{macrocode} % % \keysetup{comparison} % % In order to display glyphs from a secondary font we need a % secondary color for the glyph itself and possibly some background color. % \begin{macrocode} \tl_new:N \l_@@_compare_with_tl \tl_new:N \l_@@_compare_color_tl \tl_new:N \l_@@_compare_bgcolor_tl % \end{macrocode} % % \begin{macrocode} \keys_define:nn {@@} { ,compare-with .tl_set:N = \l_@@_compare_with_tl ,compare-with .initial:n = ,compare-color .choice: ,compare-color / none .code:n = \tl_clear:N \l_@@_compare_color_tl ,compare-color / unknown .code:n = \tl_set:Nn \l_@@_compare_color_tl { \color {#1} } ,compare-color .initial:n = red ,compare-bgcolor .choice: ,compare-bgcolor / none .code:n = \tl_clear:N \l_@@_compare_bgcolor_tl ,compare-bgcolor / unknown .code:n = \tl_set:Nn \l_@@_compare_bgcolor_tl { \colorbox {#1} } ,compare-bgcolor .initial:n = black!10 % \end{macrocode} % If we run a comparison we show different statistics that have % their own key. % \changes{v1.0g}{2022/11/12}{Change default text so that it makes % more sense if only a portion of the font is displayed (gh/4)} % \begin{macrocode} ,statistics-compare-format .cs_set:Np = \@@_format_compare_stats:nnnnnn #1#2#3#4#5#6 ,statistics-compare-format .initial:n = \parbox{\linewidth}{ Total~ number~ of~ glyphs~ shown~ from~ \texttt{#1}:~#2\\ Comparison~ font~ \texttt{#3}~ has~ #5~ missing~ and~ #6~ extra~ glyphs} } % \end{macrocode} % % % By default, i.e., if no font for comparison has been specified, we % handle missing glyphs by displaying a missing glyph symbol. % \begin{macrocode} \cs_new_eq:NN \@@_handle_missing_glyph:n \@@_handle_missing_glyph_std:n % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_format_glyph:n} % Every glyph is typeset in a box of equal width with the glyph % centered and if necessary protruding on both sides. % \begin{macrocode} \cs_new:Npn \@@_format_glyph:n #1 { \hbox_to_wd:nn {\l_@@_glyph_box_dim} { \hss #1 \hss } } % \end{macrocode} % % \keysetup{glyph typesetting} % The key to customize the width. The 6pt are fine for most cases. % \begin{macrocode} \dim_new:N\l_@@_glyph_box_dim % \end{macrocode} % % \begin{macrocode} \keys_define:nn {@@} { glyph-width .dim_set:N = \l_@@_glyph_box_dim ,glyph-width .initial:n = 6pt } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_if_uchar_exists:n} % For testing whether or not a slot position contains a glyph we % need to resort to low-level methods, because so far % \texttt{expl3} doesn't offer an interface. % \begin{macrocode} \prg_set_conditional:Npnn \@@_if_uchar_exists:n #1 { TF , T } { \tex_iffontchar:D \tex_font:D #1 \scan_stop: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % % % % % \subsection{Handling a single row} % % % \begin{macro}{\@@_handle_hex_C:n} % As promised here is the read definition for % \cs{@@_handle_hex_C:n} in all its glory. % \begin{macrocode} \cs_set:Npn \@@_handle_hex_C:n #1 { % \end{macrocode} % We are now at the start of a new row (but with the last row not % yet typeset) and this last row may need a Unicode block heading % before it. This is the reason why we have to delay the % typesetting, because in case the line doesn't contain any glyphs % we want to typeset neither and that is only known after all % slots in the row have been processed. % \begin{macrocode} \@@_maybe_typeset_a_row_and_display_a_block_title: % \end{macrocode} % We then store away the value for the third hex digit (denoted as % C) in order to start with the next row. % \begin{macrocode} \tl_gset:Nn\g_@@_hex_C_tl{#1} % \end{macrocode} % Being at the start of a new row we might be at the start of a new % Unicode block. If so we have to update the block title to add in % front of the row when we typeset it (or in front of one of the % next rows if the first rows in the is block have no glyphs). If % we are still in the same block no update happens. % \begin{macrocode} \@@_update_block_title:n { \g_@@_hex_H_tl \g_@@_hex_A_tl \g_@@_hex_B_tl \g_@@_hex_C_tl } % \end{macrocode} % We now check if this row is within the requested range, i.e., % greater than or equal to \cs{l_@@_range_start_tl} and not greater than % \cs{l_@@_range_end_tl}. % \begin{macrocode} \int_compare:nNnF { " \g_@@_hex_H_tl \g_@@_hex_A_tl \g_@@_hex_B_tl \g_@@_hex_C_tl 0 } < { "\l_@@_range_start_tl } { \int_compare:nNnTF { " \g_@@_hex_H_tl \g_@@_hex_A_tl \g_@@_hex_B_tl \g_@@_hex_C_tl 0 } > { "\l_@@_range_end_tl } % \end{macrocode} % If we are past the \texttt{end-range} we break out the clist % mapping, to avoind unnecessary repetition. This should be % propagated back to the outer clists as well (not done). % \begin{macrocode} { \clist_map_break: } % \end{macrocode} % If we are within range we process the slots in the row by first % initializing \cs{g_@@_row_tl} with the row title (the info on the % left) and then loop through all slots the row to append glyphs % (or missing glyphs) to \cs{g_@@_row_tl} to build up everything we % need to finally typeset it. % \begin{macrocode} { \tl_gset:Nx \g_@@_row_tl { \exp_not:N \@@_format_row_title:n { \g_@@_hex_H_tl \g_@@_hex_A_tl \g_@@_hex_B_tl \g_@@_hex_C_tl } } \clist_map_function:NN \c_@@_hex_digits_clist \@@_handle_hex_D:n } } } % \end{macrocode} % \end{macro} % % % \begin{macro}{\@@_format_row_title:n} % The function to format the row title on the left, as used above. % \changes{v1.0g}{2022/11/12}{Add key hex-digits-row-format to allow % customizing the row title on the left (gh/3)} % \begin{macrocode} \cs_new:Npn \@@_format_row_title:n #1 { \texttt { \footnotesize \l_@@_color_tl \@@_format_row_hex_digits:n {#1} } } % \end{macrocode} % \end{macro} % % % % \keysetup{ranges} % % For the range we have two keys, its start and the end. By default the % whole range from 0 to FFFF is processed. % % \begin{macrocode} \tl_new:N \l_@@_range_start_tl \tl_new:N \l_@@_range_end_tl % \end{macrocode} % % \begin{macrocode} \keys_define:nn {@@} { ,range-start .tl_set:N = \l_@@_range_start_tl ,range-start .initial:n = 0000 ,range-end .tl_set:N = \l_@@_range_end_tl ,range-end .initial:n = FFFF } % \end{macrocode} % % % % % % \begin{macro}{\@@_maybe_typeset_a_row_and_display_a_block_title:} % The function handles the just-finished row and, if the row does not % consist only of missing glyphs, typesets it. If necessary it also typesets % a Unicode block name first. % \begin{macrocode} \cs_new:Npn \@@_maybe_typeset_a_row_and_display_a_block_title: { % \end{macrocode} % We first check if the row had any real glyphs. % \begin{macrocode} \bool_if:NTF \g_@@_glyph_seen_bool { % \end{macrocode} % If the row needs typesetting the fun part starts. We first look % at the content of \cs{g_@@_block_title_tl}. % \begin{macrocode} \tl_if_empty:NTF \g_@@_block_title_tl { % \end{macrocode} % It is empty we are in the middle of a block and we can ignore % the Unicode title. However, we have to see if the previous row % (or several) was missing (i.e., contained no glyphs). In that % case we leave a little extra space, otherwise we just finish the % previous row % \begin{macrocode} \bool_if:NTF \g_@@_row_missing_bool { \@@_debug_nl:n{A}\\[6pt] } { \@@_debug_nl:n{B}\\ } } { % \end{macrocode} % Otherwise we first have to typeset the Unicode block title (or % whatever should happen instead). % \begin{macrocode} \typeout{ Processing~ \tl_use:N \g_@@_block_title_tl } \bool_if:NTF \l_@@_display_block_bool { % \end{macrocode} % If we are to typeset the title the action depends a bit on % whether we are at the very first row or typesetting a later block. % \begin{macrocode} \bool_if:NTF \g_@@_first_row_bool { \bool_gset_false:N \g_@@_first_row_bool \@@_debug_nl:n{C}\\[-4pt] } { \@@_debug_nl:n{D}\\[8pt] \noalign{\vskip 1pt plus 1pt} % space above block: customizable? } % \noalign{\smallskip} % space above block: customizable? \multicolumn{17}{c}{\normalfont \bfseries \tl_use:N \g_@@_block_title_tl} % \end{macrocode} % After the block title is typeset we may want to add a row of hex % digits as well if that was requested, otherwise we only leave a % bit of extra space. % \begin{macrocode} \bool_if:NTF \l_@@_blockwise_hex_digits_bool { \@@_debug_nl:n{E}\\* \@@_display_row_of_hex_digits: \@@_debug_nl:n{H}\\*[2pt] } { \@@_debug_nl:n{F}\\*[2pt] } } { % \end{macrocode} % If the Unicode block title is not typeset we may still have to do % someting special and again it differs if we at the very beginning % of the table (because there we do nothing except changing the % state of \cs{g_@@_first_row_bool}). % \begin{macrocode} \bool_if:NTF \g_@@_first_row_bool { \bool_gset_false:N \g_@@_first_row_bool } { \@@_debug_nl:n{G~ (new~ block)} \l_@@_display_block_action_tl } } % \end{macrocode} % Once we are past the block title we clear it, so that it is not % retypeset before the next row. % \begin{macrocode} \tl_gclear:N \g_@@_block_title_tl } % \end{macrocode} % The final action is to typeset the row and reset the booleans (in % case they were true; if they are false already then we do this % unnecessarily, but that is probably faster than testing first). % \begin{macrocode} \bool_gset_false:N \g_@@_glyph_seen_bool \bool_gset_false:N \g_@@_row_missing_bool \tl_use:N \g_@@_row_tl } % \end{macrocode} % Current row had no glyphs; remember that fact, and that is all we % have to do in that case. % \begin{macrocode} { \bool_gset_true:N \g_@@_row_missing_bool } } % \end{macrocode} % \end{macro} % % % \subsection{Initialisation at the start of the table} % % % \begin{macro}{\g_@@_first_row_bool,\g_@@_glyph_seen_bool,\g_@@_row_missing_bool} % Declare the three booleans used in the code below. They will tell % us answers to the following questions: % \begin{itemize} % \item Are we processing the first row? % \item Have we seen any glyph so far (in the current row)? % \item Did we have one or more missing rows recently? % \end{itemize} % \begin{macrocode} \bool_new:N \g_@@_first_row_bool \bool_new:N \g_@@_glyph_seen_bool \bool_new:N \g_@@_row_missing_bool % \end{macrocode} % \end{macro} % \begin{macro}{\@@_initialize_table_rows:} % At the start of a table we are processing the first row % and so we (obviously) haven't seen a glyph yet and there wasn't a % missing row recently. % \begin{macrocode} \cs_new:Npn \@@_initialize_table_rows: { \bool_gset_true:N \g_@@_first_row_bool \bool_gset_false:N \g_@@_glyph_seen_bool \bool_gset_false:N \g_@@_row_missing_bool % \end{macrocode} % And clearly the glyph count for the font(s) is zero. % \begin{macrocode} \int_gzero:N \g_@@_glyph_int \int_gzero:N \g_@@_glyph_only_B_int \int_gzero:N \g_@@_glyph_also_B_int } % \end{macrocode} % \end{macro} % % % % % \subsection{Handling block titles} % % \begin{macro}{g_@@_block_title_tl} % We keep the current block title in this token list. % \begin{macrocode} \tl_new:N \g_@@_block_title_tl % \end{macrocode} % \end{macro} % \begin{macro}{\@@_update_block_title:n} % A block title is updated when the hex digits A,B,C have a certain % value, so this is nothing more than a huge case switch. % \begin{macrocode} \cs_new:Npn \@@_update_block_title:n #1 { \tl_gset:Nx \g_@@_block_title_tl { \int_case:nnF{ "#1 } { { "000 }{ Basic~ Latin } { "008 }{ Latin-1~ Supplement } { "010 }{ Latin~ Extended-A } { "018 }{ Latin~ Extended-B } { "025 }{ IPA~ Extensions } { "02B }{ Spacing~ Modifier~ Letters } { "030 }{ Combining~ Diacritical~ Marks } { "037 }{ Greek~ and~ Coptic } { "040 }{ Cyrillic } { "053 }{ Armenian } { "059 }{ Hebrew } { "060 }{ Arabic } { "070 }{ Syriac } { "075 }{ Arabic~ Supplement } { "078 }{ Thaana } { "07C }{ NKo } { "090 }{ Devanagari } { "098 }{ Bengali } { "0A0 }{ Gurmukhi } { "0A8 }{ Gujarati } { "0B0 }{ Oriya } { "0B8 }{ Tamil } { "0C0 }{ Telugu } { "0C8 }{ Kannada } { "0D0 }{ Malayalam } { "0D8 }{ Sinhala } { "0E0 }{ Thai } { "0E8 }{ Lao } { "0F0 }{ Tibetan } { "100 }{ Myanmar } { "10A }{ Georgian } { "110 }{ Hangul~ Jamo } { "120 }{ Ethiopic } { "138 }{ Ethiopic~ Supplement } { "13A }{ Cherokee } { "140 }{ Unified~ Canadian~ Aboriginal~ Syllabics } { "168 }{ Ogham } { "16A }{ Runic } { "170 }{ Tagalog } { "172 }{ Hanunoo } { "174 }{ Buhid } { "176 }{ Tagbanwa } { "178 }{ Khmer } { "180 }{ Mongolian } { "190 }{ Limbu } { "195 }{ Tai~ Le } { "198 }{ New~ Tai~ Le } { "19E }{ Khmer~ Symbols } { "1A0 }{ Buginese } { "1B0 }{ Balinese } { "1D0 }{ Phonetic~ Extensions } { "1D8 }{ Phonetic~ Extensions~ Supplement } { "1DC }{ Combining~ Diacritical~ Marks~ Supplement } { "1E0 }{ Latin~ Extended~ Additional } { "1F0 }{ Greek~ Extended } { "200 }{ General~ Punctuation } { "207 }{ Superscripts~ and~ Subscripts } { "20A }{ Currency~ Symbols } { "20D }{ Combining~ Diacritical~ Marks~ for~ Symbols } { "210 }{ Letterlike~ Symbols } { "215 }{ Number~ Forms } { "219 }{ Arrows } { "220 }{ Mathematical~ Operators } { "230 }{ Miscellaneous~ Technical } { "240 }{ Control~ Pictures } { "244 }{ Optical~ Character~ Recognition } { "246 }{ Enclosed~ Alphanumerics } { "250 }{ Box~ Drawing } { "258 }{ Block~ Elements } { "25A }{ Geometric~ Shapes } { "260 }{ Miscellaneous~ Shapes } { "270 }{ Dingbats } { "27C }{ Miscellaneous~ Mathematical~ Symbols-A } { "27F }{ Supplemental~ Arrows-A } { "280 }{ Braille~ Patterns } { "290 }{ Supplemental~ Arrows-B } { "298 }{ Miscellaneous~ Mathematical~ Symbols-B } { "2A0 }{ Supplemental~ Mathematical~ Operators } { "2B0 }{ Miscellaneous~ Symbols~ and~ Arrows } { "2C0 }{ Glagolitic } { "2C6 }{ Latin~ Extended-C } { "2C8 }{ Coptic } { "2D0 }{ Georgian~ Supplement } { "2D3 }{ Tifinagh } { "2D8 }{ Ethiopic~ Extended } { "2E0 }{ Supplemental~ Punctuation } { "2E8 }{ CJK~ Radicals~ Supplement } { "2F0 }{ Kangxi~ Radicals } { "2FF }{ Ideographic~ Description~ Characters } { "300 }{ CJK~ Symbols~ and~ Punctuation } { "304 }{ Hiragana } { "30A }{ Katakana } { "310 }{ Bopomofo } { "313 }{ Hangul~ Compatibility~ Jamo } { "319 }{ Kanbun } { "31A }{ Bopomofo~ Extended } { "31C }{ CJK~ Strokes } { "31F }{ Katakana~ Phonetic~ Extensions } { "320 }{ Enclosed~ CJK~ Letters~ and~ Months } { "330 }{ CJK~ Compatibility } { "4DC }{ Yijing~ Hexagram~ Symbols } { "A00 }{ Yi~ Syllables } { "A49 }{ Yi~ Radicals } { "A70 }{ Modifier~ Tone~ Letters } { "A72 }{ Latin~ Extended-D } { "A80 }{ Syloti~ Nagri } { "A84 }{ Phags-pa } { "A88 }{ Saurashtra } { "A8E }{ Devanagari Extended } { "A90 }{ Kayah Li } { "A93 }{ Rejang } { "A96 }{ Hangul Jamo Extended-A } { "A98 }{ Javanese } { "A9E }{ Myanmar Extended-B } { "AA0 }{ Cham } { "AA6 }{ Myanmar Extended-A } { "AA8 }{ Tai Viet } { "AAE }{ Meetei Mayek Extensions } { "AB0 }{ Ethiopic Extended-A } { "AB3 }{ Latin Extended-E } { "AB7 }{ Cherokee Supplement } { "ABC }{ Meetei Mayek } { "AC0 }{ Hangul Syllables } { "D7B }{ Hangul Jamo Extended-B } { "D80 }{ High Surrogates } { "DB8 }{ High Private Use Surrogates } { "DC0 }{ Low Surrogates } { "E00 }{ Private~ Use~ Area } { "F90 }{ CJK~ Compatibility~ Ideographs } { "FB0 }{ Alphabetic~ Presentation~ Forms } { "FB5 }{ Arabic~ Presentation~ Forms-A } { "FE0 }{ Variation~ Selectors } { "FE1 }{ Vertical~ Forms } { "FE2 }{ Combining~ Half~ Marks } { "FE3 }{ CJK~ Compatibility~ Forms } { "FE5 }{ Small~ Form~ Variants } { "FE7 }{ Arabic~ Presentation~ Forms-B } { "FF0 }{ Halfwidth~ and Fullwidth~ Forms } { "FFF }{ Specials~ ... } %% ... Plane 1 ... { "1000 }{ Linear~ B~ Syllabary } { "1008 }{ Linear~ B~ Ideograms } { "1010 }{ Aegean~ Numbers } { "1014 }{ Ancient~ Greek~ Numbers } { "1019 }{ Ancient~ Symbols } { "101D }{ Phaistos~ Disc } { "1028 }{ Lycian } { "102A }{ Carian } { "102E }{ Coptic~ Epact~ Numbers } { "1030 }{ Old~ Italic } { "1033 }{ Gothic } { "1035 }{ Old~ Permic } { "1038 }{ Ugaritic } { "103A }{ Old~ Persian } { "1040 }{ Deseret } { "1045 }{ Shavian } { "1048 }{ Osmanya } { "104B }{ Osage } { "1050 }{ Elbasan } { "1053 }{ Caucasian~ Albanian } { "1060 }{ Linear~ A } { "1080 }{ Cypriot~ Syllabary } { "1084 }{ Imperial~ Aramaic } { "1086 }{ Palmyrene } { "1088 }{ Nabataean } { "108E }{ Hatran } { "1090 }{ Phoenician } { "1092 }{ Lydian } { "1098 }{ Meroitic~ Hieroglyphs } { "109A }{ Meroitic~ Cursive } { "10A0 }{ Kharoshthi } { "10A6 }{ Old~ South~ Arabian } { "10A8 }{ Old~ North~ Arabian } { "10AC }{ Manichaean } { "10B0 }{ Avestan } { "10B4 }{ Inscriptional~ Parthian } { "10B6 }{ Inscriptional~ Pahlavi } { "10B8 }{ Psalter~ Pahlavi } { "10C0 }{ Old~ Turkic } { "10C8 }{ Old~ Hungarian } { "10E6 }{ Rumi~ Numeral~ Symbols } { "1100 }{ Brahmi } { "1108 }{ Kaithi } { "110D }{ Sora~ Sompeng } { "1110 }{ Chakma } { "1115 }{ Mahajani } { "1118 }{ Sharada } { "111E }{ Sinhala~ Archaic~ Numbers } { "1120 }{ Khojki } { "1128 }{ Multani } { "112B }{ Khudawadi } { "1130 }{ Grantha } { "1140 }{ Newa } { "1148 }{ Tirhuta } { "1158 }{ Siddham } { "1160 }{ Modi } { "1166 }{ Mongolian~ Supplement } { "1168 }{ Takri } { "1170 }{ Ahom } { "118A }{ Warang~ Citi } { "11A0 }{ Zanabazar~ Square } { "11A5 }{ Soyombo } { "11AC }{ Pau~ Cin~ Hau } { "11C0 }{ Bhaiksuki } { "11C7 }{ Marchen } { "11D0 }{ Masaram~ Gondi } { "1200 }{ Cuneiform } { "1240 }{ Cuneiform~ Numbers~ and~ Punctuation } { "1248 }{ Early~ Dynastic~ Cuneiform } { "1300 }{ Egyptian~ Hieroglyphs } { "1440 }{ Anatolian~ Hieroglyphs } { "1680 }{ Bamum~ Supplement } { "16A4 }{ Mro } { "16AD }{ Bassa~ Vah } { "16B0 }{ Pahawh~ Hmong } { "16F0 }{ Miao } { "16FE }{ Ideographic~ Symbols~ and~ Punctuation } { "1700 }{ Tangut } { "1880 }{ Tangut~ Components } { "1B00 }{ Kana~ Supplement } { "1B10 }{ Kana~ Extended-A } { "1B17 }{ Nushu } { "1BC0 }{ Duployan } { "1BCA }{ Shorthand~ Format~ Controls } { "1D00 }{ Byzantine~ Musical~ Symbols } { "1D10 }{ Musical~ Symbols } { "1D20 }{ Ancient~ Greek~ Musical~ Notation } { "1D30 }{ Tai~ Xuan~ Jing~ Symbols } { "1D36 }{ Counting~ Rod~ Numerals } { "1D40 }{ Mathematical~ Alphanumeric~ Symbols } { "1D80 }{ Sutton~ SignWriting } { "1E00 }{ Glagolitic~ Supplement } { "1E80 }{ Mende~ Kikakui } { "1E90 }{ Adlam } { "1EE0 }{ Arabic~ Mathematical~ Alphabetic~ Symbols } { "1F00 }{ Mahjong~ Tiles } { "1F03 }{ Domino~ Tiles } { "1F0A }{ Playing~ Cards } { "1F10 }{ Enclosed~ Alphanumeric~ Supplement } { "1F20 }{ Enclosed~ Ideographic~ Supplement } { "1F30 }{ Miscellaneous~ Symbols~ and~ Pictographs } { "1F60 }{ Emoticons } { "1F65 }{ Ornamental~ Dingbats } { "1F68 }{ Transport~ and~ Map~ Symbols } { "1F70 }{ Alchemical~ Symbols } { "1F78 }{ Geometric~ Shapes~ Extended } { "1F80 }{ Supplemental~ Arrows-C } { "1F90 }{ Supplemental~ Symbols~ and~ Pictographs } { "2000 }{ CJK~ Unified~ Ideographs~ Extension~ B } { "2A70 }{ CJK~ Unified~ Ideographs~ Extension~ C } { "2B74 }{ CJK~ Unified~ Ideographs~ Extension~ D } { "2B82 }{ CJK~ Unified~ Ideographs~ Extension~ E } { "2CEB }{ CJK~ Unified~ Ideographs~ Extension~ F } { "2F80 }{ CJK~ Compatibility~ Ideographs~ Supplement } { "E010 }{ Tags } { "E000 }{ Variation~ Selectors~ Supplement } { "F000 }{ Supplementary~ Private~ Use~ Area-A } % higher up not covered! } % \end{macrocode} % If none of the above has matched we are somewhere within a block % so we want keep the current name. However, since the case % statement was executed within a |\tl_gset:Nx| we have to do this % by passing the current block name back. % \begin{macrocode} { \tl_use:N \g_@@_block_title_tl } } } % \end{macrocode} % \end{macro} % % % \keysetup{display blocks} % % The Unicode blocks may get indicated in different ways: with titles, % only through rules, or not at all. Here is the necessary setup. % % \begin{macrocode} \bool_new:N \l_@@_display_block_bool \tl_new:N \l_@@_display_block_action_tl % \end{macrocode} % % \begin{macrocode} \keys_define:nn {@@} { ,display-block .choice: ,display-block / titles .code:n = \bool_set_true:N \l_@@_display_block_bool \tl_set:Nn \l_@@_display_block_action_tl {\\} ,display-block / rules .code:n = \bool_set_false:N \l_@@_display_block_bool \tl_set:Nn \l_@@_display_block_action_tl {\\ \midrule} ,display-block / none .code:n = \bool_set_false:N \l_@@_display_block_bool \tl_set:Nn \l_@@_display_block_action_tl {\\} ,display-block .initial:n = titles } % \end{macrocode} % % That's all of the programming using the L3 layer. % \begin{macrocode} \ExplSyntaxOff % \end{macrocode} % What remains is to require all packages needed \ldots % \begin{macrocode} \RequirePackage{longtable,booktabs,caption,fontspec} % \end{macrocode} % \ldots and executing all options passed to the % package via \cs{usepackage}. % \begin{macrocode} \ProcessKeysPackageOptions{@@} % % \end{macrocode} % % % % % % \section{The standalone \texttt{unicodefont.tex} file} % % \begin{macrocode} %<*standalone> \documentclass{article} % \end{macrocode} % % \begin{macrocode} \setlength\textwidth{470pt} \setlength\oddsidemargin{0pt} \addtolength\textheight{7\baselineskip} \addtolength\topmargin{-3\baselineskip} % \end{macrocode} % % \begin{macrocode} \usepackage{unicodefonttable} % \end{macrocode} % % \begin{macrocode} \def\DEFAULTfontname{Latin Modern Roman} \def\DEFAULTfontfeatures{} \def\DEFAULTtableconfig{} \def\DEFAULTunicodefont{} \begin{document} % \end{macrocode} % % \begin{macrocode} \typeout{^^J} % \end{macrocode} % % \begin{macrocode} \ifx\generatetable\undefined \else \typein[\answer]{^^JReuse settings from last time (default yes)?^^J^^J% [ font name = \DEFAULTfontname^^J \space unicode? = \ifx\DEFAULTunicodefont\empty yes^^J \space font features = \DEFAULTfontfeatures \else no\fi^^J \space table config = \DEFAULTtableconfig \space]} \fi % \end{macrocode} % % \begin{macrocode} \ifx\answer\empty \let\FontNameToTable\DEFAULTfontname \let\IsUnicodeFont\DEFAULTunicodefont \let\FontFeaturesToApply\DEFAULTfontfeatures \let\TableConfigurationToApply\DEFAULTtableconfig \else % \end{macrocode} % % \begin{macrocode} \typein[\FontNameToTable]% {^^JInput external font name as understood by fontspec, e.g.,^^J% 'TeX Gyre Pagella' or 'lmroman10-regular.otf'% \ifx\DEFAULTfontname\empty\else ^^J^^J[default \DEFAULTfontname]\fi:} \ifx\FontNameToTable\empty \let\FontNameToTable\DEFAULTfontname \fi % \end{macrocode} % % \begin{macrocode} \typein[\IsUnicodeFont]% {^^JIs this a Unicode font?^^J^^J% \ifx\DEFAULTunicodefont\empty [default yes]\else [default no]\fi:} % \end{macrocode} % % \begin{macrocode} \ifx\IsUnicodeFont\empty % \ifx\DEFAULTunicodefont\empty % \else \let\IsUnicodeFont\DEFAULTunicodefont % \fi \else \ifx\DEFAULTunicodefont\empty \else \let\IsUnicodeFont\empty \fi \fi % \end{macrocode} % % \begin{macrocode} \ifx\IsUnicodeFont\empty \typein[\FontFeaturesToApply]% {^^JInput font feature key/value list to apply% \ifx\DEFAULTfontfeatures\empty\else ^^J^^J[default \DEFAULTfontfeatures]\fi:} \ifx\FontFeaturesToApply\empty \let\FontFeaturesToApply\DEFAULTfontfeatures \fi \else \let\FontFeaturesToApply\DEFAULTfontfeatures \fi % \end{macrocode} % % \begin{macrocode} \typein[\TableConfigurationToApply]% {^^JInput table configuration key/value list to apply% \ifx\DEFAULTtableconfig\empty\else ^^J^^J[default \expandafter\detokenize\expandafter{\DEFAULTtableconfig}]\fi:} \ifx\TableConfigurationToApply\empty \let\TableConfigurationToApply\DEFAULTtableconfig \fi % \end{macrocode} % % \begin{macrocode} \edef\generatetable{\noexpand\displayfonttable \ifx\IsUnicodeFont\empty\else *\fi \ifx\TableConfigurationToApply\empty\else [\expandafter\unexpanded\expandafter{\TableConfigurationToApply}]\fi {\FontNameToTable}% \ifx\FontFeaturesToApply\empty\else[\FontFeaturesToApply]\fi } % \end{macrocode} % % \begin{macrocode} \fi % \end{macrocode} % % \begin{macrocode} \makeatletter \protected@write\@auxout{}{\gdef\string\generatetable {\expandafter\detokenize\expandafter{\generatetable}}} \protected@write\@auxout{}{\gdef\string\DEFAULTfontname{\FontNameToTable}} \protected@write\@auxout{}{\gdef\string\DEFAULTunicodefont{\IsUnicodeFont}} \protected@write\@auxout{}{\gdef\string\DEFAULTfontfeatures{\FontFeaturesToApply}} \protected@write\@auxout{}{\gdef\string\DEFAULTtableconfig {\expandafter\detokenize\expandafter{\TableConfigurationToApply}}} \makeatother % \end{macrocode} % % \begin{macrocode} \generatetable \end{document} % % \end{macrocode} % % % % \section{A samples file} % % \begin{macrocode} %<*samples> % \end{macrocode} % % \begin{macrocode} %< % \end{macrocode} % % \Finale % \endinput %%%%%%%%%%%%%%%%%%%