Skip to content

Commit

Permalink
feat(typesetters): Support for speaker change introduced by em-dash
Browse files Browse the repository at this point in the history
Some conventions denote speaker changes in dialogues by starting
a paragraph with an em-dash.
In these cases, the space after the em-dash shall be fixed by
default.
  • Loading branch information
Omikhleia authored and alerque committed Jan 23, 2024
1 parent 312cc12 commit 2afa4cb
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 0 deletions.
5 changes: 5 additions & 0 deletions documentation/c07-settings.sil
Expand Up @@ -189,6 +189,11 @@ Note that non-breaking spaces (U+00A0), following the guidelines of Unicode Anne

If you want to disable this behavior, the \autodoc:setting{languages.fixedNbsp} setting may be set to \code{true} to enforce fixed-width non-breaking spaces.

Some typography conventions use an em-dash at the start of a paragraph line to denote a speaker change in a dialogue.
This is the case in particular in French and Turkish typography.
By default, all spaces following an em-dash at the beginning of a paragraph in your input are replaced by a single \em{fixed} inter-word space, so that subsequent dialogue lines all start identically, while other inter-word spaces may still be variable for justification purposes.
To cancel this behavior, the \autodoc:setting{typesetter.fixedSpacingAfterInitialEmdash} setting may be set to \code{false}.

\subsection{Letter spacing settings}

You can also put spaces in between \em{letters} with the \autodoc:setting{document.letterspaceglue} setting.
Expand Down
28 changes: 28 additions & 0 deletions typesetters/base.lua
Expand Up @@ -145,6 +145,13 @@ function typesetter.declareSettings(_)
default = false,
help = "When true, a warning is issued when a soft hyphen is encountered"
})

SILE.settings:declare({
parameter = "typesetter.fixedSpacingAfterInitialEmdash",
type = "boolean",
default = true,
help = "When true, em-dash starting a paragraph is considered as a speaker change in a dialogue"
})
end

function typesetter:initState ()
Expand Down Expand Up @@ -330,6 +337,12 @@ function typesetter:endline ()
SILE.documentState.documentClass.endPar(self)
end

-- Just compute once, to avoid unicode characters in source code.
local speakerChangePattern = "^"
.. luautf8.char(0x2014) -- emdash
.. "[ " .. luautf8.char(0x00A0) .. luautf8.char(0x202F) -- regular space or NBSP or NNBSP
.. "]+"

-- Takes string, writes onto self.state.nodes
function typesetter:setpar (text)
text = text:gsub("\r?\n", " "):gsub("\t", " ")
Expand All @@ -338,6 +351,21 @@ function typesetter:setpar (text)
text = text:gsub("^%s+", "")
end
self:initline()

if SILE.settings:get("typesetter.fixedSpacingAfterInitialEmdash") and not SILE.settings:get("typesetter.obeyspaces") then
local speakerChange = false
local dialogue = luautf8.gsub(text, speakerChangePattern, function ()
speakerChange = true
return ""
end)
if speakerChange then
text = dialogue
local fontoptions = SILE.font.loadDefaults({})
local fiwsp = SILE.shaper:measureSpace(fontoptions).length -- fixed inter-word space
self:pushUnshaped({ text = luautf8.char(0x2014), options = fontoptions })
self:pushHorizontal(SILE.nodefactory.kern(fiwsp))
end
end
end
if #text >0 then
self:pushUnshaped({ text = text, options= SILE.font.loadDefaults({})})
Expand Down

0 comments on commit 2afa4cb

Please sign in to comment.