T wo T r:format.lua
From LuaTeXWiki
--- Copyright (c) 2021 by Toadstone Enterprises.
--- ISC-type license, see License.txt for details.
-----------------------------------------------------------------
local util = require("utils")
local filll = util.filll
-----------------------------------------------------------------
--- Page Layout
-- This should be set based on the current font!
tex.baselineskip = tex.sp("14pt")
-- set tex's margins to the edge of the page, so that we can define
-- our own page layout more easily
tex.hoffset = tex.sp("-1.in")
tex.voffset = tex.sp("-1.in")
-- American paper size. USA!
local paper_width = tex.sp("8.5in")
local paper_height = tex.sp("11in")
local top_margin = tex.sp("0.75in")
local right_margin = tex.sp("0.75in")
local bottom_margin = tex.sp("0.75in")
local left_margin = tex.sp("0.75in")
-- header_height is the height of the header box, and it is
-- separated from the main text box by header_sep.
local header_height = tex.sp("0.5in")
local header_sep = tex.sp("0.25in")
local footer_height = tex.sp("0.5in")
local footer_sep = tex.sp("0.25in")
-- The main text box.
local text_width = paper_width - (right_margin + left_margin)
local text_height = paper_height - (top_margin +
header_height + header_sep +
footer_height + footer_sep +
bottom_margin)
local page_number = 1
-----------------------------------------------------------------
--- We define all the fonts we will be using here.
--- This requires the luatex-plain format, or (untested) luaotfload.
-- fonts.definers.read returns a table representing the font.
-- font.define ties this font to an integer which we can use to refer
-- to the desired font.
local main_text_font_table = fonts.definers.read("lmroman12-regular.otf:mode=node;liga=true;kern=true;", tex.sp("12pt"))
local main_text_font = font.define(main_text_font_table)
local emph_text_font_table = fonts.definers.read("lmroman12-italic.otf:mode=node;liga=true;kern=true;", tex.sp("12pt"))
local emph_text_font = font.define(emph_text_font_table)
local bold_text_font_table = fonts.definers.read("lmroman12-bold.otf:mode=node;liga=true;kern=true;", tex.sp("12pt"))
local bold_text_font = font.define(bold_text_font_table)
local title_font_table = fonts.definers.read("lmroman17-regular.otf:mode=node;liga=true;kern=true;", tex.sp("17pt"))
local title_font = font.define(title_font_table)
local header_font_table = fonts.definers.read("lmroman12-regular.otf:mode=node;liga=true;kern=true;", tex.sp("12pt"))
local header_font = font.define(header_font_table)
local footer_font_table = fonts.definers.read("lmroman12-regular.otf:mode=node;liga=true;kern=true;", tex.sp("12pt"))
local footer_font = font.define(footer_font_table)
local footnote_font_table = fonts.definers.read("lmroman10-regular.otf::mode=node;liga=true;kern=true;", tex.sp("10pt"))
local footnote_font = font.define(footnote_font_table)
-- For the footnote markers.
local superscript_font_table = fonts.definers.read("lmroman7-regular.otf:mode=node;liga=true;kern=true;", tex.sp("7pt"))
local superscript_font = font.define(superscript_font_table)
-----------------------------------------------------------------
--- This is the state that we will be passing around as we typeset.
State = {-- What are we typesetting now?
-- One of "main_text", "header", "footer", or "footnote"
mode = "main_text",
-- Where we will store the main text as we build our paragraphs.
main = nil,
-- Where we store the header and footer, as we build them.
header = nil,
footer = nil,
-- We use a table of notes, indexed by footnote number
max_notes = 0,
notes = {},
-- We store some of main_loops local variables, so that we
-- can pass them around as needed.
head = nil,
tail = nil,
eat_the_white = false,
eol_seen = false,
-- We want to be able to use different parameters for typesetting
-- the different pieces of text. A header is not the same as a
-- footnote. We therefore keep a stack of tbls containing the
-- settings for formatting a paragraph (these are passed to
-- tex.linebreak).
max_tbls = 0,
tbls = {},
-- When we see a command, do_command_start will (potentially)
-- be filled in with the part of the command to do upon
-- encountering a "{"
do_command_start = nil,
-- And a stack of do_command_stops: do_command_stops
-- We need a stack, because commands can be nested.
-- e.g., an Emph inside a Bold.
-- We need only one do_command_start, because that is for
-- the current command and the next "{" seen.
max_do_command_stops = 0,
do_command_stops = {},
-- A place to store the text to be made into the header.
header_text = nil,
-- So we can format the first paragraph of a chapter
-- differently from the rest.
first_paragraph_of_chapter = false,
-- So we can format the first page of a chapter
-- differently from the rest.
first_page_of_chapter = false,
}
local main_text_tbl = {hsize = text_width,
parindent = tex.parindent,
parfillskipstretch = 2^16,
parfillskipstretch_order = 2,
font = main_text_font,
space = font.fonts[main_text_font].parameters.space,
space_stretch = font.fonts[main_text_font].parameters.space_stretch,
space_shrink = font.fonts[main_text_font].parameters.space_shrink,
lang = tex.language,
lefthyphenmin = tex.lefthyphenmin,
righthyphenmin = tex.righthyphenmin,
}
local header_tbl = {hsize = text_width,
-- The header will be centered.
leftskip = filll(),
rightskip = filll(),
parindent = 0,
parfillskipstretch = 2^16,
parfillskipstretch_order = 2,
font = header_font,
space = font.fonts[header_font].parameters.space,
space_stretch = font.fonts[header_font].parameters.space_stretch,
space_shrink = font.fonts[header_font].parameters.space_shrink,
lang = tex.language,
lefthyphenmin = tex.lefthyphenmin,
righthyphenmin = tex.righthyphenmin,
}
local footer_tbl = {hsize = text_width,
leftskip = filll(),
rightskip = filll(),
parindent = 0,
parfillskipstretch = 2^16,
parfillskipstretch_order = 2,
font = footer_font,
space = font.fonts[footer_font].parameters.space,
space_stretch = font.fonts[footer_font].parameters.space_stretch,
space_shrink = font.fonts[footer_font].parameters.space_shrink,
lang = tex.language,
lefthyphenmin = tex.lefthyphenmin,
righthyphenmin = tex.righthyphenmin,
}
local footnote_tbl = {hsize = text_width,
parindent = 0,
parfillskipstretch = 2^16,
parfillskipstretch_order = 2,
font = footnote_font,
space = font.fonts[footnote_font].parameters.space,
space_stretch = font.fonts[footnote_font].parameters.space_stretch,
space_shrink = font.fonts[footnote_font].parameters.space_shrink,
lang = tex.language,
lefthyphenmin = tex.lefthyphenmin,
righthyphenmin = tex.righthyphenmin,
}
local update_state = function(head, tail, eat_the_white, eol_seen)
-- As we pass the State around, we wil want to pass along the
-- current values of head, tail, eat_the_white, and eol_seen.
-- See main_loop and the commands for examples.
State.head = head
State.tail = tail
State.eat_the_white = eat_the_white
State.eol_seen = eol_seen
end
local update_locals = function()
-- As we return from calls in which we passed the State out, the
-- values of head, tail, eat_the_white, and eol_seen may have been
-- changed. So we update them from the current State. See main_loop
-- and the commands for examples.
local head = State.head
local tail = State.tail
local eat_the_white = State.eat_the_white
local eol_seen = State.eol_seen
return head, tail, eat_the_white, eol_seen
end
local push_tbl = function(tbl)
local max = State.max_tbls
State.max_tbls = max + 1
State.tbls[max + 1] = tbl
end
local pop_tbl = function()
local max = State.max_tbls
if (max > 0) then
local tbl = State.tbls[max]
State.tbls[max] = nil
State.max_tbls = max - 1
return tbl
else
return nil
end
end
local top_tbl = function()
local max = State.max_tbls
if (max > 0) then
return State.tbls[max]
else
return nil
end
end
local push_do_command_stop = function(do_command_stop)
local max = State.max_do_command_stops
State.max_do_command_stops = max + 1
State.do_command_stops[max + 1] = do_command_stop
end
local pop_do_command_stop = function()
local max = State.max_do_command_stops
if (max > 0) then
local do_command_stop = State.do_command_stops[max]
State.do_command_stops[max] = nil
State.max_do_command_stops = max - 1
return do_command_stop
else
return nil
end
end
local format = {paper_width = paper_width,
paper_height = paper_height,
top_margin = top_margin,
right_margin = right_margin,
bottom_margin = bottom_margin,
left_margin = left_margin,
header_height = header_height,
header_sep = header_sep,
footer_height = footer_height,
footer_sep = footer_sep,
text_width = text_width,
text_height = text_height,
page_number = page_number,
update_state = update_state,
update_locals = update_locals,
push_tbl = push_tbl,
pop_tbl = pop_tbl,
top_tbl = top_tbl,
push_do_command_stop = push_do_command_stop,
pop_do_command_stop = pop_do_command_stop,
main_text_tbl = main_text_tbl,
header_tbl = header_tbl,
footer_tbl = footer_tbl,
footnote_tbl = footnote_tbl,
main_text_font = main_text_font,
emph_text_font = emph_text_font,
bold_text_font = bold_text_font,
title_font = title_font,
header_font = header_font,
footer_font = footer_font,
footnote_font = footnote_font,
superscript_font = superscript_font,
}
return format