% \iffalse meta-comment % %% File: letterswitharrows.dtx %% Copyright 2019-2024 J. Maximilian Teegen %% %% 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 J. M. Teegen. %% %% This work consists of the file letterswitharrows.dtx and its %% derived files letterswitharrows.sty and letterswitharrows.pdf. % %<*batch> %<*gobble> \ifx\jobname\relax\let\documentclass\undefined\fi \ifx\documentclass\undefined \csname fi\endcsname % \input l3docstrip.tex \keepsilent \preamble \endpreamble \generate{\file{letterswitharrows.sty}{\from{letterswitharrows.dtx}{package}}} \endbatchfile % %<*gobble> \fi \expandafter\ifx\csname @currname\endcsname\empty \csname fi\endcsname % %<*driver> \documentclass[full]{l3doc} \usepackage[presets={abc,ABC,cAcBcC,vec-cev},tweaks=false]{letterswitharrows} \usepackage{amssymb} \usepackage{hyperref} \begin{document} \DocInput{\jobname.dtx} %% \PrintIndex \PrintChanges \end{document} % %<*gobble> \fi % % \fi % \title{The \pkg{letterswitharrows} package} % \author{Max Teegen\\ \href{mailto:tex@jmteegen.eu}{tex@jmteegen.eu}} % \date{Released 2024-10-31} % \maketitle % \begin{documentation} % This package provides math-mode commands for setting left and right arrows over mathematical symbols, so that the arrows dynamically scale with the symbols. % Here is a sample: {\large\[ % \vs \le \tv \in \vec{U_{\mathrlap\vrv}} \qquad \left\vert \vec{AB} \right\vert = \left\vert \cev{AB} \right\vert \qquad A \mathrel{\arrowoverset*[-2mu]{\between}} B % \]} % \iffalse Somehow embellishments don't work in the documentation!? \fi % While it is possible to set arrows over longer strings of symbols, the focus lies on single characters. % % Only \textsc{pdf} output is supported. Output to \textsc{ps} is implemented, but rarely tested. % For a wider range of formats there is \pkg{pgf}-based output. % \section{Usage} % The package provides the general-purpose \tn{arrowoverset} command, as well as some sets of predefined shorthand commands. % \subsection{Presets} % The presets are selected by passing them as options to the \verb|presets| package option. % For instance, to define the \verb|abc| and the \verb|vec-cev| sets of commands you would load the package like so: % \begin{verbatim} % \usepackage[presets={abc,vec-cev}]{letterswitharrows} % \end{verbatim} % By default, the \verb|abc|, \verb|ABC| and \verb|cAcBcC| presets are loaded. % \DescribeOption{abc} % Passing \verb|abc| to the \verb|presets| option allows you to use the \tn{v\meta{char}}, \tn{\meta{char}v}, and \tn{v\meta{char}v} commands for all the lower-case letters \verb|a| through \verb|z| except for \verb|v|. % \begin{function}{\v,\v,\vleft,\vright,\vv} % For the letter \verb|v| the commands \tn{vleft} and \tn{vright} are provided. % \[ \va, \vb, \vc, \dv, \vmv, F_\tv \] % \begin{verbatim} % \[ \va, \vb, \vc, \dv, \vmv, F_\tv \] % \end{verbatim} % \end{function} % \DescribeOption{ABC} % Passing \verb|ABC| to the \verb|presets| option allows you to use the \tn{v\meta{CHAR}}, \tn{\meta{CHAR}v}, and \tn{v\meta{CHAR}v} commands for all the upper-case letters \verb|A| through \verb|Z|. % \begin{function}{\v,\v} % \[ \vA, \vB, \vC, \Dv, \vEv, F_\Gv \] % \begin{verbatim} % \[ \vA, \vB, \vC, \Dv, \vEv, F_\Gv \] % \end{verbatim} % \end{function} % \DescribeOption{cAcBcC} % Passing \verb|cAcBcC| to the \verb|presets| option allows you to use the \tn{vc\meta{CHAR}}, \tn{c\meta{CHAR}v}, and \tn{vc\meta{CHAR}v} commands for all the upper-case letters \verb|A| through \verb|Z| to set arrows over \tn{mathcal}-letters. % \begin{function}{\vc,\cv} % \[ \vcA, \vcB, \vcC, \cDv, \vcEv, F_\cGv \] % \begin{verbatim} % \[ \vcA, \vcB, \vcC, \cDv, \vcEv, F_\cGv \] % \end{verbatim} % \end{function} % \DescribeOption{vec-cev} % Passing \verb|vec-cev| to the \verb|presets| option (re)defines the \tn{vec}, \tn{cev}, and \tn{vecev} commands. % \begin{function}{\vec,\cev} % Unlike the other commands these do not automatically consume subsequent subscripts or \verb|'| tokens. % \[ \vec{\mathbf{x}} := \cev{AB}\] % \begin{verbatim} % \[ \vec{\mathbf{x}} := \cev{AB}\] % \end{verbatim} % \end{function} % \subsection{The \tn{arrowoverset} command} % \begin{function}{\arrowoverset,\arrowoverset*} % \begin{syntax} % |\arrowoverset | [\meta{xoffset}] [\meta{xscale}] [\meta{yoffset}] \Arg{math} % |\arrowoverset*| [\meta{xoffset}] [\meta{xscale}] [\meta{yoffset}] \Arg{math} % \end{syntax} % This command sets a right (or left if \tn{arrowoverset*} is used) arrow over \meta{math}. % The base length of the arrow is the width of the \meta{math} multiplied by \meta{xscale}, which must be specified as a fraction \meta{num}\verb|/|\meta{denom}. % The arrow is offset by \meta{xoffset} to the right, which must be a math skip expression, and by \meta{yoffset} to the top, which must be a skip expression. % This command consumes subsequent subscripts or up to two primes \verb|'|. The former does not affect the length of the arrow. % \end{function} % \subsection{Other package options} % \DescribeOption{pgf} % If you specify the \verb|pgf| option, every arrow is drawn as a \verb|pgfpicture|. This requires the \pkg{pgf} package. % Double arrows are not implemented in pgf mode. % \begin{texnote} % You can set up custom arrow drawing code by redefining \cs{__jmt_lwa_arrow_draw:nnn}. % The command is expected to draw an arrow with its head at the current position. Its length should be \verb|#1| and it should be drawn at a font size of \verb|#2|pt. % If \verb|#3| is \verb|-| if the arrow should point rightwards and empty otherwise. % \end{texnote} % \DescribeOption{linewidth} % Specifying \verb|linewidth=| as a package option allows you to adjust the line width of the arrows to adjust for the weigth of the maths font you are using. % The default value is \verb|linewidth=0.3|. % \DescribeOption{tweaks} % Specifying the \verb|tweaks| option applies per-letter scaling adjustments to some of the single-letter shorthands. This is enabled by default. % These are specific to Latin Modern Math and subject to be changed on a whim. If you wish a more stable behaviour specify \verb|tweaks=false|. % This documentation uses \verb|tweaks=false|. % \end{documentation} % \begin{implementation} % \section{Implementation} % \changes{2019/11/21}{2019/11/21}{Require \pkg{expl3} before \tn{ProvidesExplPackage}.} % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \RequirePackage{expl3} \ProvidesExplPackage {letterswitharrows} {2024/10/31} {} {Draw arrows over math letters.} \RequirePackage{xparse,l3keys2e,mathtools} % TODO: I just use mathtools for mathrlap; replace. %<@@=jmt_lwa> \msg_new:nnn {letterswitharrows} {pdf-only} {Only~pdf~output~is~supported.} \AtBeginDocument{ \sys_if_output_pdf:F { \msg_warning:nn {letterswitharrows} {pdf-only} } } % \end{macrocode} % The drawing code. % \changes{2021/07/10}{2021/07/19}{Implement adjustable linewidth.} % \changes{2024/10/31}{2023/03/11}{Add double arrows.} % \begin{macro}{\__@@_arrow_draw_special:nnn,\__@@_arrow_draw_double:nn,\__@@_arrow_draw_pgf:nnn,\__@@_arrow_left:nn,\__@@_arrow_right:nn,\__@@_arrow_double:nn} % \begin{macrocode} \cs_new:Nn \__@@_arrow_draw_special:nnn % length, font size, sign { \sys_if_output_pdf:TF { \tex_special:D {pdf:~ q~ 1~J~1~j~ 1~0~0~\dim_to_decimal:n{#3#2pt/10}~0~0~cm~ \fp_use:c{g_@@_line_width}~w~ q~ \dim_to_decimal:n{#3#2pt/10}~0~0~1~0~0~cm~ 1~0~0~1~-1~0~cm~ 0~1~m~ .25~0~1~0~1~0~c~ 1~0~.25~0~0~-1~c~ S~ Q~ Q~ q~ 0~0~m~ -1~0~0~1~0~0~cm~ \fp_use:c{g_@@_line_width}~w~ \dim_to_decimal:n{#3#1}~0~l~S~ Q } } { \tex_special:D {"~ 1~setlinecap~1~setlinejoin~ 1~0~0~\dim_to_decimal:n{#3#2pt/10}~0~0~6~array~astore~concat~ \fp_use:c{g_@@_line_width}~setlinewidth~ gsave~ \dim_to_decimal:n{#3#2pt/10}~0~0~1~0~0~6~array~astore~concat~ 1~0~0~1~-1~0~6~array~astore~concat~ 0~1~moveto~ .25~0~1~0~1~0~curveto~ 1~0~.25~0~0~-1~curveto~ stroke~ grestore~ 0~0~moveto~ -1~0~0~1~0~0~6~array~astore~concat~ \dim_to_decimal:n{#3#1}~0~lineto~stroke } } } % TODO % \tl_new:N \g_@@_pgf_arrow_style_tl % \tl_set:Nn \g_@@_pgf_arrow_style_tl % {Computer~Modern~Rightarrow[width=#2pt*2/10,length=#2pt/10,sharp]} \cs_new:Nn \__@@_arrow_draw_pgf:nnn { \begin{pgfpicture} \pgfsetlinewidth{#2pt*\fp_use:c{g_@@_line_width}/10} \pgfsetarrowsstart {Computer~Modern~Rightarrow[width=#2pt*2/10,length=#2pt/10,sharp]} % \pgfsetarrowsstart{\tl_use:N \g_@@_pgf_arrow_style_tl} \pgfpathmoveto{\pgfpointorigin} \pgfpathlineto{\pgfpoint{-#3#1}{0cm}} \pgfusepath{stroke} \pgfresetboundingbox \end{pgfpicture} } \cs_new_eq:NN \__@@_arrow_draw:nnn \use_none:nnn \cs_new:Nn \__@@_arrow_draw_double:nn { \tex_special:D {pdf:~ q~ 1~J~1~j~ 1~0~0~\dim_to_decimal:n{#2pt/10}~0~0~cm~ \fp_use:c{g__@@_line_width}~w~ q~ \dim_to_decimal:n{#2pt/10}~0~0~1~0~0~cm~ 1~0~0~1~-1~0~cm~ 0~1~m~ .25~0~1~0~1~0~c~ 1~0~.25~0~0~-1~c~ S~ Q~ 0~0~m~ -1~0~0~1~0~0~cm~ \dim_to_decimal:n{#1}~0~l~S~ \dim_to_decimal:n{#2pt/10}~0~0~1~\dim_to_decimal:n{#1}~0~cm~ 1~0~0~1~-1~0~cm~ 0~1~m~ .25~0~1~0~1~0~c~ 1~0~.25~0~0~-1~c~ S~ Q } } \cs_new:Nn \__@@_arrow_right:nn { \skip_horizontal:n {#1} \__@@_arrow_draw:nnn {#1} {#2} {} } \cs_new:Nn \__@@_arrow_left:nn { \__@@_arrow_draw:nnn {#1} {#2} {-} \skip_horizontal:n {#1} } \cs_new:Nn \__@@_arrow_double:nn { \skip_horizontal:n {#1} \__@@_arrow_draw_double:nn {#1} {#2} } % \end{macrocode} % \end{macro} % The core functions. % \changes{2020/05/08}{2020/05/08}{Reset tabskip. Fixes spacing in aligned environments} % \begin{macro}{\__@@_arrow_overset_style:Nnncnnn,\__@@_arrow_overset:nnnnn} % \begin{macrocode} \cs_new:Npn \__@@_arrow_overset_style:Nnncnnn #1#2#3#4#5#6#7 { \hbox_set:Nn \l_tmpa_box {$\m@th#1#3$} \dim_set:Nn \l_tmpa_dim {#2 pt/10} \vbox:n { \tex_lineskiplimit:D = \maxdimen \tex_baselineskip:D = 0pt \tex_tabskip:D = 0pt \tex_lineskip:D = \dim_eval:n {\l_tmpa_dim * 3/2 + #7} \tex_halign:D { ## \tex_cr:D \skip_horizontal:n {\l_tmpa_dim / 2} $ \m@th #1 \tex_mskip:D \muskip_eval:n {#5} \use:c {#4} {\dim_eval:n{\box_wd:N \l_tmpa_box * #6}} {#2} $ \tex_cr:D \box_use_drop:N \l_tmpa_box \tex_cr:D } } } \cs_new:Nn \__@@_arrow_overset:nnnnn { % content, direction, xoffset, scale, yoffset \mathchoice { \__@@_arrow_overset_style:Nnncnnn \displaystyle {\tf@size} {#1} {__@@_arrow_#2:nn} {#3} {#4} {#5} } { \__@@_arrow_overset_style:Nnncnnn \textstyle {\tf@size} {#1} {__@@_arrow_#2:nn} {#3} {#4} {#5} } { \__@@_arrow_overset_style:Nnncnnn \scriptstyle {\sf@size} {#1} {__@@_arrow_#2:nn} {#3} {#4} {#5} } { \__@@_arrow_overset_style:Nnncnnn \scriptscriptstyle {\ssf@size} {#1} {__@@_arrow_#2:nn} {#3} {#4} {#5} } } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_arrow_overset:w,\arrowoverset} % \changes{2019/02/04}{2019/02/04}{Subscript spacing adjustments} % \begin{macrocode} \cs_new_protected:Npn \@@_arrow_overset:w { \c_group_begin_token \__@@_arrow_overset_aux:w } \cs_new:Nn \__@@_bool_convert:n { \IfBooleanTF {#1} {\c_true_bool} {\c_false_bool} } % This exp_args is necessary because _ generates the wrong token in expl3 syntax \exp_args:NNx \NewDocumentCommand \__@@_arrow_overset_aux:w {s s O{0mu} O{1} O{0ex} m t' e{\char_generate:nn {95}{8}} t'} { \__@@_arrow_overset:nnnnn { #6 \exp_args:Nf\bool_if:nT{\__@@_bool_convert:n{#7} || \__@@_bool_convert:n{#9}} { \c_math_superscript_token { \scriptscriptstyle\IfBooleanT{#7}{\prime}\IfBooleanT{#9}{\prime} } } % TODO: Better positioning etc? \exp_args:Nf\IfValueT{\use:n#8} { \c_math_subscript_token { \mathrlap{#8} } } } {\IfBooleanTF{#1}{\IfBooleanTF{#2}{double}{left}}{right}} {#3} {#4} {#5} \exp_args:Nf\IfValueTF{\use:n#8}{ % TODO: Better way to do this? This is all kinds of wrong. \hphantom{\c_math_subscript_token{#8}} } {} \c_group_end_token } \cs_set_eq:NN \arrowoverset \@@_arrow_overset:w % \end{macrocode} % Replacements for \pkg{hyperref} bookmarks. % \begin{macrocode} \AtBeginDocument{ \@ifpackageloaded{hyperref}{ \pdfstringdefDisableCommands{ % Why does this only work with Expandable? \DeclareExpandableDocumentCommand \@@_arrow_overset:w {s o o o m} { \ifpdfstringunicode {#5 \IfBooleanTF{#1}{\unichar{"20D6}}{\unichar{"20D7}}} {#5} } } }{} } % \end{macrocode} % \end{macro} % Package option handling. % \begin{variable}{\g_@@_tweak_shortcuts_bool,\g_@@_selected_presets_prop} % \begin{macro}{\__@@_arrow_draw:nnn} % \begin{macrocode} \bool_new:N \g_@@_tweak_shortcuts_bool \prop_new:N \g_@@_selected_presets_prop \keys_define:nn {letterswitharrows} { mode .choice:, mode / special .code:n = { \cs_set_eq:NN \__@@_arrow_draw:nnn \__@@_arrow_draw_special:nnn }, mode / pgf .code:n = { \RequirePackage{pgf} \ExplSyntaxOff\usepgflibrary{arrows.meta}\ExplSyntaxOn \cs_set_eq:NN \__@@_arrow_draw:nnn \__@@_arrow_draw_pgf:nnn }, mode .initial:n = {special}, pgf .meta:n = {mode = pgf}, presets .multichoices:nn = {abc, ABC, cAcBcC, vec-cev} { \int_compare:nNnTF \l_keys_choice_int = 1 { \prop_gclear:N \g_@@_selected_presets_prop } {} \prop_gput:NVn \g_@@_selected_presets_prop \l_keys_choice_tl {} }, presets .initial:n = {abc, ABC, cAcBcC}, tweaks .bool_set:N = \g_@@_tweak_shortcuts_bool, tweaks .initial:n = {true}, linewidth .fp_set:N = \g_@@_line_width, linewidth .initial:n = {.3}, } \ProcessKeysPackageOptions{letterswitharrows} % \end{macrocode} % \end{macro} % \end{variable} % \begin{macro}{\v,\v,\vleft,\vright,\vv} % \begin{macrocode} \prop_if_in:NnTF \g_@@_selected_presets_prop {abc} { \int_step_inline:nnn {1} {26} { \int_compare:nNnTF {#1} = {22} { \cs_new:cpx {vright} { \exp_not:N\@@_arrow_overset:w{v} } \cs_new:cpx {vleft} { \exp_not:N\@@_arrow_overset:w*{v} } \cs_new:cpx {vvv} { \exp_not:N\@@_arrow_overset:w**{v} } } { \cs_new:cpx {v\int_to_alph:n{#1}} { \exp_not:N\@@_arrow_overset:w{\int_to_alph:n{#1}} } \cs_new:cpx {\int_to_alph:n{#1}v} { \exp_not:N\@@_arrow_overset:w*{\int_to_alph:n{#1}} } \cs_new:cpx {v\int_to_alph:n{#1}v} { \exp_not:N\@@_arrow_overset:w**{\int_to_alph:n{#1}} } } } } {} % \end{macrocode} % \end{macro} % \begin{macro}{\v,\v,\vv} % \begin{macrocode} \prop_if_in:NnTF \g_@@_selected_presets_prop {ABC} { \int_step_inline:nnn {1} {26} { \cs_new:cpx {v\int_to_Alph:n{#1}} { \exp_not:N\@@_arrow_overset:w{\int_to_Alph:n{#1}} } \cs_new:cpx {\int_to_Alph:n{#1}v} { \exp_not:N\@@_arrow_overset:w*{\int_to_Alph:n{#1}} } \cs_new:cpx {v\int_to_Alph:n{#1}v} { \exp_not:N\@@_arrow_overset:w**{\int_to_Alph:n{#1}} } } } {} % \end{macrocode} % \end{macro} % \begin{macro}{\vc,\cv,\vcv} % \begin{macrocode} \prop_if_in:NnTF \g_@@_selected_presets_prop {cAcBcC} { \int_step_inline:nnn {1} {26} { \cs_new:cpx {vc\int_to_Alph:n{#1}} { \exp_not:N\@@_arrow_overset:w{\exp_not:N\mathcal{\int_to_Alph:n{#1}}} } \cs_new:cpx {c\int_to_Alph:n{#1}v} { \exp_not:N\@@_arrow_overset:w*{\exp_not:N\mathcal{\int_to_Alph:n{#1}}} } \cs_new:cpx {vc\int_to_Alph:n{#1}v} { \exp_not:N\@@_arrow_overset:w**{\exp_not:N\mathcal{\int_to_Alph:n{#1}}} } } } {} % \end{macrocode} % \end{macro} % \begin{macro}{\vec,\cev,\vecev} % \begin{macrocode} \prop_if_in:NnTF \g_@@_selected_presets_prop {vec-cev} { \RenewDocumentCommand \vec {m} { \@@_arrow_overset:w {#1} \scan_stop: } \DeclareDocumentCommand \cev {m} { \@@_arrow_overset:w* {#1} \scan_stop: } \DeclareDocumentCommand \vecev {m} { \@@_arrow_overset:w** {#1} \scan_stop: } } {} % \end{macrocode} % \end{macro} % Some personal-preference tweaks. % \changes{2019/02/04}{2019/02/04}{Tweaks for capital letters.} % \begin{macrocode} \bool_if:NTF \g_@@_tweak_shortcuts_bool { \prop_if_in:NnTF \g_@@_selected_presets_prop {ABC} { \int_step_inline:nnn {1} {26} { \cs_set:cpx {v\int_to_Alph:n{#1}} { \exp_not:N\@@_arrow_overset:w[2.5mu][8/10]{\int_to_Alph:n{#1}} } \cs_set:cpx {\int_to_Alph:n{#1}v} { \exp_not:N\@@_arrow_overset:w*[2.5mu][7/10]{\int_to_Alph:n{#1}} } \cs_set:cpx {v\int_to_Alph:n{#1}v} { \exp_not:N\@@_arrow_overset:w**[1.5mu][9/10]{\int_to_Alph:n{#1}} } } \cs_set:cpn {vS} { \@@_arrow_overset:w[3mu][7/10]{S} } \cs_set:cpn {vSv} { \@@_arrow_overset:w**[2mu][9/10]{S} } \cs_set:cpn {vT} { \@@_arrow_overset:w[2mu][8/10]{T} } \cs_set:cpn {Tv} { \@@_arrow_overset:w*[1mu][8/10]{T} } \cs_set:cpn {vU} { \@@_arrow_overset:w[2mu][7/10]{U} } \cs_set:cpn {Uv} { \@@_arrow_overset:w*[2mu][7/10]{U} } \cs_set:cpn {vUv} { \@@_arrow_overset:w**[1.5mu][8/10]{U} } \cs_set:cpn {vV} { \@@_arrow_overset:w[2.5mu][7/10]{V} } \cs_set:cpn {Vv} { \@@_arrow_overset:w*[2mu][7/10]{V} } \cs_set:cpn {vX} { \@@_arrow_overset:w[3mu][7/10]{X} } \cs_set:cpn {vY} { \@@_arrow_overset:w[2mu][8/10]{Y} } \cs_set:cpn {Yv} { \@@_arrow_overset:w*[2mu][7/10]{Y} } } {} \prop_if_in:NnTF \g_@@_selected_presets_prop {cAcBcC} { \int_step_inline:nnn {1} {26} { \cs_set:cpx {vc\int_to_Alph:n{#1}} { \exp_not:N\@@_arrow_overset:w[1mu][9/10]{\exp_not:N\mathcal{\int_to_Alph:n{#1}}} } \cs_set:cpx {c\int_to_Alph:n{#1}v} { \exp_not:N\@@_arrow_overset:w*[1.5mu][8/10]{\exp_not:N\mathcal{\int_to_Alph:n{#1}}} } } } {} \prop_if_in:NnTF \g_@@_selected_presets_prop {abc} { \cs_new:cpn {vell} { \@@_arrow_overset:w{\ell} } \cs_new:cpn {ellv} { \@@_arrow_overset:w*{\ell} } \cs_new:cpn {vellv} { \@@_arrow_overset:w**{\ell} } } {} } {} % \end{macrocode} % \end{implementation}