diff --git a/classes/resilient/book.lua b/classes/resilient/book.lua index b3df075..59de7c7 100644 --- a/classes/resilient/book.lua +++ b/classes/resilient/book.lua @@ -306,6 +306,14 @@ function class:registerStyles () reference = "sectioning-other-number", } }, }) + self:registerStyle("sectioning-appendix", { inherit = "sectioning-chapter" }, { + sectioning = { numberstyle= { + main = "sectioning-appendix-main-number", + header = "sectioning-appendix-head-number", + reference = "sectioning-appendix-ref-number", + }, + }, + }) self:registerStyle("sectioning-part-base-number", {}, { numbering = { display = "ROMAN" } @@ -322,6 +330,7 @@ function class:registerStyles () self:registerStyle("sectioning-part-ref-number", { inherit = "sectioning-part-base-number" }, { numbering = { before = { text ="part " } }, }) + self:registerStyle("sectioning-chapter-base-number", {}, { }) self:registerStyle("sectioning-chapter-main-number", { inherit = "sectioning-chapter-base-number" }, { @@ -337,6 +346,17 @@ function class:registerStyles () numbering = { before = { text ="chap. " } }, }) + self:registerStyle("sectioning-appendix-main-number", { inherit = "sectioning-chapter-main-number" }, { + numbering = { before = { text = "Appendix "}, + display = "ALPHA", + }, + }) + self:registerStyle("sectioning-appendix-head-number", { inherit = "sectioning-chapter-head-number" }, { + }) + self:registerStyle("sectioning-appendix-ref-number", { inherit = "sectioning-chapter-ref-number" }, { + numbering = { before = { text ="app. " } }, + }) + self:registerStyle("sectioning-other-number", {}, { numbering = { after = { text = ".", kern = "iwsp" } } }) @@ -673,6 +693,17 @@ function class:registerCommands () end end, "Applies section hooks (footers and headers, etc.)") + self:registerCommand("appendix", function (options, content) + if self.resilientState.appendix then + SU.error("Already in the \\appendix sub-division") + end + if self.resilientState.division and self.resilientState.division < 2 then + SU.error("\\appendix is not valid in " .. DIVISIONNAME[self.resilientState.division]) + end + self.resilientState.appendix = true + SILE.call("set-multilevel-counter", { id = "sections", level = 1, value = 0 }) + end, "Switch to appendix sub-division.") + self:registerCommand("part", function (options, content) if self.resilientState.division and self.resilientState.division ~= 2 then options.numbering = false @@ -682,10 +713,10 @@ function class:registerCommands () end, "Begin a new part.") self:registerCommand("chapter", function (options, content) - if self.resilientState.division and self.resilientState.division ~= 2 then + if not self.resilientState.appendix and self.resilientState.division and self.resilientState.division ~= 2 then options.numbering = false end - options.style = "sectioning-chapter" + options.style = self.resilientState.appendix and "sectioning-appendix" or "sectioning-chapter" SILE.call("sectioning", options, content) end, "Begin a new chapter.") diff --git a/examples/manual-classes/classes.sil b/examples/manual-classes/classes.sil index 427bc11..a61b6c7 100644 --- a/examples/manual-classes/classes.sil +++ b/examples/manual-classes/classes.sil @@ -314,7 +314,7 @@ The environment relies on the same-named style for its styling and on the \autodoc:setting{book.blockquote.margin} setting for its indentation (defaults to 2em). Indented quotes can be nested. -\section{Front, main and back divisions} +\section{Additional book divisions} The class supports the standard \autodoc:command{\frontmatter}, \autodoc:command{\mainmatter} and \autodoc:command{\backmatter} commands to switch between the different higher-level divisions of the document. Obviously, these commands can only occur once in the document, and in the order given above. @@ -342,10 +342,16 @@ They start a new page, and influence the style of folios. \caption{Styles used for folios in different document divisions.} \end{table} -Books not using these divisions assume "main" matter by default. -In the "front" and "back" matter divisions, parts and chapters are never numbered. +Books not using these divisions assume “main” matter by default. +In the “front” and “back” matter divisions, parts and chapters are never numbered. Not that this is not a configurable style decision, but the very definition of these divisions. -In "main" matter, they are numbered by default, although this can be changed either on the sectioning command itself, or globally with adequate styles. +In the main matter, they are numbered by default, although this can be changed either on the sectioning command itself, or globally with adequate styles. + +The class also supports the \autodoc:command{\appendix} command, which can only be invoke once, either in the main matter or in the back matter. +After that, the chapter counter is reset and chapters now use appendix sectioning styles. +By default, these styles derive from the chapter styles, with the numbering changed to uppercase letters, and the prefix text to “Appendix”. +Note that appendices are numbered even in the back matter, by default, according to common practice. +Again, this can be changed on the sectioning command itself, or globally with adequate styles. \section{Other features} diff --git a/examples/manual-styling/basics/sectioning.md b/examples/manual-styling/basics/sectioning.md index ea66c66..00caef9 100644 --- a/examples/manual-styling/basics/sectioning.md +++ b/examples/manual-styling/basics/sectioning.md @@ -75,6 +75,8 @@ numbering in the table of contents is handled with a different mechanism, as a part of the ToC styles. Whether there is a need to reconcile these solutions might be considered in a future revision.] Note that if a given context is absent, the section number will not be displayed. +This might be sufficient to disable inherited numbering in some contexts, but +in these cases, you can just set the `main` number style to `null` (without quotes). For the "main" number style, some sections may expect the number to be on its own standalone line rather than just before the section title.—Chapters and parts, diff --git a/examples/sile-resilient-manual-styles.yml b/examples/sile-resilient-manual-styles.yml index 61bf432..bf98f72 100644 --- a/examples/sile-resilient-manual-styles.yml +++ b/examples/sile-resilient-manual-styles.yml @@ -697,6 +697,38 @@ prosody: before: skip: "smallskip" +sectioning-appendix: + inherit: "sectioning-chapter" + origin: "resilient.book" + style: + sectioning: + numberstyle: + header: "sectioning-appendix-head-number" + main: "sectioning-appendix-main-number" + reference: "sectioning-appendix-ref-number" + +sectioning-appendix-head-number: + inherit: "sectioning-chapter-head-number" + origin: "resilient.book" + style: + +sectioning-appendix-main-number: + inherit: "sectioning-chapter-main-number" + origin: "resilient.book" + style: + numbering: + before: + text: "Appendix " + display: "ALPHA" + +sectioning-appendix-ref-number: + inherit: "sectioning-chapter-ref-number" + origin: "resilient.book" + style: + numbering: + before: + text: "app. " + sectioning-base: origin: "resilient.book" style: diff --git a/packages/resilient/sectioning/init.lua b/packages/resilient/sectioning/init.lua index fbce6ad..0fc51c8 100644 --- a/packages/resilient/sectioning/init.lua +++ b/packages/resilient/sectioning/init.lua @@ -36,6 +36,21 @@ local function hasContent() return hasNonGlueContent end +local function nameIfNotNull (name) + -- Nothig to fancy but there's a special case for the null value in YAML + -- style definitions. + if not name then + return nil + end + if type(name) == "string" then + return name + end + if tostring(name) == "yaml.null" then + return nil + end + SU.error("Invalid style name, expected a string or YAML null") +end + function package:registerCommands () local resolveSectionStyleDef = function (name) @@ -99,7 +114,8 @@ function package:registerCommands () -- shouldn't trigger a goodbreak in-between). -- Process the section (title) content - local numSty = secStyle.numberstyle.main and self:resolveStyle(secStyle.numberstyle.main) + local numStyName = secStyle.numberstyle.main and nameIfNotNull(secStyle.numberstyle.main) + local numSty = numStyName and self:resolveStyle(numStyName) local numDisplay = numSty and numSty.numbering and numSty.numbering.display or "arabic" -- Counter for numbered sections @@ -124,8 +140,11 @@ function package:registerCommands () hookOptions.counter = secStyle.counter.id hookOptions.level = secStyle.counter.level hookOptions.before = true -- HACK SEE BELOW - local numsty = sty.sectioning and sty.sectioning.numberstyle - and sty.sectioning.numberstyle.header + local numsty = sty.sectioning + and sty.sectioning.numberstyle + -- Only user header number if main number style is defined + and nameIfNotNull(sty.sectioning.numberstyle.main) + and nameIfNotNull(sty.sectioning.numberstyle.header) if numbering and numsty then titleHookContent = { createCommand("style:apply:number", { name = numsty, text = number }), @@ -176,9 +195,9 @@ function package:registerCommands () -- Show section number (if numbering is true AND a main style is defined) if numbering then - if secStyle.numberstyle.main then + if numStyName then titleContent[#titleContent + 1] = - createCommand("style:apply:number", { name = secStyle.numberstyle.main, text = number }) + createCommand("style:apply:number", { name = numStyName, text = number }) if SU.boolean(numSty.numbering and numSty.numbering.standalone, false) then titleContent[#titleContent + 1] = createCommand("hardbreak")