summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex')
-rw-r--r--Master/texmf-dist/tex/plain/pitex/base.ptxlua85
-rw-r--r--Master/texmf-dist/tex/plain/pitex/blocks.ptx40
-rw-r--r--Master/texmf-dist/tex/plain/pitex/files.ptx39
-rw-r--r--Master/texmf-dist/tex/plain/pitex/fonts.ptx345
-rw-r--r--Master/texmf-dist/tex/plain/pitex/fonts.ptxlua1211
-rw-r--r--Master/texmf-dist/tex/plain/pitex/inserts.ptx113
-rw-r--r--Master/texmf-dist/tex/plain/pitex/lua.ptx26
-rw-r--r--Master/texmf-dist/tex/plain/pitex/output.ptx311
-rw-r--r--Master/texmf-dist/tex/plain/pitex/pitex.tex425
-rw-r--r--Master/texmf-dist/tex/plain/pitex/references.ptx107
-rw-r--r--Master/texmf-dist/tex/plain/pitex/sections.ptx435
-rw-r--r--Master/texmf-dist/tex/plain/pitex/verbatim.ptx128
12 files changed, 2730 insertions, 535 deletions
diff --git a/Master/texmf-dist/tex/plain/pitex/base.ptxlua b/Master/texmf-dist/tex/plain/pitex/base.ptxlua
new file mode 100644
index 00000000000..615632db0d1
--- /dev/null
+++ b/Master/texmf-dist/tex/plain/pitex/base.ptxlua
@@ -0,0 +1,85 @@
+require"gates.lua"
+
+pitex = gates.new("pitex")
+pitex.misc = gates.new("pitex.misc")
+
+function pitex.log (message, ...)
+ texio.write_nl(string.format("\n" .. message .. "\n", ...))
+end
+function pitex.error (...)
+ tex.error ("! PiTeX error: " .. string.format(...) .. ".")
+end
+
+pitex.callback = gates.new("pitex.callback")
+
+-- Creates a gate with a callback's name and put it in that callback, if not
+-- already there. Adds the subgate(s).
+function pitex.callback.register (c, f)
+ if pitex.callback.type(c) == 2 then
+ pitex.callback.add(f, c)
+ else
+ pitex.callback.list{c}
+ pitex.callback.add(f, c)
+ callback.register(c, pitex.callback.execute[c])
+ end
+end
+
+-- Latin1 to UTF-8.
+local char = unicode.utf8.char
+local function convert_char (ch)
+ return char(string.byte(ch))
+end
+function pitex.callback.convert (buf)
+ return string.gsub(buf,".",convert_char)
+end
+
+pitex.callback.register("process_input_buffer", "convert")
+
+function remove_conversion ()
+ pitex.callback.close("convert", "process_input_buffer")
+end
+function restore_conversion ()
+ pitex.callback.open("convert", "process_input_buffer")
+end
+
+require("nodeinspector")
+new_inspection = nodeinspector.new_inspection
+
+local french_highmarks = {
+ string.byte("?"),
+ string.byte("!"),
+ string.byte(":"),
+ string.byte(";"),
+ }
+local french_marks = {
+ string.byte("?"),
+ string.byte("!"),
+ string.byte(":"),
+ string.byte(";"),
+ string.byte(","),
+ string.byte("."),
+ string.byte("("),
+ string.byte("["),
+ string.byte("{"),
+ }
+
+local function french_punctuation (head, ...)
+ for _, glue in ipairs(arg) do
+ if glue.id == 10 then
+ head = node.remove(head, glue)
+ node.free(glue)
+ end
+ end
+ local kern = node.new(11, 1)
+ kern.kern = tex.sp(".15em")
+ node.insert_after(head, arg[1], kern)
+end
+
+pitex.callback.french_punctuation = new_inspection(
+ french_punctuation,
+ {{id = 37, _char = french_marks}, {true, id = 37, char = french_highmarks}},
+ {{id = 10, subtype = 0}, {id = 11, subtype = 0}})
+
+pitex.callback.register("kerning", "french_punctuation")
+pitex.callback.original_kerning = node.kerning
+pitex.callback.register("kerning", "original_kerning")
diff --git a/Master/texmf-dist/tex/plain/pitex/blocks.ptx b/Master/texmf-dist/tex/plain/pitex/blocks.ptx
new file mode 100644
index 00000000000..13ba4b01e16
--- /dev/null
+++ b/Master/texmf-dist/tex/plain/pitex/blocks.ptx
@@ -0,0 +1,40 @@
+\long\def\newblocktype#1#2#3#4{%
+ \def#1{\ptx@newblock_pattern{#2}{#3}{#4}}%
+ }
+\newife\ifptx@newblock_group
+\long\def\ptx@newblock_pattern#1#2#3{%
+ \ifnext*
+ {\ptx@newblock_grouptrue\gobbleoneand{\ptx@newblock{#1}{#2}{#3}}}
+ {\ptx@newblock_groupfalse\ptx@newblock{#1}{#2}{#3}}%
+ }
+\long\def\ptx@newblock#1#2#3#4#5{%
+ \ifnextnospace*
+ {\gobbleoneand{\ptx@newblock_do#4{#1#5}{#2}{#3}}}
+ {\ptx@newblock_do#4{#1#5}{#2}{#3}{}}%
+ }
+\long\def\ptx@newblock_do#1#2#3#4#5#6{%
+ \ifptx@newblock_group
+ {\defcs{ptx@inner_\commandtoname#1:start}{\bgroup#2}%
+ \defcs{ptx@inner_\commandtoname#1:stop}{#4#6\egroup}}
+ {\defcs{ptx@inner_\commandtoname#1:start}{#2}%
+ \defcs{ptx@inner_\commandtoname#1:stop}{#4#6}}%
+ \defcs{ptx@inner_\commandtoname#1:continue}{#3#5}%
+ \def#1##1{%
+ \ifelseif{%
+ {\ifstring{##1}{|}} {\skipspace{\usecs{ptx@inner_\commandtoname#1:continue}}}
+ {\ifstring{##1}{/}} {\usecs{ptx@inner_\commandtoname#1:stop}}
+ {\ifstring{##1}{>}} {\skipspace{\usecs{ptx@inner_\commandtoname#1:start}}}
+ \iftrue {\usecs{ptx@inner_\commandtoname#1:start}##1}}%
+ }%
+ }
+
+\newblocktype\newblock{}{}{}
+
+\def\Indent{\quitvmode\kern\parindent}
+
+\gates new \Everypar {Everypar}
+\Everypar list {everypar} [0]
+ [noindent] ?{status = close} {{\setbox0=\lastbox}}
+\Everypar close {noindent}{everypar}
+\everypar={\Everypar execute {everypar}}
+\def\removenextindent{\Everypar ajar {noindent}{everypar}}
diff --git a/Master/texmf-dist/tex/plain/pitex/files.ptx b/Master/texmf-dist/tex/plain/pitex/files.ptx
new file mode 100644
index 00000000000..212b05fc076
--- /dev/null
+++ b/Master/texmf-dist/tex/plain/pitex/files.ptx
@@ -0,0 +1,39 @@
+\newread\ptx@temp_read
+\def\iffile{%
+ \ifnext[
+ {\ptx@iffile}
+ {\ptx@iffile[]}%
+ }
+\def\ptx@iffile[#1]#2{%
+ \directlua{
+ local f = kpse.find_file("\luaescapestring{#2}"\reverse\iffemptystring{#1}{, "#1"})
+ local x = f and "firstoftwo" or "secondoftwo"
+ tex.print(\the\texcatcodes, "\noexpand\\" .. x)
+ }%
+ }
+\long\def\ifffile{%
+ \ifnext[
+ {\ptx@ifffile}
+ {\ptx@ifffile[]}%
+ }
+\long\def\ptx@ifffile[#1]#2#3{%
+ \iffile[#1]{#2}{#3}{}%
+ }
+
+\long\def\inputfileor{%
+ \ifnext[
+ {\ptx@inputfileor}
+ {\ptx@inputfileor[]}%
+ }
+\long\def\ptx@inputfileor[#1]#2{%
+ \iffile[#1]{#2}{\input{#2}\relax}%
+ }
+
+\newwrite\ptx@auxfile
+\def\ptx@write_toaux{%
+ \ifnext*
+ {\gobbleoneand{\write\ptx@auxfile}}
+ {\immediate\write\ptx@auxfile}%
+ }
+
+\let\writeout\ptx@write_toaux
diff --git a/Master/texmf-dist/tex/plain/pitex/fonts.ptx b/Master/texmf-dist/tex/plain/pitex/fonts.ptx
index 6a3ceb019a8..a504846d6b0 100644
--- a/Master/texmf-dist/tex/plain/pitex/fonts.ptx
+++ b/Master/texmf-dist/tex/plain/pitex/fonts.ptx
@@ -1,44 +1,48 @@
-% I think my version of the following package might be modified.
-% So no way to be sure it'll work but on my computer
-% (anyway I use non-free fonts, so).
-%
-\input luaotfload.sty
+\inputluafile fonts.ptxlua
\pdfadjustspacing=2
-\directlua{%
-% From otfl-font-dum.lua
- local byte = string.byte
- fonts.expansions.setups['threepercent'] = {
-
- stretch = 3, shrink = 3, step = .5, factor = 1,
-
- [byte('A')] = 0.5, [byte('B')] = 0.7, [byte('C')] = 0.7, [byte('D')] = 0.5, [byte('E')] = 0.7,
- [byte('F')] = 0.7, [byte('G')] = 0.5, [byte('H')] = 0.7, [byte('K')] = 0.7, [byte('M')] = 0.7,
- [byte('N')] = 0.7, [byte('O')] = 0.5, [byte('P')] = 0.7, [byte('Q')] = 0.5, [byte('R')] = 0.7,
- [byte('S')] = 0.7, [byte('U')] = 0.7, [byte('W')] = 0.7, [byte('Z')] = 0.7,
- [byte('a')] = 0.7, [byte('b')] = 0.7, [byte('c')] = 0.7, [byte('d')] = 0.7, [byte('e')] = 0.7,
- [byte('g')] = 0.7, [byte('h')] = 0.7, [byte('k')] = 0.7, [byte('m')] = 0.7, [byte('n')] = 0.7,
- [byte('o')] = 0.7, [byte('p')] = 0.7, [byte('q')] = 0.7, [byte('s')] = 0.7, [byte('u')] = 0.7,
- [byte('w')] = 0.7, [byte('z')] = 0.7, [byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7,
- [byte('8')] = 0.7, [byte('9')] = 0.7,
- }
- }
+
\def\currentfont{}
+\def\currentsize{normal}
\def\currentstyle{rm}
\def\currentweight{rg}
\def\currentcase{lc}
\def\makecurrentfont{%
- \csname\currentfont @\currentstyle @\currentweight @\currentcase\endcsname
+ \csname\currentfont @\currentsize @\currentstyle @\currentweight @\currentcase\endcsname
}
-\def\it{%
- \def\currentstyle{it}%
+\def\normalsize{%
+ \def\currentsize{normal}%
\makecurrentfont
}
-\def\bf{%
- \def\currentweight{bf}%
+\def\small{%
+ \def\currentsize{small}%
\makecurrentfont
- }
-\def\sc{%
- \def\currentcase{sc}%
+ }
+\def\verysmall{%
+ \def\currentsize{verysmall}%
+ \makecurrentfont
+ }
+\def\smaller{%
+ \passexpanded\ifstring\currentsize{normal}%
+ {\def\currentsize{small}}
+ {\def\currentsize{verysmall}}
+ \makecurrentfont
+ }
+\def\big{%
+ \def\currentsize{big}%
+ \makecurrentfont
+ }
+\def\verybig{%
+ \def\currentsize{verybig}%
+ \makecurrentfont
+ }
+\def\bigger{%
+ \passexpanded\ifstring\currentsize{normal}%
+ {\def\currentsize{big}}
+ {\def\currentsize{verybig}}
+ \makecurrentfont
+ }
+\def\it{%
+ \def\currentstyle{it}%
\makecurrentfont
}
\def\rm{%
@@ -46,10 +50,6 @@
\makecurrentfont
}
\def\rmstring{rm}
-\def\ital#1{{\it#1}}
-\def\bold#1{{\bf#1}}
-\def\scap#1{{\sc#1}}
-\def\rom#1{{\rm#1}}
\def\emph{%
\ifx\currentstyle\rmstring
\expandafter\ital
@@ -57,71 +57,252 @@
\expandafter\rom
\fi
}
+\def\bf{%
+ \def\currentweight{bf}%
+ \makecurrentfont
+ }
+%\def\normalweight{%
+\def\rg{%
+ \def\currentweight{rg}%
+ \makecurrentfont
+ }
+\def\sc{%
+ \def\currentcase{sc}%
+ \makecurrentfont
+ }
+%\def\normalcase{%
+\def\lc{%
+ \def\currentcase{lc}%
+ \makecurrentfont
+ }
+\freedef\ital{{\it#1}}
+\freedef\bold{{\bf#1}}
+\freedef\scap{{\sc#1}}
+\freedef\rom{{\rm#1}}
\restrictparameter font :
command % The command to be used to switch to that font.
name % Actually the part common to all files' names for that font.
- type % otf, etc. The font parameter can't even load tfm's...
size % Well, the size.
+ small % Smaller size.
+ verysmall % Smaller yet.
+ big % Bigger.
+ verybig % Insanely big.
+ bold % Modifier for bold font.
+ italic % Modifier for italic font.
+ math % If set to "true", then used for math font.
+ % small, verysmall and italic should be specified
+ % (which shows I don't use it very often).
features % Font features (e.g. +onum, etc.).
- roman % The part of the file's name for the roman.
- bold % The part of the file's name for the bold roman.
- italic % The part of the file's name for the italic.
- bolditalic % The part of the file's name for the bold italic.
- % What happens is: it loads <name><roman>.<type> at <size>
- % then the same with <bold>, etc.
+ slant % A number representing an angle, loading an italic
+ % font if no real italic is a available.
+ slantsc % The same, for small caps.
+
+% The font parameter should disappear some day, it's clumsy.
+\def\setfont#1:{%
+ \setparameter font : command = #1%
+ }
\setparameter metafont : % No relation :)
size = 10pt
- features = +onum;+liga;+trep;expansion=threepercent;
- type = otf % Oh yes, this is default!
+ bold = Bold
+ italic = Italic
+ features = "+onum; +liga; +trep; +tlig; expansion=30 20 5;"
-\setparameter font: meta = metafont\par
+\setparameter font :
+ meta = metafont
\newdimen\ptx@fontsize
+\luacode
+ptx_fonts = {}
+function ptx_getfont(Font, ...)
+ if ptx_fonts[Font] then
+ local tempfont = ptx_fonts[Font]
+ for _, style in ipairs(arg) do
+ if ptx_getstyle[style] then
+ tempfont = tempfont:gsub("(%w+)@(%w+)@(%w+)@(%w+)@(%w+)",ptx_getstyle[style])
+ else
+ tempfont = nil
+ texio.write_nl("! PiTeX error: Unknown font style `style'.")
+ return Font
+ end
+ end
+ return font.id(tempfont)
+ else
+ texio.write_nl("! PiTeX error: " .. Font .. " is not a PiTeX font. It can't be changed.")
+ end
+end
+ptx_getstyle = {
+ normal = "%1@normal@%3@%4@%5",
+ small = "%1@small@%3@%4@%5",
+ verysmall = "%1@verysmall@%3@%4@%5",
+ big = "%1@big@%3@%4@%5",
+ verybig = "%1@verybig@%3@%4@%5",
+ rm = "%1@%2@rm@%4@%5",
+ it = "%1@%2@it@%4@%5",
+ rg = "%1@%2@%3@rg@%5",
+ bf = "%1@%2@%3@bf@%5",
+ lc = "%1@%2@%3@%4@lc",
+ sc = "%1@%2@%3@%4@sc"
+ }
+\luacode/
+
+\newstring{+} \newstring{-}
+\def\ptx@dofont#1#2#3#4#5{%
+ \edef\ptx@temp{\passvaluenobraces\commandtoname font : command }%
+ \ifexpression{ -\ifstring{#4}{normal} & { \ifprefix-{#5} | \ifprefix+{#5} } }
+ {\def\ptx@dofont_size{\dimexpr\usevalue font : size + #5\relax}}
+ {\def\ptx@dofont_size{#5}}%
+ \ptx@dofont_load{\ptx@temp @#4@#1@#2@lc}{#3}{}{\ptx@dofont_size}%
+ \ifstring{#1}{rm}
+ {\ptx@dofont_load{\ptx@temp @#4@#1@#2@sc}{#3}{+smcp;}{\ptx@dofont_size}%
+ \ifattribute font : slant % Loading a slanted version of the font if no italic was given
+ {\ptx@dofont_load{\ptx@temp @#4@it@#2@lc}{#3}{slant=\usevalue font: slant ;}{\ptx@dofont_size}
+ \ifattribute font : slantsc {}
+ {\ptx@dofont_load{\ptx@temp @#4@it@#2@sc}{#3}{+smcp;slant=\usevalue font: slant ;}{\ptx@dofont_size}}}{}%
+ \ifattribute font : slantsc
+ {\ptx@dofont_load{\ptx@temp @#4@it@#2@sc}{#3}{+smcp;slant=\usevalue font: slantsc ;}{\ptx@dofont_size}}{}}%
+ {\ifattribute font : slantsc {}{\ptx@dofont_load{\ptx@temp @#4@it@#2@sc}{#3}{+smcp;}{\ptx@dofont_size}}}
+ }
+
+\def\ptx@dofont_load#1#2#3#4{%
+ \passcs\font{#1}="\usevalue font : name #2:#3\usevalue font : features " at #4\relax
+ \ptx@lua{ptx_fonts[font.id("#1")] = "#1"}%
+ }
+
+
+
\def\dofont#1#2#3{%
- \passcs\font{\passvalue\commandtoname font : command @#1@#2@lc} =
- "\usevalue font : name \usevalue font : #3 .\usevalue font : type :\usevalue font : features " at \usevalue font : size \relax
- \passcs\font{\passvalue\commandtoname font : command @#1@#2@sc} =
- "\usevalue font : name \usevalue font : #3 .\usevalue font : type :+smcp;\usevalue font : features " at \usevalue font : size \relax
+ \passvalue{\ptx@dofont{#1}{#2}{#3}{normal}} font : size
+ \passvalue{\ptx@dofont{#1}{#2}{#3}{small}} font : small
+ \passvalue{\ptx@dofont{#1}{#2}{#3}{verysmall}} font : verysmall
+ \passvalue{\ptx@dofont{#1}{#2}{#3}{big}} font : big
+ \passvalue{\ptx@dofont{#1}{#2}{#3}{verybig}} font : verybig
+%
+ \ifvalue font : math = true
+ {\ifstring{#1#2}{rmrg}
+ {\passcs{\textfont0=}{\passvalue\commandtoname font : command @normal@#1@#2@lc}%
+ \passcs{\scriptfont0=}{\passvalue\commandtoname font : command @small@#1@#2@lc}%
+ \passcs{\scriptscriptfont0=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc}
+ \passcs{\textfont2=}{\passvalue\commandtoname font : command @normal@#1@#2@lc}%
+ \passcs{\scriptfont2=}{\passvalue\commandtoname font : command @small@#1@#2@lc}%
+ \passcs{\scriptscriptfont2=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc}}
+ {\iffstring{#1#2}{itrg}
+ {\passcs{\textfont1=}{\passvalue\commandtoname font : command @normal@#1@#2@lc}%
+ \passcs{\scriptfont1=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc}%
+ \passcs{\scriptscriptfont1=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc}}}%
+ }{}%
}
+
+\gates new \FontLoader {FontLoader}
+\FontLoader list {fontloader}
+ [fl_command]
+ {%
+ \passvaluenobraces\edef font : command {%
+ \def\noexpand\currentfont{\passvalue\commandtoname font : command }%
+ \noexpand\makecurrentfont}}
+ (fl_load)
+ . ( fl_roman )
+ . . [ fl_doromanregular ]
+ {\dofont{rm}{rg}{}}
+ . . [ fl_doromanbold ] ? {conditional = -\ifvalue font : bold = none }
+ {\dofont{rm}{bf}{/\usevalue font : bold }}
+ . ( fl_italic ) ? {conditional = -\ifvalue font : italic = none }
+ . . [ fl_doitalicregular ]
+ {\dofont{it}{rg}{/\usevalue font : italic }}
+ . . [ fl_doitalicbold ] ? {conditional = -\ifvalue font : bold = none }
+ {\dofont{it}{bf}{/\usevalue font : italic /\usevalue font : bold }}
+ [fl_use] ? {conditional = \ifvalue font : command = {\mainfont} }
+ {\mainfont}
+ (fl_post)
+ . [fl_delete]
+ {\deleteparameter font:}
+ . [fl_meta]
+ {\setattribute font : meta = metafont }
+
\defactiveparameter font {%
- \ifattribute #1 : command
- {%
- \passvaluenobraces\edef #1 : command {%
- \def\noexpand\currentfont{\passvalue\commandtoname #1 : command }%
- \noexpand\makecurrentfont
- }%
- % If #1 = name isn't defined, roman, bold, etc. are supposed to hold the
- % font's full (file) name.
- \ifattribute #1 : roman
- {\dofont{rm}{rg}{roman}%
- \ifattribute #1 : bold
- {\dofont{rm}{bf}{bold}}%
- {}}%
- {}%
- \ifattribute #1 : italic
- {\dofont{it}{rg}{italic}%
- \ifattribute #1 : bolditalic
- {\dofont{it}{bf}{bolditalic}}%
- {}}%
- {}}%
- {}%
- \ifvalue #1 : command = {\mainfont} \mainfont{}% Calls font if it is \mainfont.
- \deleteattribute #1 : command
- \deleteattribute #1 : name
- \deleteattribute #1 : type
- \deleteattribute #1 : size
- \deleteattribute #1 : features
- \deleteattribute #1 : roman
- \deleteattribute #1 : bold
- \deleteattribute #1 : italic
- \deleteattribute #1 : bolditalic
+ \FontLoader execute {fontloader}%
}
-%
+
+
+
+
+
+
+
\long\def\color#1#2{%
\pdfcolorstack0 push {#1 rg #1 RG}%
#2%
\pdfcolorstack0 pop%
- } \ No newline at end of file
+ }
+
+\newattribute\ptx@underline_attribute
+\luacode
+local do_underline = function (head,order,ratio,sign)
+ local item, leader = head, false
+ while item do
+ leader = false
+ if node.has_attribute(item,\attributenumber\ptx@underline_attribute)
+ and not (item.id == 10 and (item.subtype == 8 or item.subtype == 9)) then
+ local item_line = node.new(2)
+ item_line.depth = tex.sp("1.4pt")
+ item_line.height = tex.sp("-1pt")
+ if node.has_field(item,"spec") then
+ item_line.width = item.spec.width
+ if order == 0 then
+ if sign == 1 then
+ item_line.width = item_line.width + ratio * item.spec.stretch
+ else
+ item_line.width = item_line.width - ratio * item.spec.shrink
+ end
+ else
+ if item.spec.stretch_order > 0 or item.spec.shrink_order > 0 then
+ lualog(item.spec.stretch_order)
+ item_line.width = 1
+ item.subtype = 100
+ item.leader = item_line
+ leader = true
+ end
+ end
+ elseif node.has_field(item,"width") then
+ item_line.width = item.width
+ elseif node.has_field(item,"kern") then
+ item_line.width = item.kern
+ end
+ if leader then
+ item = item.next
+ else
+ local item_kern = node.new(11)
+ item_kern.kern = -item_line.width
+ node.insert_after(head,item,item_line)
+ node.insert_after(head,item,item_kern)
+ item = item_line.next
+ end
+ else
+ item = item.next
+ end
+ end
+end
+pitex.misc.underline = function (head)
+ for line in node.traverse_id(0,head) do
+ do_underline(line.list,line.glue_order,line.glue_set,line.glue_sign)
+ end
+ return head
+end
+pitex.callback.register("post_linebreak_filter", "pitex.misc:underline")
+pitex.callback.close("pitex.misc:underline", "post_linebreak_filter")
+\luacode/
+
+\freedef\underline{%
+ \ptx@lua{%
+ pitex.callback.ajar("pitex:underline", "post_linebreak_filter")
+ }
+% local plf = callback.list_functions("post_linebreak_filter")
+% if not plf or not plf["underline"] then
+% callback.add_function(underline, "underline", "post_linebreak_filter")
+% end}%
+ \quitvmode % Otherwise it might also underline the indentation box.
+ \ptx@underline_attribute=0\relax
+ #1\unsetattribute\ptx@underline_attribute
+ }
diff --git a/Master/texmf-dist/tex/plain/pitex/fonts.ptxlua b/Master/texmf-dist/tex/plain/pitex/fonts.ptxlua
new file mode 100644
index 00000000000..391ee9a6766
--- /dev/null
+++ b/Master/texmf-dist/tex/plain/pitex/fonts.ptxlua
@@ -0,0 +1,1211 @@
+-- *** UTILITY FUNCTIONS ***
+local function get_locals (tab)
+ local tb = {}
+ for lib, keys in pairs(tab) do
+ keys = string.explode(keys)
+ for _, k in ipairs(keys) do
+ tb[k] = _G[lib][k]
+ end
+ end
+ return tb
+end
+
+-- str
+-- string manipulation
+local str = get_locals {string = "explode gsub match format lower upper"}
+
+-- Removes space at the beginning and end and conflates multiple spaces.
+function str.trim (s)
+ s = str.match(s, "^%s*(.-)%s*$")
+ s = str.gsub(s, "%s+", " ")
+ return s
+end
+
+-- Extracts a pattern from a string, i.e. removes it and returns it.
+-- If "full", then the entire pattern is removed, not only the captures.
+function str.extract (s, pat, full)
+ local cap = str.match(s, pat)
+ if cap then
+ if full then
+ s = str.gsub(s, pat, "")
+ else
+ s = str.gsub(s, cap, "")
+ end
+ end
+ return cap, s
+end
+-- /str
+
+
+-- lp
+-- advanced string manipulation
+lpeg.locale(lpeg)
+local lp = get_locals {lpeg = "match P C S Ct V alnum"}
+lp.space = lpeg.space^0
+-- /lp
+
+
+-- tab
+-- table manipulation
+local tab = get_locals {table = "insert remove sort"}
+
+-- Adds val to tab, creating it if necessary.
+function tab.update (tb, val)
+ tb = tb or {}
+ tab.insert(tb, val)
+ return tb
+end
+
+-- Adds subtable (empty, or val) to tb at entry key, unless it already exists.
+function tab.subtable (tb, key, val)
+ tb[key] = tb[key] or val or {}
+end
+
+-- Writes a table to an extenal file.
+local function write_key (key, ind)
+ return ind .. '["' .. key .. '"] = '
+end
+
+function tab.write (tb, f, ind)
+ for a, b in pairs (tb) do
+ if type(a) == "string" then
+ a = '"' .. a .. '"'
+ end
+ a = "[" .. a .. "]"
+ if type(b) == "table" then
+ f:write(ind, a, " = {")
+ tab.write(b, f, ind .. " ")
+ f:write(ind, "},")
+ else
+ if type(b) == "boolean" then
+ b = b and "true" or "false"
+ elseif type(b) == "string" then
+ b = '"' .. b .. '"'
+ end
+ f:write(ind, a, " = ", b, ",")
+ end
+ end
+end
+
+-- Returns a full copy of a table. Not copying of metatables necessary for the
+-- moment.
+function tab.copy (tb)
+ local t = {}
+ for k, v in pairs (tb) do
+ if type(v) == "table" then
+ v = tab.copy(v)
+ end
+ t[k] = v
+ end
+ return t
+end
+
+-- Sorts two tables containing modifiers (Italic, etc.).
+function tab.sortmods (a, b)
+ local A, B = "", ""
+ for _, x in ipairs (a) do
+ A = A .. " " .. x
+ end
+ for _, x in ipairs (b) do
+ B = B .. " " .. x
+ end
+ return A < B
+end
+
+-- Turns an array into a hash.
+function tab.tohash(tb)
+ local t = {}
+ for _, k in ipairs(tb) do
+ t[k] = true
+ end
+ return t
+end
+-- /tab
+
+-- lfs
+-- files etc.
+local lfs = get_locals {lfs = "dir isdir isfile mkdir", kpse = "expand_var show_path find_file"}
+
+-- Returns anything after the last dot, i.e. an extension.
+function lfs.extension (s)
+ return str.lower(str.match(s, "%.([^%.]*)$"))
+end
+
+local extensions = {
+ otf = "opentype",
+ ttf = "truetype",
+ ttc = "truetype",
+}
+function lfs.type (s)
+ return extensions[lfs.extension(s)]
+end
+
+local kpse_extensions = {
+ otf = "opentype fonts",
+ ttf = "truetype fonts",
+ ttc = "truetype fonts",
+}
+function lfs.kpse (s)
+ return kpse_extensions[lfs.extension(s)]
+end
+
+-- Returns anything after the last slash, i.e. a pathless file.
+function lfs.nopath (f)
+ return str.match(f, "[^/]*$")
+end
+
+-- Creates a directory; the arguments are the successive subdirectories.
+function lfs.ensure_dir (...)
+ local arg, path = {...}
+ for _, d in ipairs(arg) do
+ if path then
+ path = path .. "/" .. d
+ else
+ path = d
+ end
+ path = str.gsub(path, "//", "/")
+ if not lfs.isdir(path) then
+ lfs.mkdir(path)
+ end
+ end
+ return path
+end
+
+-- Turns "foo/blahblah/../" into "foo/" (such going into and leaving
+-- directories happens with kpse). Also puts everything to lowercase.
+function lfs.smooth_file (f)
+ f = str.gsub(f, "/.-/%.%./", "/")
+ f = str.gsub(f, "^%a", str.lower)
+ return f
+end
+-- /lfs
+
+
+-- wri
+-- messages
+local wri, write_nl = {}, texio.write_nl
+
+function wri.report (s, ...)
+ write_nl(str.format(s, unpack(arg)))
+end
+
+function wri.error (s, ...)
+ tex.error(str.format(s, unpack(arg)))
+end
+-- /wri
+
+
+-- various
+-- the last one is, of course, not the least
+local io = get_locals {io = "open lines"}
+local os = get_locals {os = "date"}
+local num = get_locals {math = "abs tan rad floor pi", tex = "sp"}
+local fl = get_locals {fontloader = "open close to_table info", font = "read_tfm"}
+-- /various
+
+
+-- *** END OF UTILITY FUNCTIONS ***
+
+
+
+--- *** CREATING THE LIBRARY *** ---
+local settings
+if lfs.find_file"foundry-settings.lua" then
+ settings = require"foundry-settings.lua"
+else
+ settings = {normal = {}, features = {}}
+end
+local font_families = {}
+local normal_names = {}
+for _, name in ipairs(settings.normal) do
+ normal_names[name] = true
+end
+local local_path = lfs.expand_var("$TEXMFLOCAL")
+local foundry_path = lfs.ensure_dir (local_path, "tex", "luatex", "foundry")
+local library_file = foundry_path .. "/" .. "readable.txt"
+--local library_file = "c:/texlive/texmf-local/tex/plain/pitex/readable.txt"
+--local library_file = "readable.txt"
+
+-- Analyze a font file and return a name and a table
+-- with modifiers.
+local function extract_font (file, names)
+ local fi, subname
+ -- Trying to open a font in ttc, using the names returned by fontloader.info
+ if names then
+ local name = names.fullname
+ if name then
+ fi = fl.open (file, name)
+ end
+ if not fi then
+ name = names.fontname
+ if name then
+ fi = fl.open
+ end
+ if not fi then
+ fl.error("Can't open %s", file)
+ return
+ end
+ end
+ subname = name
+ else
+ fi = fl.open(file)
+ end
+ -- Getting the most precise information. Not necessarily the best
+ -- solution, but since the user can modify the library, it's not so bad.
+ local fam, name = fi.names[1].names.preffamilyname or fi.names[1].names.family or fi.familyname, fi.fontname
+ local spec = fi.names[1].names.prefmodifiers or fi.names[1].names.subfamily or ""
+ local subfam, _spec
+ local t = { [0] = file }
+ -- Removing mods like Regular, Book, etc.
+ for name in pairs(normal_names) do
+ spec = str.gsub(spec, name, "")
+ end
+ if subname then
+ tab.insert(t, "[font = " .. subname .. "]")
+ end
+ if spec ~= "" then
+ spec = str.explode(spec)
+ for _, s in ipairs(spec) do
+ tab.insert(t, s)
+ end
+ end
+ fl.close(fi)
+ return fam, t
+end
+
+-- Searches directories for font files, and pass them to
+-- extract_font. The fonts are collected in a table.
+-- The fonts_done table is updated when the library is read,
+-- so when a font is missing and one needs to recheck files,
+-- only those that arent in the libraries are considered.
+local fonts_done = {}
+local function check_fonts (rep, tb)
+ for f in lfs.dir (rep) do
+ if f ~= "." and f ~= ".." then
+ f = str.gsub(rep, "/$", "") .. "/" .. f
+ if lfs.isdir(f) then
+ check_fonts(f, tb)
+ elseif lfs.isfile(f) and not fonts_done[lfs.nopath(f)] then
+ local e = lfs.extension(f)
+ if e == "ttf" or e == "otf" then
+ local fam, file = extract_font(f)
+ if fam then
+ tab.subtable(tb, fam)
+ tab.insert(tb[fam], file)
+ end
+ elseif e == "ttc" then
+ local info = fl.info(f)
+ for _, i in ipairs(info) do
+ local fam, file = extract_font(f, i)
+ if fam then
+ tab.subtable(tb, fam)
+ tab.insert(tb[fam], file)
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+-- Writes the library to an external file.
+-- Type is "a" if what's going on is recheck_fonts.
+local function write_lib (fams, file, type)
+ local read_table = {}
+ for fam, tb in pairs(fams) do
+ tab.insert(read_table, fam)
+ for _, ttb in ipairs(tb) do
+ tab.sort(ttb)
+ end
+ tab.sort(tb, tab.sortmods)
+ end
+ tab.sort(read_table)
+ local readable = io.open(file, type)
+ for n, fam in ipairs(read_table) do
+ local log
+ if type == "a" then
+ log = true
+ if n == 1 then
+ wri.report("\nAdding new font(s):")
+ readable:write("\n\n% Added automatically " .. os.date() .. "\n\n")
+ end
+ wri.report(fam)
+ end
+ readable:write(fam .. " :")
+ for n, f in ipairs(fams[fam]) do
+ log = log and " "
+ readable:write("\n ")
+ for _, t in ipairs(f) do
+ log = log and log .. " " .. t
+ readable:write(" " .. t)
+ end
+ log = log and log .. " " .. '"' .. f[0] .. '"'
+ readable:write(" " .. '"' .. lfs.nopath(f[0]) .. '",')
+ if log then wri.report(log) end
+ if n == #fams[fam] then
+ readable:write("\n\n")
+ end
+ end
+ end
+ readable:close()
+end
+
+
+-- If there is no library, we create it.
+local font_paths = lfs.show_path("opentype fonts")
+font_paths = str.gsub(font_paths, "\\", "/")
+font_paths = str.gsub(font_paths, "/+", "/")
+font_paths = str.gsub(font_paths, "!!", "")
+font_paths = str.explode(font_paths, ";+")
+
+if not lfs.find_file(library_file) then
+ wri.report("I must create the library; please wait, that can take some time.")
+ for _, rep in ipairs(font_paths) do
+ check_fonts(rep, font_families)
+ end
+ write_lib(font_families, library_file, "w")
+end
+
+-- Reads the library file, turning it into a table.
+local explode_semicolon = lp.P{
+ lp.Ct(lp.V"data"^1),
+ data = lp.C(((1 - lp.S";[") + (lp.S"[" * (1 - lp.S"]")^0 * lp.S"]" ))^1) / str.trim * (lp.S";" + -1),
+ }
+local explode_comma = lp.P{
+ lp.Ct(lp.V"data"^1),
+ data = lp.C(((1 - lp.S",[") + (lp.S"[" * (1 - lp.S"]")^0 * lp.S"]" ))^1) / str.trim * (lp.S"," + -1),
+ }
+
+local function load_library (lib)
+ local LIB = ""
+ local lib_file = lfs.find_file(lib)
+ if not lib_file then
+ wri.error("I can't find library %s.", lib)
+ return
+ end
+
+ for l in io.lines(lib_file) do
+ if not str.match(l, "^%s*%%") then
+ if str.match(l, "^%s*$") then
+ LIB = LIB .. ";"
+ else
+ LIB = LIB .. " " .. l
+ end
+ end
+ end
+ LIB = str.gsub(LIB, ";%s*;", ";;")
+ LIB = str.gsub(LIB, ";+", ";")
+ LIB = str.gsub(LIB, "^;", "")
+ LIB = str.gsub(LIB, "%s+", " ")
+
+ LIB = lp.match(explode_semicolon, LIB)
+
+ local newlib = {}
+ for _, t in ipairs(LIB) do
+ local fam, files = str.match(t, "(.-):(.*)")
+ local current_mods
+ if files then
+ files = lp.match(explode_comma, files)
+ fam = str.explode(fam, ",")
+ local root
+ for n, f in ipairs (fam) do
+ f = str.trim(f)
+ if n == 1 then
+ root = f
+ if type(newlib[f]) == "string" then
+ wri.error("Name `%s' is already used as an alias for `%s'; it is now overwritten to denote a family", f, newlib[f])
+ newlib[f] = {}
+ else
+ newlib[f] = newlib[f] or {}
+ end
+ else
+ if newlib[f] then
+ wri.error("The name `%s' is already used. I ignore it as an alias for `%s'", f, root)
+ else
+ newlib[f] = root
+ end
+ end
+ end
+ for _, f in ipairs(files) do
+ local reset
+ reset, f = str.extract(f, "^%.%.", true)
+ if reset then current_mods = nil end
+ local mods, file, feats = str.match(f, '([^"]*)"(.*)"')
+ if mods then
+ fonts_done[lfs.nopath(file)] = true
+ feats, mods = str.extract(mods, "%[([^%]]-)]", true)
+ mods = str.explode(mods)
+ if current_mods then
+ for _, t in ipairs(current_mods) do
+ tab.insert(mods, t)
+ end
+ if current_mods.feats then
+ feats = feats or ""
+ feats = current_mods.feats .. "," .. feats
+ end
+ end
+ local sizes, real_mods = {}, {}
+ for n, s in ipairs(mods) do
+ if tonumber(s) then
+ tab.insert(sizes, tonumber(s))
+ else
+ tab.insert(real_mods, s)
+ end
+ end
+ sizes = #sizes > 0 and sizes or {0}
+ tab.sort(real_mods)
+ local T = newlib[root]
+ for _, t in ipairs(real_mods) do
+ t = str.trim(t)
+ if t ~= "" then
+ T[t] = T[t] or {}
+ T = T[t]
+ end
+ end
+ T.__files = T.__files or {}
+ for _, s in ipairs(sizes) do
+ T.__files[s] = {str.trim(file), feats}
+ end
+ else
+ feats, mods = str.extract(f, "%[([^%]]-)]", true)
+ if current_mods then
+ for _, mod in ipairs(str.explode(mods)) do
+ tab.insert(current_mods, mod)
+ end
+ if feats then
+ current_mods.feats = current_mods.feats and current_mods.feats .. "," .. feats or feats
+ end
+ else
+ current_mods = str.explode(mods)
+ current_mods.feats = feats
+ end
+ end
+ end
+ end
+ end
+ return newlib
+end
+
+local library = {}
+library.default = load_library(library_file)
+
+-- Same as above, but used when rechecking (if a font isn't found in libraries).
+local function recheck_fonts ()
+ local tb = {}
+ for _, rep in ipairs(font_paths) do
+ check_fonts(rep, tb)
+ end
+ write_lib(tb, library_file, "a")
+ library.default = load_library(library_file)
+end
+
+
+-- This is public.
+function new_library (lib)
+ local l = load_library(lib)
+ if l then
+ tab.insert(library, l)
+ end
+end
+
+--- *** END OF LIBRARY MANAGEMENT *** ---
+
+
+
+--- *** FONT CREATION *** ---
+
+
+-- Creates a new substitution for trep.
+local function add_sub (f, num, sub)
+ num, sub = f.map.map[num], f.map.map[sub]
+ if f.glyphs[num] and f.glyphs[sub] then
+ local x = f.glyphs[num]
+ tab.subtable(x, "lookups")
+ x.lookups.tex_trep = { { type = "substitution", specification = {variant = f.glyphs[sub].name} } }
+ end
+end
+
+-- Creates a new ligature for tlig.
+local function add_lig (f, lig, ...)
+ lig = f.map.map[lig]
+ if lig then
+ arg = {...}
+ local components
+ for _, c in ipairs(arg) do
+ c = f.map.map[c]
+ c = c and f.glyphs[c]
+ if c then
+ c = c.name
+ components = components and components .. " " .. c or c
+ else
+ components = nil
+ break
+ end
+ end
+ if components then
+ local x = f.glyphs[lig]
+ tab.subtable(x, "lookups")
+ tab.subtable(x.lookups, "tex_tlig")
+ tab.insert(x.lookups.tex_tlig, { type = "ligature",
+ specification = {char = x.name, components = components} })
+ end
+ end
+end
+
+-- Loops over all the constitutents of ligatures, creating intermediary
+-- ligatures if necessary. E.g. "f f i" is broken into:
+-- f + f = ff.lig
+-- ff.lig + i = ffi.lig
+-- Then when loading the font if the intermediary ligatures do not exist
+-- (e.g. "1/" in "1 / 4") a phantom character is added to the font; which might
+-- be dangerous (e.g. "1/" will create a node without character if no "4" follows).
+-- The ".lig" suffix is arbitrary but all glyphs marked as ligatures are also registered
+-- with such a name, so if there's an "f f" ligature in a font, no matter its name, "ff.lig"
+-- will point to it.
+local function ligature (comp, tb, phantoms)
+ local i = str.gsub(comp[1], "%.lig$", "") .. comp[2] .. ".lig"
+ phantoms[i] = true
+ tab.insert(tb.all_ligs, i)
+ tab.subtable(tb, comp[1])
+ tb[comp[1]][comp[2]] = { char = i, type = 0 } -- The type could be something else.
+ tab.remove(comp, 1)
+ tab.remove(comp, 1)
+ if #comp > 0 then
+ tab.insert(comp, 1, i)
+ ligature(comp, tb, phantoms)
+ end
+end
+
+local function get_lookups (t, lookup_table)
+ if t then
+ for _, tb in pairs(t) do
+ local _tb = { tags = {} }
+ if tb.features then
+ for _, feats in pairs(tb.features) do
+ local _tag = {}
+ if feats.scripts then
+ for _, scr in pairs(feats.scripts) do
+ _tag[scr.script] = {}
+ for _, lang in pairs(scr.langs) do
+ tab.insert (_tag[scr.script], str.trim(lang))
+ end
+ end
+ end
+ for _, sub in pairs(tb.subtables) do
+ tab.insert(_tb, sub.name)
+ end
+ _tb.tags[feats.tag] = _tag
+ end
+ end
+ if tb.name then
+ local tp = tb.type or "no_type"
+ tab.subtable(lookup_table, tp)
+ lookup_table[tp][tb.name] = _tb
+ end
+ end
+ end
+end
+
+function create_font (filename, extension, path, subfont, write)
+
+ local data = fl.open(filename, subfont)
+ fontfile = fl.to_table(data)
+ fl.close(data)
+
+ local lookups = {}
+
+ local name_touni = { }
+ local max_char = 0
+ for chr, gly in pairs(fontfile.map.map) do
+ max_char = chr > max_char and chr or max_char
+ -- Some glyphs have the same name in some fonts,
+ -- e.g. the several hyphens.
+ local name = fontfile.glyphs[gly].name
+ while name_touni[name] do
+ name = name .. "_"
+ end
+ name_touni[name] = chr
+ end
+
+ if fontfile.gsub then
+ tab.insert(fontfile.gsub,
+ { type = "gsub_single",
+ name = "tex_trep",
+ subtables = { {name = "tex_trep"} },
+ features = { { tag = "trep"} } })
+ tab.insert(fontfile.gsub,
+ { type = "gsub_ligature",
+ name = "tex_tlig",
+ subtables = { {name = "tex_tlig"} },
+ features = { { tag = "tlig"} } })
+ for _, tb in ipairs(fontfile.gsub) do
+ for __, ttb in ipairs(tb.subtables) do
+ if tb.type == "gsub_contextchain" then
+ lookups[tb.name] = lookups[tb.name] or { type = tb.type }
+ tab.insert(lookups[tb.name], ttb.name)
+ end
+ lookups[ttb.name] = { type = tb.type }
+ lookups["-" .. ttb.name] = { type = tb.type }
+ end
+ end
+ end
+
+ if fontfile.gpos then
+ for _, tb in ipairs(fontfile.gpos) do
+ for __, ttb in ipairs(tb.subtables) do
+ lookups[ttb.name] = { type = tb.type }
+ lookups["-" .. ttb.name] = { type = tb.type }
+ end
+ end
+ end
+
+ if fontfile.kerns then
+ for _, class in ipairs(fontfile.kerns) do
+ local max = 0
+ for a in pairs (class.seconds) do
+ max = max < a and a or max
+ end
+ if type(class.lookup) == "string" then
+ lookups[class.lookup] = { type = "gpos_pair", firsts = class.firsts, seconds = class.seconds, offsets = class.offsets, max = max}
+ else
+ for _, lk in ipairs(class.lookup) do
+ lookups[lk] = { type = "gpos_pair", firsts = class.firsts, seconds = class.seconds, offsets = class.offsets, max = max}
+ end
+ end
+ end
+ end
+
+ add_sub(fontfile, 96, 8216) -- ` to quoteleft
+ add_sub(fontfile, 39, 8217) -- ' to apostrophe (quoteright)
+
+ add_lig(fontfile, 8220, 8216, 8216) -- quoteleft + quoteleft to quotedblleft
+ add_lig(fontfile, 8221, 8217, 8217) -- quoteright + quoteright to quotedblright
+ add_lig(fontfile, 8211, 45, 45) -- -- to endash
+ add_lig(fontfile, 8212, 8211, 45) -- --- (i.e. endash + -) to emdash
+ add_lig(fontfile, 161, 63, 96) -- ?` to inverted question mark
+ add_lig(fontfile, 161, 63, 8216) -- The same, with `turned to quoteleft.
+ add_lig(fontfile, 191, 33, 96) -- !` to inverted exclamation mark
+ add_lig(fontfile, 191, 33, 8216) -- Idem.
+
+ local characters, phantom_ligatures = {}, {}
+ for chr, gly in pairs(fontfile.map.map) do
+ local glyph, char = fontfile.glyphs[gly], {}
+
+ char.index = gly
+ char.name = glyph.name
+ char.width = glyph.width
+ if glyph.boundingbox then
+ char.depth = -glyph.boundingbox[2]
+ char.height = glyph.boundingbox[4]
+ end
+ if glyph.italic_correction then
+ char.italic = glyph.italic_correction
+ elseif glyph.width and glyph.boundingbox then
+ char.italic = glyph.boundingbox[3] - glyph.width
+ end
+ tab.subtable(characters, chr)
+ characters[chr] = char
+
+ if glyph.lookups then
+ for lk, tb in pairs(glyph.lookups) do
+ local _lk = "-" .. lk
+ if lookups[lk] and lookups[_lk] then
+ for _, l in ipairs(tb) do
+ if l.type == "substitution" then
+
+ tab.subtable(lookups[lk], "pairs")
+ lookups[lk].pairs[glyph.name] = l.specification.variant
+
+ tab.subtable(lookups[_lk], "pairs")
+ lookups[_lk].pairs[l.specification.variant] = glyph.name
+
+ elseif l.type == "ligature" then
+
+ local comp, lig = str.explode(l.specification.components), l.specification.char
+ local lig = ""
+ for _, c in ipairs(comp) do
+ lig = lig .. c
+ end
+
+ tab.subtable(lookups, lk)
+ tab.subtable(lookups[lk], "ligs", {all_ligs = {}})
+ ligature(comp, lookups[lk].ligs, phantom_ligatures)
+ name_touni[lig .. ".lig"] = chr
+
+ end
+ end
+ end
+ end
+ end
+
+ if glyph.kerns then
+ for _, kern in pairs(glyph.kerns) do
+ local lks = type(kern.lookup) == "table" and kern.lookup or {kern.lookup}
+ for _, lk in ipairs(lks) do
+ tab.subtable(lookups[lk], "kerns")
+ tab.subtable(lookups[lk].kerns, glyph.name)
+ lookups[lk].kerns[glyph.name][kern.char] = kern.off
+ end
+ end
+ end
+
+ end
+
+ for lig in pairs(phantom_ligatures) do
+ if not name_touni[lig] then
+ max_char = max_char + 1
+ name_touni[lig] = max_char
+ characters[max_char] = {name = lig}
+ end
+ end
+
+ local lookup_table = {}
+ get_lookups(fontfile.gsub, lookup_table)
+ get_lookups(fontfile.gpos, lookup_table)
+ get_lookups(fontfile.lookups, lookup_table, true)
+
+ if fontfile.lookups then
+ for name, lk in pairs(fontfile.lookups) do
+ local tb, format = {}, lk.format
+ for _, rule in ipairs(lk.rules) do
+ local ttb = { lookups = rule.lookups }
+ for pos, seq in pairs(rule[format]) do
+ ttb[pos] = {}
+ for _, glyfs in ipairs(seq) do
+ glyfs = str.explode(glyfs)
+ glyfs = tab.tohash(glyfs)
+ tab.insert(ttb[pos], glyfs)
+ end
+ end
+ tab.insert(tb, ttb)
+ end
+ lookups[name] = tb
+ end
+ end
+
+ local loaded_font = {
+
+ direction = 0,
+ filename = filename,
+ format = extension,
+ fullname = fontfile.names[1].names.fullname,
+ name = fontfile.fontname,
+ psname = fontfile.fontname,
+ type = "real",
+ units_per_em = fontfile.units_per_em,
+
+ auto_expand = true,
+
+ cidinfo = fontfile.cidinfo,
+
+ -- Used only to adjust absoluteslant.
+ italicangle = -fontfile.italicangle,
+ name_to_unicode = name_touni,
+ max_char = max_char,
+ lookups = lookups,
+ lookup_table = lookup_table,
+ characters = characters
+ }
+
+ if write then
+ local f = io.open(path, "w")
+ f:write("return {")
+ tab.write(loaded_font, f, "\n")
+ f:write("}")
+ f:close()
+ end
+
+ return loaded_font
+
+end
+
+-- GETTING A FONT
+
+-- Finds a font file, and returns the original
+-- file and the Lua version.
+local name_luafile, get_features
+local function is_font (name, mods, size)
+
+ local lib, library_filename
+ for l, t in ipairs(library) do
+ if t[name] then
+ library_filename = t[name]
+ lib = t
+ break
+ end
+ end
+ if not library_filename then
+ library_filename = library.default[name]
+ lib = library.default
+ end
+
+ if library_filename then
+ if type(library_filename) == "string" then
+ library_filename = lib[library_filename]
+ end
+ tab.sort(mods)
+ local T = library_filename
+ for _, t in ipairs(mods) do
+ local found
+ for tag in pairs(T) do
+ if str.match(tag, "^" .. t) then
+ T = T[tag]
+ found = true
+ break
+ end
+ end
+ if not found then
+ T = nil
+ break
+ end
+ end
+
+ if T and T.__files then
+ local file, feats
+ local diff = 10000
+ for s, f in pairs(T.__files) do
+ if num.abs(s - size) < diff then
+ diff = num.abs(s - size)
+ file, feats = f[1], f[2]
+ end
+ end
+ file, _file = lfs.find_file(file, lfs.kpse(file)), file
+ if file then
+ file = str.gsub(file, "\\", "/")
+ else
+ return 1, _file
+ end
+ local features = {}
+ if feats then
+ get_features(feats, features)
+ end
+ local lua = name_luafile(file, features.font)
+ lua = lfs.isfile(lua) and lua
+ return file, lua, feats
+ end
+ end
+end
+
+-- Returns the full path to the Lua version of the font.
+-- "sub" is a font in ttc.
+function name_luafile (file, sub)
+ local lua
+ sub = sub and "_" .. sub or ""
+ sub = str.gsub(sub, " ", "_")
+ if str.match(file, "/") then
+ lua = str.match(file, ".*/(.-)%....$")
+ else
+ lua = str.match(file, "(.-)%....$")
+ end
+ lua = lua .. sub
+ return foundry_path .. "/" .. lua .. ".lua"
+end
+
+local function apply_size (font, size, letterspacing, parameters)
+ if (size < 0) then size = (- 655.36) * size end
+ local to_size = size / font.units_per_em
+ font.size = size
+ font.designsize = size
+ font.to_size = to_size
+ local italic = font.italicangle or 0
+ local space, stretch, shrink, extra
+ if parameters == "mono" then -- Creates a monospaced font with space equal to the
+ -- width of an "m" and no stretch or shrink.
+ space = font.characters[109].width * to_size
+ stretch, shrink, extra = 0, 0, 0
+ else
+ parameters = parameters and str.explode(parameters) or {}
+ space = (parameters[1] or 0.25) * size
+ stretch = (parameters[2] or 0.166666) * size
+ shrink = (parameters[3] or 0.111111) * size
+ extra = (parameters[4] or 0.111111) * size
+ end
+ font.parameters = {
+ slant = size * num.floor(num.tan(italic * num.pi/180)), -- \fontdimen 1
+ space = space, -- \fontdimen 2
+ space_stretch = stretch, -- \fontdimen 3
+ space_shrink = shrink, -- \fontdimen 4
+ x_height = size * 0.4, -- \fontdimen 5
+ quad = size, -- \fontdimen 6
+ extra_space = extra -- \fontdimen 7
+ }
+
+ letterspacing = letterspacing or 1
+ for c, t in pairs(font.characters) do
+ if t.width then
+ t.width, t.height, t.depth = t.width * to_size * letterspacing, t.height * to_size, t.depth * to_size
+ t.expansion_factor = 1000
+ if t.italic then
+ t.italic = t.italic * to_size
+ end
+ end
+ end
+
+ return font
+end
+
+
+local get_mods = lp.Ct((lp.space * lp.S"/" * lp.C(lp.alnum^1))^0)
+local get_feats = lp.Ct((lp.C((1 - lp.S",;")^1) * (lp.S",;" + -1))^1)
+function get_features (features, tb)
+ features = lp.match(get_feats, features) or {}
+ for _, f in ipairs(features) do
+ if str.match(f, "=") then
+ local key, val = str.match(f, "%s*(.-)%s*=%s*(.*)")
+ val = str.trim(val)
+ if val == "false" then
+ tb[key] = nil
+ else
+ tb[key] = val
+ end
+ else
+ f = str.trim(f)
+ neg, f = str.extract(f, "^%-")
+ if neg then
+ tb[f] = nil
+ else
+ _, f = str.extract(f, "^%+")
+ tb[f] = true
+ end
+ end
+ end
+end
+
+local lookup_functions = {}
+
+function lookup_functions.gsub_single (tb, f)
+ local name_touni = f.name_to_unicode
+ for a, b in pairs(tb.pairs) do
+ local _a, _b = name_touni[a], name_touni[b]
+ f.max_char = f.max_char + 1
+ f.characters[f.max_char] = f.characters[_a]
+ f.characters[_a] = f.characters[_b]
+ name_touni[a], name_touni[b] = f.max_char, _a
+ end
+ return f
+end
+
+function lookup_functions.gsub_ligature (tb, f)
+ local name_touni = f.name_to_unicode
+ tb.ligs.all_ligs = nil
+ for a, tb in pairs(tb.ligs) do
+ a = name_touni[a]
+ tab.subtable(f.characters[a], "ligatures")
+ for b, ttb in pairs(tb) do
+ b, c = name_touni[b], name_touni[ttb.char]
+ f.characters[a].ligatures[b] = {char = c, type = ttb.type}
+ end
+ end
+ return f
+end
+
+local function kern_pairs (tb, firsts, seconds, offset)
+ for _, c1 in ipairs(str.explode(firsts)) do
+ for __, c2 in ipairs(str.explode(seconds)) do
+ tab.subtable(tb, c1)
+ tb[c1][c2] = offset
+ end
+ end
+end
+
+local function kern_classes (firsts, seconds, offsets, max)
+ local kerns = {}
+ for f, F in pairs (firsts) do
+ for s, S in pairs (seconds) do
+ local off = offsets[(f-1) * max + s]
+ if off then
+ kern_pairs (kerns, F, S, off)
+ end
+ end
+ end
+ return kerns
+end
+
+local function apply_kerns (f, kerns, to_size)
+ local name_touni = f.name_to_unicode
+ to_size = to_size or 1
+ for c1, ttb in pairs(kerns) do
+ for c2, off in pairs(ttb) do
+ tab.subtable(f.characters[name_touni[c1]], "kerns")
+ f.characters[name_touni[c1]].kerns[name_touni[c2]] = off * to_size
+ end
+ end
+end
+
+function lookup_functions.gpos_pair (tb, f)
+ -- These are the big kern classes.
+ if tb.offsets then
+ local name_touni = f.name_to_unicode
+ for n, off in pairs(tb.offsets) do
+ tb.offsets[n] = off * f.to_size
+ end
+ local kerns = kern_classes(tb.firsts, tb.seconds, tb.offsets, tb.max)
+ apply_kerns(f, kerns)
+ end
+ -- These are the ones retrieved from individual glyphs.
+ if tb.kerns then
+ apply_kerns(f, tb.kerns, f.to_size)
+ end
+ return f
+end
+
+function lookup_functions.gsub_contextchain (tb, f)
+ local name_touni = f.name_to_unicode
+ local T = f.contextchain or {}
+ for _, llk in ipairs(tb) do
+ if fontfile.lookups then
+ local sub, Sub = fontfile.lookups[llk].rules[1].lookups
+ local chain = fontfile.lookups[llk].rules[1].coverage
+ local cur, current = str.explode(chain.current[1]), {}
+ local aft, after = chain.after and str.explode(chain.after[1]) or {}, {}
+ for _, c in ipairs(cur) do
+ c = name_touni[c]
+ if sub then
+ Sub = {}
+ for n, x in ipairs(sub) do
+ Sub[n] = name_touni[fontfile.glyphs[f.characters[c].index].lookups[x .. "_s"][1].specification.variant]
+ end
+ end
+ local t = { lookup = Sub}
+ tab.subtable(T, C)
+ for __, a in ipairs(aft) do
+ tab.subtable(t, "after")
+ t.after[name_touni[a]] = true
+ end
+ tab.insert(T[c], t)
+ end
+ end
+ end
+ f.contextchain = T
+ return f
+end
+
+local function _isactive (tb, ft, sc, lg)
+ for t in pairs(tb.tags) do
+ if ft[t] then
+ if t[sc] then
+ for _, lang in pairs(tb[sc]) do
+ if lang == lg then
+ return true
+ end
+ end
+ else
+ return true
+ end
+ end
+ end
+end
+
+
+local lookup_types = {
+ "gsub_single",
+ "gsub_ligature",
+ "gpos_pair"
+ }
+
+local function activate_lookups (font, features, script, lang)
+ for _, type in ipairs(lookup_types) do
+ if font.lookup_table and font.lookup_table[type] then
+ for l, tb in pairs(font.lookup_table[type]) do
+ if _isactive(tb, features, script, lang) then
+ for _, lk in ipairs(tb) do
+ local lt = font.lookups[lk]
+ if lt then
+ font = lookup_functions[type](lt, font)
+ end
+ end
+ end
+ end
+ end
+ end
+ return font
+end
+
+local function load_font (name, size, id, done)
+ local loaded_font = lfs.find_file(name, "tfm")
+ if loaded_font then
+ loaded_font = fl.read_tfm(loaded_font, size)
+ else
+ local original = str.trim(str.match(name, "[^:]*"))
+ local family, mods, feats
+ family, name = str.extract(name, "([^/:]*)")
+ family = str.trim(family)
+ mods, name = str.extract(name, "[^:]*")
+ mods = lp.match(get_mods, mods) or {}
+ feats = str.extract(name, ":(.*)") or ""
+ local features = tab.copy(settings.features)
+ get_features(feats, features)
+
+ local at_size
+ if features.size then
+ at_size = features.size
+ else
+ at_size = size
+ at_size = at_size > 0 and at_size or at_size * - 655.36
+ at_size = at_size / 65536
+ end
+ local source, lua, add_feats = is_font(family, mods, at_size)
+ if add_feats then get_features(add_feats, features) end
+
+ if type(source) == "string" then
+ local cache = features.cache or "yes"
+ if lua then
+ if cache == "no" or cache == "rewrite" then
+ loaded_font = create_font(source, lfs.type(source), lua, features.font, cache == "rewrite")
+ else
+ loaded_font = dofile(lua)
+ end
+ else
+ lua = name_luafile(source, features.font)
+ loaded_font = create_font(source, lfs.type(source), lua, features.font, cache ~= "no")
+ end
+ else
+ if not done then
+ if type(source) == "number" then
+ wri.error("The library says `%s' matches `%s', but I can't find that file anywhere. Clean up your library!", original, lua)
+ else
+ recheck_fonts()
+ return load_font(original, size, id, true)
+ end
+ else
+ wri.error("I can't find `%s'. I return a default font to avoid further errors.", original)
+ end
+ end
+
+ if loaded_font then
+
+ local expansion = features.expansion and str.explode(features.expansion) or {}
+ loaded_font.stretch = expansion[1] or 0
+ loaded_font.shrink = expansion[2] or 0
+ loaded_font.step = expansion[3] or 0
+
+ local extend = features.extend or 1
+ loaded_font.extend = extend * 1000
+ local slant
+ if features.absoluteslant then
+ local italic = loaded_font.italicangle or 0
+ slant = features.absoluteslant - italic
+ else
+ slant = features.slant or 0
+ end
+ loaded_font.slant = num.tan(num.rad(slant)) * 1000
+
+ loaded_font = apply_size(loaded_font, size, features.letterspacing, features.space)
+ loaded_font = activate_lookups(loaded_font, features, features.script, features.lang)
+
+ loaded_font.name = loaded_font.name .. id
+ loaded_font.fullname = loaded_font.fullname .. id
+ local embedding = features.embedding or "subset"
+ if embedding ~= "no" and embedding ~= "subset" and embedding ~= "full" then
+ wri.error("Invalid value `%s' for the `embedding' feature. Value should be `no', `subset' or `full'.", embedding)
+ embedding = "subset"
+ end
+ loaded_font.embedding = embedding
+ else
+ loaded_font = fl.read_tfm(lfs.find_file("cmr10", "tfm"), size)
+ end
+ end
+ return loaded_font
+end
+
+callback.register("define_font", load_font)
diff --git a/Master/texmf-dist/tex/plain/pitex/inserts.ptx b/Master/texmf-dist/tex/plain/pitex/inserts.ptx
new file mode 100644
index 00000000000..70155f5d7eb
--- /dev/null
+++ b/Master/texmf-dist/tex/plain/pitex/inserts.ptx
@@ -0,0 +1,113 @@
+% This is a mess.
+\newinsert\ptx@insert_footnotes
+\dimen\ptx@insert_footnotes20\baselineskip
+\skip\ptx@insert_footnotes12pt
+\count\ptx@insert_footnotes1000
+
+\newcount\ptx@footnote_count
+\newbox\ptx@footnote_box
+\newif\iffootnote
+
+\def\footnote{%
+ \global\advance\ptx@footnote_count1
+ \maintextfalse \footnotetrue
+ \ifnext[
+ {\ptx@label_withand{\the\ptx@footnote_count}\ptx@footnote}
+ {\ptx@footnote}%
+ }
+\long\def\ptx@footnote#1{%
+ {\verysmall
+ \unskip\kern.1em
+ \raise.53em\hbox{\the\ptx@footnote_count}%
+ \global\setbox\ptx@footnote_box\hbox{\the\ptx@footnote_count}%
+ }%
+ \insert\ptx@insert_footnotes\bgroup
+ \verysmall
+ \baselineskip12pt
+ \leftskip=0pt \rightskip=\leftskip
+ \floatingpenalty20000
+ \noindent\vrule width0pt depth0pt height9pt
+ \hbox to 0pt{\hss\the\ptx@footnote_count\hskip.5em\hfill}#1%
+ \egroup
+ \futurelet\temp\getpunc
+ }
+
+\def\getpunc{%
+ \bgroup
+ \ifx\temp\virgule
+ \kern-.4\wd\ptx@footnote_box,%
+ \egroup
+ \expandafter\gobble
+ \else
+ \ifx\temp\point
+ \kern-.4\wd\ptx@footnote_box.%
+ \egroup
+ \expandafter\expandafter\expandafter\gobble
+ \else
+ \egroup
+ \fi
+ \fi
+ \maintexttrue \footnotefalse
+ }
+
+
+\newinsert\ptx@insert_figures
+\dimen\ptx@insert_figures\vsize
+\count\ptx@insert_figures1000
+\newcount\ptx@figure_count
+\newcount\ptx@table_count
+\newbox\ptx@figure_captionbox
+\newif\iffigure
+
+\newblock*\figure
+ {\ifnextnospace*
+ {\def\ptx@figure_type{table}\def\ptx@figure_word{Table}\gobbleoneand\ptx@figure_do}
+ {\def\ptx@figure_type{figure}\def\ptx@figure_word{Fig.}\ptx@figure_do}}
+ {\egroup
+ \insert\ptx@insert_figures{%
+ \penalty0
+ \floatingpenalty0
+ \vbox to \ptx@figure_measure{0}{\ht\ptx@box_temp+\dp\ptx@box_temp+\ht\ptx@figure_captionbox}{2\baselineskip}{%
+ \box\ptx@box_temp
+ \vfill
+ \vskip\baselineskip
+ \box\ptx@figure_captionbox
+ \vskip\baselineskip}}}
+\def\ptx@figure_do{%
+ \maintextfalse
+ \figuretrue
+ \global\advance\usecs{ptx@\ptx@figure_type _count}1
+ \def\ptx@label{\usevalue chapter:internalcount .\the\usecs{ptx@\ptx@figure_type _count}}%
+ \ifnextnospace[
+ {\ptx@figure_getcaption}
+ {\ptx@figure_getcaption[]}}
+
+\def\ptx@figure_getcaption[#1]{%
+ \setbox\ptx@figure_captionbox\vbox{%
+ \leftskip3em \rightskip\leftskip \parindent0pt
+ \ifdefined\figurefont
+ \figurefont
+ \else
+ \verysmall
+ \fi
+ \baselineskip16pt
+ \leavevmode
+ \llap{\bf \ptx@figure_word~\usevalueand chapter:internalcount {.}{}\the\usecs{ptx@\ptx@figure_type _count}\hskip.5em}#1}%
+ \setbox\ptx@box_temp=\vbox\bgroup
+ \leftskip0pt plus1fill \rightskip\leftskip \parindent0pt
+ }
+
+\newwhile\ptx@figure_measure3{#1+1}{#2}{#3}{%
+ \reverse\straighteniff{ifdim}
+ {\dimexpr\baselineskip*\numexpr(#1)<\dimexpr(#2)\relax}
+ {\breakwhile{\dimexpr(\numexpr(#1)\baselineskip\reverse\iffemptystring{#3}{+#3})\relax}}
+ }
+
+\newblock\infigure
+ {\par \setbox\ptx@box_temp=\hbox\bgroup
+ \leftskip0pt plus1fill \rightskip\leftskip \parindent0pt }
+ {\egroup
+ \kern-\prevdepth \nointerlineskip
+ \vbox to \ptx@figure_measure{0}{\ht\ptx@box_temp+\dp\ptx@box_temp}{}
+ {\vfil\box\ptx@box_temp\vfil}%
+ }
diff --git a/Master/texmf-dist/tex/plain/pitex/lua.ptx b/Master/texmf-dist/tex/plain/pitex/lua.ptx
new file mode 100644
index 00000000000..b41c5af338e
--- /dev/null
+++ b/Master/texmf-dist/tex/plain/pitex/lua.ptx
@@ -0,0 +1,26 @@
+\def\inputluafile#1 {\directlua{dofile(kpse.find_file("#1"))}}
+
+\inputluafile base.ptxlua
+
+\def\ptx@lua{\directlua name {Internal PiTeX chunk}}
+
+\newcatcodetable\luacatcodes{\#\%\^^M\~=12}
+\newtoks\ptx@luacode_list
+\newif\ifptx@luacode_store
+% Mimicks a block (\newblock isn't defined yet
+% and anyway it wouldn't be very useful).
+\def\luacode{%
+ \begingroup
+ \catcodetable\luacatcodes
+ \ifnext[
+ {\ptx@luacode_store}
+ {\ptx@luacode_store[]}}
+\bgroup
+\setcatcodes{\^^M=12}%
+\long\gdef\ptx@luacode_store[#1]^^M#2\luacode/{% So line count is right.
+ \endgroup%
+ \ifemptystring{#1}%
+ {\ptx@lua{#2}}%
+ {\def#1{#2}}%
+ }%
+\egroup
diff --git a/Master/texmf-dist/tex/plain/pitex/output.ptx b/Master/texmf-dist/tex/plain/pitex/output.ptx
new file mode 100644
index 00000000000..20a0dc677f2
--- /dev/null
+++ b/Master/texmf-dist/tex/plain/pitex/output.ptx
@@ -0,0 +1,311 @@
+\defactiveparameter page {%
+ \settovalue\pdfpagewidth #1 : width
+ \settovalue\pdfpageheight #1 : height
+ \settovalue\baselineskip #1 : baselineskip
+ \settovalueor\topskip #1 : topskip {\topskip=\baselineskip}%
+ \settovalue\pdfhorigin #1 : left
+ \ifattribute #1 : right
+ {\hsize = \dimexpr(\pdfpagewidth-\pdfhorigin-\usevalue #1 : right )\relax}
+ {\settovalue\hsize #1 : hsize }%
+ \settovalue\pdfvorigin #1 : top
+ \settovalue\parindent #1 : parindent
+ \settovalue\parskip #1 : parskip
+ \ifattribute #1 : lines {\vsize=\usevalue #1 : lines \baselineskip}{}%
+ }
+
+\restrictparameter page :
+ width
+ height
+ hsize
+ baselineskip
+ topskip
+ left
+ right
+ top
+ lines
+ parindent
+ parskip
+\par
+
+% Defaults... they don't produce anything beautiful.
+% I redefine them on every job.
+\setparameter page:
+ height = 28cm
+ width = 21cm
+ hsize = 15cm
+ baselineskip = 12pt
+ lines = 42
+ left = 1in
+ top = 1in
+ parskip = 0pt
+
+\widowpenalty151
+\clubpenalty0
+\holdinginserts1
+\newdimen\outputsize
+\newif\ifheader
+
+\gates new \OutputRoutine {OutputRoutine}%
+
+\OutputRoutine list {output}
+ [precheck]
+ {%
+ \global\holdinginserts0
+ \OutputRoutine skip {precheck, shipout}{output}%
+ \ifnum\outputpenalty<\widowpenalty
+ \global\outputsize=\vsize
+ \else
+ \ifnum\outputpenalty=10000
+ \global\outputsize=\vsize
+ \else
+ \ifdim\pagegoal<\vsize
+ \global\advance\vsize-\baselineskip
+ \global\outputsize=\dimexpr\vsize+\baselineskip\relax
+ \else
+ \global\advance\vsize\baselineskip
+ \global\outputsize=\dimexpr\vsize-\baselineskip\relax
+ \fi
+ \fi
+ \fi
+ \unvbox\outputbox
+ \ifnum\outputpenalty=10000
+ \penalty0
+ \else
+ \penalty\outputpenalty
+ \fi}
+%
+ (shipout)
+ . (inserts)
+ . . [inserts_figures] ?{conditional = \unless\ifvoid\ptx@insert_figures} {%
+ \setbox\outputbox=\vbox to \outputsize{%
+ \box\ptx@insert_figures
+ \unvbox\outputbox}}
+ . . [inserts_footnotes] ?{conditional = \unless\ifvoid\ptx@insert_footnotes} {%
+ \setbox\outputbox=\vbox to \outputsize{%
+ \unvbox\outputbox
+ \vfil
+ \vskip.5\skip\ptx@insert_footnotes
+ \vbox to0pt{\vss\hrule width .3\hsize}%
+ \vskip.5\skip\ptx@insert_footnotes
+ \unvbox\ptx@insert_footnotes}}
+ %
+ . [headers] {%
+ \setbox\outputbox=\vbox{%
+ \kern-3\baselineskip
+ \vbox to3\baselineskip{%
+ \hbox to\hsize{\strut\baselineskip {0pt}%
+ \normalsize\rm\sc
+ \ifodd\pageno
+ \hfill\usevalue chapter : inner_title \rlap{\kern1em \the\pageno}\kern-3em
+ \else
+ \kern-3em\llap{\the\pageno\kern1em }\usevalue chapter : inner_title \hfill
+ \fi}
+ \vfill}
+ \nointerlineskip
+ \box\outputbox}}
+ %
+ . [ship] {%
+ \settovalue\pdfhorigin page : left
+ \shipout\box\outputbox}
+ %
+ . [postship] {%
+ \global\holdinginserts1
+ \global\vsize\outputsize
+ \global\advance\count0 1
+ \ifnum\insertpenalties>0
+ \ifnum\outputpenalty=\clearpagepenalty
+ \hbox{}\vfil\penalty\outputpenalty
+ \fi
+ \fi}
+
+
+\output{%
+ \OutputRoutine execute {output}%
+ }
+
+
+
+% MARGIN NOTES
+\setparameter marginnote :
+ hsize = 3cm
+ hpos = fr
+ font = \it
+ parindent = 0pt
+ side = right
+ gap = 1em
+
+\newcount\notecount
+\newattribute\ptx@marginnote_attribute
+\def\marginnote{%
+ \ifnext[
+ {\ptx@marginnote}
+ {\ptx@marginnote[]}%
+ }
+
+\long\def\ptx@marginnote[#1]#2{%
+ \setparameterlist{marginnote@temp}{meta = marginnote, #1}%
+ \global\advance\notecount 1
+ \global\expandafter\newbox\csname marginnote_\the\notecount\endcsname
+ \global\expandafter\setbox\csname marginnote_\the\notecount\endcsname=
+ \vtop{%
+ \settovalue\hsize marginnote@temp : hsize
+ \settovalue{\advance\hsize} marginnote@temp : gap
+ \leftskip=0pt \rightskip=0pt plus 1 fil \parfillskip=0pt\relax
+ \ifcasevalue marginnote@temp : hpos
+ \val ff \rightskip=0pt \parfillskip=0pt plus 1 fil
+ \val rf \leftskip=0pt plus 1 fil \rightskip=1pt
+ \val rr \leftskip=0pt plus 1 fil
+ \endval
+ \ifvalue marginnote@temp : side = left
+ {\settovalue{\advance\rightskip} marginnote@temp : gap }
+ {\settovalue{\advance\leftskip} marginnote@temp : gap }%
+ \settovalue\baselineskip marginnote@temp : baselineskip
+ \settovalue\parindent marginnote@temp : parindent
+ \usevalue marginnote@temp : font
+ #2}%
+ \quitvmode % Must be outside the attribute's scope, otherwise the
+ % paragraphs DIR whatsit might get in the way.
+ \bgroup
+ \ifvalue marginnote@temp : side = left
+ {\ptx@marginnote_attribute=-\expandafter\the\csname marginnote_\the\notecount\endcsname}
+ {\ptx@marginnote_attribute=\expandafter\the\csname marginnote_\the\notecount\endcsname}\relax
+ \pdfliteral{}%
+ \egroup
+ \deleteparameter marginnote@temp:%
+ }
+
+\luacode
+local WHAT, HLIST, KERN = node.id("whatsit"), node.id("hlist"), node.id("kern")
+local GLUE, SPEC = node.id("glue"), node.id("glue_spec")
+local marginnote_table = {}
+function pitex.misc.mark_lines (head)
+ for line in node.traverse_id(HLIST, head) do
+ local t = {left = {}, right = {}}
+ local item = line.head
+ while item do
+ local next = item.next
+ if item.id == WHAT then
+ local attr = node.has_attribute(item, \attributenumber\ptx@marginnote_attribute)
+ if attr then
+ if attr < 0 then
+ table.insert(t.left, -attr)
+ else
+ table.insert(t.right, attr)
+ end
+ line.head = node.remove(line.head, item)
+ end
+ end
+ item = next
+ end
+ if #t.left > 0 or #t.right > 0 then
+ table.insert(marginnote_table, t)
+ node.set_attribute(line, \attributenumber\ptx@marginnote_attribute, #marginnote_table)
+ end
+ end
+ return head
+end
+
+pitex.callback.register("post_linebreak_filter", "pitex.misc:mark_lines")
+
+local lheight, rheight = 0, 0
+local function update_height (h)
+ lheight = lheight + h
+ rheight = rheight + h
+end
+
+local function first_dim (n, t)
+ while n do
+ if node.has_field(n, "kern") then
+ return n.kern
+ elseif node.has_field(n, "spec") then
+ return n.spec.width
+ elseif node.has_field(n, "height") then
+ return t == "height" and n.height or n.depth
+ else
+ n = t == "height" and n.next or n.prev
+ end
+ end
+ return 0
+end
+
+function process_marginalia (head)
+ lheight, rheight = 0, 0
+ local item, first = node.slide(head), true
+ while item do
+ if node.has_field(item, "kern") then
+ if not first then
+ update_height(item.kern)
+ end
+ elseif node.has_field(item, "spec") then
+ if not first then
+ update_height(item.spec.width)
+ end
+ elseif node.has_field(item, "height") then
+ if first then
+ first = false
+ else
+ update_height(item.depth)
+ end
+ local attr = node.has_attribute(item, \attributenumber\ptx@marginnote_attribute)
+ if attr then
+ for side, notes in pairs (marginnote_table[attr]) do
+ if #notes > 0 then
+ local note
+ for _, n in ipairs(notes) do
+ if note then
+ local n, g, s = tex.box[n], node.new(GLUE), node.new(SPEC)
+ local d = first_dim(node.tail(note.head), "depth")
+ local h = first_dim(n.head, "height")
+ s.width = tex.baselineskip.width - (d + h)
+ g.spec = s
+ note.depth = note.depth + s.width + n.height + n.depth
+ node.insert_after(note.head, node.tail(note.head), g)
+ g.next, n.head.prev = n.head, g
+ else
+ note = tex.box[n]
+ end
+ end
+ first = true
+ local upward = note.depth - first_dim(node.tail(note.head), "depth")
+ local remainingheight = side == "left" and lheight or rheight
+ if upward > remainingheight then
+ upward = remainingheight - upward
+ else
+ upward = 0
+ end
+ local kern = node.new(KERN, 1)
+ kern.kern = upward - note.height - item.depth
+ node.insert_before(note.list, note.list, kern)
+ note.list = kern
+ if side == "left" then
+ note.shift = -note.width
+ lheight = upward
+ else
+ note.shift = item.width
+ rheight = upward
+ end
+ note.height, note.depth = 0, 0
+ node.insert_after(head, item, note)
+ else
+ if side == "left" then
+ lheight = lheight + item.height
+ else
+ rheight = rheight + item.height
+ end
+ end
+ end
+ else
+ update_height(item.height)
+ end
+ end
+ item = item.prev
+ end
+end
+\luacode/
+
+\OutputRoutine def {processmarginalia}{%
+ \ptx@lua{process_marginalia(tex.box[255].list)}%
+ }
+
+\OutputRoutine add {processmarginalia}[first]{shipout}
+
diff --git a/Master/texmf-dist/tex/plain/pitex/pitex.tex b/Master/texmf-dist/tex/plain/pitex/pitex.tex
index 5b62b8b5529..fcaa7f5132c 100644
--- a/Master/texmf-dist/tex/plain/pitex/pitex.tex
+++ b/Master/texmf-dist/tex/plain/pitex/pitex.tex
@@ -3,8 +3,10 @@
% archived on CTAN).
%
% Perhaps in the future, when this achieves some kind of
-% format-like completude, there'll be a documentation and
-% it'll be publicly announced.
+% format-like completude, it'll be publicly announced. In the
+% meanwhile, a documentation exists (pitex-doc.pdf, also readable
+% in a text editor as pitex-doc.txt).
+%
%
% You can of course use those macros, but you are on your
% own, and the files will probably be modified without announcement.
@@ -13,333 +15,168 @@
%
% The files needed are:
%
-% texapi.tex (an independent package \input in the following file)
-% yax.tex (an independent package)
-% fonts.ptx (piTeX font "management")
-% luaotfload.sty (an independent package (not by me))
-% sections.ptx (piTeX sectionning commands)
+% texapi.tex (an independent package for programming)
+% yax.tex (an independent package for key=value interface)
+% gates.tex and gates.lua (an independant package for overall architecture)
+% navigator.tex (an independant package for PDF features)
+% lua.ptx and base.ptxlua (Lua side)
+% files.ptx (file management)
+% fonts.ptx, fonts.ptxlua and foundry-settings.lua
+% (fonts, should be independant some day; actually
+% fonts.ptxlua can be used independantly, but there is
+% no doc)
+% sections.ptx (sectionning commands)
+% blocks.ptx (text blocks)
+% references.ptx (labels and references)
+% verbatim.ptx (typesetting verbatim)
+% inserts.ptx (footnotes and figures, a mess)
+% output.ptx (output routine)
+%
+% The file i-pitex.lua is needed only to typeset the documentation with the
+% Interpreter package.
%
-% Date: July 2010.
+%
+% Date: November 2011.
%
%
% User interface
\input yax % which itself \input's texapi
+\input gates
\setcatcodes{\@\_=11}
-\def\ptx@error{\senderror{PiTeX}}
+\suppressoutererror=1
-% This to write in latin1.
-\directlua{%
- lualog = function (message)
- texio.write_nl("") texio.write_nl("")
- texio.write_nl(message)
- texio.write_nl("") texio.write_nl("")
- end
- function convert(buf)
- return string.gsub(buf,"(.)", function (ch)
- return unicode.utf8.char(string.byte(ch))
- end)
- end
- callback.register('process_input_buffer',convert)
- }
+% MESSAGES
+\def\ptx@error{\senderror{PiTeX}}
+\def\ptx@log#1{%
+ \immediate\write17{^^J#1^^J}%
+ }
+\def\ptx@warn#1{%
+ \ptx@log{PiTeX warning: #1}%
+ }
+% ATTRIBUTES
\newcount\ptx@attribute_count
+\ptx@attribute_count=100 % The first 100 attributes are scratch.
\def\newattribute#1{%
\advance\ptx@attribute_count1
- \edefcs{ptx@attribute_#1}{10\the\ptx@attribute_count}%
+ \attributedef#1=\ptx@attribute_count
+ \xdefcs{ptx@attribute:\commandtoname#1}{\the\ptx@attribute_count}%
+ }
+\def\unsetattribute#1{#1=-"7FFFFFFF\relax}
+\def\attributenumber#1{\usecs{ptx@attribute:\commandtoname#1}}
+
+% FREEDEF
+\def\freedef#1{%
+ \def#1{%
+ \ifnextnospace"
+ {\ptx@freedef_quote#1}
+ {\ifnextnospace/
+ {\ptx@freedef_slash#1}
+ {\usecs{ptx@freedef_user:\commandtoname#1}}}%
+ }%
+ \defcs{ptx@freedef_user:\commandtoname#1}##1%
+ }
+\def\ptx@freedef_quote#1"#2"{%
+ \usecs{ptx@freedef_user:\commandtoname#1}{#2}%
+ }
+\def\ptx@freedef_slash#1/#2/{%
+ \usecs{ptx@freedef_user:\commandtoname#1}{#2}%
}
-\def\ptx@attribute_number#1{\usecs{ptx@attribute_#1}}
-\def\ptx@attribute_set#1{\passcs\attribute{ptx@attribute_#1}=1\relax}
-\def\ptx@attribute_unset#1{\passcs\attribute{ptx@attribute_#1}=-"7FFFFFFF\relax}
-\newdimen\urvsize
-\urvsize\vsize
-\def\inputpitexfile#1 {\input #1.ptx }
+\newbox\ptx@box_temp
-\inputpitexfile fonts
-\inputpitexfile sections
-% No footnotes in documentations.
-%\input footnotes.tex
-% I redefine the output routine on every job.
-%\input output.tex
+\newif\ifmaintext
+\maintexttrue
-\defactiveparameter document{%
- \pdfinfo{%
- /Author (\usevalueor #1 : author {Unknown author})
- /Title (\usevalueor #1 : pdftitle {\usevalueor #1 : title {No title}})
- \ifattribute #1 : subject {/Subject (\usevalue #1 : subject )}{}
- \ifattribute #1 : keywords {/Keywords (\usevalue #1 : keywords )}{}
- }%
- \pdfcatalog{%
- /PageMode
- \ifcasevalue #1 : display
- \val outlines /UseOutlines
- \val signets /UseOutlines % French!
- \val thumbs /UseThumbs
- \val thumbnails /UseThumbs
- \val full /FullScreen
- \val fullscreen /FullScreen
- \elseval /UseNone
- \endval
- }%
+% CATCODE TABLES
+\newcount\ptx@catcodetable_count
+\ptx@catcodetable_count=100 % First 100 are scratch.
+\def\newcatcodetable#1#2{%
+ \global\advance\ptx@catcodetable_count1
+ \chardef#1=\ptx@catcodetable_count
+ \begingroup
+ \setcatcodes{#2}%
+ \savecatcodetable#1%
+ \endgroup
}
-\restrictparameter document : author title pdftitle date subject keywords display version\par
-\restrictattribute document:display outlines signets thumbs thumbnails full fullscreen\par
+\newcatcodetable\texcatcodes{\@\_=12}
+\def\inputpitexfile#1 {\input #1.ptx }
-\defactiveparameter page{%
- \settovalue\pdfpagewidth #1 : pagewidth
- \settovalue\pdfpageheight #1 : pageheight
- \settovalue\baselineskip #1 : baselineskip
- \settovalueor\topskip #1 : topskip {\topskip=\baselineskip}%
- \settovalue\pdfhorigin #1 : left
- \ifattribute #1 : right
- {\hsize = \dimexpr(\pdfpagewidth-\pdfhorigin-\usevalue #1 : right )\relax}
- {\settovalue\hsize #1 : hsize }%
- \settovalue\pdfvorigin #1 : top
- \settovalue\parindent #1 : parindent
- \settovalue\parskip #1 : parskip
- \ifattribute #1 : lines {\vsize=\usevalue #1 : lines \baselineskip}{}%
- }
-\restrictparameter page : pagewidth
- pageheight
- hsize
- baselineskip
- topskip
- left
- right
- top
- lines
- parindent
- parskip
- \par
-
-% Defaults... they don't produce anything beautiful.
-% I redefine them on every job.
-\setparameter page:
- pageheight = 28cm
- pagewidth = 21cm
- hsize = 15cm
- baselineskip = 12pt
- lines = 42
- left = 1in
- top = 1in
- parskip = 0pt
+\inputpitexfile lua
+\inputpitexfile files
+\inputpitexfile fonts
+\inputpitexfile sections
+\inputpitexfile blocks
+\inputpitexfile references
+\inputpitexfile verbatim
+\inputpitexfile inserts
+\inputpitexfile output
+\input navigator.tex
+
+% AUXILIARY FILE
+\iffile{\jobname.aux}{%
+ \ptx@lua{%
+ remove_conversion()
+ tex.print("\luaescapestring{\noexpand\input\noexpand\jobname.aux}")
+ }%
+ \directlua{restore_conversion()}}
+\immediate\openout\ptx@auxfile=\jobname.aux
+% PDF SETTINGS
+\restrictparameter document : author title pdftitle date pdfdate subject keywords mode layout version\par
+\restrictattribute document : mode outlines bookmarks thumbs thumbnails attachments files oc\par
+\restrictattribute document : layout onepage onecolumn twopage twocolumn twopage* twocolumn*\par
-% Should be used with YaX to set parameters.
-\long\pdef\newblock{%
- \ifnext*{\gobbleoneand\ptx@newblock_group}
- {\ptx@newblock_nogroup}%
- }
-\def\ptx@newblock_nogroup#1#2#3{%
- \def#1{\ifnext/{\gobbleoneand{#3}}{#2}}%
- }
-\def\ptx@newblock_group#1#2#3{%
- \def#1{\ifnext/{\gobbleoneand{#3\egroup}}{\bgroup#2}}%
- }
-\def\antigobblespace{%
- \ifcatnext a{ }{\iffnext({ }}%
+\suppressoutererror=1
+\let\ptx@bye\bye
+\def\bye{%
+ \passvalueand{\setattribute navigator : title = } document : pdftitle { }{}
+ % The "date" attribute in the "document" parameter isn't supposed to hold a
+ % PDF-date, as navigator expects.
+ \deleteattribute document : date
+ \passvalueand{\setattribute navigator : date = } document : pdfdate { }{}
+ \finishpdffile\ptx@bye
}
+\setattribute navigator : meta = document
-% PDF links
-\def\dest#1#2{%
- \ifcs{ptx@link_name=#1}
- {\ptx@error{Link `#1' already exists}#2}
- {\letcs{ptx@link_name=#1}\relax
- \bgroup
- \ifvmode
- \pdfdest name {#1} xyz #2%
- \else
- \setbox0=\hbox{#2}%
- \raise\ht0\hbox{\pdfdest name {#1} xyz}#2%
- \fi
- \egroup
- }%
- }
-\def\link#1#2{%
- \pdfstartlink attr {/Border [0 0 0]} goto name {#1}#2\pdfendlink
- }
+% Turns a dimen into PostScript points, without the unit (as wanted by PDF).
+\def\pdfpoint#1{%
+ \directlua{%
+ local d = "\the\dimexpr#1"
+ d = string.gsub(d, "pt", "")
+ tex.print(tostring(d * (72/72.27)))
+ }}
-% Margin notes à la Bringhurst: aligned with the line they refer
-% to, unless they bleed into the bottom margin, in which case they
-% are shifted up so that their bottom line is aligned with the
-% page's bottom line. Totally experimental. It'd be nice if I could
-% do that with sections too (so that a note doesn't bleed into the
-% next section).
-\newattribute{note}
-\def\note{\ifnext[{\ptx@note}{\ptx@note[0pt]}}
-\def\ptx@note[#1]#2{%
- \ptx@attribute_set{note}%
- \setbox0=\hbox{\vtop{% We need the box's height minus its first line, hence the vtop.
- \notefont \baselineskip=9pt
- \hsize\dimexpr\pdfpagewidth-(\pdfhorigin+\hsize+4em)\relax
- \rightskip=0pt plus 1fil
- \it\noindent #2}}%
- \ptx@attribute_unset{note}%
- \ht0=0pt \dp0=0pt
- \vadjust{%
- \kern-\dimexpr(2pt+#1)\relax
- \moveright\dimexpr\hsize+1em
- \box0
- \kern\dimexpr2pt+#1}%
- \vrule height 0pt width 0pt depth 2pt
-% Problem: if the line where the note appears is last of its
-% box, the box has no depth and vfilling doesn't work properly.
- }%
-\directlua{%
- %
- % Box255 is traversed from the last node upward.
- % Each node with dimension adds to the "remaining height",
- % which is used when a note is encountered: if the note's depth
- % (minus its last box's depth) is larger than the remaining height,
- % then it is shifted upward, so that it doesn't bleed in the bottom
- % margin. When computing the remaining height, kerns and glues aren't
- % taken into account until a box has been seen (and the depth of
- % that first box isn't added either), so the note doesn't even
- % bleed into available page space that isn't filled with text.
- %
- process_marginalia = function (head)
- local remainingheight, first, item = 0, true, node.slide(head)
- while item do
- if node.has_attribute(item,\ptx@attribute_number{note}) then
- local depth = item.list.depth - node.tail(item.list.list).depth
- if depth > remainingheight then
- lualog("A note has been shifted on page " .. tex.count[0] ..
- " by an amount of " .. (depth-remainingheight)/65536 .. "pt.")
- item.list.shift = remainingheight-depth
- end
- elseif node.has_field(item, "height") then
- remainingheight = remainingheight+item.height
- if first then
- first = false
- else
- remainingheight = remainingheight + item.depth
- end
- elseif node.has_field(item,"kern") then
- if not first then
- remainingheight = remainingheight+item.kern
- end
- elseif node.has_field(item, "spec") then
- if not first then
- remainingheight = remainingheight+item.spec.width
- end
- end
- item = item.prev
- end
- end
- }
-\def\processmarginalia{%
- \directlua{process_marginalia(tex.box[255].list)}%
- }
-\def\stoppage{\penalty-10000\relax}
-\def\clearpage{\vfil\stoppage\relax}
-\def\needspace#1{%
- \penalty0
- \ifdim\dimexpr\pagegoal-\pagetotal<\dimexpr#1\relax
- \clearpage
- \fi
- }
-% Verbatim facilities.
-\newbox\ptx@box_temp
-\def\tcode#1{{\codefont#1}}
-\long\def\com#1{%
- \bgroup
- \codefont
- \string#1%
- \egroup
- \antigobblespace
+% TEX SETTINGS
+\long\def\ptx@tex_set#1#2#3{%
+ \ifcs{#2}
+ {\usecs{#2}=#3\relax}
+ {\ptx@error{No TeX parameter `#2'}}
}
-\def\arg#1{{\codefont\it<#1>}\iffnext\spacechar{\kern.2ex }}
-\def\barg#1{{\codefont\char"007B\relax{\it<#1>}\char"007D\relax}}
-\def\oarg#1{{\codefont[{\it<#1>}]}}
-
-\def\exampleskip{\vskip\baselineskip}
-\def\example{%
- \exampleskip
- \bgroup
- \parindent0pt
- \setcatcodes{\\\{\}\$\&\#\^\_\ \~\%=12,\^^M=13}%
- \codefont
- \readexample
- }%
-\let\ptx@example_original\example
-\bgroup
-\setcatcodes{\\=12,\|=0,\^^M=13}%
-|gdef|readexample#1^^M#2\example/{#2|egroup|exampleskip}%
-|restorecatcodes%
-\setcatcodes{\^^M=13}%
-\gdef^^M{\quitvmode\endgraf}%
-\egroup%
-\def\verb#1{%
- \def\ptx@verb##1#1{##1\egroup}%
- \bgroup
- \setcatcodes{\\\{\}\$\&\#\^\_\ \~\%=12}%
- \codefont
- \ptx@verb
+\defactiveparameter tex {%
+ \parameterloop #1 : \ptx@tex_set
}
-%
-% Read and process examples.
-%
-\newwrite\ptx@examplewrite
-
-\bgroup
-\setcatcodes{\%=12,\/=14}
-\gdef\Example{/
- \immediate\openout\ptx@examplewrite=\jobname.pex
- \immediate\write\ptx@examplewrite{% This is a scratch file used to typeset examples in \jobname.tex.}/
- \immediate\write\ptx@examplewrite{% You can delete it.}/
- \immediate\write\ptx@examplewrite{%}/
- \bgroup
- \setcatcodes{\\\#\%\^^M\ =12}/
- \writeexample
- }/
-\egroup
-
-\bgroup
-\setcatcodes{\^^M=12}%
-\gdef\writeexample#1^^M{%
- \immediate\write\ptx@examplewrite{\noexpand\example}%
- \ptx@writeexample}%
-\gdef\ptx@writeexample#1^^M{%
- \passexpanded{\ifstring{#1}}{\examplestring}%
- {\immediate\write\ptx@examplewrite{\string\example/}%
- \immediate\closeout\ptx@examplewrite\egroup%
- \processexample}%
- {\immediate\write\ptx@examplewrite{\primunexpanded{#1}}%
- \ptx@writeexample}%
- }%
-{\setcatcodes{\\=12,\|=0}|gdef|examplestring{\Example/}}%
-\egroup
+\frenchspacing
+\maxdepth=\maxdimen
-\def\typesetexample{%
- {\input\jobname.pex }%
- }
-\def\doexamplenogroup{\let\example\ptx@Example\input\jobname.pex \let\example\ptx@example_original}
-\def\doexample{{\doexamplenogroup}}
-\def\ptx@Example{%
- \iffnext/{\gobbleoneand\endinput}%
+\def\antigobblespace{%
+ \ifcatnext a{ }{\iffnext({ }}%
}
-% To be redefined for different layout.
-\def\processexample{\typesetexample\doexample}
-\def\verb#1{%
- \def\ptx@verb##1#1{##1\egroup}%
- \bgroup
- \setcatcodes{\\\{\}\$\&\#\^\_\ \~\%=12}%
- \codefont
- \ptx@verb
+\def\strut#1#2{%
+ \vrule height#1 depth#2 width0pt
}
-
\newdimen\extraboxspace
\newdimen\ptx@extraboxspace_top
\newdimen\ptx@extraboxspace_right
@@ -385,13 +222,15 @@
-\expandafter\noPT\the\ptx@extraboxspace_left
\expandafter\noPT\the\dimexpr(\ht\ptx@box_temp+\ptx@extraboxspace_top)\relax
\expandafter\noPT\the\dimexpr(\wd\ptx@box_temp+\ptx@extraboxspace_left+\ptx@extraboxspace_right)\relax
- -\expandafter\noPT\the\dimexpr(\ht\ptx@box_temp+\ptx@extraboxspace_top+\dp0+\ptx@extraboxspace_bottom)\relax
+ -\expandafter\noPT\the\dimexpr(\ht\ptx@box_temp+\ptx@extraboxspace_top+\dp\ptx@box_temp+\ptx@extraboxspace_bottom)\relax
re f Q}%
#2}%
\egroup
}
-\def\trace{\tracingcommands4 \tracingmacros4 }
+\def\og{\char"00AB~} \def\fg{~\char"00BB\antigobblespace}
+
+\def\trace{\tracingcommands3 \tracingmacros2 }
\def\untrace{\tracingcommands0 \tracingmacros0 }
-\restorecatcodes \ No newline at end of file
+\restorecatcodes
diff --git a/Master/texmf-dist/tex/plain/pitex/references.ptx b/Master/texmf-dist/tex/plain/pitex/references.ptx
new file mode 100644
index 00000000000..038b90bc261
--- /dev/null
+++ b/Master/texmf-dist/tex/plain/pitex/references.ptx
@@ -0,0 +1,107 @@
+% This is a mess.
+\def\ptx@label{}%
+\def\label#1{%
+ \ifcs{ptx@label_user:#1}
+ {\ptx@error{Label `#1' already exists. Find another one}}
+ {\global\letcs{ptx@label_user:#1}\relax
+ \ptx@label_write{ptx@ref_user:#1}\ptx@label
+ \ptx@label_write{ptx@ref_chapter:#1}{\usevalue chapter : internalcount }%
+ \ptx@label_write{ptx@ref_section:#1}{\usevalue section : beforenumber \usevalue section : internalcount }%
+ \ptx@label_write{ptx@ref_subsection:#1}{\usevalue subsection : beforenumber \usevalue subsection : internalcount }%
+ \ptx@label_write{ptx@ref_paragraph:#1}{\usevalue paragraph : beforenumber \usevalue paragraph : internalcount }%
+ \iffootnote
+ \ptx@label_write{ptx@ref_footnote:#1}{\the\ptx@footnote_count}%
+ \fi
+ \ptx@write_toaux*{\defcs{ptx@ref_page:#1}{\the\pageno}}}%
+ }
+\def\ptx@label_with#1[#2]{%
+ \def\ptx@label{#1}%
+ \label{#2}%
+ \ignorespaces
+ }
+\def\ptx@label_and#1[#2]{%
+ \label{#2}%
+ #1%
+ }
+\def\ptx@label_withand#1#2[#3]{%
+ \ptx@label_with#1[#3]%
+ #2%
+ }
+\newif\ifptx@rerun
+\def\ptx@rerun{%
+ \unless\ifptx@rerun
+ \global\ptx@reruntrue
+ \ptx@warn{You need a rerun.}%
+ \fi
+ }
+\def\ptx@label_write#1#2{%
+ \unless\ifptx@rerun
+ \edef\ptx@temp{#2}%
+ \ifcs{#1}
+ {\passexpanded{\passexpandedcs{\reverse\iffstring}{#1}}\ptx@temp\ptx@rerun}
+ {\ptx@rerun}%
+ \fi
+ \ptx@write_toaux{\defcs{#1}{#2}}%
+ }
+
+
+
+\def\ref{%
+ \ifnextnospace[
+ {\ptx@ref_getpre}
+ {\ptx@ref_getpre[]}%
+ }
+\def\ptx@ref_getpre[#1]{%
+ \ifnextnospace[
+ {\ptx@ref_getpost{#1}}
+ {\ptx@ref_getpost{#1}[]}%
+ }
+\def\ptx@ref_getpost#1[#2]#3#{%
+ \passtrim{#3}{\ptx@ref_do{#1}{#2}}%
+ }
+\def\ptx@ref_do#1#2#3#4{%
+ \ifcs{ptx@ref_user:#4}
+ {\ifemptystring{#3}
+ {\ptx@ref_typeset{\usecs{ptx@ref_user:#4}}}
+ {\ifstring{#3}{page}\ptx@refpage_typeset\ptx@ref_typeset{\usecs{ptx@ref_#3:#4}}}
+ {#1}{#2}}
+ {??\ptx@rerun}%
+ }
+\protected\def\ptx@ref_typeset#1#2#3{#2#1#3}
+\newcount\ptx@ref_pagerefcount
+\protected\def\ptx@refpage_typeset#1#2#3{%
+ \global\advance\ptx@ref_pagerefcount1
+ \ifcs{ptx@pageref_number:\the\ptx@ref_pagerefcount}
+ {\unless\ifnum\usecs{ptx@pageref_number:\the\ptx@ref_pagerefcount}=#1\relax
+ #2#1#3%
+ \fi}
+ {??\ptx@rerun}%
+ \expandafter\ptx@pageref_write\expandafter{\the\ptx@ref_pagerefcount}%
+ }
+\def\ptx@pageref_write#1{%
+ \ptx@write_toaux*{\defcs{ptx@pageref_number:#1}{\the\pageno}}%
+ }
+
+\let\xref\ref
+\def\sref{\unskip\ref[ section~][] section}
+\def\Sref{\unskip\ref[ section~][] subsection}
+\def\cref{\unskip\ref[ chapitre~][] chapter}
+\def\pref{\unskip\ref[ (p.~][)] page}
+\def\Pref{\unskip\ref[ p.~][] page}
+\def\fref{\unskip\ref[ figure~][]}
+\def\Fref#1{\fref{#1}\pref{#1}}
+\def\tref{\unskip\ref[ tableau~][]}
+\def\Tref#1{\tref{#1}\pref{#1}}
+\def\fnref{\unskip\ref[ note~][] footnote}
+\def\FNref#1{\fnref{#1}\pref{#1}}
+\def\multiref#1"#2"{%
+ \passtrim{#1}{\ptx@multiref_loop{first}{#2}}%
+ }
+\def\ptx@multiref#1#2#3{%
+ \ptx@multiref_loop{#2}{#3}{#1}%
+ }
+\newfor\ptx@multiref_loop{2}#3{%
+ \reverse\iffstring{#1}{first}{, }%
+ \usecs{#3ref}{#2}%
+ \passarguments{}{#2}
+ }
diff --git a/Master/texmf-dist/tex/plain/pitex/sections.ptx b/Master/texmf-dist/tex/plain/pitex/sections.ptx
index 1c56112bdac..a6d1f954319 100644
--- a/Master/texmf-dist/tex/plain/pitex/sections.ptx
+++ b/Master/texmf-dist/tex/plain/pitex/sections.ptx
@@ -1,144 +1,180 @@
-\def\ptx@bookmark_list{}
-\def\ptx@bookmark_stack{}
-\def\createbookmark{%
- \ifnextnospace[{\ptx@createbookmark}{\ptx@createbookmark[]}%
- }
-\def\ptx@createbookmark[#1]#2#3#4{%
- \passexpanded{\ptx@bookmark_add{#2}{{#3}{#4}{#1}}}\ptx@bookmark_stack
- }
-\bgroup
-\setcatcodes{\{\}=12,<=1,>=2}
-\gdef\ptx@leftbrace<{>
-\gdef\ptx@rightbrace<}>
-\egroup
-\newfor\ptx@bookmark_add{2}#3,{%
- \straightenif{ifdim}{#1pt>#3pt }
- {\eaddright\ptx@bookmark_list{#2\ptx@leftbrace}
- \retrieverest{\ptx@bookmark_addtostack{#1,#3,}}}
- {\eaddright\ptx@bookmark_list{\ptx@rightbrace,}}
- }[\eaddright\ptx@bookmark_list{#2\ptx@leftbrace}
- \ptx@bookmark_addtostack{#1,}{}]
-\def\ptx@bookmark_addtostack#1#2{\def\ptx@bookmark_stack{#1#2}}
-\newfor\ptx@bookmark_endlist#1,{%
- \eaddright\ptx@bookmark_list{\ptx@rightbrace,}%
- }
-\newfor\ptx@bookmark_process#1#2#3#4,{%
- \ptx@bookmark_subcount{0}{#1}{#2}{#3}{#4}%
- \reverse\iffemptystring{#4}{\ptx@bookmark_process{#4}}%
- }
-\newfor\ptx@bookmark_subcount{4}#5,{%
- \passarguments{#1+1}{#2}{#3}{#4}
- }[\def\ptx@bookmark_sign{-}%
-% \def\ptx@bookmark_options{}%
-% \ptx@option_launchloop{bookmark}{#4}%
- \pdfoutline attr {#4} goto name {#3} count \ptx@bookmark_sign\the\numexpr(#1) {#2}%
- ]
-\def\processbookmarks{%
- \reverse\iffemptycommand\ltr@bookmark_list{%
- \expandafter\ptx@bookmark_endlist\expandafter{\ptx@bookmark_stack}
- \bgroup
- \setcatcodes{_@=11}
- \scantokens\expandafter{\expandafter\gdef\expandafter\ptx@bookmark_list\expandafter{\ptx@bookmark_list}}%
- \egroup
- \expandafter\ptx@bookmark_process\expandafter{\ptx@bookmark_list}}
+\newcount\ptx@penalty
+\ptx@penalty=-10000
+
+\def\newbreakpenalty#1{%
+ \advance\ptx@penalty-1
+ \edef#1{\the\ptx@penalty\relax}
}
-%\let\ptx@end\end
-%\def\end{\processbookmarks\ptx@end}
-%
-\newcount\ptx@section_link
-\let\sectionaction\unbrace
-\def\tosection#1#2{%
- \reverse\iffcs{ptx@section_dest:#1}
- {\global\advance\ptx@section_link1
- \xdefcs{ptx@section_dest:#1}{\the\ptx@section_link}}%
- \sectionaction{\pdfstartlink attr {/Border [0 0 0]} goto name {ptx@section_link:\usecs{ptx@section_dest:#1}}#2\pdfendlink}%
+
+\newbreakpenalty\clearpagepenalty
+\def\clearpage{\vfil\penalty\clearpagepenalty}
+
+\newbreakpenalty\breakpagepenalty
+\def\breakpage{\vfil\penalty\breakpagepenalty}
+
+\def\whitepage{\clearpage\shipout\hbox{}\advancepageno}
+
+% TODO: Rewrite in Lua.
+\def\needspace#1{%
+ \par\penalty0
+ \ifdim\dimexpr\pagegoal-\pagetotal<\dimexpr#1\relax
+ \breakpage
+ \fi
+ }
+
+\def\iflines#1{%
+ \par\penalty0
+ \ifdim\dimexpr(\pagegoal-\pagetotal) < \numexpr(#1)\baselineskip
+ \expandafter\secondoftwo
+ \else
+ \expandafter\firstoftwo
+ \fi}
+
+\long\def\ignorepars#1{%
+ \ifxnextnospace\par
+ {\gobbleoneand{\ignorepars{#1}}}
+ {#1}%
}
-\newcount\ptx@section_skip % A count, since vertical skips are expressed in number of lines.
\def\sectioncommand#1#2#3{%
\ifnext[
{\ptx@sectioncommand{#1}{#2}{#3}}
- {\ptx@sectioncommand{#1}{#2}{#3}[ptx@noop]}%
+ {\ptx@sectioncommand{#1}{#2}{#3}[]}%
}
\def\ptx@sectioncommand#1#2#3[#4]{%
- \par\removelastskip\penalty0
- \ifvalue #1 : clear = true
- {\vfil\penalty-10000}% Clear the page...
- {% Or skip some lines. The "beforeskip" attribute is
- % the number of blank lines one wants before a section
- % title, afterskip is the same thing after,
- % and "minimum" is the minimum number of lines
- % one wants after the section title.
- \ifdim\dimexpr(\pagegoal-\pagetotal) < \numexpr(\usevalueor #1 : beforeskip 0+\usevalueor #1 : afterskip 0+\usevalueor #1 : minimum 0) \baselineskip
- \vfil\penalty-10000 % Not enough room.
- \else
- \vskip\usevalueor #1 : beforeskip 0 \baselineskip
- \fi}%
-%
-% Sections have an internal count, incremented here.
- \storevalueor\ptx@tempsectioncount #1 : internalcount {\def\ptx@tempsectioncount{0}}%
- \esetattribute #1 : internalcount = {\the\numexpr(\ptx@tempsectioncount+1)}
- \resetbelow{#1}% Resets all internal counts of sections which depend on the current one (i.e. "section" depends on "chapter", etc.).
-%
-%
- \ptx@attribute_set{section}%
- \ifvalue #1 : link = true {%
- \ifcs{ptx@section_dest:#4}
- {\edef\ptx@temp{ptx@section_link:\usecs{ptx@section_dest:#4}}}
- {\global\advance\ptx@section_link1
- \edef\ptx@temp{ptx@section_link:\the\ptx@section_link}%
- \reverse\iffstring{#4}{ptx@noop}{\xdefcs{ptx@section_dest:#4}{\the\ptx@section_link}}}%
- \pdfdest name {\ptx@temp} xyz
- \passexpanded{\createbookmark[\usevalue #1 : bookmarkstyle ]{\usevalueor #1 : bookmarklevel 0}{\detokenize{#2}}}{\ptx@temp}%
- }{}%
- \noindent
- \hskip\usevalueor #1 : indent {0pt}%
- \bgroup
- \ifattribute #1 : color {\pdfcolorstack0 push {\usevalueand #1 : color { rg}{} \usevalueand #1 : color { RG}{}}}{}%
- \usevalue #1 : font
- \ifvalue #1 : number = none {}{%
- \usevalue #1 : beforenumber
- \ifcasevalue #1 : number
- \val roman \makeroman
- \val arabic \unbrace
- \endval{\usevalue #1 : internalcount }%
- \usevalue #1 : afternumber
- }%
- #3%
- \ifattribute #1 : color {\pdfcolorstack0 pop}{}
- \egroup
- \ifvalue #1 : inline = true
- {}
- {\vskip\usevalueor #1:afterskip 0\baselineskip}%
- \ptx@attribute_unset{section}%
- }
-\newwhile\resetbelow1{}{%
- \ifattribute #1 : below
- {\storevalue\tempbelow #1 : below
- \esetattribute\tempbelow : internalcount = 0
- \passvalue{\changewhile} #1 : below
- }{\breakwhile{}}%
+ \Section execute {section}{#1}{#2}{#3}{#4}%
+ \ignorepars{}%
}
\def\makeroman#1{%
\uppercase\expandafter{\romannumeral#1\relax}%
}
+\newif\ifsectiontitle
+
+\luacode
+pitex.sections = { sections = {} }
+function pitex.sections.increment (type)
+ local n = type
+ type = pitex.sections.sections[type] or { num = 0 }
+ type.num = type.num + 1
+ local level = type.level
+ if level then
+ for name, tb in pairs(pitex.sections.sections) do
+ tb.num = tb.level > level and 0 or tb.num
+ end
+ end
+end
+function pitex.sections.counter (type)
+ type = pitex.sections.sections[type]
+ return type and type.num or -1
+end
+\luacode/
+
+\def\declaresection#1#2{%
+ \ptx@lua{pitex.sections.sections.#1 = {num = 0, level = #2}}%
+ }
+
+\def\incrementsection#1{%
+ \ptx@lua{pitex.sections.increment("#1")}%
+ }
+
+\def\getsectioncounter#1{%
+ \ptx@lua{tex.print(pitex.sections.counter ("#1"))}%
+ }
+
+%%% Gates in section %%%
+
+\gates new \Section {Section}
+\Section list {section} [4]
+ (section_break) [2]
+ . [section_vmode] [1] ?{conditional = \ifvalue #1 : vmode = true } {\par\removelastskip\penalty0 }
+ . [section_clearpage] [1] ?{conditional = \ifvalue #1 : clear = true } {\clearpage}
+ . [section_beforeskip] [2] ?{conditional = -\ifvalue #1 : clear = true }
+ {% Or skip some lines. The "beforeskip" attribute is
+ % the number of blank lines one wants before a section
+ % title, afterskip is the same thing after,
+ % and "minimum" is the minimum number of lines
+ % one wants after the section title.
+ \ifexpression{%
+ -\ifdim\dimexpr(\pagegoal-\pagetotal) < 0pt &
+ \ifdim\dimexpr(\pagegoal-\pagetotal) < \numexpr(\usevalueor #1 : beforeskip 0+\usevalueor #1 : afterskip 0+\usevalueor #1 : minimum 0) \baselineskip}
+ {\breakpage} % Not enough room.
+ {\passvaluenobracesand\vskip #1 : beforeskip \baselineskip{}}}
+%
+ [section_advance] [1] {\incrementsection{#1}}
+%
+ [section_bookmark] [4] ?{conditional = \ifvalue #1 : link = true } {%
+ \passvalueand{\outline[meta = #1bookmark]} #1 : bookmarklevel {[#4]{#3}}{}}
+%
+ [section_toc] [3] ?{conditional = \ifvalue #1 : toc = true } {%
+ \edef\ptx@temp{{#1}{\ifvalue #1 : number = none {}{\getsectioncounter{#1}}}{\unexpanded{\unexpanded{#3}}}{\the\pageno}}%
+ \expandafter\writeout\expandafter*\expandafter{\expandafter\noexpand\expandafter\ptx@toc\ptx@temp}}
+%
+ [section_pre] {%
+ \bgroup
+ \maintextfalse
+ \sectiontitletrue
+ \ptx@section_attribute=0\relax}
+%
+ (section_typeset) [2]
+ . [section_number] [2] {%
+ \ifvalue #1 : number = none
+ {\Section return3 {#1}{}{#2}}
+ {\Section return3
+ {#1}
+ {\usevalueor #1 : numbercommand \unbrace
+ {\usevalue #1 : beforenumber
+ \ifcasevalue #1 : number
+ \val roman \makeroman
+ \val arabic \unbrace
+ \endval{\getsectioncounter{#1}}%
+ \usevalue #1 : afternumber }}
+ {#2}}}
+%
+ . [section_heading] [3] {%
+ \Section return2 {#1}{#2\usevalueor #1 : function \unbrace{#3}\usevalue #1 : aftertitle }}
+%
+ . [section_addfont] [2] {\Section return {#1}{\usevalue #1 : font #2}}
+%
+ . [section_addcolor] [2] ?{conditional = \ifattribute #1 : color } {%
+ \Section return {#1}{\passvalueand\color #1 : color {{#2}}{}}}
+%
+ . [section_do] [2] {%
+ \noindent
+ \settovalue\hskip #1 : indent
+ #2%
+ \ifvalue #1 : inline = true {}{\settovalue\rightskip #1 :ragged \endgraf}}
+%
+ [section_post] {\egroup}
+%
+ [section_afterskip] [1] ?{conditional = -\ifvalue #1 : inline = true } {%
+ \vskip\usevalueor #1 : afterskip 0\baselineskip
+ \ifvalue #1 : removenextindent = true {\removenextindent}{}}
+
\setparameter metasection :
- clear = false
- minimum = 3
- inline = false
- number = arabic
- link = true
- afternumber = "\kern.3em"
+ clear = false
+ vmode = true
+ minimum = 3
+ inline = false
+ number = arabic
+ afternumber = "\kern.3em"
+ link = true
+ ragged = 0pt
+ toc = true
+ removenextindent = true
+
+\declaresection {chapter} 1
+\declaresection {section} 2
+\declaresection {subsection} 3
+\declaresection {paragraph} 4
-\setparameter chapter section subsection :
- meta = metasection
+\setparameter chapter section subsection paragraph:
+ meta = metasection
\setparameter chapter :
clear = true
number = arabic
- below = section
afterskip = 3
indent = "0pt plus 1fill"
beforenumber = "chapitre "
@@ -147,25 +183,66 @@
\setparameter section :
beforeskip = 2
- below = subsection
bookmarklevel = 2
-\setparameter subsection :
+\setparameter subsection paragraph:
font = \it
beforeskip = 1
- beforenumber = "\usevalue section:internalcount ."
+
+\setparameter subsection:
+ beforenumber = "\getsectioncounter{section}."
minimum = 3
bookmarklevel = 3
+\setparameter paragraph:
+ beforenumber = "\getsectioncounter{section}.\getsectioncounter{subsection}."
+ minimum = 2
+ inline = true
+ aftertitle = ".\hskip.333em"
+ bookmarklevel = 4
+
+\setparameter chapterbookmark sectionbookmark subsectionbookmark paragraphbookmark:
+ meta = navigator
+
\def\chaptertitle{}%
-\def\chapter#1{%
- \def\chaptertitle{#1}%
+\freedef\chapter{%
\sectioncommand{chapter}{#1}{#1}%
}
-\def\section#1{\sectioncommand{section}{#1}{#1}}
-\def\subsection#1{\sectioncommand{subsection}{#1}{#1}}
+\freedef\section{\sectioncommand{section}{#1}{#1}}
+\freedef\subsection{\sectioncommand{subsection}{#1}{#1}}
+\freedef\paragraph{\sectioncommand{paragraph}{#1}{#1}}
-\newattribute{section}
+\newif\ifptx@sectioninfile
+\def\sectioninfile{%
+ \ifnextnospace*
+ {\ptx@sectioninfilefalse
+ \gobbleoneand\ptx@sectioninfile}
+ {\ptx@sectioninfiletrue
+ \ptx@sectioninfile}%
+ }
+
+\freedef\ptx@sectioninfile{%
+ \ptx@sectioninfile_do{#1}%
+ }
+\def\ptx@sectioninfile_do#1 #2 #3 {%
+ \sectioncommand{#2}{#1}{#1}%
+ \ptx@section_getlabel{#3}%
+ \ifptx@sectioninfile
+ \input #3\relax
+ \fi
+ }
+\newstring/
+\newwhile\ptx@section_getlabel1{#1}{%
+ \ifcontains/{#1}%
+ {\splitstringat/{#1}{\gobbleoneand\changewhile}}
+ {\label{#1}\breakwhile}%
+ }
+\freedef\ptx@sectioninfile_gobble{%
+ \ptx@sectioninfile_gobblerest
+ }
+\def\ptx@sectioninfile_gobblerest#1 #2 #3 {}
+
+\newattribute\ptx@section_attribute
%
% Move pending titles if they happen. They shouldn't by themselves,
% but the next paragraph might want more room than available
@@ -177,41 +254,79 @@
% TeX-inserted (e.g. \baselineskip).
% This is probably totally insufficient.
%
-\directlua{%
- onelineskip = node.new(11)
- onelineskip.kern = tex.baselineskip.width
- move_pendingtitles = function (head)
- local item, first = node.slide(head), true
- while item do
- if node.has_attribute(item,\ptx@attribute_number{section}) then
- local nextitem = item.prev
- node.remove(head,item)
- if not ((item.id == 10 or item.id == 11) and first) then
- node.insert_before(tex.lists.contrib_head, tex.lists.contrib_head, item)
- tex.lists.contrib_head = item
- end
- if item.id == 0 then
- if first then
- first = false
- if not (tex.lists.contrib_head.next.id == 10 and tex.lists.contrib_head.next.subtype == 0) then
- node.insert_after(tex.lists.contrib_head, item, node.copy(onelineskip))
- lualog("A title has been moved from page " .. tex.count[0] ..
- " to page " .. tex.count[0]+1 .. ".")
- end
+\luacode
+onelineskip = node.new(11)
+onelineskip.kern = tex.baselineskip.width
+remove_pendingtitles = function (head)
+ local item, first = node.slide(head), true
+ while item do
+ if node.has_attribute(item,\attributenumber\ptx@section_attribute) then
+ local nextitem = item.prev
+ node.remove(head,item)
+ if not ((item.id == 10 or item.id == 11) and first) then
+ node.insert_before(tex.lists.contrib_head, tex.lists.contrib_head, item)
+ tex.lists.contrib_head = item
+ end
+ if item.id == 0 then
+ if first then
+ first = false
+ if not (tex.lists.contrib_head.next.id == 10 and tex.lists.contrib_head.next.subtype == 0) then
+ node.insert_after(tex.lists.contrib_head, item, node.copy(onelineskip))
+ lualog("A title has been moved from page " .. tex.count[0] ..
+ " to page " .. tex.count[0]+1 .. ".")
end
- else
end
- item = nextitem
else
- if item.id == 0 or item.id == 1 then
- item = nil
- else
- item = item.prev
- end
+ end
+ item = nextitem
+ else
+ if item.id == 0 or item.id == 1 then
+ item = nil
+ else
+ item = item.prev
end
end
end
- }
+end
+\luacode/
+
\def\removependingtitles{%
- \directlua{move_pendingtitles(tex.box[255].list)}%
- } \ No newline at end of file
+ \ptx@lua{remove_pendingtitles(tex.box[255].list)}%
+ }
+
+
+% ToC: this is an inefficient mess.
+
+\def\ptx@toc_tok{}
+\def\ptx@toc#1#2#3#4{%
+ \addright\ptx@toc_tok{%
+ \usecs{ptx@toc_item:#1}{#2}{#3}{#4}}%
+ }
+
+\def\tableofcontents{%
+ \bgroup
+ \parindent=0pt
+ \ifemptycommand\ptx@toc_tok
+ {\ptx@warn{No table of contents.}}
+ {\ptx@toc_tok}%
+ \egroup
+ }
+
+\long\def\ptx@def_tocitem#1#2#3#4{%
+ \defcs{ptx@toc_item:#1}##1##2##3{%
+ \edefcs{ptx@toc_current#1}{##1}%
+ \bgroup\par\quitvmode
+ \leftskip#2\relax
+ \rightskip=0pt plus 1fil
+ #3\reverse\iffemptystring{##1}{\llap{#4##1\kern1em}}%
+ ##2\leaders\hbox{. }\hfill\hbox to .8cm{\hfil##3}\par
+ \egroup}%
+ }
+
+\ptx@def_tocitem{chapter}{0pt}{\big\bf\sc}{}
+\ptx@def_tocitem{section}{1cm}{\sc}{}
+\ptx@def_tocitem{subsection}{2cm}{\it}
+ {\reverse\iffemptycs{ptx@toc_currentsection}{\usecs{ptx@toc_currentsection}.}}
+\ptx@def_tocitem{paragraph}{3cm}{}
+ {\reverse\iffemptycs{ptx@toc_currentsection}{\usecs{ptx@toc_currentsection}.}%
+ \reverse\iffemptycs{ptx@toc_currentsubsection}{\usecs{ptx@toc_currentsection}}.}
diff --git a/Master/texmf-dist/tex/plain/pitex/verbatim.ptx b/Master/texmf-dist/tex/plain/pitex/verbatim.ptx
new file mode 100644
index 00000000000..a4e2a7ed2b3
--- /dev/null
+++ b/Master/texmf-dist/tex/plain/pitex/verbatim.ptx
@@ -0,0 +1,128 @@
+% Verbatim facilities.
+\newcatcodetable\verbcatcodes{\\\{\}\$\&\#\^\_\~\%=12,\ \^^M=13}
+
+\def\verb#1{%
+ \def\ptx@verb##1#1{\ptx@verb_punc{}{##1}\egroup}%
+ \bgroup
+ \catcodetable\verbcatcodes
+ \iffcommand\codefont\codefont
+ \ptx@verb
+ }
+
+% Hack to prevent French spacing before punctuation. I should find
+% something better (attributes marking material to be left alone when
+% the French punctuation kicks in in the "kerning" callback).
+\def\ptx@verb_punc#1#2{%
+ \ifelseif{%
+ {\ifcontains:{#2}} {\splitstringat:{#2}{\ptx@verb_glue{#1}:}}
+ {\ifcontains;{#2}} {\splitstringat;{#2}{\ptx@verb_glue{#1};}}
+ {\ifcontains!{#2}} {\splitstringat!{#2}{\ptx@verb_glue{#1}!}}
+ {\ifcontains?{#2}} {\splitstringat?{#2}{\ptx@verb_glue{#1}?}}
+ \iftrue {#1#2}}%
+ }
+\def\ptx@verb_glue#1#2#3#4{%
+ \ptx@verb_punc{#1#3\kern0pt#2}{#4}%
+ }
+
+\bgroup
+\setcatcodes{\ \^^M=13}%
+\gdef {\quitvmode\spacecs}%
+\gdef^^M{\quitvmode\par}%
+\egroup
+
+\def\tcode#1{{\codefont#1}}
+\long\def\com#1{%
+ \bgroup
+ \codefont
+ \string#1%
+ \egroup
+ \antigobblespace
+ }
+\freedef\arg{{\codefont\it<#1>}\iffnext\spacechar{\kern.2ex }}
+\freedef\barg{{\codefont\char"007B\relax\arg{#1}\char"007D\relax}}
+\freedef\oarg{{\codefont[\arg{#1}]}}
+
+\luacode
+pitex.verbatims = {}
+local function prepare_verbatim (chunk, name)
+ return function (str)
+ if not str:match("^%s*\noexpand\\" .. chunk .. "/") then
+ table.insert(pitex.verbatims[name], str)
+ return "%"
+ else
+ pitex.callback.remove("process_verbatim", "process_input_buffer")
+ return "\noexpand\\usecs{ptx@inner_verbatimstop:" .. chunk .. "}"
+ end
+ end
+end
+
+function install_verbatim (chunk, regime, name)
+ pitex.verbatims[name] = { regime = regime }
+ pitex.callback.process_verbatim = prepare_verbatim(chunk, name)
+ pitex.callback.register("process_input_buffer", "process_verbatim")
+end
+
+function do_verbatim(name, exec)
+ if exec then
+ tex.print(pitex.verbatims[name])
+ else
+ tex.print(pitex.verbatims[name].regime, pitex.verbatims[name])
+ end
+end
+\luacode/
+
+\def\ptx@verbatim_last{}
+
+\def\newverbatim#1{%
+ \ifnext[
+ {\ptx@newverbatim#1}
+ {\ptx@newverbatim#1[\verbcatcodes]}%
+ }
+
+\long\def\ptx@newverbatim#1[#2]#3#4{%
+ \edef#1{%
+ \bgroup\primunexpanded{#3}%
+ \bgroup\primunexpanded{\setcatcodes{\^^M=12}}%
+ \noexpand\ptx@verbatim{\commandtoname#1}{#2}}%
+ \defcs{ptx@inner_verbatimstop:\commandtoname#1}{#4\egroup}%
+ }
+
+\bgroup
+\setcatcodes{\^^M=12}%
+\gdef\ptx@verbatim#1^^M{%
+ \egroup%
+ \ptx@verbatim_prepare#1\relax%
+ }%
+\egroup
+
+\def\ptx@verbatim_prepare#1#2{%
+ \ifnext[
+ {\ptx@verbatim_do{#1}{#2}}
+ {\ptx@verbatim_do{#1}{#2}[last]}%
+ }
+
+\def\ptx@verbatim_do#1#2[#3]{%
+ \gdef\ptx@verbatim_last{#3}%
+ \directlua{install_verbatim("#1", \the#2, "#3")}%
+ }
+
+\newverbatim\verbatim{}
+ {\codefont\parindent0pt %\hsize=\maxdimen
+ \directlua{pitex.callback.close("french_punctuation", "kerning")}\relax
+ \vskip\baselineskip\printverbatim\relax
+ \directlua{pitex.callback.open("french_punctuation", "kerning")}
+ \vskip\baselineskip\removenextindent}
+
+\def\doverbatim{%
+ \ifnext[
+ {\ptx@doverbatim{true}}
+ {\ptx@doverbatim{true}[\ptx@verbatim_last]}%
+ }
+\def\printverbatim{%
+ \ifnext[
+ {\ptx@doverbatim{nil}}
+ {\ptx@doverbatim{nil}[\ptx@verbatim_last]}%
+ }
+\def\ptx@doverbatim#1[#2]{%
+ \directlua{do_verbatim("#2", #1)}%
+ }