diff options
18 files changed, 4100 insertions, 546 deletions
diff --git a/Master/texmf-dist/doc/plain/pitex/README b/Master/texmf-dist/doc/plain/pitex/README index 0322fcdc5a3..13fd5c71927 100644 --- a/Master/texmf-dist/doc/plain/pitex/README +++ b/Master/texmf-dist/doc/plain/pitex/README @@ -3,22 +3,36 @@ typeset documentations for my packages (that's why it is 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. -The file is supposed to be \input on plain TeX with LuaTeX, at least v.0.6. - +The file is supposed to be \input on plain TeX with LuaTeX, at least v.0.7. The files needed are: -texapi.tex (an independent package) -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, like most files here anyway) +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. -Licensing of these files is covered by LPPL.
\ No newline at end of file +Licensing of these files is covered by LPPL. diff --git a/Master/texmf-dist/doc/plain/pitex/foundry-settings.lua b/Master/texmf-dist/doc/plain/pitex/foundry-settings.lua new file mode 100644 index 00000000000..5c24caa9378 --- /dev/null +++ b/Master/texmf-dist/doc/plain/pitex/foundry-settings.lua @@ -0,0 +1,19 @@ +return { + + features = { + kern = true, + liga = true, + trep = true, + tlig = true, + script = "latn", + lang = "dflt", + --stretch = 30, + --shrink = 20, + --step = 10, + }, + + normal = { + "Normal", "Regular", "Book", + }, + +} diff --git a/Master/texmf-dist/doc/plain/pitex/i-pitex.lua b/Master/texmf-dist/doc/plain/pitex/i-pitex.lua new file mode 100644 index 00000000000..4559a1901db --- /dev/null +++ b/Master/texmf-dist/doc/plain/pitex/i-pitex.lua @@ -0,0 +1,163 @@ +local gsub, match, gmatch = string.gsub, string.match, string.gmatch +local insert = table.insert +local add_pattern = interpreter.add_pattern + +-- CLASS 1: things that prevent other things, thanks to protection. +interpreter.default_class = 1 + +-- "> foo ..." as the first line of a paragraph signals a description +-- of foo. +local function describe (buffer, num) + if num == 1 then + local line = buffer[num] + line = line .. " " + line = gsub(line, "^> ", "") + line = gsub(line, "{<(.-)>}", "\\hskip1pt\\hbox{\\barg{%1}}") + line = gsub(line, "^(.-)%s+", "\\describe{%1}{") + line = gsub(line, "%[<(.-)>%]", "\\hskip1pt\\hbox{\\oarg{%1}}") + line = gsub(line, "<(.-)>", "\\hskip1pt\\hbox{\\arg{%1}}") + line = gsub(line, "\\hfil", "", 1) + line = gsub(line, "%s*$", "}", 1) + buffer[num] = line + interpreter.protect(num) + else + return 2 + end +end +add_pattern{pattern = "^[\\>]", call = describe} + +-- Verbatim material is marked by a 10-space indent. +local function verbatim (buffer) + for n, l in ipairs(buffer) do + buffer[n] = gsub(l, "%s%s%s%s%s%s%s%s%s%s","", 1) + end + insert(buffer, 1, [[\verbatim]]) + if gsub(buffer[#buffer], + interpreter.paragraph, "") == "" then + buffer[#buffer] = [[\verbatim/]] + else + insert(buffer, [[\verbatim/]]) + end + interpreter.protect() +end +add_pattern{pattern = "^%s%s%s%s%s%s%s%s%s%s", call = verbatim} + +-- CLASS 2: protecting control sequences, so they're verbatim. +interpreter.default_class = 2 +add_pattern { + pattern = "(\\[%a@]+)", + replace = '"%1"'} + + +-- CLASS 3: things that precede other things. +interpreter.default_class = 3 + +-- Tables. +local function table (buffer) + buffer[1] = "PROTECT\\tablePROTECT" + if buffer[#buffer] == "" then + buffer[#buffer-1] = "PROTECT\\table/PROTECT" + else + buffer[#buffer] = "PROTECT\\table/PROTECT" + end + local cells = 0 + for i, l in ipairs(buffer) do + if match(l, "^%-%-%-") then + l = "%" + else + l = gsub(l, "^|", "") + l = gsub(l, "|%s*$", "PROTECT\\crPROTECT") + local c = 0 + l = gsub(l, "|", function () c = c + 1 return "&" end) + cells = c > cells and c or cells + end + buffer[i] = l + end + for i, l in ipairs(buffer) do + if match(l, "\\cr") then + local c = 0 + for tab in gmatch(l, "&") do + c = c + 1 + end + for x = 1, cells - c do + buffer[i] = gsub(l, "\\cr", "\\span\\cr") + end + end + end +end +add_pattern{pattern = "^%-%-%-", call = table} + +-- Sections. +local function make_header(buffer, num, _, pattern) + if num + 1 == #buffer then + local l = buffer[1] + l = gsub(l, "^%s*", "") + l = "\\" .. pattern.type .. "{" .. l + if match(l, ":([%S]+)%s*$") then + l = gsub(l, "%s*:([%a_]+)%s*$", "}PROTECT[%1]PROTECT") + else + l = l .. "}" + end + buffer[1] = l + buffer[num] = "" + end +end +add_pattern {pattern = "^%s*===", call = make_header, type = "section"} +add_pattern {pattern = "^%s*~~~", call = make_header, type = "subsection"} +add_pattern {pattern = "^%s%s%s*%-%-%s+(.-)%s+%-%-", + call = function (buffer, line, _, pattern) + buffer[line] = gsub(buffer[line], pattern.pattern, "\\paragraph{%1}") + buffer[line] = gsub(buffer[line], "%s*:(%S+)", "PROTECT[%1]PROTECT") + end} + + +-- CLASS 4: things with no order of preference. +interpreter.default_class = 4 + +add_pattern {pattern = "%*(.-)%*", replace = "\\emph{%1}"} +add_pattern {pattern = "%*%*(.-)%*%*", replace = "\\bold{%1}"} +add_pattern {pattern = "%?([a-zA-Z]+)", replace = "\\attr{%1}"} +add_pattern {pattern = "!([a-zA-Z]+)", replace = "\\param{%1}"} +add_pattern {pattern = "=([a-zA-Z]+)", replace = "\\value{%1}"} +add_pattern {pattern = "|(.-)|", replace = "\\gateaction{%1}"} +add_pattern {pattern = "<(.-)>", replace = "\\arg{%1}"} +add_pattern {pattern = "{<(.-)>}", replace = "\\barg{%1}", offset = 7} +add_pattern {pattern = "%[<(.-)>%]", replace = "\\oarg{%1}", offset = 7} +add_pattern {pattern = "TeX", replace = "\\TeX{}", offset = 2} + +add_pattern {pattern = "(texapi)(.?)", offset = 7, + replace = function (a, b) + a = "\\emph{texapi}" + if b == "'" then + a = a .. "\\kern.2em'" + else + a = a .. b + end + return a + end} + +-- Links. +add_pattern {pattern = "%s*%[see%s+([%a_]+)%]", + call = function (buffer, line, index, pattern) + local l = buffer[line] + local pre, post = l:sub(1, index-1), l:sub(index) + local text + if pre:match("{.-}$") then + pre, text = match(pre, "(.*){(.-)}$") + else + pre, text = match(pre, "(.-)(%a+)$") + end + post = gsub(post, pattern.pattern, "\\jumplink{PROTECT%1PROTECT}{" .. text .. "}", 1) + buffer[line] = pre .. post + end} +add_pattern {pattern = ":([%a_]+)", replace = "\\anchor{PROTECT%1PROTECT}"} + + +-- CLASS 0: the broom wagon +interpreter.default_class = 0 + +interpreter.protector('"') +add_pattern {pattern = '"(.-)"', replace = "\\verb`%1`", class = 0} + +interpreter.protector("PROTECT") +add_pattern {pattern = "PROTECT(.-)PROTECT", replace = "%1", class = 0} diff --git a/Master/texmf-dist/doc/plain/pitex/pitex-doc.pdf b/Master/texmf-dist/doc/plain/pitex/pitex-doc.pdf Binary files differnew file mode 100644 index 00000000000..dbcbfa7e96e --- /dev/null +++ b/Master/texmf-dist/doc/plain/pitex/pitex-doc.pdf diff --git a/Master/texmf-dist/doc/plain/pitex/pitex-doc.tex b/Master/texmf-dist/doc/plain/pitex/pitex-doc.tex new file mode 100644 index 00000000000..63c6281717d --- /dev/null +++ b/Master/texmf-dist/doc/plain/pitex/pitex-doc.tex @@ -0,0 +1,106 @@ +\input pitex + +\setparameter document : + author = "Paul Isambert" + title = "The PiTeX documentation" + date = "November 2011" + layout = onecolumn + mode = bookmarks + +\setparameter page: + height = 24cm + left = 4cm + hsize = 32pc + +\setfont\mainfont : + name = "Chaparral Pro" + size = 10pt + bold = Semi + big = 50pt + +\setfont\codefont : + name = "Lucida Console" + size = 8pt + slant = .15 + features = "space = mono" + bold italic = none + +\setparameter marginnote: + baselineskip = 9pt + font = "\small\it" + +\setparameter section: + font = \sc + + +\OutputRoutine remove {headers, inserts}{shipout} + +\newblock\table + {\ifdim\lastskip=\baselineskip + \needspace{2\baselineskip}% + \else + \needspace{3\baselineskip}% + \vskip\baselineskip + \fi + \halign\bgroup##\unskip\hfil&&\kern1em##\unskip\hfil\cr} + {\egroup + % This is a horrible hack to circumvent a bug in LuaTeX (\prevdepth not + % updated after \halign) (rev 4277). + \directlua{% + local n = tex.lists.page_head + while n.next do + n = n.next + end + tex.nest[tex.nest.ptr].prevdepth = n.depth}% + \vskip\baselineskip + }% + + +\def\describe#1#2{% + \needspace{2\baselineskip}% + \bgroup\codefont + \noindent\color{.8 0 0}{\llap{\string#1\kern.3em}% + #2\par\egroup}\removenextindent + \ignorespaces} + +\def\comarg{\arg{command}\antigobblespace} +\def\textarg{\arg{text}} + +\def\filesection#1{\section{File: \tcode{#1}}} +\pdfdef\verb`#1`{#1} + +\def\attr#1{{\codefont\color{0 .5 0}{#1}}} +\def\param#1{{\codefont\color{.8 0 0}{#1}}} +\def\value#1{{\codefont\color{.3 .3 .6}{#1}}} + +\def\texapi{\emph{texapi}} +\def\navigator{\emph{Navigator}} +\def\tex{\TeX\antigobblespace} + +%%% Redefining \TeX to look better with Chaparral. +\def\TeX{% + T\kern-.13em + \lower.5ex \hbox {E}% + \kern-.03em X% + } + + + + + +\vbox to 50pt{% + \vfil + \hbox{% + \hbox{\big\sc Pi\kern-.08em\TeX}% + \kern1cm + \vbox{% + \hbox{Paul Isambert}% + \hbox{\codefont zappathustra@free.fr}% + \hbox{November 2011}}}% + \vfil + } + +\input interpreter +\interpretfile{pitex}{pitex-doc.txt} + +\bye diff --git a/Master/texmf-dist/doc/plain/pitex/pitex-doc.txt b/Master/texmf-dist/doc/plain/pitex/pitex-doc.txt new file mode 100644 index 00000000000..168e7e7b18a --- /dev/null +++ b/Master/texmf-dist/doc/plain/pitex/pitex-doc.txt @@ -0,0 +1,1057 @@ +Introduction +============ + +If you're reading this, either you saw "\input pitex" at the beginning +of the documentation of one of my packages, or you spend desperate hours +browsing CTAN, or you're Arnaud Schmittbuhl. In any case, you're welcome +to use the PiTeX macros, provided that you don't forget that: nothing +is guaranteed; changes might occur without warning nor retrocompatibility; +the documentation isn't necessarily up-to-date; and, if you still want +to, you must load PiTeX with "\input pitex" on top of plain TeX, using +LuaTeX. + +What is PiTeX? Originally, it was a set of files I loaded with plain TeX +to typeset documentation for my packages. But it's not just a few macros +anymore, but rather a format in progress. The format might never see the +public light, but if it does, its originality (compared to existing +format) will be an organization based on the Gates package: everything +will be highly customizable, not because there are tons of options +(although that can be the case too), but because big operations are +divided into gates, i.e. macros with a handle that you can control without +having to rewrite (nor understand) the big operation you're modifying; +which big operation also keeps its integrity, because removing or adding +something is neatly done. It also means that PiTeX can be changed +piecewise, and made into something that bears little resemblance to the +original code. In other words, there is nothing private, nothing forbidden. +For the moment, only sectionning commands and the output routine, plus +callback management in Lua and \everypar, are written with gates. See +the Gates documentation for further information. + +Another thing with PiTeX is that it will rely heavily on external packages. +There will be as little PiTeX-only code as possible. Rather, in line +with Gates, each area will be independant code able to work with other +formats. That is no simple task, though, and far from complete. For +instance, the user's interface is made with YaX, which can be used (and +is used) elsewhere. + +PiTeX uses three types of files: mandatory external packages, i.e. +independant code that PiTeX can't do without, optional external packages, +i.e. independant code that can be used, but is not automatically loaded, +and mandatory PiTeX-only files. All mandatory files aren't necessary to +the same degree, though, and in the future switches might be available +to load only some of them. Currently, the files are: + +------------------------------------------------------------------ +| **Mandatory external packages** | +------------------------------------------------------------------ +| texapi | Macros to write independant code. | +| YaX | User's interface (and convenient programming tool) | +| | with "key = value" style). | +| Gates | Overall architecture for modular code. | +| Navigator | PDF features (links, bookmarks...) | +| | Currently used by sections, but might become | +| | non-mandatory (although strongly recommended). | +------------------------------------------------------------------ + +--------------------------------------------------------------------------- +| **Mandatory PiTeX files** | +--------------------------------------------------------------------------- +| pitex.tex | The main file that inputs the other, | +| | and contains a few macros. | +| lua.ptx | Lua-related macros. | +| base.ptxlua | Lua functions, input in the previous file. | +| files.ptx | Dealing with files. | +| fonts.ptx | Interface for fonts; relies on the next file. | +| fonts.ptxlua | The Lua fontloader; should become independant | +| | some day. | +| foundry-settings.lua | Default settings for the fontloader. | +| sections.ptx | Sectionning commands. | +| blocks.ptx | Blocks (delimited text with special formatting). | +| references.ptx | Labels and references. | +| verbatim.ptx | Typesetting verbatim material. | +| inserts.ptx | Footnotes and figures. | +| output.ptx | Page layout and output routine. | +--------------------------------------------------------------------------- + +The following can be used with PiTeX; actually I only list the packages +I've written, but anything working with plain TeX (e.g. TikZ) works with +PiTeX. + +---------------------------------------------------------------------------- +| **Optional external packages** | +---------------------------------------------------------------------------- +| Librarian | To create bibliographies without BibTeX. | +| Lecturer | For screen presentations. | +| Interpreter | To write text with non-TeX markup (as this documentation); | +| | Interpreter does the conversion on the fly. | +---------------------------------------------------------------------------- + +The PiTeX distribution also contains "i-pitex.lua", an interpretation +file for Interpreter used to typeset documentations, like the one you +are currently reading. Which is why you can read it quite comfortably +as a plain text file in a text editor (see "pitex-doc.txt"). + +The rest of this document is a terse description of existing commands, +parameters, and of course, gates. + + + + + +Fonts (fonts.ptx and fonts.ptxlua) +================================== + +The fontloader uses gates, but only superficially. They won't be +documented here. + +\setfont <command>:<attributes> +Sets <command> to call the font described in <attributes>; all defaults +to the values of the !metafont parameter. If <command> is \mainfont, the +font is called at once. Also, \codefont is used in some places (e.g. +verbatim). + +> name +The family name of the font; e.g. Chaparral Pro for the main text of +this document. + +> size (dimension) +The size of the font. + +> small (dimension) +The size of the font when \small is called. Can be a relative value by +prefixing it with "-" or "+", in which case it is set relative to ?size. + +> verysmall (dimension) +The size (possibly relative) for \verysmall. + +> big (dimension) +The size (possibly relative) for \big. + +> verybig (dimension) +The size (possibly relative) for \verybig. + +> bold (font modifier) +The modifier used for the bold version of the font, without the leading slash; +!metafont sets it to "Bold". + +> italic (font modifier) +Same as !bold for the italic version; set to "Italic" by !metafont. + +> math (true or false) +If true, math fonts will be created. + +> features +Well, err, font features... + +> slant (angle) +The slant applied to the font to create a fake italic. + +> slantsc (angle) +The slant applied to the font to create fake italic smallcaps; if not +given, defaults to ?slant. + +There's actually much more going under the hood, but "font.ptxlua" (the +font loader itself) is a work in progress, and undocumented. + +The same macros as in plain TeX can be used, except they're cumulative, +i.e. "\it\bf" switches to a bold italic. + +\it +Switches to italics. + +\rm +Switches to roman. + +\bf +Switches to bold. + +\rg +Switches to regular weight. + +\sc +Switches to small capitals. + +\lc +Switches to lower case (i.e. not small caps). + +\ital <text> +Typesets <text> in italics. + +\bold <text> +Typesets <text> in bold. + +\scap <text> +Typesets <text> in small caps. + +\rom <text> +Typesets <text> in roman. + +\emph <text> +Typesets <text> in italics or roman, depending on whether the current +font is roman or italics, respectively. + +\underline <text> +Underlines <text>. Wow. + +\small +Switches to small font. + +\verysmall +Switches to very small font. + +\big +Switches to big font. + +\verybig +Got it? + +\normalsize +Switches to default size. + +\smaller +Switches to the font smaller than the current one (e.g. \normalsize if +you're currently using \big). + +\bigger +Same as \smaller, the other way around. + +\color <color><text> +Typesets <text> with <color>, which should be a triplet "R G B" with +each value between 0 and 1. + + + + + +Sections (sections.ptx) +======================= + +Sections are among the victims of my fanaticism for grid-typesetting. + + + + Main sectioning commands + ~~~~~~~~~~~~~~~~~~~~~~~~ + +\declaresection <type><level> +Creates a new section type with <level>. This is not necessary to make +\sectioncommand work with <type>, but with it all declared sections of +level larger than <level> are reset (i.e. their counters are set to 0). +Sections with <type> chapter, section, subsection and paragraph are +already declared. + +\incrementsection <type> +Increments the counter of section <type>. If <type> hasn't been declared, +a new <type> is created, but without a level. + +\getsectioncounter <type> +Returns the value of section <type>'s counter, or -1 if there is no +section of that type. + +\sectioncommand <type><title><alternate title>[<label>] +Creates a section heading of type <type> with <title>. See the details +of the gates involved below. The <type> refers to the parameter of the +same name. The <alternate title> is very likely to disappear. + +\chapter <title>[<label>] +Equivalent to \sectioncommand{chapter}{<title>}{<title>}[<label>]. + +\section <title>[<label>] +Equivalent to \sectioncommand{section}{<title>}{<title>}[<label>]. + +\subsection <title>[<label>] +Equivalent to \sectioncommand{subsection}{<title>}{<title>}[<label>]. + +\paragraph <title>[<label>] +Equivalent to \sectioncommand{paragraph}{<title>}{<title>}[<label>]. + +\ifsectiontitle +A conditional that is true when the section title is being typeset (sets by +the section_pre gate below. + +\sectioninfile <optional star><title><space><type><space><file><space> +Creates a section with the contents of a file, unless there's an optional +star (useful to typeset only parts of a big document); <title> is a +\freedef argument, hence it can be given between braces, double quotes +or slashes (but the <space> is nonetheless mandatory); <type> is a section +type, and <file> is a file to be input: it shouldn't have an extension +(tex files are searched), but it can be a path with "/" as a separator. +A \label is also created, with the tail of <file> as its argument. In +other words, the following: + + \sectioninfile "A chapter" chapter mydir/myfile + +is equivalent to: + + \chapter{A chapter} + \label{myfile} + \input mydir/myfile.tex + +The \sectioncommand macro only contains a list gate, "section", itself +containing the gates typesetting a section heading; all the gates belong +to the "Section" family associated with the \Section command. Here are +all the gates involved; the first number between parentheses indicates +how many arguments the gate should receive, the second how many it +returns. + +------------------------------------------------------------------------------- +| section | (4, 0) | section_break | (1, 0) | section_vmode | (1, 0) | +| | | | | section_clearpage | (1, 0) | +| | | | | section_beforeskip | (1, 0) | +| | | section_advance | (1, 0) | | | +| | | section_advance | (1, 0) | | | +| | | section_bookmark | (4, 0) | | | +| | | section_toc | (3, 0) | | | +| | | section_pre | (0, 0) | | | +| | | section_typeset | (2, 2) | section_number | (2, 3) | +| | | | | section_heading | (3, 2) | +| | | | | section_addfont | (2, 2) | +| | | | | section_addcolor | (2, 2) | +| | | | | section_do | (2, 0) | +| | | section_post | (0, 0) | | | +| | | section_afterskip | (1, 0) | | | +------------------------------------------------------------------------------- + +Here's how the gates work: + +> section <type><title><alternate title><label> +The main list gate that contains all sections. In what follows, when I +mention an attribute, I mean the attribute of the parameter <type>. + +> section_break <type> +An l-gate managing whatever must happen before the section title is +typeset. + +> section_vmode <type> +Inserts a \par and removes last skip. (Conditional: ?vmode is =true.) + +> section_clear <type> +Inserts a \clearpage. (Conditional: ?clear is =true.) + +> section_beforeskip <type> +Creates a vertical skip before the heading. If the current page cannot +accommodate ?beforeskip + ?minimum + ?afterskip worth of lines, then +the section heading is typeset on the next page (using \breakpage). If +the current page can accommodate the section, a skip of ?beforeskip +lines is inserted. The gate doesn't return anything. (Conditional: +?clear is not =true.) + +> section_advance <type> +Increments the section counter, and resets the counters of those sections +whose level is larger than <type>'s level (provided <type> has been +declared with \declaresection and thus given a level). The gate doesn't +return anything. + +> section_bookmark <type><title><alternate title><label> +The bookmark is created with Navigator's \outline command as follows: + + \outline[meta = <type>bookmark]{<bookmarklevel>}[<label>]{<alternate title>} + +only if ?bookmarklevel is defined. For types chapter, section, subsection +and paragraph, the related !chapterbookmark, !sectionbookmark, +!subsectionbookmark and !paragraphbookmark parameters are predefined, +with simply ?meta set to =navigator. The <alternate title> is likely +to disappear, since Navigator can handle things correctly. The gate +doesn't return anything. (Conditional: ?link is =true.) + +> section_toc <type><title><alternate title> +Writes what should be written to the auxiliary file for the next run +to produce a table of contents. The gate doesn't return anything. +(Conditional: ?toc is =true.) + +> section_pre +Prepares the typesetting: open a group, sets \maintextfalse and +\sectiontitletrue, and sets a LuaTeX attribute to 0 (so the section title +is marked and can be spotted in the output routine). The gates doesn't +return anything. + +> section_typeset <type><title> +A list gate containing the gates used to typeset the section heading. +It returns its final two arguments if only because list gate automatically +return. See description below. + +> section_post +Closes the group opened in section_pre. The gate doesn't return anything. + +> section_afterskip <type> +Creates a vertical skip of ?afterskip lines. Also, calls \removenextindent +if ?removenextindent is =true. The gate doesn't return anything. +(Conditional: ?inline is not =true.) + +Here are the gates contained in section_pre. Beware, there the nature +of the passed arguments slightly changes. + +> section_indent <type> +Goes into horizontal mode and inserts an indent of width ?indent. The +gate doesn't return anything. + +> section_number <type><title> +Sets the section number, if ?number isn't =none. The number is surrounded +by ?beforenumber and ?afternumber, converted to roman or arabic number +according to the value of ?number, and the whole is passed to ?numbercommand +(if it exists). The gate returns the following three arguments: +<type><number><title>, where <number> is what's just been described. + +> section_heading <type><number><title> +Sets the <title>: it is prefixed with <number>, passed to ?function if +it exists, and suffixed with ?aftertitle if any. The gate returns <type> +and <title> as just described. + +> section_addfont <type><title> +Prefixes <title> with the value of font and returns its two arguments. + +> section_addcolor <type><title> +Adds color to the title and returns its two arguments. (Conditional: +?color is =true.) + +> section_do <type><title> +At last! Inserts an horizontal skip of width ?indent, typesets <title>, +and if ?inline isn't =true, sets \rightskip to ?ragged. Oh, yes, this +could be divided into smaller gates. The gates doesn't return anything. + +The relevant parameters are the one corresponding to the type of the +section, i.e. !chapter, !section, !subsection, !paragraph, which all +have !metasection as their meta-parameter. The relevant attributes are: + +> vmode (true or false) +If =true, goes into vertical mode before typesetting the heading. + +> clear (true or false) +If =true, the section starts on a new page. + +> beforeskip (glue) +The skip added before the heading. + +> afterskip (glue) +The skip added after the heading. + +> minimum (number) +The minimum number of lines that should be present on the page after the +section heading. The "section_skip" gate above starts a new page if +?beforeskip + ?afterskip + ?minimum can't be accommodated. + +> inline (true or false) +If =true, the section heading is inserted at the beginning of the following +paragraph. + +> number (arabic, roman or none) +The way the section number should be typeset; =none means the number +isn't typeset. + +> beforenumber +Material to be added before the section number. + +> afternumber +Material to be added after the section number. + +> numbercommand (control sequence) +A macro to which the section number (surrounded by ?beforenumber and +?afternumber) is passed. + +> function (control sequence) +A macro to which the section title is passed. + +> aftertitle +Material added after the section title. + +> font +Font for the heading. + +> color (a triplet of values) +Color for the heading. + +> indent (glue) +The value of the glue added before the section title. + +> ragged (glue) +The value of \rightskip for the heading. + +> toc (true or false) +Sets whether the section should be added to the table of contents or +not. + +> removenextindent (true or false) +Sets whether the next paragraph should be unindented. + +> link (true or false) +Sets whether a bookmark should be created with the section's title. + +> bookmarklevel (number) +The level of the bookmark created for the section (how surprising). +Further specification of the bookmark is done with !chapterbookmark, +!sectionbookmark, !subsectionbookmark, !paragraphbookmark, whose only +specification is that ?meta is set to =navigator. New "<type>bookmark"'s +can be created, of course. See the documentation of Navigator for advanced +use. + + + + Various commands + ~~~~~~~~~~~~~~~~ + +\tableofcontents +Writes the table of contents (needs two runs). Not customizable for the +time being! + +\newbreakpenalty <command> +Defines <command> as a number below "-10000", suffixed with a \relax. +The idea is to use it to break a page and check it in the output routine. + +\clearpage +Fills the rest of the page with white space. + +\clearpagepenalty +Penalty associated with \clearpage. + +\breakpage +Same as \clearpage. They shouldn't be used for the same reasons. I use +\clearpage at the end of a chapter, and \breakpage elsewhere (e.g. when +a section heading would be orphaned and must move to the next page). The +latter triggers nothing special, but the former can be identified in the +output routine and for instance suppress footers. + +\breakpagepenalty +Penalty associated with \breakpage. + +\needspace <dimen> +Moves to the next page if there's less than <dimen>. + +\iflines <number><true><false> +Executes <true> if there's at least <number> lines left on the page, and +<false> otherwise. + +\ignorepars <material> +Ignores incoming \par commands (and spaces too) and executes <material>. +Useful when a blank line looks good in the source but you don't want it +to signal a paragraph's end. The command is used by sectionning commands, +so that if the section's title is supposed to be inserted at the beginning +of the next paragraph (e.g. if ?inline is =true), you can nonetheless +leave a blank line after the command. + + + +References (references.ptx) +=========================== + +There is a nice reference system, but it is a mess and should be rewritten +in Lua. So it isn't fully described here. + +\label <name> +Sets a label with <name>. + +\ref [<pre>][<post>] <reference type> {<name>} +Makes a reference. Beware of the syntax: label should be enclosed between +braces, because the left brace is the delimiter for <reference name>, +which in turn should be enclosed in braces. E.g. a call is: + + \ref page {mylabel} + +What is returned depends on <reference type>. If it is empty, then what +is returned is the value of \ptx@label when \label{<name>} was issued. +I think some commands define \ptx@label (nice in blocks, for instance). +Otherwise, <reference type> can be page, chapter, section, subsection, +paragraph or footnote (the latter if and only if \label was issued in a +footnote). The returned text is prefixed with <pre> and suffixed with +<post>. + +Also, if <reference type> is page, it may take three runs to make things +work, because it is checked whether the returned value is the current +page, in which case nothing is printed (it's stupid to refer to the +current page). As mentioned above, this is a mess. + +There also are commands like "\sref{label}" and the like, which are +shorthands for e.g. "\ref[ section~][] section {label}". + + + + + +Blocks (blocks.ptx) +=================== + + +Blocks are what are called environments elsewhere: they mark up a section +of the document, and generally apply some special operations. Given a +block myblock, it is launched with "\myblock", closed with "\myblock/" +and continued with "\myblock|". As you might imagine, this implies poking +at the next token, which in some rare case might be troublesome; hence, +\myblock can be followed by an optional ">" whose only goal is to protect +the next token. (You can also use a \relax, of course.) + +\newblock <optional star><command><pre><optional start><optional middle><post> +Defines <command> as a block. If the first optional star is present, the +block is executed inside a group. If the second optional star is present, +then the <middle> argument should be present too. The block is defined +as follow: <pre> is executed at the beginning (i.e. "\myblock" or +"\myblock>"), <middle> is executed when the block is continued (i.e. +"\myblock|"), and <post> is executed when the block is closed (i.e. +"\myblock/"). If <middle> is not given, then "\myblock|" does nothing. +For instance, the following defines a grouped block (so the \rightskip +setting doesn't affect the rest of the document); note the \par at the +end, so the paragraph is built before the group is closed: + + \newblock*\raggedblock{\rightskip=0pt plus 1fil\relax}{\par} + +And here's a simple example with a middle part: + + \newblock\listblock{\vskip\baselineskip-- } + *{\par-- } + {\vskip\baselineskip} + +The continuation part can be used as a partial block opening: some markers +are repeated (the dash) others are not (the vertical space). + +\newblocktype <command><pre><middle><post> +Defines <command> as a block definition command like \newblock with +<pre>, <middle> and <post> to be executed by default before the user-supplied +versions. The \newblock command itself has been thus defined, with empty +arguments. Arguments, after: + + \newblocktype\newlist{\vskip\baselineskip--} + {\par--} + {\vskip\baselineskip} + +Then \newlist\listblock{}{} will have the same definition as in the +previous example (no need to supply a <middle> part, it's in the default), +and a variation can be created. + +\removenextindent +Removes the indentation box of the next paragraph (used by section +macros). Technically, it sets ajar the "noindent" gate in the "everypar" +gate list (itself registered in the \everypar token list, which shouldn't +be handled otherwise if flexibility is to be ensured). Those two gates +belong to the "Everypar" family associated with the \Everypar command. + +\Indent +Indents the next paragraph even if it \removenextindent has been issued +(a \kern is added). + + + + + + +Dealing with files (files.ptx) +============================== + +\iffile [<format>]<file><true><false> +Executes <true> if "kpse.find_file" (from the LuaTeX "kpse" library, +implementing "kpathsea") with file type <format> (default: "tex"), and +<false> otherwise. + +\ifffile [<format>]<file><true> +Same as \iffile, except nothing happens when the file isn't found. Yes, +three *f*'s. + +\inputfileor [<format>]<file><no file> +Reads file <file> or executes <no file>. + +\writeout <optional star><general text> +Writes <general text> to the auxilary file that is read at the beginning +of each job. Without a star, writing happens at once (it's \immediate), +with it writing is delayed until the current page is shipped out. + + + + + +Verbatim (verbatim.ptx) +======================= + +\verbcatcodes +A catcode table with usual verbatim catcodes: special characters have +catcode 12, except space and end-of-line, which have catcode 13 and are +defined to \quitvmode\spacecs and \quitvmode\par by default. + +\newverbatim <command>[<catcode table>]<pre><post> +Defines a new block <command> with <catcode table>, <pre> at the beginning +and <post> at the end. If <catcode table> is missing, \verbcatcodes is +used. Verbatim blocks work as follows: first, there is no continuation +command, i.e. only "\myverbatimblock" and "\myverbatimblock/" are allowed, +not "\myverbatimblock|" (it might exist somewhere in the future). Second, +the block opening takes one optional argument between brackets, which +is the name of the verbatim block. Third, <pre> is executed at the +beginning, and <post> at the end, as defined with \newverbatim. Fourth, +the end statement "\myverbatimblock/" should be on a line of its own. +What a verbatim block does is the following (not taking into account +what <pre> and <post> execute): it stores its contents as is, along with +the <catcode table> the block was declared with, and that's it. Then +come the following two functions. + +\doverbatim [<name>] +Executes the contents of <name> (with the current catcode regime). If +name is missing, last is used, a special name which refers to the last +verbatim block. + +\printverbatim [<name>] +Executes the contents of <name> (or last if <name> is missing) with the +catcode table associated with the block <name> was stored with. Since +that catcode table is \verbcatcodes by default, it generally results in +the contents being typeset. + +As an example: + + \newverbatim\myverbatim{\vskip\baselineskip} + {\printverbatim\vskip\baselineskip} + \myverbatim[example] + \def\foo{hello !}% + \foo + \myverbatim/ + And now we are going to print: \doverbatim[example]. + +\verbatim +A predefined verbatim block, designed as follows: + + \newverbatim\verbatim{\codefont\parindent0pt} + {\vskip\baselineskip\printverbatim\relax + \vskip\baselineskip\removenextindent} + +I.e. it switches to the console-like font, sets the paragraph indentation +to nothing, prints its contents between two blank lines and removes the +indentation of the paragraph to follow. + +Each verbatim block adds a table to the Lua table "pitex.verbatims" (yes, +with an *s*); the key is the block's name, and the value is a table with +lines as values, indexed by numbers, plus a "regime" key which returns +the catcode table's number of the block. For instance, the core operation +performed by "\printverbatim[<name>]" is: + + tex.print(pitex.verbatims[<name>].regime, pitex.verbatims[<name>]) + + + + + +Insertions (inserts.ptx) +======================== + +Insertions are still a mess, and not related to parameters. Yet you can +use: + +\footnote <text> +Typesets <text> in a footnote. How astounding. + +\figure [<title>] +A block creating a figure with title <title>. + +\table [<title>] +The same as <figure>, except "Table" will be used instead of "Fig" in +the caption. + +\infigure +Ablock creating a figure in the main text, i.e. between paragraphs. + + + + +Layout and output routine (output.ptx) +===================================== + +The page layout can be specified with the !page parameter, whose attributes +are: + +> width (dimension) +The width of the page. + +> height (dimension) +The height of the page. + +> baselineskip (glue) +The baseline distance. + +> topskip (glue) +The distance between the top of the textblock and the first baseline. + +> top (dimension) +The height of the upper margin. + +> lines +The number of lines on a page. + +> hsize (dimension) +The width of the textblock. + +> left (dimension) +Width of the left margin. + +> right (dimension) +Width of the right margin. If specified, ?hsize is ignored and the +texblock's width is set to ?width - ?left - ?right. + +> parindent (dimension) +The width of the indentation. + +> parskip (glue) +The glue between paragraphs. + +The output routine holds nothing very interesting for the moment. I +used to redefine it for each job. Now it is set up with gates, but I +haven't taken the time yet to make it really powerful. Plus I should +rewrite everything in Lua as much as possible. Anyway, \output contains +the "output" gate, from the "OutputRoutine" family associated with the +\OutputRoutine command; the gates work as follows (passed arguments +aren't indicated, because there isn't any; although someday perhaps the +gates will pass a box between them, to be less dependant on \outputbox, +which is used, by the way, instead of box 255, so any box register can +be used): + +--------------------------------------------------------------- +| output | precheck | | | +| | shipout | processmarginalia | | +| | | inserts | inserts_figures | +| | | | inserts_footnotes | +| | | headers | | +| | | ship | | +| | | postship | | +--------------------------------------------------------------- + +> output +The main list gate, holding the following. + +> precheck +Checks whether \outputpenalty is smaller than \widowpenalty. If not, +\vsize is increased or decreased (if there are inserts) by \baselineskip, +so that the widow is accommodated or a line is given to the next page. +In any case, the output box is repassed to TeX with "\holdinginserts=0". +The gate is then set to "skip", so it isn't executed again. + +> shipout +A list gate containing gates to write the page. By default it is skipped, +so it isn't executed when the previous gate is, and vice-versa. + +> processmarginalia +Insert the marginal notes (see \marginnote below). Can be obviously +removed if there are no such notes. + +> inserts +An l-gate containing the following two m-gates. + +> inserts_figures +Adds the figures. (Conditional: the box "\ptx@insert_figures" isn't +empty.) + +> inserts_footnotes +Adds the footnotes. (Conditional: the box "\ptx@insert_footnotes" isn't +empty.) + +> headers +Inserts headers or footers, i.e. page number, running title, etc. + +> ship +Ships out the page. + +> postship +Resets some stuff (set "output_shipout" back to "skip"), and increments +the page number. + +And now a lonely command: + +\marginnote [options]<text> +Produces a marginal note with <text>. Uses the attributes (font, +baselineskip, hsize) of the !marginnote parameter, with the following +attributes: + +> hsize (dimension) +Width of the textblock in the note. + +> hpos (ff, fr, rf, rr) +Justification of the text: flushed on both sides, ragged on the right, +ragged on the left, ragged on both sides. + +> font +Font used to typeset the note. + +> parindent (dimension) +Paragraph indentation for the note. + +> side (left or right) +Side of the note relative to the textblock. That should depend on whether +the note is on an odd or even side, but for the moment that is not the +case. + +> gap (dimension) +Distance between the textblock and the note. + + + + + +Lua facilities (lua.ptx and base.ptxlua) +======================================== + +\inputluafile <file> +Shorthand for \directlua{dofile(kpse.find_file(<file>))}. + +\luacatcodes +A catcode table with Lua-convenient catcodes: "#", "~", "%" and the end +of file "^^M" are set to catcode 12. + +\luacode +A block to write Lua code with the catcodes above. + +Lua code in PiTeX is organized mostly in gates; "pitex" is a gate table +associated with family "pitex", "pitex.callback" is another table +associated with family "pitex.callback", and "pitex.misc" is a third +table associated (how surprising) with family "pitex.misc". The +division of labour isn't perfectly defined, to say the least. + +The "pitex" family holds general commands, namely: + +> pitex.log (<message>, ...) +Writes a <message> formatted as "string.format(<message>, ...)" + +> pitex.error (<message>, ...) +Same as the previous function, but less friendly. + +The "pitex.callback" family is concerned with callback management. It +has one interesting function (well, a gate) devoted to handling functions +in callbacks as gates: + +> pitex.callback.register (<callback>, <gate>) +An l-gate is registered in the callback, with subgates added to it; the +name of the l-gate is the same as the callback where it is registered +(with the family prefix "pitex.callback" added when necessary). For +instance the list gate containing functions to used in "process_input_buffer" +is called "process_input_buffer". Ordinary you would add a subgate to +such a callback with the "add" action: + + pitex.callback.add ("mygate", "process_input_buffer") + +However, the l-gate associated with the callback isn't created by +default, nor registered in the callback. This means that "add" above +will fail miserably if "process_input_buffer" hasn't been created +beforehand. This function is meant to circumvent that: if the l-gate +exists, it boils down to "add"; otherwise it creates it and registers +it in the callback, and then add the gate. Note that the syntax follows +the original "callback.register" function, with the callback first and +the function second, even though you're adding gates to l-gates, with +the syntax of "add" being subgates first, l-gate second. To manage the +gates, thus created, you can then rely on the original gate actions. + +So, when I say `gates "X" and "Y" are registered in callback "Z"', it +means `gates "X" and "Z" are subgates of l-gate "pitex.callback:Z", +itself registered in callback "Z"'; unless otherwise indicated, "X" and +"Z" belong to the "pitex.callback" family. + +And here are the gates registered in callbacks: "process_input_buffer" +contains "convert", which turns latin1 into UTF-8. Verbatim blocks also +register "process_verbatim", which is removed when the block ends. The +"kerning" callback contains "french_punctuation", meant to add thin +space before some punctuation mark, and "original_kerning", which is +just a gate version of the "node.kerning" function. In "post_linebreak_filter" +you'll find "pitex.misc:underline", which deals with material to be +underline and "pitex.misc:mark_lines", which marks lines where a margin +note is to be added. Those last two gates should be rewritten as complex +l-gates (they're just big functions for the moment) some day. If you +neither underline nor use marginal notes, you can remove them. + + + + +Things that didn't make it elsewhere (pitex.tex) +================================================ + +General properties of the document can be set with the !document parameter, +with the following attributes (the !navigator parameter has a ?meta +attribute set to !document, which is why you'll find attributes here +used by Navigator): + +> author +The author of the document. + +> title +The title of the document. + +> pdftitle +The title that Navigator will use for the document's properties (defaults +to ?title). + +> date +The date of the document + +> pdfdate +The date that Navigator will use for the document's properties; should +be a properly formatted PDF date (this corresponds to the ?date attribute +in the !navigator parameter; note that ?pdfdate doesn't defaults to +?date, because the latter is supposed to hold a readable date). + +> subject +For the document's properties. + +> keywords +Again, the properties. + +> mode (outlines, bookmarks, thumbs, thumbnails, attachments, files, oc) +What should be displayed in the navigation bar when the document is +opened. See the documentation to Navigator. + +> layout (onepage, onecolumn, twopage, twocolumn, twopage*, twocolumn*) +How the document is displayed when opened. See the documentation of +Navigator. + +\newattribute <command> +Defines <command> as an attribute register. + +\unsetattribute <command> +Unsets attribute <command>. + +\attributenumber <command> +Returns the number of attribute register <command> (not its value; you +get the value with \the; this is to pass to Lua). + +\freedef <command>{<definition>} +Same as "\def\foo#1{...}", except <command> can take its argument between +double quotes (°") or slahes (/), and of course as single token or +brace-delimited. + +\ifmaintext +Conditional that is true when in main text; inserts, section headings, +etc., should turn it to false, and sets their own to true. + +\newcatcodetable <command><catcode settings> +Defines <command> as a catcode table with <catcode settings>; the latter +are "<list of characters> = catcode" pairs, separated by commas, like +the argument of texapi's \setcatcodes. + +\texcatcodes +A code catcode table with the traditional catcodes. + +\inputpitexfile <file><space> +Inputs <file> unless the initialization script says otherwise. If <file> +has no extension, ".ptx" is used. + +\antigobblespace +Adds a space if the next character has catcode 11 or is an opening +parenthesis. For instance, after "\def\tex{\TeX\antigobblespace}", you +can type "\tex is typesetting program" without worrying for gobbled +space. Note that only ASCII letters have catcode 11 by default (not +accented characters). + +\strut <height><depth> +Produces an invisible vertical rule with the specified dimensions. + +\colorbox [<dimensions>]<RGB color><text> +Puts <text> in a colored box with background color <RGB color> (e.g. +three space-separated numbers between 0 and 1) and with padding <dimensions>. +If <dimensions> is missing, padding is done according to the \extraboxspace +length. Otherwise, if <dimensions> contains one value, it is used on all +side; if there are two values (separated by commas), the first is used +for top and bottom padding, and the second for left and right padding; +with three value, the third specifies bottom padding, and a fourth +specifies left padding. Very unlikely to remain in its present state or +to remain at all. + +\extraboxspace +Default padding for the previous command. + +\og +Produces an opening guillemet: "«" (character "0x00AB"). + +\fg +Produces a closing guillemet: "»" (character "0x00BB"). Uses \antigobblespace. + +\trace +Sets \tracingcommands to 3 and \tracingmacros to 2. + +\untrace +Sets \tracingcommands and \tracingmacros to 0. 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)}% + } |