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

sile-typesetter / sile / 11645631468

02 Nov 2024 08:31PM UTC coverage: 66.687% (-2.7%) from 69.34%
11645631468

Pull #2072

github

alerque
refactor(cli): Redo option parsing enabled by mlua v0.10 scopes
Pull Request #2072: Setup Lua module for exporting Rust functions to Lua

2 of 2 new or added lines in 2 files covered. (100.0%)

476 existing lines in 28 files now uncovered.

12087 of 18125 relevant lines covered (66.69%)

5249.73 hits per line

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

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

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

6
local isLatin = function (char)
UNCOV
7
   return (char > 0x20 and char <= 0x24F)
×
UNCOV
8
      or (char >= 0x300 and char <= 0x36F)
×
UNCOV
9
      or (char >= 0x1DC0 and char <= 0x1EFF)
×
UNCOV
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?
UNCOV
15
   if not SILE.scratch.lastRubyBox then
×
UNCOV
16
      return
×
17
   end
18
   -- Does the current reading start with a latin?
UNCOV
19
   if not isLatin(SU.codepoint(SU.firstChar(reading))) then
×
UNCOV
20
      return
×
21
   end
22
   -- Did we have some nodes recently?
UNCOV
23
   local top = #SILE.typesetter.state.nodes
×
UNCOV
24
   if top < 2 then
×
25
      return
×
26
   end
27
   -- Have we had other stuff since the last ruby node?
28
   if
UNCOV
29
      SILE.typesetter.state.nodes[top] ~= SILE.scratch.lastRubyBox
×
UNCOV
30
      and SILE.typesetter.state.nodes[top - 1] ~= SILE.scratch.lastRubyBox
×
31
   then
UNCOV
32
      return
×
33
   end
34
   -- Does the previous reading end with a latin?
UNCOV
35
   if not isLatin(SU.codepoint(SU.lastChar(SILE.scratch.lastRubyText))) then
×
UNCOV
36
      return
×
37
   end
38
   -- OK, we need a spacer!
UNCOV
39
   SILE.typesetter:pushGlue(SILE.settings:get("ruby.latinspacer"))
×
40
end
41

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

UNCOV
50
function package.declareSettings (_)
×
UNCOV
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

UNCOV
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

UNCOV
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

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

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

UNCOV
86
      checkIfSpacerNeeded(reading)
×
87

UNCOV
88
      local rubybox = SILE.call("hbox", {}, function ()
×
UNCOV
89
         SILE.settings:temporarily(function ()
×
UNCOV
90
            SILE.call("noindent")
×
UNCOV
91
            SILE.call("ruby:font")
×
UNCOV
92
            SILE.typesetter:typeset(reading)
×
93
         end)
94
      end)
95
      rubybox.outputYourself = function (box, typesetter, line)
UNCOV
96
         local ox = typesetter.frame.state.cursorX
×
UNCOV
97
         local oy = typesetter.frame.state.cursorY
×
UNCOV
98
         typesetter.frame:advanceWritingDirection(rubybox.width)
×
UNCOV
99
         typesetter.frame:advancePageDirection(-SILE.settings:get("ruby.height"))
×
UNCOV
100
         SILE.outputter:setCursor(typesetter.frame.state.cursorX, typesetter.frame.state.cursorY)
×
UNCOV
101
         for i = 1, #box.value do
×
UNCOV
102
            local node = box.value[i]
×
UNCOV
103
            node:outputYourself(typesetter, line)
×
104
         end
UNCOV
105
         typesetter.frame.state.cursorX = ox
×
UNCOV
106
         typesetter.frame.state.cursorY = oy
×
107
      end
108
      -- measure the content
UNCOV
109
      local cbox = SILE.call("hbox", {}, content)
×
UNCOV
110
      SU.debug("ruby", "base box is", cbox)
×
UNCOV
111
      SU.debug("ruby", "reading is", rubybox)
×
UNCOV
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
UNCOV
117
         local diff = rubybox:lineContribution() - cbox:lineContribution()
×
UNCOV
118
         local to_insert = SILE.types.length(diff / 2)
×
UNCOV
119
         SU.debug("ruby", "Ruby is longer, inserting", to_insert, "either side of base")
×
UNCOV
120
         cbox.width = rubybox:lineContribution()
×
UNCOV
121
         rubybox.height = 0
×
UNCOV
122
         rubybox.width = 0
×
123
         -- add spaces at beginning and end
UNCOV
124
         table.insert(cbox.value, 1, SILE.types.node.glue(to_insert))
×
UNCOV
125
         table.insert(cbox.value, SILE.types.node.glue(to_insert))
×
126
      end
UNCOV
127
      SILE.scratch.lastRubyBox = rubybox
×
UNCOV
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}
UNCOV
156
]]
×
157

UNCOV
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

© 2026 Coveralls, Inc