Git Product home page Git Product logo

latex3's Introduction

The expl3 (LaTeX3) Development Repository

Overview

The repository contains development material for expl3. This includes not only code to be developed into the expl3 kernel, but also a variety of test, documentation and more experimental material. All of this code works on top of LaTeX2e.

The following directories are present in the repository:

  • l3kernel: code forms the expl3 kernel and all stable code. With a modern LaTeX2e kernel, this code is loaded during format creation; when using an older LaTeX2e kernel, this material is accessible using the expl3 package.
  • l3backend: code for backend (driver) level interfaces across the expl3 codebase; none of this code has public interfaces, and so no distinction is made between stable and experimental code.
  • l3packages: code which is written to be used on top of LaTeX2e to explore interfaces; this bundle is now made up of historical material, and the concepts have been migrated to the LaTeX2e kernel
  • l3experimental: code which is written to be used on top of LaTeX2e to experiment with code and interface concepts. The interfaces for these packages are still under active discussion. Parts of this code may eventually be migrated to l3kernel.
  • l3trial: material which is under very active development, for potential addition to l3kernel or l3experimental. Material in this directory may include potential replacements for existing modules, where large-scale changes are under-way. This code is not released to CTAN.
  • l3leftovers: code which has been developed in the past by The LaTeX Project but is not suitable for use in its current form. Parts of this code may be used as the basis for new developments in l3kernel or l3experimental over time.

Support material for development is found in:

  • support, which contains files for the automated test suite which are 'local' to the repository.

Documentation is found in:

  • articles: discussion of concepts by team members for publication in TUGBoat or elsewhere.

The repository also contains the directory xpackages. This contain code which is being moved (broadly) l3experimental. Over time, xpackages is expected to be removed from the repository.

Issues

The issue tracker for expl3 is currently located on GitHub.

Build status

We use GitHub Actions as a hosted continuous integration service. For each commit, the build status is tested using the current release of TeX Live.

Current build status: build status

Development team

This code is developed by The LaTeX Project.

Copyright

This README file is copyright 2021-2024 The LaTeX Project.

latex3's People

Contributors

blefloch avatar car222222 avatar dakhubgit avatar davidcarlisle avatar dbitouze avatar dcpurton avatar dependabot[bot] avatar dffischer avatar eg9 avatar evanaad avatar frankmittelbach avatar frougon avatar gucci-on-fleek avatar hmenke avatar jlaurens avatar josephwright avatar mbertucci47 avatar mgkurtz avatar muzimuzhi avatar phelypeoleinik avatar qinglee avatar skillmon avatar stone-zeng avatar switwu avatar texhackse avatar tomh-overleaf avatar witiko avatar wspr avatar wtsnjp avatar zauguin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

latex3's Issues

Message management for expandable errors

\msg_expandable_error:n is currently doing what we really don't like about LaTeX2e's \PackageError: mixing the error messages into the code. I haven't looked at the l3msg module long enough to think of how the management could take place.

Probably, l3msg uses props a lot. For an expandable version, the expandable \prop_get:Nn and \prop_if_in:NnTF will be useful.

\toks_put_(left/right)

The toks_put_left functions use a \q_stop delimiter, and break when a toks contains \q_stop. For instance,

 \RequirePackage{expl3}
 \ExplSyntaxOn
 \toks_new:N \l_my_toks
 \toks_set:Nn \l_my_toks {\q_stop}
 \toks_put_left:Nn \l_my_toks {}

This can be avoided as follows. That code could be simplified (removing the current #3 in the auxiliary function), but for some reason I wanted to hand code some more in order to optimize the non-:n variants.

 \cs_new_protected_nopar:Npn \toks_put_left_A:Nn #1 {
   \exp_after:wN \toks_put_left_A_aux:nnnn \exp_after:wN 
   { \toks_use:N #1 }
   {#1}{}
 }
 \cs_new:Npn \toks_put_left_A_aux:nnnn #1 #2 #3 #4 { #2 { #3 #4 #1 } }

 \cs_new_protected_nopar:Npn \toks_put_left_A:No #1 {
   \exp_after:wN \toks_put_left_A_aux:nnnn \exp_after:wN 
   { \toks_use:N #1 }
   {#1 \exp_after:wN } {}
 }
 \cs_new_protected_nopar:Npn \toks_put_left_A:Nf #1 {
   \exp_after:wN \toks_put_left_A_aux:nnnn \exp_after:wN 
   { \toks_use:N #1 }
   {#1 \exp_after:wN } {\tex_romannumeral:D -`\0}
 }

On the other hand, the \toks_put_right:No function (and :NV and :Nf) can be accelerated a little bit by realizing that \tex_the:D fully expands what follows until a register is found.

 \cs_new_protected:Npn \toks_put_right:No #1#2 {
    #1 \exp_after:wN { \toks_use:N \exp_after:wN #1 #2 }
 }

xparse internal functions assume \escapechar value

[Reported by Bruno Le Floch (slightly edited)]

xparse uses \use:c{\token_to_str:N #1} which
breaks when \escapechar is -1. Either you can change the \escapechar
locally, or you can \use:c{ \cs_to_str:N \\ \cs_to_str:N #1}. One
drawback of the second method is when the name of the control sequence
#1 starts with a space, which would then disappear. Of course, this
shouldn't happen.

\RequirePackage{xparse}
\ExplSyntaxOn
\escapechar=-1
\DeclareDocumentCommand{\foo}{ m o }{Hello,~#1~#2.}
\escapechar=92
\show\foo
\ExplSyntaxOff

\documentclass{article}
\begin{document}
\foo{Joseph}[Wright]
\end{document}

More elaborate \box_show:...

Currently, we just have \box_show:N = \tex_showbox:D. That's moderately useful (at least for me), as with default settings of \tracingonline, \showboxbreadth and \showboxdepth, that prints almost nothing, to the log. I'd prefer something like

\cs_new_protected:Npn \box_show:Nnn #1#2#3
   {
      \group_begin:
         \int_set:Nn \tex_showboxbreadth:D { #2 }
         \int_set:Nn \tex_showboxdepth:D { #3 }
         \int_set_eq:NN \tex_tracingonline:D \c_one % \c_two?
         \tex_showbox:D #1
      \group_end:
   }

This would print some useful info on the terminal, similar to \int_show:N and friends. Then we can make \box_show:N be equal to \box_show:Nnn with useful defaults (but I'm happy sticking with \box_show:N = \tex_showbox:D).

Bug: `\tl_clear_new:N` introduces the variable locally

Since all variables should be either globally undefined, or globally defined, \tl_clear_new:N should introduce the variable globally when it does not exist. A not-too-slow code for that (without checking whether #1 is "do-not-use") would be

\cs_new:Npn \tl_clear_new:N #1 
  {
     \cs_if_exist:NTF #1 { \tl_clear:N #1 } { \tl_gclear:N #1 }
  }

\iow_wrap broken when arg contains \bgroup

I only have a high-level example:

\RequirePackage{xparse}
\DeclareDocumentCommand{\foo}{O{\bgroup}}{#1}

breaks when trying to write the info message for the signature. What happens is that parsing with \futurelet is not sufficient to distinguish explicit { from \bgroup. Then \iow_wrap_group:n thinks that it has an explicit { in front of it, and grabs an undelimited argument, puts a brace and continues parsing, hitting the same character.

Two solutions: simply detokenize before wrapping (maybe only in some situations?), or do some more elaborate parsing.

XeLaTeX and xparse error with MikTeX (Undefined control sequence)

When I attempt to compile the minimal .tex file:
---snip---
% !TEX TS-program = xelatex
% !TEX encoding = UTF-8
\documentclass[11pt]{article}
\usepackage{fontspec}
\begin{document}
Problem with xparse.sty
\end{document}
---snip---

using XeLaTex Version 3.1415926-2.3-0.9997.5 (MiKTeX 2.9), I am getting the following error:

---snip---
("C:\Program Files (x86)\MiKTeX 2.9\tex\latex\l3packages\xparse\xparse.sty"
! Undefined control sequence.
\ExplFileName

l.57 ...e}{\ExplFileVersion}{\ExplFileDescription}
---snip---

I've verified that I don't have a conflict with an earlier version of xparse.sty elsewhere, and that the current version of l3kernel/l3packages on CTAN (downloaded on 2011-August-18) exhibits the same problem.

Tiny typos

l3basics.dtx, l. 747: \cs{use:nnn}\cs{use:nnnn}
l. 945: \begin{function}{[EXP]\begin{function}[EXP]
l. 955: \begin{function}EXP]\begin{function}[EXP]

Faster unbraced expansion

The unbraced expansions which start with a bunch of N can be improved. But \::o_unbraced and others are still very necessary when building commands such as e.g. \exp_last_unbraced:Noo.

\cs_new:Npn \exp_last_unbraced:Nf #1#2 { \exp_after:wN #1 \tex_romannumeral:D -`0 #2 }
\cs_new:Npn \exp_last_unbraced:NV #1 #2 { 
      \exp_after:wN #1 \tex_romannumeral:D -`0 \exp_eval_register:N #2 }
\cs_new:Npn \exp_last_unbraced:No #1 #2 { \exp_after:wN #1 #2 }
\cs_new:Npn \exp_last_unbraced:Nv #1 #2 { 
      \exp_after:wN #1 \tex_romannumeral:D -`0 \exp_eval_register:c #2 }
\cs_new:Npn \exp_last_unbraced:NcV #1 #2 #3 { 
      \exp_after:wN #1 
      \cs:w #2 \exp_after:wN \cs_end: 
      \tex_romannumeral:D -`0 \exp_eval_register:N #2 
}
\cs_new:Npn \exp_last_unbraced:NNV #1 #2 #3 { 
      \exp_after:wN #1 
      \exp_after:wN #2
      \tex_romannumeral:D -`0 \exp_eval_register:N #3 
}
\cs_new:Npn \exp_last_unbraced:NNNV #1 #2 #3 #4 { 
      \exp_after:wN #1 
      \exp_after:wN #2
      \exp_after:wN #3
      \tex_romannumeral:D -`0 \exp_eval_register:N #4 
}
\cs_new:Npn \exp_last_unbraced:NNo #1#2#3 { 
      \exp_after:wN #1 \exp_after:wN #2 #3
}
\cs_new:Npn \exp_last_unbraced:NNNo #1#2#3#4 { 
      \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 #4
}

Rationalise l3doc syntax for functions/macros

Via Joseph:

The current syntax

 \begin{function}{
   \some_function:nn       / (EXP) (TF) ,
   \some_other_function:nn / (EXP) (TF) ,
 }

is rather awkward. I think we should stick to the more usual optional
argument to the environment, and therefore only document functions
together which have the same behaviour:

 \begin{function}[exp,TF]{
   \some_function:nn       ,
   \some_other_function:nn ,
 }

Also, this will nicely tie in to finally make the syntax for function and macro consistent.

\fp_pow:Nn\X{x} for -1<x<1

Three issues with \fp_pow:Nn: the docs say that x

should be a positive real number or a negative integer

but it seems to work for negative reals as well.

Secondly, and more importantly, it appears to be giving incorrect values for x less than one; thirdly, -1<x<0 throws an error. See example below:

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\fp_new:N \Z
\fp_set:Nn \Z {10}
\fp_pow:Nn \Z {-1.5}
$10^{-1.5}=\fp_to_tl:N \Z$~(correct)\par
\fp_set:Nn \Z {10}
\fp_pow:Nn \Z {1.5}
$10^{1.5}=\fp_to_tl:N \Z$~(correct)\par
\fp_set:Nn \Z {10}
\fp_pow:Nn \Z {0.5}
$10^{0.5}=\fp_to_tl:N \Z$~(incorrect)\par

% Bug:
%\fp_set:Nn \Z {10}
%\fp_pow:Nn \Z {-0.5}
%$10^{-0.5}=\fp_to_tl:N \Z$~(incorrect)
\end{document}

coffins won't typeset on internal handles

I think the behaviour of the attached example is contrary to expectations; when you ask for a coffin to be typeset "at" one of its internal handles, the whole coffin should be placed with that handle aligned with the current "insertion point"; in the examples below, the first looks good but I'd expect the second two to have their contents overlap with the box that precedes the coffin.

    \documentclass{article}
    \usepackage{expl3}
    \begin{document}
    \ExplSyntaxOn
    \coffin_new:N \0
    \coffin_new:N \1
    \coffin_new:N \2
    \hcoffin_set:Nn \1 {\fbox{coffin one}}
    \hcoffin_set:Nn \2 {\fbox{coffin two}}
    \coffin_join:NnnNnnnn \0 {hc} {vc} \1 {l} {b} {0pt} {0pt}
    \coffin_join:NnnNnnnn \0 {l} {b}   \2 {r} {b} {0pt} {0pt} 

    \coffin_mark_handle:Nnnn \0 {l} {b} {red}
    \rule{1ex}{1ex}\coffin_typeset:Nnnnn \0 {l} {b} {0pt} {0pt}

    \par\bigskip
    \coffin_mark_handle:Nnnn \0 {hc} {vc} {blue}
    \rule{1ex}{1ex}\coffin_typeset:Nnnnn \0 {hc} {vc} {0pt} {0pt}

    \par\bigskip
    \coffin_mark_handle:Nnnn \0 {\1-l} {\1-b} {green}
    \rule{1ex}{1ex}\coffin_typeset:Nnnnn \0 {\1-l} {\1-b} {0pt} {0pt}
    \ExplSyntaxOff
    \end{document}

More robust \cs_to_str:N

Right now, if a control sequence name starts with a space, and the escapechar is either a space or unprintable (e.g. less than -1), then the space gets lost. The following version should fix that, and tests suggest that it may be up to 20 percent faster.

 \cs_new:Npn \cs_to_str_C:N {
       \if:w \tex_romannumeral:D -`0 \token_to_str:N \ % <backslash><space>
           \cs_to_str_Ci:w
       \fi:
       \exp_after:wN \use_none:n \tex_string:D
 }
 \cs_new:Npn \cs_to_str_Ci:w \fi: \exp_after:wN \use_none:n 
 { ~ \tex_romannumeral:D -`0 \fi: }

\ExplSyntaxNames... broken

By e-mail from Dale Sedivic

\documentclass{article}

\usepackage{expl3}

\ExplSyntaxNamesOn
\ExplSyntaxNamesOff

\begin{document}

Colons break: boom!

\end{document} 

l3file uses non-existent \seq_remove_element:Nn

As subject, really. \seq_remove_element:Nn is needed here, as file names are stored in sequences and not in comma-lists in the latest code. I have a definition for \seq_remove_element:Nn, but as the sequence module is currently undergoing some revision will wait for the dust to settle.

Seq map functions not nestable

Unlike their clist cousins, \seq_map_inline:Nn etc. can't be nested:

    \seq_new:N \foo
    \seq_push:Nn \foo {a}
    \seq_push:Nn \foo {b}
    \seq_push:Nn \foo {c}
 
    \seq_map_inline:Nn \foo {
      [#1 \seq_map_inline:Nn \foo { (##1) }]
    }

The problem, of course, that the cleanup code just clobbers any previous definition:

\cs_set_eq:NN \seq_elt:w \ERROR

I know the seq module is in flux a little at the moment, but this will remind me to check later.

Faster `\cs_if_free:N` tests, for faster loading

Loading speed is an issue for slow computers. One very much used function is \cs_new:Npn. Currently \cs_new:Npn \foo:N produces 138 lines in the log. With the changes below, we reduce to 75 lines. It seems to speed up the loading by roughly 10% (I was hoping for more...). On a similar note, I would advise against using the Nn variants, which take ~100 more lines...

Proposal to change \cs_if_free:N to

\prg_set_conditional:Npnn \cs_if_free:N #1 {p,TF,T,F} {
  \cs_if_exist:NTF #1 
  \prg_return_false:
  { \cs_if_do_not_use_r:N #1 }
}

where the _r variant of \cs_if_do_not_use:N is defined below.

Currently \cs_if_do_not_use_p:N #1 returns true if

  • #1 has : in its \cs_to_str:N, and
  • the part after : is exactly D.

This is equivalent to

  • #1 finishes with :D, and
  • there is no other : in its name.

I propose to relax the second condition (refusing slightly more functions) to get a faster test, which just checks whether the name finishes with :D.

\group_begin:
  \tex_catcode:D `\; = 12\tex_relax:D 
  \tex_uccode:D `\; = `\:
  \tex_catcode:D `\O = 12\tex_relax:D
  \tex_uccode:D `\O = `\D
  \tex_uccode:D `\- = `\-
  \tex_uccode:D `\` = `\`
  \tex_uccode:D `\= = `\=
  \tex_uccode:D `\: = `\:
\tex_uppercase:D 
{
  \group_end:

A slightly weird kind of conditional, which does \prg_return_true/false: rather than expanding to \c_true/false_bool as the predicate variant, or to some \use for the TF variants.

  % used for "\cs_if_free"
  \cs_set:Npn \cs_if_do_not_use_r:N #1 {
    \tex_ifcat:D X 
                 \exp_after:wN \cs_if_do_not_use_aux: 
                 \token_to_str:N #1 A ;O A
                 X
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }

The predicate variant seems to be used somewhere in l3expan.

  \cs_set:Npn \cs_if_do_not_use_p:N #1 {
    \tex_ifcat:D X 
                 \exp_after:wN \cs_if_do_not_use_aux: 
                 \token_to_str:N #1 A ;O A
                 X
      \exp_after:wN \c_false_bool
    \else:
      \exp_after:wN \c_true_bool
    \fi:
  }

We need something special just for the case of the cs \D when the escape character is : (just one tiny case :-s). Otherwise, we grab until :DA, where A has catcode letter (hence not present in the result of \token_to_str:N).

  \cs_set:Npn \cs_if_do_not_use_aux: {
    \tex_ifnum:D `\: = \tex_escapechar:D
      \exp_after:wN \use_i:nn
    \fi:
    \blf_cs_if_do_not_use_aux:w
  }
  \cs_set:Npn \cs_if_do_not_use_aux:w #1 ;O A { }
}

Don't trust this code: I might have screwed up slightly.

`\clist_map_variable:...` and `#1`

One use I see for the map_variable functions is that they avoid doubling hashes when nesting, contrarily to their map_inline counterparts. Both tl and seq data types follow that, while \clist_map_variable directly derives from \clist_map_inline, without the required x-expansion-and-\exp_not:n.

\tl_new:N \l_my_tl
\tl_put_right:Nn \l_my_tl {a}
\tl_map_variable:NNn \l_my_tl \X { \iow_term:x { \X #1 } }
\seq_new:N \l_my_seq 
\seq_put_left:Nn \l_my_seq {a}
\seq_map_variable:NNn \l_my_seq \X { \iow_term:x { \X #1 } }
\clist_new:N \l_my_clist
\clist_put_left:Nn \l_my_clist {a}
\clist_map_variable:NNn \l_my_clist \X { \iow_term:x { \X #1 } }

I am not sure what the cleanest way to fix that would be.

xparse creates local functions; should it?

I'm not sure what the expected behaviour for

\group_begin:
  <catcode setup>
  \DeclareDocumentCommand \foo {} {foo}
\group_end:

should be. I'd probably expect the default behaviour to create global commands but have a starred version (or something) to create local ones. But I'm not sure really. What do you think?

Interface for \endlinechar, \newlinechar

An interface for \tex_endlinechar:D and \tex_newlinechar:D is needed when manipulating xparse verbatim arguments with more than one line. Typically, one has to do

\RequirePackage{xparse}
\ExplSyntaxOn
\DeclareDocumentCommand{\foo}{+v}
  {
    \tl_rescan:nn
      {
         \int_set:Nn \tex_newlinechar:D {13} % convert the input ^^M to new lines.
         \int_set:Nn \tex_endlinechar:D {13} % convert the new lines into ^^M when reading.
      }
      {#1}
  }
\ExplSyntaxOff
\foo+Some normal text.

More of it.+

Without the settings to \tex_newlinechar:D and \tex_endlinechar:D, the text after the first ^^M is lost, since \scantokens is seen as a single-liner, and catcode 5 characters tell TeX to gobble anything that follows in the line.

\mode_if_...: should all be protected, without `\scan_align_safe_stop:`

For the moment, the \mode_if_math: family of conditionals starts with \scan_align_safe_stop: to work properly in a case like \halign{$#$\cr \mode_if_math:TF {y} {n} \cr }. This is non-expandable since it can insert \scan_stop: at unwanted places. In particular, \halign{#\cr \bool_if:nTF { \mode_if_math_p: } {}{} \cr crashes on a Missing number error when the innards of \bool_if:nTF reach \scan_stop:.

Protected macros are not expanded at the start of alignment cells, they are expanded by \number (used in \bool_if:nTF), and they do not break ligatures, so that might be the way to go: make the four \mode_if_math: conditionals protected, and remove their \scan_align_safe_stop:.

\mode_if_horizontal:, \mode_if_vertical: and \mode_if_inner: need the same treatment as \mode_if_math:, e.g.,

\halign{A#\cr
    \mode_if_horizontal:TF {\message{T}}{\message{F}}
    \mode_if_horizontal:TF {\message{T}}{\message{F}}
    \cr}

Package identification

I guess I agree with Rasmus here:

I was writing a document where I had \newcommand{\filename}{\texttt}. After including siunitx, I started getting the error "\filename already defined". A little (very little, actually) digging showed that the problem was the call of \GetIdInfo (from l3names.sty) in l3keys2e , which (ab)uses the user-namespace macro \filename to return the result of the string parsing. Since \filename (and friends) is only used in the immediately following \ProvidesExplPackage, it would probably be better to use some scratch macros. Or, changing \GetIdInfo so that the caller must provide macros to store the results in, or a template for such macros (say \Info_Return_, which would lead to \Info_Return_filename etc.) Undefining \filename after is has been used is not enough (in case I had put my definition of \filename above the first package using l3-syntax, it would be silently re- or undefined).

We've spoken about this before (Joseph had some good ideas at one point), and this is not the first time it has come up.

Missing escaped string chars

I think perhaps we should have a short list of constant escape characters such as LaTeX2e's \@backslashchar. E.g.,

\c_backslash_str
\c_percent_str
\c_lbrace_str
\c_rbrace_str

and so on. (I think ‘str’ is clearer than ‘char’ here but I could be wrong.)

(Issue by Will, written while logged into the wrong account.)

\token_if_..._register

Those conditionals are broken if escapechar is not 92 (standard value). Namely, these tests will always return false (I think) if the escapechar is different from its value at definition time.

Also, \token_if_count_register should take care of \count and \countdef, and the same is true for other registers.

We may also give a \token_if_int, which recognizes both \count123 and \mathchar"123, since both are used in l3int.

(I'm logging this issue mostly for myself. I'll think of a fix.)

\prg_return_true/false:

I would like to change \prg_return_true: and \prg_return_false: to

\cs_set:Npn \prg_return_true: { \tex_expandafter:D \use_i:nn \tex_romannumeral:D }
\cs_set:Npn \prg_return_false: { \tex_expandafter:D \use_ii:nn \tex_romannumeral:D }

and have the ending of conditionals as follows:

...TF  -> ... \c_zero
...F   -> ... \c_zero { }
...T   -> ... \c_zero \use:n \use_none:n
...p   -> ... \c_zero \c_one \c_zero

I think it would make conditionals quicker.

EDIT: the T variant I gave was wrong. Only l3basics changes, with the following functions affected: \prg_return_true:, \prg_return_false: (given above), the \prg_generate_..._form_parm:Nnnnn, and \prg_generate_..._form_count:Nnnnn

New definitions:

\cs_set:Npn \prg_generate_p_form_parm:Nnnnn #1#2#3#4#5{
  \exp_args:Nc #1 {#2_p:#3}#4{#5 \c_zero 
    \c_true_bool \c_false_bool
  }
}
\cs_set:Npn \prg_generate_TF_form_parm:Nnnnn #1#2#3#4#5{
  \exp_args:Nc#1 {#2:#3TF}#4{#5 \c_zero 
  }
}
\cs_set:Npn \prg_generate_T_form_parm:Nnnnn #1#2#3#4#5{
  \exp_args:Nc#1 {#2:#3T}#4{#5 \c_zero 
    \use:n \use_none:n
  }
}
\cs_set:Npn \prg_generate_F_form_parm:Nnnnn #1#2#3#4#5{
  \exp_args:Nc#1 {#2:#3F}#4{#5 \c_zero 
    { }
  }
}

And

\cs_set:Npn \prg_generate_p_form_count:Nnnnn #1#2#3#4#5{
  \cs_generate_from_arg_count:cNnn {#2_p:#3} #1 {#4}{#5 \c_zero 
    \c_true_bool \c_false_bool
  }
}
\cs_set:Npn \prg_generate_TF_form_count:Nnnnn #1#2#3#4#5{
  \cs_generate_from_arg_count:cNnn {#2:#3TF} #1 {#4}{#5 \c_zero 
  }
}
\cs_set:Npn \prg_generate_T_form_count:Nnnnn #1#2#3#4#5{
  \cs_generate_from_arg_count:cNnn {#2:#3T} #1 {#4}{#5 \c_zero 
    \use:n \use_none:n
  }
}
\cs_set:Npn \prg_generate_F_form_count:Nnnnn #1#2#3#4#5{
  \cs_generate_from_arg_count:cNnn {#2:#3F} #1 {#4}{#5 \c_zero 
    { }
  }
}

Seems all test pass.

Names of the tl replacement functions

On latex-l, Frank writes:

\tl_remove_all_in:Nn
\tl_remove_in:Nn

The _in seems to me unnecessary and I would personally prefer

\tl_remove_once:Nn
\tl_remove_all:Nn

And I agree these new names are better.

Deprecated macros

Please keep all deprecated macros in the documentation and add the date of deprecation. Also, all robust deprecated macros should produce a warning when called. Otherwise nobody will ever notice that something has been deprecated!

Provide a test for output mode

In issue 32 the point was made that using pdfTeX as an engine is not the same as PDF output. We don't currently have a test for the later. I'm not clear on whether we'll want one long-term (this depends on how output mode is selected), but we should perhaps have something at least in package mode. \mode_if_output_pdf:(TF) might fit with other names we currently use.

xparse edge case

Here's an example where an optional o argument followed by an optional g argument aren't registered correctly; things work if the g argument is placed on the end, but then you get possible undesirable space-not-ignoring. I can't remember the internals of xparse enough to know if something like {mogm} is even intended to be valid syntax, though.

\documentclass{article}
\usepackage{xparse}
\begin{document}
\DeclareDocumentCommand\foo{mmogm}{[#1] / [#2] / [#3] / [#4] / [#5]}
(\foo{first} {2nd} {last})\par
(\foo{first} {2nd} [old] {last})\par
(\foo{first} {2nd} {new} {last})\par
(\foo{first} {2nd} [old] {new} {last})\par

\bigskip
\RenewDocumentCommand\foo{mmgom}{[#1] / [#2] / [#3] / [#4] / [#5]}
(\foo{first} {2nd} {last})\par
(\foo{first} {2nd} [old] {last})\par
(\foo{first} {2nd} {new} {last})\par
(\foo{first} {2nd} {new} [old] {last})\par
\end{document}

(Issue by Will, written while logged into the wrong account.)

\quark_if_recursion_tail_stop:n has edge cases

Bruno has submitted the following re-implementation of \quark_if_recursion_tail_stop:n for edge cases noted below.

% The `:n` quark tests are currently broken: both lines below crash.
%
%   \quark_if_recursion_tail_stop:n {{{{a}}}}
%   \quark_if_recursion_tail_stop:n {{ab\iffalse}\fi}
%
% Here is the proposed fix (changing of course `Mquark` to `quark`). FYI,
%     `\if_catcode:w A \tl_to_str:n {...} A` 
% tests whether {...} is empty. It is a variant of 
%     `\exp_after:wN \if_meaning:w \exp_after:wN A \tl_to_str:n {...} A`
% which is the version used for `\tl_if_empty:n(TF)`.

\cs_new:Npn \Mquark_if_recursion_tail_stop:n #1 {
  \if_catcode:w A \tl_to_str:n \exp_after:wN {
    \Mquark_if_recursion_tail_aux:w #1 \q_recursion_stop
                     \q_recursion_tail \q_recursion_stop \q_stop
  } A
  \exp_after:wN \use_none_delimit_by_q_recursion_stop:w
  \fi:
}
\cs_new:Npn \Mquark_if_recursion_tail_stop_do:nn #1#2 {
  \if_catcode:w A \tl_to_str:n \exp_after:wN {
    \Mquark_if_recursion_tail_aux:w #1 \q_recursion_stop 
                     \q_recursion_tail \q_recursion_stop \q_stop
  } A
  \exp_after:wN \use_i_delimit_by_q_recursion_stop:nw
  \else:
  \exp_after:wN\use_none:n
  \fi:
  {#2}
}
\cs_new:Npn \Mquark_if_recursion_tail_aux:w #1 \q_recursion_tail #2
     \q_recursion_stop #3 \q_stop { #1 #2 }

Please document for each macro when it was added

Knowing at which date a certain macro was added is important for filling out the minimum version date field in \usepackage. One can retrieve this information with svn log and the likes, but that doesn't work if you install L3 from a repository. Therefore for each macro it should be documented when it has been introduced.

General \prg_break: to end inline mappings cleanly

The inline (and variable) mappings for tl, clist, and prop (at least) leave some code after the user breaks. This prevents the definition of a sensible \tl_map_break:n.

\tl_const:Nn \c_my_tl {a}
\tl_map_inline:Nn \c_my_tl { \exp_after:wN \tex_show:D \tl_map_break: }

will show what follows on the input stream. A cleaner approach can be found in the l3seq module where mapping functions are defined with \seq_break_point:n { <termination code> } and \seq_map_break:n makes sure that the code given by the user is put after the <termination code>.

Using module-specific break points and breaking functions, would lead to problems in nesting mappings if the user wants to exit two mappings at a time: the tokens meant to restore definitions for the inner-most mapping would be skipped, leading to problems later.

Hence I propose to have the break system in l3prg, and copy the functions (except of course \prg_break_point:n, which may not change) for each module.

\cs_new_eq:NN \prg_break_point:n \use:n 
\cs_new:Npn \prg_break: #1 \prg_break_point:n #2 {#2}
\cs_new:Npn \prg_break:n #1 #2 \prg_break_point:n #3 {#3 #1}

\cs_new_eq:NN \seq_break: \prg_break:
\cs_new_eq:NN \seq_break:n \prg_break:n

Possibly, the check module could do some dark magic to check that a given \<module>_break: is breaking a mapping started by the correct module.

`\tl_if_in` and `\tl_replace_once/all`

\tl_if_in:Nn(TF) and \tl_if_in:nn(TF) are buggy right now, just as the \tl_replace_...:Nnn were earlier.

It is in fact possible to both fix and simplify, using no quark. Note that #2 cannot contain braces since it is used to delimit an argument. Thus \tl_tmp:w will grab the trailing #2 if and only if it is not present in #1, and there is no risk of an overlap.

\prg_set_protected_conditional:Npnn \tl_if_in:nn #1#2 { T , F , TF }
  {
    \cs_set:Npn \tl_tmp:w ##1 #2 { }
    \tl_if_empty:oTF { \tl_tmp:w #1 {} #2 } 
        \prg_return_false: \prg_return_true:
  }
\prg_set_protected_conditional:Npnn \tl_if_in:Nn #1#2 { T , F , TF }
  {
    \cs_set:Npn \tl_tmp:w ##1 #2 { }
    \exp_args:No \tl_if_empty:oTF { \exp_after:wN \tl_tmp:w #1 {} #2 } 
        \prg_return_false: \prg_return_true:
  }

On a related note, just as token lists can contain unescaped # thanks to \exp_not:n in an x-expansion context, it is possible to make \tl_replace_once:Nnn and \tl_replace_all:Nnn accept unescaped # in the third argument (replacement text). I just took the last definitions and replaced every definition of \tl_tmp:w containing #4 (replacement text for the auxiliaries) by an x-type definition, wrapping the relevant tokens in \exp_not:n. It is possible to get a quark-less \tl_replace_once, but it is probably twice slower than the current.

I also removed the "weird-looking \use:n"... I believe that it must be a hangover from a previous implementation, since it simply follows a definition, and wraps four harmless tokens. I may be missing something, though.

\RequirePackage{expl3}
\ExplSyntaxOn

\cs_set_protected:Npn \tl_replace_once_aux:NNnn #1#2#3#4
  {
    \cs_set_protected:Npx \tl_tmp:w ##1 #3 ##2 \q_stop
      {
        \exp_not:N \quark_if_no_value:nF {##2}
          {
            \tl_set:No \exp_not:N \l_tl_replace_tl { ##1 \exp_not:n{#4} }
            \exp_not:n
              { 
                \cs_set_protected:Npn \tl_tmp:w ##1 \q_nil #3 \q_no_value 
                  { \tl_put_right:No \l_tl_replace_tl {##1} }
              }
            \exp_not:n{\tl_tmp:w \prg_do_nothing:} ##2
            \exp_not:n{#1 #2 \l_tl_replace_tl}
          }
      }
    \exp_after:wN \tl_tmp:w \exp_after:wN \prg_do_nothing:
    #2 \q_nil #3 \q_no_value \q_stop
}

\cs_set_protected:Npn \tl_replace_all_aux:NNnn #1#2#3#4
  {
    \tl_clear:N \l_tl_replace_tl
    \cs_set_protected:Npx \tl_tmp:w ##1 #3 ##2 \q_stop
      {
        \exp_not:N \quark_if_no_value:nTF {##2}
          {
            \exp_not:n
              {
                \cs_set_protected:Npn \tl_tmp:w ##1 \q_nil ##2 \q_stop
                  { \tl_put_right:No \l_tl_replace_tl {##1} }
              }
            \exp_not:N \tl_tmp:w ##1 \exp_not:N \q_stop
          }
          {
            \exp_not:n { \tl_put_right:No \l_tl_replace_tl } 
              { ##1 \exp_not:n{#4} }
            \exp_not:n { \tl_tmp:w \prg_do_nothing: } ##2 \exp_not:N \q_stop
          }
      }
    \exp_after:wN \tl_tmp:w \exp_after:wN \prg_do_nothing:
    #2 \q_nil #3 \q_no_value \q_stop
    #1 #2 \l_tl_replace_tl
  }

l3keys2e.sty: \ProcessPackageOptions hangs after 2011/06/05 l3packages update

The code of the trivial package mypkg.sty below defines key draft. If draft is given as a class option, LaTeX hangs at the command \ProcessKeysOptions. The error message is:

! Undefined control sequence.
\c_keys_root_tl
mypkg/\keys_latexe_remove_equals:n {draft}.cmd:n
l.12 \ProcessKeysOptions{mypkg}

%%%%%%%%%%%%%%
% Package file mypkg.sty:
%%%%%%%%%%%%%%

\RequirePackage{expl3}
\RequirePackage{l3keys2e}
\ProvidesExplPackage{mypkg}{2011/06/07}{0.1}{triv. example pkg.}

\newcommand\isdraft{no}
\keys_define:nn{mypkg}{
draft .choice:,
draft / true .code:n = {\renewcommand\isdraft{yes}},
draft / false .code:n = {\renewcommand\isdraft{no}},
draft .default:n = {true}
}
\ProcessKeysOptions{mypkg}

%%%%%%
% Test file:
%%%%%%

\documentclass[draft]{article} %LaTeX hangs at \ProcessKeysOptions{...}
\usepackage{mypkg}

\begin{document}
Draft mode: \isdraft.
\end{document}

\prevdepth management in the galley module

One reasonable application of the galley module is to collect material from various places in a vertical box (galley). The naive code for that would be

 \box_new:N \g_my_box
 \cs_new_protected:Npn \my_append:n #1
   { \vbox_gset:Nn \g_my_box { \vbox_unpack_clear:N \g_my_box #1 } }
 \my_append:n { Hello. }
 \my_append:n { Hello again. }

This does not quite work: the horizontal boxes from the two lines are on top of each other with no baseline skip. A fix is to somehow preserve the \prevdepth before closing the vertical box, and restoring it when collecting the next material. I think this fits in the scope of a galley module.

l3kernel/l3packages updates break fontspec small caps font selection

From the MiKTeX mailing list, the following code

\documentclass[12pt]{article}
\usepackage{fontspec}
\usepackage{xunicode}
\usepackage{xltxtra}
\setmainfont{TeX Gyre Termes}
\begin{document}
\textsc{Small Capitals}
\end{document}

gives the error

LaTeX Font Warning: Font shape `EU1/TeXGyreTermes(0)/m/sc' undefined
(Font)              using `EU1/TeXGyreTermes(0)/m/n' instead on input line 7.

Expandable `\clist_if_in_numrange:nn`

In the current l3candiates, there is a non-expandable \clist_if_in_numrange:nn, with a comment that it could be made expandable. The topic came up on LaTeX-L, so I copy the code here. I have the feeling that it may be better to use a double dash as a range delimiter: --2,4--7,10--. Two reasons: practical, so that negative numbers are easy to use in this context, and typographical: the correct way to write a number range (1989--2010) in a text uses an en-dash (I believe?).

% \begin{macro}[pTF]{\clist_if_in_numrange:nn}
%   Expandable version of what's now in |l3candidates.dtx|.
%   A `numrange' is like |-2,5-8,17-| (can be unsorted).
%
%   The following possibilities are supported for the numrange:
%   \begin{itemize}
%   \item |4|, a simple integer
%   \item |5-8|, a range of integers
%   \item |-2| or |17-| for open-ended ranges.
%   \item |-| for accepting everything (?).
%   \end{itemize}
%   Numeric expression (or negative integers) can be enclosed within braces.
%   However, this may not work super well yet. In particular, right now, you
%   will have to use two pairs of braces when giving a single negative number,
%   since grabbing the element of a clist loses one pair of braces, and the
%   minus sign would then be interpreted as a delimiter for an open-ended
%   range.
%
%    \begin{macrocode}
\prg_set_conditional:Npnn \clist_if_in_numrange:nn  #1 #2 {p,TF,T,F}
   {
      \exp_args:Nf \clist_numrange_recurse:nw
         { \int_eval:n {#1} }
         #2,\q_recursion_tail,\q_recursion_stop
   }
\cs_new:Npn \clist_numrange_recurse:nw #1 #2,
   {
      \quark_if_recursion_tail_stop_do:nn {#2} {\prg_return_false:}
      \clist_numrange_parse:nwww {#1} #2 - #2 - \q_stop
      \clist_numrange_recurse:nw {#1}
   }
\cs_set:Npn \clist_numrange_parse:nwww #1 #2 - #3 - #4 \q_stop
   {
       \tl_if_empty:nF {#2}{
          \int_compare:nNnT {#1}<{#2} {\use_none_delimit_by_q_stop:w}
        }
       \tl_if_empty:nF {#3}{
          \int_compare:nNnT {#1}>{#3} {\use_none_delimit_by_q_stop:w}
       }
       \use_i_delimit_by_q_recursion_stop:nw {\prg_return_true:}
       \q_stop
   }
%    \end{macrocode}
% \end{macro} 

Active characters

Here is a partial idea for what could be done to active characters.

\group_begin:
\tex_catcode:D `\~=13\tex_relax:D
\prg_stepwise_inline:nnnn {0} {255} {1} {
     \tex_lccode:D `\~ = #1\relax
     \tex_lowercase:D { \cs_new:Npx ~ { \exp_not:N \active_char:N \token_to_str:N ~ } }
}
\group_end:

\cs_new:Npn \active_char:N #1 { 
      \cs_if_exist:cTF { active_ \l_active_state_tl _ \token_to_str:N #1 : } {
            \use:c { active_ \l_active_state_tl _ \token_to_str:N #1 : }
      } {
            \use:c { active_ \l_active_state_tl :N } #1
      }
}
\tl_new:Npn \l_active_state_tl {string}
\cs_new:Npn \active_string:N #1 { \token_to_str:N #1 }
\cs_new:cpn {active_string_^:} {\sp}
\cs_new:cpn {active_string_&:} {&}

And packages such as listings which makes characters active in a specific environment should define \active_listings:N (or each one of the character-specific commands), and the environment should change \l_active_state_tl to listings, and change catcodes, of course, but would not need to redefine active characters each time.

For instance, this makes it easy to have otherwise active characters inside a \label: just change \l_active_state_tl to string before putting the user-given code into the \csname construction. Similarly, each time a length/number is needed, we get ., digits and (possibly active??) letters to expand to themselves (with catcode 12), suitable for a length.

For tables, I would have preferred to make & into an active character \let to be an implicit character of catcode 4 over the whole document, but tables are completely another story, and I think we can live without \halign and the corresponding constraint on the catcode of &.

Escaping local definitions from groups

Sometimes people need to define a token list (or whatever) locally within the group just outside the current group. To do that, a possibility (in want of better names) is

\tl_new:N \l_group_end_tl 
\cs_new_protected_nopar:Npn \special_group_begin: 
    { 
         \group_begin: 
         \tl_set:Nn \l_group_end_tl { \group_end: } 
    }
\cs_new_protected_nopar:Npn \special_group_end: { \l_group_end_tl } 

\cs_new_protected_nopar:Npn \escape_tl_def:N #1 {
      \tl_put_right:Nx \l_group_escape_tl { \tl_set:Nn \exp_not:N #1{ #1 } }
}
\cs_new_eq:NN \escape_clist_def:N \escape_tl_def:N
\cs_new_eq:NN \escape_seq_def:N \escape_tl_def:N
\cs_new_eq:NN \escape_prop_def:N \escape_tl_def:N

\cs_new_protected_nopar:Npn \escape_int_def:N #1   {
    \tl_put_right:Nx \l_group_escape_tl { \int_set:Nn \exp_not:N #1{ \int_use:N #1 } }
}

This could be used in particular to open and close environments, since this is the most common situation from which users/programmers may want to escape their definition. The same could be done for groups closed with an implicit brace (e.g. boxes etc.), or \left...\right groups: it suffices to define \l_group_escape_tl accordingly at the start of the environment.

Macro parameter character in xparse default

The \xparse_grab_...:w functions should use x expansion with \exp_not:n to define \xparse_grab_arg:w, because the rest of the argument specification can contain arbitrary user input. For instance, in the following, the first use of \foo shows that we lost one hash (compare with \showtokens{##}), and the second use crashes.

\RequirePackage{xparse}
\DeclareDocumentCommand{\foo}{oO{##}}{\showtokens{#1,#2}}
\foo[a]
\foo[a[b]]

To fix that, all of the \xparse_grab_...:w must be amended. Is it worth it (I can't think of a single real case where this might be useful)?

Message filtering system needs a proper interface

Currently, there is only the low-level \msg_redirect_module:nnn, etc.. There are issues with the function names here, and also there is no way to easily reverse a redirection. Moreover, the interface is no good for users. (Noting so this is not forgotten.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.