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