• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sile-typesetter / sile / 9409557472

07 Jun 2024 12:09AM UTC coverage: 69.448% (-4.5%) from 73.988%
9409557472

push

github

alerque
fix(build): Distribute vendored compat-5.3.c source file

12025 of 17315 relevant lines covered (69.45%)

6023.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/packages/ruby/init.lua
1
local base = require("packages.base")
×
2

3
local package = pl.class(base)
×
4
package._name = "ruby"
×
5

6
local isLatin = function (char)
7
   return (char > 0x20 and char <= 0x24F)
×
8
      or (char >= 0x300 and char <= 0x36F)
×
9
      or (char >= 0x1DC0 and char <= 0x1EFF)
×
10
      or (char >= 0x2C60 and char <= 0x2c7F)
×
11
end
12

13
local checkIfSpacerNeeded = function (reading)
14
   -- First, did we have a ruby node at all?
15
   if not SILE.scratch.lastRubyBox then
×
16
      return
×
17
   end
18
   -- Does the current reading start with a latin?
19
   if not isLatin(SU.codepoint(SU.firstChar(reading))) then
×
20
      return
×
21
   end
22
   -- Did we have some nodes recently?
23
   local top = #SILE.typesetter.state.nodes
×
24
   if top < 2 then
×
25
      return
×
26
   end
27
   -- Have we had other stuff since the last ruby node?
28
   if
29
      SILE.typesetter.state.nodes[top] ~= SILE.scratch.lastRubyBox
×
30
      and SILE.typesetter.state.nodes[top - 1] ~= SILE.scratch.lastRubyBox
×
31
   then
32
      return
×
33
   end
34
   -- Does the previous reading end with a latin?
35
   if not isLatin(SU.codepoint(SU.lastChar(SILE.scratch.lastRubyText))) then
×
36
      return
×
37
   end
38
   -- OK, we need a spacer!
39
   SILE.typesetter:pushGlue(SILE.settings:get("ruby.latinspacer"))
×
40
end
41

42
function package:_init ()
×
43
   base._init(self)
×
44
   -- Japanese language support defines units which are useful here
45
   self:loadPackage("font-fallback")
×
46
   SILE.call("font:add-fallback", { family = "Noto Sans CJK JP" })
×
47
   SILE.languageSupport.loadLanguage("ja")
×
48
end
49

50
function package.declareSettings (_)
×
51
   SILE.settings:declare({
×
52
      parameter = "ruby.height",
53
      type = "measurement",
54
      default = SILE.types.measurement("1zw"),
55
      help = "Vertical offset between the ruby and the main text",
56
   })
57

58
   SILE.settings:declare({
×
59
      parameter = "ruby.latinspacer",
60
      type = "glue",
61
      default = SILE.types.node.glue("0.25em"),
62
      help = "Glue added between consecutive Latin ruby",
63
   })
64

65
   SILE.settings:declare({
×
66
      parameter = "ruby.opentype",
67
      type = "boolean",
68
      default = true,
69
      help = "Use OpenType tate feature instead of of a bold weight",
70
   })
71
end
72

73
function package:registerCommands ()
×
74
   self:registerCommand("ruby:font", function (_, _)
×
75
      if SILE.settings:get("ruby.opentype") then
×
76
         SILE.call("font", { size = "0.6zw", features = "+ruby" })
×
77
      else
78
         SILE.call("font", { size = "0.6zw", weight = 700 })
×
79
      end
80
   end)
81

82
   self:registerCommand("ruby", function (options, content)
×
83
      local reading = SU.required(options, "reading", "\\ruby")
×
84
      SILE.typesetter:setpar("")
×
85

86
      checkIfSpacerNeeded(reading)
×
87

88
      local rubybox = SILE.call("hbox", {}, function ()
×
89
         SILE.settings:temporarily(function ()
×
90
            SILE.call("noindent")
×
91
            SILE.call("ruby:font")
×
92
            SILE.typesetter:typeset(reading)
×
93
         end)
94
      end)
95
      rubybox.outputYourself = function (box, typesetter, line)
96
         local ox = typesetter.frame.state.cursorX
×
97
         local oy = typesetter.frame.state.cursorY
×
98
         typesetter.frame:advanceWritingDirection(rubybox.width)
×
99
         typesetter.frame:advancePageDirection(-SILE.settings:get("ruby.height"))
×
100
         SILE.outputter:setCursor(typesetter.frame.state.cursorX, typesetter.frame.state.cursorY)
×
101
         for i = 1, #box.value do
×
102
            local node = box.value[i]
×
103
            node:outputYourself(typesetter, line)
×
104
         end
105
         typesetter.frame.state.cursorX = ox
×
106
         typesetter.frame.state.cursorY = oy
×
107
      end
108
      -- measure the content
109
      local cbox = SILE.call("hbox", {}, content)
×
110
      SU.debug("ruby", "base box is", cbox)
×
111
      SU.debug("ruby", "reading is", rubybox)
×
112
      if cbox:lineContribution() > rubybox:lineContribution() then
×
113
         SU.debug("ruby", "Base is longer, offsetting ruby to fit")
×
114
         -- This is actually the offset against the base
115
         rubybox.width = SILE.types.length(cbox:lineContribution() - rubybox:lineContribution()) / 2
×
116
      else
117
         local diff = rubybox:lineContribution() - cbox:lineContribution()
×
118
         local to_insert = SILE.types.length(diff / 2)
×
119
         SU.debug("ruby", "Ruby is longer, inserting", to_insert, "either side of base")
×
120
         cbox.width = rubybox:lineContribution()
×
121
         rubybox.height = 0
×
122
         rubybox.width = 0
×
123
         -- add spaces at beginning and end
124
         table.insert(cbox.value, 1, SILE.types.node.glue(to_insert))
×
125
         table.insert(cbox.value, SILE.types.node.glue(to_insert))
×
126
      end
127
      SILE.scratch.lastRubyBox = rubybox
×
128
      SILE.scratch.lastRubyText = reading
×
129
   end)
130
end
131

132
package.documentation = [[
133
\begin{document}
134
\font:add-fallback[family=Noto Sans CJK JP]
135
\use[module=packages.ruby]
136
Japanese texts often contain pronunciation hints (called \em{furigana}) for difficult kanji or foreign words.
137
These hints are traditionally placed either above (in horizontal typesetting) or beside (in vertical typesetting) the word that they explain.
138
The typesetting term for these glosses is \em{ruby}.
139

140
The \autodoc:package{ruby} package provides the \autodoc:command[check=false]{\ruby[reading=<ruby text>]{<base text>}} command which sets a piece of ruby above or beside the base text.
141
For example:
142

143
\set[parameter=ruby.height,value=12pt]
144
\define[command=ja]{\font[family=Noto Sans CJK JP,language=ja]{\process}}
145

146
\begin{autodoc:codeblock}
147
\\ruby[reading=\ja{れいわ}]\{\ja{令和}\}
148
\end{autodoc:codeblock}
149

150
Produces:
151
\medskip
152
\ja{\ruby[reading=れいわ]{令和}}
153

154
\font:remove-fallback
155
\end{document}
156
]]
×
157

158
return package
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc