diff --git a/build-aux/list-dist-files.sh.in b/build-aux/list-dist-files.sh.in index c007dcb00..4c7af2f6c 100755 --- a/build-aux/list-dist-files.sh.in +++ b/build-aux/list-dist-files.sh.in @@ -8,7 +8,7 @@ finder () { printf '%s' "SILEDATA =" finder core -name '*.lua' -not -name '*_spec.lua' -not -name 'version.lua' -not -name 'features.lua' -not -name 'pathsetup.lua' -finder classes inputters languages outputters packages shapers typesetters pagebuilders -name '*.lua' -not -name '*_spec.lua' +finder classes inputters languages outputters packages shapers types typesetters pagebuilders -name '*.lua' -not -name '*_spec.lua' finder classes i18n packages -name '*.ftl' finder packages -name '*.svg' diff --git a/core/deprecations.lua b/core/deprecations.lua index 8540753d8..d3c20bc28 100644 --- a/core/deprecations.lua +++ b/core/deprecations.lua @@ -70,6 +70,53 @@ SILE.readFile = function (filename) return SILE.processFile(filename) end +local usetypes = function (type) + SU.deprecated(("SILE.%s"):format(type), ("SILE.types.%s"):format(type), "0.15.0", "0.16.0", ([[ + In order to keep things tidy internally, more easily allow 3rd party + packages to override core functions, and substitute some slow bits + with Rust modules, internal types have been moved from the top level + SILE global to a types namespace. + + Please substitute 'SILE.%s()' with 'SILE.types.%s()'. + ]]):format(type, type)) + return SILE.types[type] +end + +SILE.color = setmetatable({}, { + __call = function (_, ...) return usetypes("color")(...) end, + __index = function () return usetypes("color") end, + }) + +SILE.measurement = setmetatable({}, { + __call = function (_, ...) return usetypes("measurement")(...) end, + __index = function () return usetypes("measurement") end, + }) + +SILE.length = setmetatable({}, { + __call = function (_, ...) return usetypes("length")(...) end, + __index = function () return usetypes("length") end, + }) + +local usetypes2 = function (old, new, type) + SU.deprecated(("SILE.%s.%s"):format(old, type), ("SILE.types.%s.%s"):format(new, type), "0.15.0", "0.16.0", ([[ + In order to keep things tidy internally, more easily allow 3rd party + packages to override core functions, and substitute some slow bits + with Rust modules, internal types have been moved from the top level + SILE global to a types namespace. + + Please substitute 'SILE.%s.%s()' with 'SILE.types.%s.%s()'. + ]]):format(old, type, new, type)) + return SILE.types[new][type] +end + +SILE.nodefactory = setmetatable({}, { + __index = function (_, type) return usetypes2("nodefactory", "node", type) end, + }) + +SILE.units = setmetatable({}, { + __index = function (_, type) return usetypes2("units", "unit", type) end, + }) + SILE.colorparser = function (input) SU.deprecated("SILE.colorparser", "SILE.color", "0.14.0", "0.16.0", [[Color results are now color objects, not just tables with relevant values.]]) diff --git a/core/parserbits.lua b/core/parserbits.lua index 13d42b251..f41e7373f 100644 --- a/core/parserbits.lua +++ b/core/parserbits.lua @@ -5,8 +5,9 @@ local C, Cf, Cg, Ct, Cmt = lpeg.C, lpeg.Cf, lpeg.Cg, lpeg.Ct, lpeg.Cmt local function isaunit (_, _, unit) -- TODO: fix race condition so we can validate units - if not SILE or not SILE.units then return true end - return SILE.units[unit] and true or false + local factory = rawget(SILE.types, "unit") + if not SILE or not factory then return true end + return factory[unit] and true or false end local function inferpoints (number) diff --git a/core/sile.lua b/core/sile.lua index c5c7ea19a..7a94c6412 100644 --- a/core/sile.lua +++ b/core/sile.lua @@ -85,19 +85,13 @@ SILE.classes = core_loader("classes") SILE.packages = core_loader("packages") SILE.typesetters = core_loader("typesetters") SILE.pagebuilders = core_loader("pagebuilders") +SILE.types = core_loader("types") --- Internal libraries that don't make assumptions on load, only provide something +-- Internal libraries that don't try to use anything on load, only provide something SILE.parserBits = require("core.parserbits") SILE.frameParser = require("core.frameparser") -SILE.color = require("core.color") -SILE.units = require("core.units") SILE.fontManager = require("core.fontmanager") - --- Internal libraries that assume globals, may be picky about load order -SILE.measurement = require("core.measurement") -SILE.length = require("core.length") SILE.papersize = require("core.papersize") -SILE.nodefactory = require("core.nodefactory") -- NOTE: -- See remainaing internal libraries loaded at the end of this file because diff --git a/packages/math/base-elements.lua b/packages/math/base-elements.lua index 2a57d3367..bfc7b1640 100644 --- a/packages/math/base-elements.lua +++ b/packages/math/base-elements.lua @@ -1,4 +1,4 @@ -local nodefactory = require("core.nodefactory") +local nodefactory = require("types.node") local hb = require("justenoughharfbuzz") local ot = require("core.opentype-parser") local syms = require("packages.math.unicode-symbols") diff --git a/core/color.lua b/types/color.lua similarity index 100% rename from core/color.lua rename to types/color.lua diff --git a/core/color_spec.lua b/types/color_spec.lua similarity index 100% rename from core/color_spec.lua rename to types/color_spec.lua diff --git a/core/length.lua b/types/length.lua similarity index 100% rename from core/length.lua rename to types/length.lua diff --git a/core/measurement.lua b/types/measurement.lua similarity index 100% rename from core/measurement.lua rename to types/measurement.lua diff --git a/core/nodefactory.lua b/types/node.lua similarity index 68% rename from core/nodefactory.lua rename to types/node.lua index fbb17a21e..50f5cb4fe 100644 --- a/core/nodefactory.lua +++ b/types/node.lua @@ -1,4 +1,4 @@ -local nodefactory = {} +local nodetypes = {} -- This infinity needs to be smaller than an actual infinity but bigger than the infinite stretch -- added by the typesetter. See https://github.com/sile-typesetter/sile/issues/227 @@ -16,19 +16,19 @@ end local _dims = pl.Set { "width", "height", "depth" } -nodefactory.box = pl.class() -nodefactory.box.type = "special" +nodetypes.box = pl.class() +nodetypes.box.type = "special" -nodefactory.box.height = nil -nodefactory.box.depth = nil -nodefactory.box.width = nil -nodefactory.box.misfit = false -nodefactory.box.explicit = false -nodefactory.box.discardable = false -nodefactory.box.value = nil -nodefactory.box._default_length = "width" +nodetypes.box.height = nil +nodetypes.box.depth = nil +nodetypes.box.width = nil +nodetypes.box.misfit = false +nodetypes.box.explicit = false +nodetypes.box.discardable = false +nodetypes.box.value = nil +nodetypes.box._default_length = "width" -function nodefactory.box:_init (spec) +function nodetypes.box:_init (spec) if type(spec) == "string" or type(spec) == "number" or SU.type(spec) == "measurement" @@ -52,24 +52,24 @@ function nodefactory.box:_init (spec) end -- De-init instances by shallow copying properties and removing meta table -function nodefactory.box:_tospec () +function nodetypes.box:_tospec () return pl.tablex.copy(self) end -function nodefactory.box:tostring () +function nodetypes.box:tostring () return self:__tostring() end -function nodefactory.box:__tostring () +function nodetypes.box:__tostring () return self.type end -function nodefactory.box.__concat (a, b) +function nodetypes.box.__concat (a, b) return tostring(a) .. tostring(b) end -function nodefactory.box:absolute () - local clone = nodefactory[self.type](self:_tospec()) +function nodetypes.box:absolute () + local clone = nodetypes[self.type](self:_tospec()) for dim in pairs(_dims) do clone[dim] = self[dim]:absolute() end @@ -79,101 +79,101 @@ function nodefactory.box:absolute () return clone end -function nodefactory.box:lineContribution () +function nodetypes.box:lineContribution () -- Regardless of the orientations, "width" is always in the -- writingDirection, and "height" is always in the "pageDirection" return self.misfit and self.height or self.width end -function nodefactory.box:outputYourself () +function nodetypes.box:outputYourself () SU.error(self.type.." with no output routine") end -function nodefactory.box:toText () +function nodetypes.box:toText () return self.type end -function nodefactory.box:isBox () +function nodetypes.box:isBox () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type == "hbox" or self.type == "zerohbox" or self.type == "alternative" or self.type == "nnode" or self.type == "vbox" end -function nodefactory.box:isNnode () +function nodetypes.box:isNnode () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type=="nnode" end -function nodefactory.box:isGlue () +function nodetypes.box:isGlue () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type == "glue" end -function nodefactory.box:isVglue () +function nodetypes.box:isVglue () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type == "vglue" end -function nodefactory.box:isZero () +function nodetypes.box:isZero () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type == "zerohbox" or self.type == "zerovglue" end -function nodefactory.box:isUnshaped () +function nodetypes.box:isUnshaped () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type == "unshaped" end -function nodefactory.box:isAlternative () +function nodetypes.box:isAlternative () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type == "alternative" end -function nodefactory.box:isVbox () +function nodetypes.box:isVbox () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type == "vbox" end -function nodefactory.box:isInsertion () +function nodetypes.box:isInsertion () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type == "insertion" end -function nodefactory.box:isMigrating () +function nodetypes.box:isMigrating () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.migrating end -function nodefactory.box:isPenalty () +function nodetypes.box:isPenalty () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type == "penalty" end -function nodefactory.box:isDiscretionary () +function nodetypes.box:isDiscretionary () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type == "discretionary" end -function nodefactory.box:isKern () +function nodetypes.box:isKern () SU.warn("Deprecated function, please use boolean is_ property to check types", true) return self.type == "kern" end -nodefactory.hbox = pl.class(nodefactory.box) -nodefactory.hbox.type = "hbox" +nodetypes.hbox = pl.class(nodetypes.box) +nodetypes.hbox.type = "hbox" -function nodefactory.hbox:_init (spec) - nodefactory.box._init(self, spec) +function nodetypes.hbox:_init (spec) + nodetypes.box._init(self, spec) end -function nodefactory.hbox:__tostring () +function nodetypes.hbox:__tostring () return "H<" .. tostring(self.width) .. ">^" .. tostring(self.height) .. "-" .. tostring(self.depth) .. "v" end -function nodefactory.hbox:scaledWidth (line) +function nodetypes.hbox:scaledWidth (line) return SU.rationWidth(self:lineContribution(), self.width, line.ratio) end -function nodefactory.hbox:outputYourself (typesetter, line) +function nodetypes.hbox:outputYourself (typesetter, line) local outputWidth = self:scaledWidth(line) if not self.value.glyphString then return end if typesetter.frame:writingDirection() == "RTL" then @@ -187,32 +187,32 @@ function nodefactory.hbox:outputYourself (typesetter, line) end end -nodefactory.zerohbox = pl.class(nodefactory.hbox) -nodefactory.zerohbox.type = "zerohbox" -nodefactory.zerohbox.value = { glyph = 0 } +nodetypes.zerohbox = pl.class(nodetypes.hbox) +nodetypes.zerohbox.type = "zerohbox" +nodetypes.zerohbox.value = { glyph = 0 } -nodefactory.nnode = pl.class(nodefactory.hbox) -nodefactory.nnode.type = "nnode" -nodefactory.nnode.language = "" -nodefactory.nnode.pal = nil -nodefactory.nnode.nodes = {} +nodetypes.nnode = pl.class(nodetypes.hbox) +nodetypes.nnode.type = "nnode" +nodetypes.nnode.language = "" +nodetypes.nnode.pal = nil +nodetypes.nnode.nodes = {} -function nodefactory.nnode:_init (spec) +function nodetypes.nnode:_init (spec) self:super(spec) if 0 == self.depth:tonumber() then self.depth = _maxnode(self.nodes, "depth") end if 0 == self.height:tonumber() then self.height = _maxnode(self.nodes, "height") end if 0 == self.width:tonumber() then self.width = SU.sum(SU.map(function (node) return node.width end, self.nodes)) end end -function nodefactory.nnode:__tostring () +function nodetypes.nnode:__tostring () return "N<" .. tostring(self.width) .. ">^" .. tostring(self.height) .. "-" .. tostring(self.depth) .. "v(" .. self:toText() .. ")" end -function nodefactory.nnode:absolute () +function nodetypes.nnode:absolute () return self end -function nodefactory.nnode:outputYourself (typesetter, line) +function nodetypes.nnode:outputYourself (typesetter, line) -- See typesetter:computeLineRatio() which implements the currently rather messy -- and probably slightly dubious 'hyphenated' logic. -- Example: consider the word "out-put". @@ -236,30 +236,30 @@ function nodefactory.nnode:outputYourself (typesetter, line) end end -function nodefactory.nnode:toText () +function nodetypes.nnode:toText () return self.text end -nodefactory.unshaped = pl.class(nodefactory.nnode) -nodefactory.unshaped.type = "unshaped" +nodetypes.unshaped = pl.class(nodetypes.nnode) +nodetypes.unshaped.type = "unshaped" -function nodefactory.unshaped:_init (spec) +function nodetypes.unshaped:_init (spec) self:super(spec) self.width = nil end -function nodefactory.unshaped:__tostring () +function nodetypes.unshaped:__tostring () return "U(" .. self:toText() .. ")"; end -getmetatable(nodefactory.unshaped).__index = function (_, _) +getmetatable(nodetypes.unshaped).__index = function (_, _) -- if k == "width" then SU.error("Can't get width of unshaped node", true) end -- TODO: No idea why porting to proper Penlight classes this ^^^^^^ started -- killing everything. Perhaps because this function started working and would -- actually need to return rawget(self, k) or something? end -function nodefactory.unshaped:shape () +function nodetypes.unshaped:shape () local node = SILE.shaper:createNnodes(self.text, self.options) for i=1, #node do node[i].parent = self.parent @@ -267,27 +267,27 @@ function nodefactory.unshaped:shape () return node end -function nodefactory.unshaped.outputYourself (_) +function nodetypes.unshaped.outputYourself (_) SU.error("An unshaped node made it to output", true) end -nodefactory.discretionary = pl.class(nodefactory.hbox) +nodetypes.discretionary = pl.class(nodetypes.hbox) -nodefactory.discretionary.type = "discretionary" -nodefactory.discretionary.prebreak = {} -nodefactory.discretionary.postbreak = {} -nodefactory.discretionary.replacement = {} -nodefactory.discretionary.used = false +nodetypes.discretionary.type = "discretionary" +nodetypes.discretionary.prebreak = {} +nodetypes.discretionary.postbreak = {} +nodetypes.discretionary.replacement = {} +nodetypes.discretionary.used = false -function nodefactory.discretionary:__tostring () +function nodetypes.discretionary:__tostring () return "D(" .. SU.concat(self.prebreak, "") .. "|" .. SU.concat(self.postbreak, "") .."|" .. SU.concat(self.replacement, "") .. ")"; end -function nodefactory.discretionary:toText () +function nodetypes.discretionary:toText () return self.used and "-" or "_" end -function nodefactory.discretionary:markAsPrebreak () +function nodetypes.discretionary:markAsPrebreak () self.used = true if self.parent then self.parent.hyphenated = true @@ -295,11 +295,11 @@ function nodefactory.discretionary:markAsPrebreak () self.is_prebreak = true end -function nodefactory.discretionary:cloneAsPostbreak () +function nodetypes.discretionary:cloneAsPostbreak () if not self.used then SU.error("Cannot clone a non-used discretionary (previously marked as prebreak)") end - return SILE.nodefactory.discretionary({ + return SILE.types.node.discretionary({ prebreak = self.prebreak, postbreak = self.postbreak, replacement = self.replacement, @@ -309,7 +309,7 @@ function nodefactory.discretionary:cloneAsPostbreak () }) end -function nodefactory.discretionary:outputYourself (typesetter, line) +function nodetypes.discretionary:outputYourself (typesetter, line) -- See typesetter:computeLineRatio() which implements the currently rather -- messy hyphenated checks. -- Example: consider the word "out-put-ter". @@ -339,229 +339,229 @@ function nodefactory.discretionary:outputYourself (typesetter, line) end end -function nodefactory.discretionary:prebreakWidth () +function nodetypes.discretionary:prebreakWidth () if self.prebw then return self.prebw end self.prebw = SILE.length() for _, node in ipairs(self.prebreak) do self.prebw:___add(node.width) end return self.prebw end -function nodefactory.discretionary:postbreakWidth () +function nodetypes.discretionary:postbreakWidth () if self.postbw then return self.postbw end self.postbw = SILE.length() for _, node in ipairs(self.postbreak) do self.postbw:___add(node.width) end return self.postbw end -function nodefactory.discretionary:replacementWidth () +function nodetypes.discretionary:replacementWidth () if self.replacew then return self.replacew end self.replacew = SILE.length() for _, node in ipairs(self.replacement) do self.replacew:___add(node.width) end return self.replacew end -function nodefactory.discretionary:prebreakHeight () +function nodetypes.discretionary:prebreakHeight () if self.prebh then return self.prebh end self.prebh = _maxnode(self.prebreak, "height") return self.prebh end -function nodefactory.discretionary:postbreakHeight () +function nodetypes.discretionary:postbreakHeight () if self.postbh then return self.postbh end self.postbh = _maxnode(self.postbreak, "height") return self.postbh end -function nodefactory.discretionary:replacementHeight () +function nodetypes.discretionary:replacementHeight () if self.replaceh then return self.replaceh end self.replaceh = _maxnode(self.replacement, "height") return self.replaceh end -function nodefactory.discretionary:replacementDepth () +function nodetypes.discretionary:replacementDepth () if self.replaced then return self.replaced end self.replaced = _maxnode(self.replacement, "depth") return self.replaced end -nodefactory.alternative = pl.class(nodefactory.hbox) +nodetypes.alternative = pl.class(nodetypes.hbox) -nodefactory.alternative.type = "alternative" -nodefactory.alternative.options = {} -nodefactory.alternative.selected = nil +nodetypes.alternative.type = "alternative" +nodetypes.alternative.options = {} +nodetypes.alternative.selected = nil -function nodefactory.alternative:__tostring () +function nodetypes.alternative:__tostring () return "A(" .. SU.concat(self.options, " / ") .. ")" end -function nodefactory.alternative:minWidth () +function nodetypes.alternative:minWidth () local minW = function (a, b) return SU.min(a.width, b.width) end return pl.tablex.reduce(minW, self.options) end -function nodefactory.alternative:deltas () +function nodetypes.alternative:deltas () local minWidth = self:minWidth() local rv = {} for i = 1, #self.options do rv[#rv+1] = self.options[i].width - minWidth end return rv end -function nodefactory.alternative:outputYourself (typesetter, line) +function nodetypes.alternative:outputYourself (typesetter, line) if self.selected then self.options[self.selected]:outputYourself(typesetter, line) end end -nodefactory.glue = pl.class(nodefactory.box) -nodefactory.glue.type = "glue" -nodefactory.glue.discardable = true +nodetypes.glue = pl.class(nodetypes.box) +nodetypes.glue.type = "glue" +nodetypes.glue.discardable = true -function nodefactory.glue:__tostring () +function nodetypes.glue:__tostring () return (self.explicit and "E:" or "") .. "G<" .. tostring(self.width) .. ">" end -function nodefactory.glue.toText (_) +function nodetypes.glue.toText (_) return " " end -function nodefactory.glue:outputYourself (typesetter, line) +function nodetypes.glue:outputYourself (typesetter, line) local outputWidth = SU.rationWidth(self.width:absolute(), self.width:absolute(), line.ratio) typesetter.frame:advanceWritingDirection(outputWidth) end -- A hfillglue is just a glue with infinite stretch. -- (Convenience so callers do not have to know what infinity is.) -nodefactory.hfillglue = pl.class(nodefactory.glue) -function nodefactory.hfillglue:_init (spec) +nodetypes.hfillglue = pl.class(nodetypes.glue) +function nodetypes.hfillglue:_init (spec) self:super(spec) self.width = SILE.length(self.width.length, infinity, self.width.shrink) end -- A hssglue is just a glue with infinite stretch and shrink. -- (Convenience so callers do not have to know what infinity is.) -nodefactory.hssglue = pl.class(nodefactory.glue) -function nodefactory.hssglue:_init (spec) +nodetypes.hssglue = pl.class(nodetypes.glue) +function nodetypes.hssglue:_init (spec) self:super(spec) self.width = SILE.length(self.width.length, infinity, infinity) end -nodefactory.kern = pl.class(nodefactory.glue) -nodefactory.kern.type = "kern" -- Perhaps some smell here, see comment on vkern -nodefactory.kern.discardable = false +nodetypes.kern = pl.class(nodetypes.glue) +nodetypes.kern.type = "kern" -- Perhaps some smell here, see comment on vkern +nodetypes.kern.discardable = false -function nodefactory.kern:__tostring () +function nodetypes.kern:__tostring () return "K<" .. tostring(self.width) .. ">" end -nodefactory.vglue = pl.class(nodefactory.box) -nodefactory.vglue.type = "vglue" -nodefactory.vglue.discardable = true -nodefactory.vglue._default_length = "height" -nodefactory.vglue.adjustment = nil +nodetypes.vglue = pl.class(nodetypes.box) +nodetypes.vglue.type = "vglue" +nodetypes.vglue.discardable = true +nodetypes.vglue._default_length = "height" +nodetypes.vglue.adjustment = nil -function nodefactory.vglue:_init (spec) +function nodetypes.vglue:_init (spec) self.adjustment = SILE.measurement() self:super(spec) end -function nodefactory.vglue:__tostring () +function nodetypes.vglue:__tostring () return (self.explicit and "E:" or "") .. "VG<" .. tostring(self.height) .. ">"; end -function nodefactory.vglue:adjustGlue (adjustment) +function nodetypes.vglue:adjustGlue (adjustment) self.adjustment = adjustment end -function nodefactory.vglue:outputYourself (typesetter, line) +function nodetypes.vglue:outputYourself (typesetter, line) typesetter.frame:advancePageDirection(line.height:absolute() + line.depth:absolute() + self.adjustment) end -function nodefactory.vglue:unbox () +function nodetypes.vglue:unbox () return { self } end -- A vfillglue is just a vglue with infinite stretch. -- (Convenience so callers do not have to know what infinity is.) -nodefactory.vfillglue = pl.class(nodefactory.vglue) -function nodefactory.vfillglue:_init (spec) +nodetypes.vfillglue = pl.class(nodetypes.vglue) +function nodetypes.vfillglue:_init (spec) self:super(spec) self.height = SILE.length(self.width.length, infinity, self.width.shrink) end -- A vssglue is just a vglue with infinite stretch and shrink. -- (Convenience so callers do not have to know what infinity is.) -nodefactory.vssglue = pl.class(nodefactory.vglue) -function nodefactory.vssglue:_init (spec) +nodetypes.vssglue = pl.class(nodetypes.vglue) +function nodetypes.vssglue:_init (spec) self:super(spec) self.height = SILE.length(self.width.length, infinity, infinity) end -nodefactory.zerovglue = pl.class(nodefactory.vglue) +nodetypes.zerovglue = pl.class(nodetypes.vglue) -nodefactory.vkern = pl.class(nodefactory.vglue) +nodetypes.vkern = pl.class(nodetypes.vglue) -- FIXME TODO -- Here we cannot do: --- nodefactory.vkern.type = "vkern" +-- nodetypes.vkern.type = "vkern" -- It cannot be typed as "vkern" as the pagebuilder doesn't check is_vkern. -- So it's just a vglue currrenty, marked as not discardable... --- But on the other hand, nodefactory.kern is typed "kern" and is not a glue... +-- But on the other hand, nodetypes.kern is typed "kern" and is not a glue... -- Frankly, the discardable/explicit flags and the types are too -- entangled and point towards a more general design issue. -- N.B. this vkern node is only used in the linespacing package so far. -nodefactory.vkern.discardable = false +nodetypes.vkern.discardable = false -function nodefactory.vkern:__tostring () +function nodetypes.vkern:__tostring () return "VK<" .. tostring(self.height) .. ">" end -nodefactory.penalty = pl.class(nodefactory.box) -nodefactory.penalty.type = "penalty" -nodefactory.penalty.discardable = true -nodefactory.penalty.penalty = 0 +nodetypes.penalty = pl.class(nodetypes.box) +nodetypes.penalty.type = "penalty" +nodetypes.penalty.discardable = true +nodetypes.penalty.penalty = 0 -function nodefactory.penalty:_init (spec) +function nodetypes.penalty:_init (spec) self:super(spec) if type(spec) ~= "table" then self.penalty = SU.cast("number", spec) end end -function nodefactory.penalty:__tostring () +function nodetypes.penalty:__tostring () return "P(" .. tostring(self.penalty) .. ")"; end -function nodefactory.penalty.outputYourself (_) +function nodetypes.penalty.outputYourself (_) end -function nodefactory.penalty.toText (_) +function nodetypes.penalty.toText (_) return "(!)" end -function nodefactory.penalty:unbox () +function nodetypes.penalty:unbox () return { self } end -nodefactory.vbox = pl.class(nodefactory.box) -nodefactory.vbox.type = "vbox" -nodefactory.vbox.nodes = {} -nodefactory.vbox._default_length = "height" +nodetypes.vbox = pl.class(nodetypes.box) +nodetypes.vbox.type = "vbox" +nodetypes.vbox.nodes = {} +nodetypes.vbox._default_length = "height" -function nodefactory.vbox:_init (spec) +function nodetypes.vbox:_init (spec) self.nodes = {} self:super(spec) self.depth = _maxnode(self.nodes, "depth") self.height = _maxnode(self.nodes, "height") end -function nodefactory.vbox:__tostring () +function nodetypes.vbox:__tostring () return "VB<" .. tostring(self.height) .. "|" .. self:toText() .. "v".. tostring(self.depth) ..")"; end -function nodefactory.vbox:toText () +function nodetypes.vbox:toText () return "VB[" .. SU.concat(SU.map(function (node) return node:toText() end, self.nodes), "") .. "]" end -function nodefactory.vbox:outputYourself (typesetter, line) +function nodetypes.vbox:outputYourself (typesetter, line) typesetter.frame:advancePageDirection(self.height) local initial = true for _, node in ipairs(self.nodes) do @@ -574,14 +574,14 @@ function nodefactory.vbox:outputYourself (typesetter, line) typesetter.frame:newLine() end -function nodefactory.vbox:unbox () +function nodetypes.vbox:unbox () for i = 1, #self.nodes do if self.nodes[i].is_vbox or self.nodes[i].is_vglue then return self.nodes end end return {self} end -function nodefactory.vbox:append (box) +function nodetypes.vbox:append (box) local nodes = box if not box then SU.error("nil box given", true) end if nodes.type then @@ -601,112 +601,112 @@ function nodefactory.vbox:append (box) self.depth = lastdepth end -nodefactory.migrating = pl.class(nodefactory.hbox) -nodefactory.migrating.type = "migrating" -nodefactory.migrating.material = {} -nodefactory.migrating.value = {} -nodefactory.migrating.nodes = {} +nodetypes.migrating = pl.class(nodetypes.hbox) +nodetypes.migrating.type = "migrating" +nodetypes.migrating.material = {} +nodetypes.migrating.value = {} +nodetypes.migrating.nodes = {} -function nodefactory.migrating:__tostring () +function nodetypes.migrating:__tostring () return "" end local _deprecated_nodefactory = {} _deprecated_nodefactory.newHbox = function (spec) - return nodefactory.hbox(spec) + return node.hbox(spec) end _deprecated_nodefactory.newNnode = function (spec) - return nodefactory.nnode(spec) + return node.nnode(spec) end _deprecated_nodefactory.newUnshaped = function (spec) - return nodefactory.unshaped(spec) + return node.unshaped(spec) end _deprecated_nodefactory.newDisc = function (spec) - return nodefactory.discretionary(spec) + return node.discretionary(spec) end _deprecated_nodefactory.disc = function (spec) - return nodefactory.discretionary(spec) + return node.discretionary(spec) end _deprecated_nodefactory.newAlternative = function (spec) - return nodefactory.alternative(spec) + return node.alternative(spec) end _deprecated_nodefactory.newGlue = function (spec) - return nodefactory.glue(spec) + return node.glue(spec) end _deprecated_nodefactory.newKern = function (spec) - return nodefactory.kern(spec) + return node.kern(spec) end _deprecated_nodefactory.newVglue = function (spec) - return nodefactory.vglue(spec) + return node.vglue(spec) end _deprecated_nodefactory.newVKern = function (spec) - return nodefactory.vkern(spec) + return node.vkern(spec) end _deprecated_nodefactory.newPenalty = function (spec) - return nodefactory.penalty(spec) + return node.penalty(spec) end _deprecated_nodefactory.newDiscretionary = function (spec) - return nodefactory.discretionary(spec) + return node.discretionary(spec) end _deprecated_nodefactory.newVbox = function (spec) - return nodefactory.vbox(spec) + return node.vbox(spec) end _deprecated_nodefactory.newMigrating = function (spec) - return nodefactory.migrating(spec) + return node.migrating(spec) end _deprecated_nodefactory.zeroGlue = function () - return nodefactory.glue() + return node.glue() end _deprecated_nodefactory.hfillGlue = function () - return nodefactory.hfillglue() + return node.hfillglue() end _deprecated_nodefactory.vfillGlue = function () - return nodefactory.vfillglue() + return node.vfillglue() end _deprecated_nodefactory.hssGlue = function () - return nodefactory.hssglue() + return node.hssglue() end _deprecated_nodefactory.vssGlue = function () - return nodefactory.vssglue() + return node.vssglue() end _deprecated_nodefactory.zeroHbox = function () - return nodefactory.zerohbox() + return node.zerohbox() end _deprecated_nodefactory.zeroVglue = function () - return nodefactory.zerovglue() + return node.zerovglue() end -setmetatable(nodefactory, { +setmetatable(nodetypes, { __index = function (_, prop) if _deprecated_nodefactory[prop] then - SU.deprecated("SILE.nodefactory." .. prop, "SILE.nodefactory." .. prop:match("n?e?w?(.*)"):lower(), "0.10.0", "0.14.0") + SU.deprecated("SILE.types.node." .. prop, "SILE.types.node." .. prop:match("n?e?w?(.*)"):lower(), "0.10.0", "0.14.0") elseif type(prop) == "number" then -- luacheck: ignore 542 -- Likely at attempt to iterate (or dump) the table, sort of safe to ignore else - SU.error("Attempt to access non-existent SILE.nodefactory." .. prop) + SU.error("Attempt to access non-existent SILE.types.node." .. prop) end end }) -return nodefactory +return nodetypes diff --git a/spec/nodefactory_spec.lua b/types/node_spec.lua similarity index 75% rename from spec/nodefactory_spec.lua rename to types/node_spec.lua index a78ca3475..44314dffe 100644 --- a/spec/nodefactory_spec.lua +++ b/types/node_spec.lua @@ -1,10 +1,10 @@ SILE = require("core.sile") describe("The node factory", function() - it("should exist", function() assert.is.truthy(SILE.nodefactory) end) + it("should exist", function() assert.is.truthy(SILE.types.node) end) describe("hboxes", function() - local hbox = SILE.nodefactory.hbox({ width = 20, height = 30, depth = 3 }) + local hbox = SILE.types.node.hbox({ width = 20, height = 30, depth = 3 }) it("should have width", function () assert.is.equal(20, hbox.width:tonumber()) end) it("should have height", function () assert.is.equal(30, hbox.height:tonumber()) end) it("should have depth", function () assert.is.equal(3, hbox.depth:tonumber()) end) @@ -15,9 +15,9 @@ describe("The node factory", function() end) describe("vboxes", function() - local hbox1 = SILE.nodefactory.hbox({ width = 10, height = 5, depth = 2 }) - local hbox2 = SILE.nodefactory.hbox({ width = 11, height = 6, depth = 3 }) - local vbox = SILE.nodefactory.vbox({ height = 4, depth = 3, nodes = { hbox1, hbox2 } }) + local hbox1 = SILE.types.node.hbox({ width = 10, height = 5, depth = 2 }) + local hbox2 = SILE.types.node.hbox({ width = 11, height = 6, depth = 3 }) + local vbox = SILE.types.node.vbox({ height = 4, depth = 3, nodes = { hbox1, hbox2 } }) it("should have nodes", function () assert.is.equal(2, #vbox.nodes) end) it("should have height", function () assert.is.equal(6, vbox.height:tonumber()) end) it("should have depth", function () assert.is.equal(3, vbox.depth:tonumber()) end) @@ -28,9 +28,9 @@ describe("The node factory", function() end) describe("nnodes", function () - local hbox1 = SILE.nodefactory.hbox({ width = 10, height = 5, depth = 3 }) - local hbox2 = SILE.nodefactory.hbox({ width = 20, height = 10, depth = 5 }) - local nnode = SILE.nodefactory.nnode({ text = "test", nodes = { hbox1, hbox2 } }) + local hbox1 = SILE.types.node.hbox({ width = 10, height = 5, depth = 3 }) + local hbox2 = SILE.types.node.hbox({ width = 20, height = 10, depth = 5 }) + local nnode = SILE.types.node.nnode({ text = "test", nodes = { hbox1, hbox2 } }) it("should have width", function () assert.is.equal(30, nnode.width:tonumber()) end) it("should have depth", function () assert.is.equal(5, nnode.depth:tonumber()) end) it("should have height", function () assert.is.equal(10, nnode.height:tonumber()) end) @@ -40,10 +40,10 @@ describe("The node factory", function() end) describe("discs", function () - local nnode1 = SILE.nodefactory.nnode({ width = 20, height = 30, depth = 3, text = "pre" }) - local nnode2 = SILE.nodefactory.nnode({ width = 20, height = 30, depth = 3, text = "break" }) - local nnode3 = SILE.nodefactory.nnode({ width = 20, height = 30, depth = 3, text = "post" }) - local discretionary = SILE.nodefactory.discretionary({ prebreak = { nnode1, nnode2 }, postbreak = { nnode3, nnode2 } }) + local nnode1 = SILE.types.node.nnode({ width = 20, height = 30, depth = 3, text = "pre" }) + local nnode2 = SILE.types.node.nnode({ width = 20, height = 30, depth = 3, text = "break" }) + local nnode3 = SILE.types.node.nnode({ width = 20, height = 30, depth = 3, text = "post" }) + local discretionary = SILE.types.node.discretionary({ prebreak = { nnode1, nnode2 }, postbreak = { nnode3, nnode2 } }) it("should stringify", function() assert.is.equal("D(N<20pt>^30pt-3ptv(pre)N<20pt>^30pt-3ptv(break)|N<20pt>^30pt-3ptv(post)N<20pt>^30pt-3ptv(break)|)", tostring(discretionary)) end) end) diff --git a/core/units.lua b/types/unit.lua similarity index 88% rename from core/units.lua rename to types/unit.lua index 909c5ed5a..452ecab9f 100644 --- a/core/units.lua +++ b/types/unit.lua @@ -1,16 +1,18 @@ -local units = { +local bits = require("core.parserbits") + +local unittypes = { pt = { relative = false, value = 1 } } -setmetatable(units, { +setmetatable(unittypes, { __newindex = function (self, unit, spec) local def = SU.required(spec, "definition", "registering unit " .. unit) local relative = SU.boolean(spec.relative, false) if type(def) == "string" then - local parsed = SILE.parserBits.measurement:match(def) + local parsed = bits.measurement:match(def) if not parsed then SU.error("Could not parse unit definition '"..def.."'") end if not self[parsed.unit] then SU.error("Unit " .. unit .. " defined in terms of unknown unit " .. parsed.unit) @@ -36,36 +38,36 @@ setmetatable(units, { end }) -units["twip"] = { +unittypes["twip"] = { definition = "0.05pt" } -units["mm"] = { +unittypes["mm"] = { definition = "2.8346457pt" } -units["cm"] = { +unittypes["cm"] = { definition = "10mm" } -units["m"] = { +unittypes["m"] = { definition = "100cm" } -units["hm"] = { +unittypes["hm"] = { definition = "0.01mm" } -units["in"] = { +unittypes["in"] = { definition = "72pt" } -units["ft"] = { +unittypes["ft"] = { definition = "12in" } -- Picas are 1/6 inch, used in Docbook images -units["pc"] = { +unittypes["pc"] = { definition = "0.166666667in" } @@ -81,7 +83,7 @@ local checkFrameDefined = function () end end -units["%pw"] = { +unittypes["%pw"] = { relative = true, definition = function (value) checkPaperDefined() @@ -89,7 +91,7 @@ units["%pw"] = { end } -units["%ph"] = { +unittypes["%ph"] = { relative = true, definition = function (value) checkPaperDefined() @@ -97,7 +99,7 @@ units["%ph"] = { end } -units["%pmin"] = { +unittypes["%pmin"] = { relative = true, definition = function (value) checkPaperDefined() @@ -105,7 +107,7 @@ units["%pmin"] = { end } -units["%pmax"] = { +unittypes["%pmax"] = { relative = true, definition = function (value) checkPaperDefined() @@ -113,7 +115,7 @@ units["%pmax"] = { end } -units["%fw"] = { +unittypes["%fw"] = { relative = true, definition = function (value) checkFrameDefined() @@ -121,7 +123,7 @@ units["%fw"] = { end } -units["%fh"] = { +unittypes["%fh"] = { relative = true, definition = function (value) checkFrameDefined() @@ -129,7 +131,7 @@ units["%fh"] = { end } -units["%fmin"] = { +unittypes["%fmin"] = { relative = true, definition = function (value) checkFrameDefined() @@ -137,7 +139,7 @@ units["%fmin"] = { end } -units["%fmax"] = { +unittypes["%fmax"] = { relative = true, definition = function (value) checkFrameDefined() @@ -145,7 +147,7 @@ units["%fmax"] = { end } -units["%lw"] = { +unittypes["%lw"] = { relative = true, definition = function (value) local lskip = SILE.settings:get("document.lskip") @@ -157,7 +159,7 @@ units["%lw"] = { end } -units["ps"] = { +unittypes["ps"] = { relative = true, definition = function (value) local ps = SILE.settings:get("document.parskip") @@ -166,7 +168,7 @@ units["ps"] = { end } -units["bs"] = { +unittypes["bs"] = { relative = true, definition = function (value) local bs = SILE.settings:get("document.baselineskip") @@ -175,28 +177,28 @@ units["bs"] = { end } -units["em"] = { +unittypes["em"] = { relative = true, definition = function (value) return value * SILE.settings:get("font.size") end } -units["ex"] = { +unittypes["ex"] = { relative = true, definition = function (value) return value * SILE.shaper:measureChar("x").height end } -units["spc"] = { +unittypes["spc"] = { relative = true, definition = function (value) return value * SILE.shaper:measureChar(" ").width end } -units["en"] = { +unittypes["en"] = { relative = true, definition = "0.5em" } @@ -205,7 +207,7 @@ units["en"] = { -- width of a full-width character. In SILE terms it isn't: measuring an "m" in -- a 10pt Japanese font gets you 5 points. So we measure a full-width character -- and use that as a unit. We call it zw following ptex (zenkaku width) -units["zw"] = { +unittypes["zw"] = { relative = true, definition = function (v) local zenkakuchar = SILE.settings:get("document.zenkakuchar") @@ -220,4 +222,4 @@ units["zw"] = { end } -return units +return unittypes