[latex3-commits] [git/LaTeX3-latex3-babel] master: \babel(pre|post)hyphenation refactored. (1b572f3)

Javier email at dante.de
Mon Mar 15 17:45:33 CET 2021


Repository : https://github.com/latex3/babel
On branch  : master
Link       : https://github.com/latex3/babel/commit/1b572f322a0c08f66b3d56e340ec70b5cea1e79c

>---------------------------------------------------------------

commit 1b572f322a0c08f66b3d56e340ec70b5cea1e79c
Author: Javier <email at localhost>
Date:   Mon Mar 15 17:45:33 2021 +0100

    \babel(pre|post)hyphenation refactored.
    
    * Faster and more reliable.


>---------------------------------------------------------------

1b572f322a0c08f66b3d56e340ec70b5cea1e79c
 README.md                                          |   4 +-
 babel.dtx                                          | 245 +++++++++++----------
 babel.ins                                          |   2 +-
 babel.pdf                                          | Bin 820602 -> 821036 bytes
 bbcompat.dtx                                       |   2 +-
 .../guides/non-standard-hyphenation-with-luatex.md | 103 +++++++--
 news-guides/guides/using-babel-with-plain.md       |   7 +-
 news-guides/news/whats-new-in-babel-3.56.md        |   5 +
 samples/lua-beamer.pdf                             | Bin 22433 -> 35256 bytes
 9 files changed, 226 insertions(+), 142 deletions(-)

diff --git a/README.md b/README.md
index e90e11d..6e5d75f 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-## Babel 3.55.2305
+## Babel 3.55.2312
 
 This package manages culturally-determined typographical (and other)
 rules, and hyphenation patterns for a wide range of languages. Many
@@ -50,7 +50,7 @@ respective authors.
        * Key 'space' in \babelprehyphenation.
        * Multiple 'insert's allowed.
        * Fixes:
-         - 'insert' and 'data' not always set/get the expected node.
+         - 'insert' and 'data' didn't always set/get the expected node.
          
 3.55   2021-03-03??
        * Captions for Uyghur.
diff --git a/babel.dtx b/babel.dtx
index 24b897e..72c544a 100644
--- a/babel.dtx
+++ b/babel.dtx
@@ -31,7 +31,7 @@
 %
 % \iffalse
 %<*filedriver>
-\ProvidesFile{babel.dtx}[2021/03/08 v3.55.2305 The Babel package]
+\ProvidesFile{babel.dtx}[2021/03/15 v3.55.2312 The Babel package]
 \documentclass{ltxdoc}
 \GetFileInfo{babel.dtx}
 \usepackage{fontspec}
@@ -4849,8 +4849,8 @@ help from Bernd Raichle, for which I am grateful.
 % \section{Tools}
 %
 %    \begin{macrocode}
-%<<version=3.55.2305>>
-%<<date=2021/03/08>>
+%<<version=3.55.2312>>
+%<<date=2021/03/15>>
 %    \end{macrocode}
 %
 % \textbf{Do not use the following macros in \texttt{ldf} files. They
@@ -13881,6 +13881,31 @@ end
     Babel.hyphenate_replace(head, 1)
   end
 
+  function Babel.debug_hyph(w, wn, sc, first, last, last_match)
+    local ss = ''
+    for pp = 1, 40 do
+      if wn[pp] then
+        if wn[pp].id == 29 then
+          ss = ss .. unicode.utf8.char(wn[pp].char)
+        else
+          ss = ss .. '{' .. wn[pp].id .. '}'
+        end
+      end
+    end
+    print('nod', ss)
+    print('lst_m',
+      string.rep(' ', unicode.utf8.len(
+         string.sub(w, 1, last_match))-1) .. '>')
+    print('str', w)
+    print('sc', string.rep(' ', sc-1) .. '^')
+    if first == last then
+      print('f=l', string.rep(' ', first-1) .. '!')
+    else
+      print('f/l', string.rep(' ', first-1) .. '[' ..
+        string.rep(' ', last-first-1) .. ']')
+    end
+  end
+
   Babel.us_char = string.char(31)
 
   function Babel.hyphenate_replace(head, mode)
@@ -13891,11 +13916,11 @@ end
 
     while true do  &% for each subtext block
 
-      local w, wn, nw, lang = Babel.fetch_subtext[mode](word_head)
+      local w, w_nodes, nw, lang = Babel.fetch_subtext[mode](word_head)
 
       if Babel.debug then
         print()
-        print('@@@@@', w, nw)
+        print((mode == 0) and '@@@@<' or '@@@@>', w)
       end
 
       if nw == nil and w == '' then break end
@@ -13910,7 +13935,7 @@ end
         local r = lbkr[lang][k].replace
 
         if Babel.debug then
-          print('=====', p, mode)
+          print('*****', p, mode)
         end
 
         &% This variable is set in some cases below to the first *byte*
@@ -13921,7 +13946,7 @@ end
         &% For every match.
         while true do
           if Babel.debug then
-            print('-----')
+            print('=====')
           end
           local new  &% used when inserting and removing nodes
           local refetch = false
@@ -13944,20 +13969,15 @@ end
           first = u.len(w:sub(1, first-1)) + 1
           last  = u.len(w:sub(1, last-1)) &% now last points to C
 
-          if Babel.debug then
-            print(p)
-            print('', 'sc', 'first', 'last', 'last_m', '#w', rc, 'w')
-          end
-
           &% This loop stores in n small table the nodes
           &% corresponding to the pattern. Used by 'data' to provide a
-          &% predictable behavior with 'insert' (now wn is modified on
+          &% predictable behavior with 'insert' (now w_nodes is modified on
           &% the fly), and also access to 'remove'd nodes.
           local sc = first-1           &% Used below, too
           local data_nodes = {}
 
           for q = 1, last-first+1 do
-            data_nodes[q] = wn[sc+q]
+            data_nodes[q] = w_nodes[sc+q]
           end
 
           &% This loop traverses the matched substring and takes the
@@ -13968,149 +13988,143 @@ end
 
           while rc < last-first+1 do &% for each replacement
             if Babel.debug then
-              print('.....', #data_nodes)
+              print('.....', rc + 1)
             end
             sc = sc + 1
             rc = rc + 1
 
             if Babel.debug then
-              local ss = ''
-              for pp = 1, 20 do
-                if wn[pp] then
-                  if wn[pp].id == 29 then
-                    ss = ss .. unicode.utf8.char(wn[pp].char)
-                  else
-                    ss = ss .. '{' .. wn[pp].id .. '}'
-                  end
-                end
-              end
-              print(ss)
+              Babel.debug_hyph(w, w_nodes, sc, first, last, last_match)
             end
 
             local crep = r[rc]
-            local char_node = wn[sc]
-            local char_base = char_node
-            local end_replacement = false
+            local item = w_nodes[sc]
+            local item_base = item
             local placeholder = Babel.us_char
+            local d
 
             if crep and crep.data then
-              char_base = data_nodes[crep.data]
-            end
-
-            if Babel.debug then
-              print('*', sc, first, last, last_match, char_node.id, rc, w)
+              item_base = data_nodes[crep.data]
             end
 
             if crep and next(crep) == nil then &% = {}
-              last_match = save_last
+              last_match = save_last    &% Optimization
+              goto next
 
             elseif crep == nil then &% = remove
-              node.remove(head, char_node)
-              table.remove(wn, sc)
+              node.remove(head, item)
+              table.remove(w_nodes, sc)
               w = u.sub(w, 1, sc-1) .. u.sub(w, sc+1)
-              last_match = utf8.offset(w, sc)
               sc = sc - 1  &% Nothing has been inserted.
+              last_match = utf8.offset(w, sc+1)
+              goto next
+
+            elseif crep and crep.string then
+              local str = crep.string(matches)
+              if str == '' then  &% Gather with nil
+                node.remove(head, item)
+                table.remove(w_nodes, sc)
+                w = u.sub(w, 1, sc-1) .. u.sub(w, sc+1)
+                sc = sc - 1  &% Nothing has been inserted.
+              else
+                local loop_first = true
+                for s in string.utfvalues(str) do
+                  d = node.copy(item_base)
+                  d.char = s
+                  if loop_first then
+                    loop_first = false
+                    head, new = node.insert_before(head, item, d)
+                    if sc == 1 then
+                      word_head = head
+                    end
+                    w_nodes[sc] = d
+                    w = u.sub(w, 1, sc-1) .. u.char(s) .. u.sub(w, sc+1)
+                  else
+                    sc = sc + 1
+                    head, new = node.insert_before(head, item, d)
+                    table.insert(w_nodes, sc, new)
+                    w = u.sub(w, 1, sc-1) .. u.char(s) .. u.sub(w, sc)
+                  end
+                  if Babel.debug then
+                    print('.....', 'str')
+                    Babel.debug_hyph(w, w_nodes, sc, first, last, last_match)
+                  end
+                end  &% for
+                node.remove(head, item)
+              end  &% if ''
+              last_match = utf8.offset(w, sc+1)
+              goto next
 
             elseif mode == 1 and crep and (crep.pre or crep.no or crep.post) then
-              local d = node.new(7, 0)   &% (disc, discretionary)
-              d.pre     = Babel.str_to_nodes(crep.pre, matches, char_base)
-              d.post    = Babel.str_to_nodes(crep.post, matches, char_base)
-              d.replace = Babel.str_to_nodes(crep.no, matches, char_base)
-              d.attr = char_base.attr
+              d = node.new(7, 0)   &% (disc, discretionary)
+              d.pre     = Babel.str_to_nodes(crep.pre, matches, item_base)
+              d.post    = Babel.str_to_nodes(crep.post, matches, item_base)
+              d.replace = Babel.str_to_nodes(crep.no, matches, item_base)
+              d.attr = item_base.attr
               if crep.pre == nil then  &% TeXbook p96
                 d.penalty = crep.penalty or tex.hyphenpenalty
               else
                 d.penalty = crep.penalty or tex.exhyphenpenalty
               end
-              head, new = node.insert_before(head, char_node, d)
-              end_replacement = true
+              placeholder = '|'
+              head, new = node.insert_before(head, item, d)
+
+            elseif mode == 0 and crep and (crep.pre or crep.no or crep.post) then
+              &% ERROR
+
+            elseif crep and crep.penalty then
+              d = node.new(14, 0)   &% (penalty, userpenalty)
+              d.attr = item_base.attr
+              d.penalty = crep.penalty
+              head, new = node.insert_before(head, item, d)
 
             elseif crep and crep.space then
-              local quad = 655360      &% 10 pt = 655360 = 10 * 65536
-              if char_base.font then
-                local quad = font.getfont(char_base.font).size
-              end 
-              local d = node.new(12, 13)      &% (glue, spaceskip)
+              &% 655360 = 10 pt = 10 * 65536 sp
+              d = node.new(12, 13)      &% (glue, spaceskip)
+              local quad = font.getfont(item_base.font).size or 655360
               node.setglue(d, crep.space[1] * quad,
                               crep.space[2] * quad,
                               crep.space[3] * quad)
-              placeholder = '|'
-              head, new = node.insert_before(head, char_node, d)
-              end_replacement = true
+              if mode == 0 then
+                placeholder = '|'
+              end
+              head, new = node.insert_before(head, item, d)
 
-            elseif crep and crep.penalty then
-              local d = node.new(14, 0)   &% (penalty, userpenalty)
-              d.attr = char_base.attr
-              d.penalty = crep.penalty
-              head, new = node.insert_before(head, char_node, d)
-              end_replacement = true
+            elseif mode == 0 and crep and crep.space then
+              &% ERROR
 
-            elseif crep and crep.string then
-              local str = crep.string(matches)
-              if str == '' then  &% Gather with nil
-                refetch = true
-                if sc == 1 then
-                  word_head = char_node.next
-                end
-                head, new = node.remove(head, char_node)
-              elseif char_node.id == 29 and u.len(str) == 1 then
-                char_node.char = string.utfvalue(str)
-                w = u.sub(w, 1, sc-1) .. str .. u.sub(w, sc+1)
-                last_match = utf8.offset(w, sc+1)
-              else
-                refetch = true
-                local n
-                for s in string.utfvalues(str) do
-                  if char_node.id == 7 then
-                    &% TODO. Remove this limitation.
-                    texio.write_nl('Automatic hyphens cannot be replaced, just removed.')
-                  else
-                    n = node.copy(char_base)
-                  end
-                  n.char = s
-                  if sc == 1 then
-                    head, new = node.insert_before(head, char_node, n)
-                    word_head = head
-                  else
-                    node.insert_before(head, char_node, n)
-                  end
-                end
-                node.remove(head, char_node)
-              end  &% string length
-            end  &% if char and char.string (ie replacement cases)
+            end  &% ie replacement cases
 
             &% Shared by disc, space and penalty. 
-            if end_replacement then
-              if sc == 1 then
-                word_head = head
-              end
-              if crep.insert then
-                w = u.sub(w, 1, sc-1) .. placeholder .. u.sub(w, sc)
-                table.insert(wn, sc, new)
-                last = last + 1
-                last_match = save_last
-              else
-                node.remove(head, char_node)
-                w = u.sub(w, 1, sc-1) .. placeholder .. u.sub(w, sc+1)
-                last_match = utf8.offset(w, sc)
-              end
+            if sc == 1 then
+              word_head = head
+            end
+            if crep.insert then
+              w = u.sub(w, 1, sc-1) .. placeholder .. u.sub(w, sc)
+              table.insert(w_nodes, sc, new)
+              last = last + 1
+            else
+              w_nodes[sc] = d
+              node.remove(head, item)
+              w = u.sub(w, 1, sc-1) .. placeholder .. u.sub(w, sc+1)
             end
+          
+            last_match = utf8.offset(w, sc+1)
+          
+            ::next::
+            
           end  &% for each replacement
 
-          if Babel.debug then
-            print('/', sc, first, last, last_match, #w, rc,  w)
-          end
+          &% si son 'iguales', estamos al final
 
-          &% TODO. refetch will be eventually unnecesary.
-          if refetch then
-            w, wn, nw, lang = Babel.fetch_subtext[mode](word_head)
+
+          if Babel.debug then
+              print('.....', '/')
+              Babel.debug_hyph(w, w_nodes, sc, first, last, last_match)
           end
 
         end  &% for match
 
-        if Babel.debug then
-           print('//', sc, first, last, last_match, '#w', rc,  w)
-        end
       end  &% for patterns
 
       ::next::
@@ -14118,6 +14132,7 @@ end
     end  &% for substring
     return head
   end
+  
   &% This table stores capture maps, numbered consecutively
   Babel.capture_maps = {}
 
diff --git a/babel.ins b/babel.ins
index 89d04e5..f551c14 100644
--- a/babel.ins
+++ b/babel.ins
@@ -26,7 +26,7 @@
 %% and covered by LPPL is defined by the unpacking scripts (with
 %% extension .ins) which are part of the distribution.
 %%
-\def\filedate{2021/03/08}
+\def\filedate{2021/03/15}
 \def\batchfile{babel.ins}
 \input docstrip.tex
 
diff --git a/babel.pdf b/babel.pdf
index 8384a1e..64e9ea8 100644
Binary files a/babel.pdf and b/babel.pdf differ
diff --git a/bbcompat.dtx b/bbcompat.dtx
index de70e9f..49cc2be 100644
--- a/bbcompat.dtx
+++ b/bbcompat.dtx
@@ -30,7 +30,7 @@
 %
 % \iffalse
 %<*dtx>
-\ProvidesFile{bbcompat.dtx}[2021/03/08 v3.55.2305]
+\ProvidesFile{bbcompat.dtx}[2021/03/15 v3.55.2312]
 %</dtx>
 %
 %% File 'bbcompat.dtx'
diff --git a/news-guides/guides/non-standard-hyphenation-with-luatex.md b/news-guides/guides/non-standard-hyphenation-with-luatex.md
index eaca6cd..b613f6e 100644
--- a/news-guides/guides/non-standard-hyphenation-with-luatex.md
+++ b/news-guides/guides/non-standard-hyphenation-with-luatex.md
@@ -1,6 +1,5 @@
 # Non-standard hyphenation with `luatex`
 
-These notes refer to a new feature in babel, in 3.37. With works only with LaTeX using the luatex engine.
 
 Here is a simple example of a declaration:
 ```tex
@@ -9,24 +8,55 @@ Here is a simple example of a declaration:
   {}
 }
 ```
-
-It consists of the language the transformation is applied to (here `ngerman`), a pattern with the string to be handled (here `ck`) and a replacement with a list containing exactly the same number of elements as the pattern. The language here refers to a set of hyphenation rules, ie, to `\language`. So, the first letter in the pattern is replaced with the first item in the list, the second letter with the second item and so on. (This is not strictly true, because the replace list is filled with nil's if shorter.)
-
-‘Automatic’ hyphenation points, as inserted by the hyphenation algorithm, are entered in the pattern as vertical bars (`|`). Explicit hyphens are entered as `=`. Spaces are allowed for clarity, but they are discarded.
+It consists of:
+* the language the transformation is applied to (here `ngerman`);
+* a pattern with the string to be handled (here `ck`);
+* a replacement with a list containing exactly the same number of
+  elements as the pattern (except if there are inserted elements, as
+  explained below).
+
+The language here refers to a set of hyphenation rules, ie, to
+`\language`. So, the first letter in the pattern is replaced with the
+first item in the list, the second letter with the second item and so
+on. (This is not strictly true, because the replace list is filled with
+nil's if shorter.)
+
+## Rules
+
+‘Automatic’ hyphenation points, as inserted by the hyphenation
+algorithm, are entered in the pattern as vertical bars (`|`). Explicit
+hyphens are entered as `=`. Spaces are allowed for clarity, but they
+are discarded.
 
 The items in the replacement list are of four kinds:
 
-1) An empty group `{}` leaves the corresponding item untouched.
-
-2) A list like `{ no = c, pre = k-, post = }` replaces the letter by the corresponding discretionary. Only one of the keys is necessary, and the rest defaults to empty. By default the penalty is `\hyphenpenalty` or `\exhyphenpenalty` (_TeXbook_, p96), but a different value can be set with the key `penalty`. A further field is `data` - automatic hyphens contain no information about the font and the like, and with this key you can set which element in the list (as captured) they will the taken from.
-
-3) The key `string` replaces the character with the string. If empty, the char node is removed; to insert chars, just use a multi-character string. The nodes created are literal copies of the original, but with new characters.
-
-4) With `remove` the node is, well, removed (ie, it's like and empty `string=`).
-
-The pattern is matched with lua empty captures, which are automatically added before and after the string. You may set other empty captures, to reduce the number of items in the replacement list, like
+1. An empty group `{}` leaves the corresponding item **untouched**.
+2. A list like `{ no = c, pre = k-, post = }` replaces the letter by
+the corresponding **discretionary**. Only one of the keys is necessary,
+and the rest defaults to empty. By default the penalty is
+`\hyphenpenalty` or `\exhyphenpenalty` (_TeXbook_, p96), but a
+different value can be set with the key `penalty`. A further field is
+`data` - automatic hyphens contain no information about the font and
+the like, and with this key you can set which element in the list (as
+captured) they will the taken from.
+3. The key `string` replaces the character with the string. If empty,
+the char node is removed; to insert chars, just use a multi-character
+string. The nodes created are literal copies of the original, but with
+new characters.
+4. With `remove` the node is, well, removed (ie, it's like and empty
+`string=`).
+5. (Development) **Spaces** are declared with something like `space =.2
+.1 0`. The values are in em units, and they are the natural width, the
+`plus`, and the `minus`. Here, you may need `data`, too.
+
+A few keys can be used in conjunction with `insert`, which must be the
+very first one in the replacement. 
+
+The pattern is matched with lua empty captures, which are automatically
+added before and after the string. You may set different empty captures,
+to reduce the number of items in the replacement list:
 ```tex
-\babelposthyphenation{ngerman}{avery()long()pattern}{
+\babelposthyphenation{ngerman}{very()long()pattern}{
   string = L,
   string = OOO,
   string = N,
@@ -34,9 +64,16 @@ The pattern is matched with lua empty captures, which are automatically added be
 }
 ```
 
-Dots, characters classes (with %) and char-sets (with `[]`, including complementing and ranges) are allowed, too. When using the dot, be aware it matches `|` and `=`, too. A matched `|` or `=` cannot be currently replaced by a string.
+Dots, characters classes (with %) and char-sets (with `[]`, including
+complementing and ranges) are allowed, too. When using the dot, be
+aware it matches `|` and `=`, too. A matched `|` or `=` cannot be
+currently replaced by a string.
 
-Ordinary captures are allowed _inside_ the empty captures (the must resolve to exactly one character). In the pattern, the syntax {n} is a backreference matching the _n_-th capture inside the empty captures. This syntax can be used in the replacement strings, with the corresponding capture:
+Ordinary captures are allowed _inside_ the empty captures (they must
+resolve to exactly one character). In the pattern, **the syntax `{n}`**
+is a backreference matching the _n_-th capture inside the empty
+captures. This syntax can be used in the replacement strings, with the
+corresponding capture:
 ```tex
 \babelposthyphenation{ngerman}{([fmtrp]) | {1}}{
   { no = {1}, pre = {1}{1}- },
@@ -49,7 +86,10 @@ Ordinary captures are allowed _inside_ the empty captures (the must resolve to e
 }
 ```
 
-Since the percent sign has a quite different meaning in lua and tex, as a convenience the {} syntax can be used to enter character classes in the pattern, too (ie, {d} becomes %d, but note {1} is not the same as %1).
+Since the percent sign has a quite different meaning in lua and tex, as
+a convenience the {} syntax can be used to enter **character classes**
+in the pattern, too (ie, `{d}` becomes `%d`, but note `{1}` is not
+internally the same as `%1`).
 
 And here is a complete example:
 ```tex
@@ -77,7 +117,13 @@ Aufführende Aufführendem Aufführenden Aufführender Aufführendes
 \end{document}
 ```
 
-In the replacement list, there is an extended syntax which allows to map the captured characters. For example, `{2|ΐΰῒῢ|ίύὶὺ}` means: if the second captured char is ΐ replace it with ί, ύ with ύ, and so on. This feature is particularly useful when a letter changes if there is a hyphen, and also when transliterating. Here is a partial example of the latter (the full example is [here](../news/whats-new-in-babel-3.44.md), with digraphs and trigraphs):
+In the replacement list, there is an extended syntax which allows to
+**map the captured characters**. For example, `{2|ΐΰῒῢ|ίύὶὺ}` means: if
+the second captured char is ΐ replace it with ί, ύ with ύ, and so on.
+This feature is particularly useful when a letter changes if there is a
+hyphen, and also when transliterating. Here is a partial example of the
+latter (the full example is [here](../news/whats-new-in-babel-3.44.md),
+with digraphs and trigraphs):
 ```tex
 \babelprehyphenation{transrussian}
   {([ABVGDEËZIJKLMNOPRSTUFHÈY"abvgdeëzijklmnoprstufhèy'])}{
@@ -86,16 +132,19 @@ In the replacement list, there is an extended syntax which allows to map the cap
 }
 ```
 
-A few further examples:
+## Short examples
 
-* In Spanish, if there are one or two vowels between two hyphenation points, the first one takes precedence (in other words, the second one is penalised):
+* In Spanish, if there are one or two vowels between two hyphenation
+  points, the first one takes precedence (in other words, the second
+  one is penalised):
 ```tex
 \babelposthyphenation{ngerman}{[aeiouáéíóú]|[aeiouáéíóú][aeiouáéíóú]|}{
   {}, {}, {}, {},
   { pre=-, penalty=1000, data=4 },
 }
 ```
-* In Greek, a diaeresis disappears if the vowel group is broken (see Németh, _TUGboat_ 87):
+* In Greek, a diaeresis disappears if the vowel group is broken (see
+  Németh, _TUGboat_ 87):
 ```tex
 \babelposthyphenation{ngerman}{greek}{α|ΐο}{
   {},
@@ -135,3 +184,13 @@ In cases like this, you may want to use maps as described above.
 With `{A}*` we consider the possibility of leading characters like `(`
 or `“`, because `{A}` it's the same as `%A` in lua. This part is placed
 before that to be processed, which is enclosed between `() ()`.
+
+* Here is an example showing how to group two similar rules. The
+  pattern means ‘either < or > repeated’. Then, the first replacement
+  selects the character based on the captured one.
+```tex
+\babelprehyphenation{english}{ ([<>]){1} }{
+  string = {1|<>|“”},
+  remove
+}
+```
diff --git a/news-guides/guides/using-babel-with-plain.md b/news-guides/guides/using-babel-with-plain.md
index 2feb38d..bb357c7 100644
--- a/news-guides/guides/using-babel-with-plain.md
+++ b/news-guides/guides/using-babel-with-plain.md
@@ -12,11 +12,16 @@ means **many of the features added in the last few months (well, years)
 won't work**.
 
 It is worth noting Babel is *not* compatible with the original Plain,
-but rather with a format named `blplain` (admittedly, the manual is
+but rather with a format named `bplain` (admittedly, the manual is
 somewhat misleading in this regard). Apparently this format has never
 found its way into most of distributions. Version 3.9 added support for
 e-Plain, because the changes to achieve it were minimal. **When the
 manual refers to Plain, it actually means e-Plain and pdf-Plain**, which
 are the formats used *de facto* in most cases. 
 
+## User’s level
+
+
+## Developer’s level
+
 
diff --git a/news-guides/news/whats-new-in-babel-3.56.md b/news-guides/news/whats-new-in-babel-3.56.md
index a6cceb8..da53928 100644
--- a/news-guides/news/whats-new-in-babel-3.56.md
+++ b/news-guides/news/whats-new-in-babel-3.56.md
@@ -37,6 +37,11 @@ then matches):
 As you can see, now multiple insertions are allowed, which is often
 necessary when a space is added.
 
+In addition, the code has been refactored, to improve both stability
+with overlapping patterns and speed. With those changes, the next step
+is to will be new keys in `ini` files to define transformation rules.
+French spacing is a case in point.
+
 ## Fixes
 
 * When writing the previous feature, some anomalous behavior when
diff --git a/samples/lua-beamer.pdf b/samples/lua-beamer.pdf
index 4afe10f..e29bf77 100644
Binary files a/samples/lua-beamer.pdf and b/samples/lua-beamer.pdf differ





More information about the latex3-commits mailing list.