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

sile-typesetter / sile / 14335207249

08 Apr 2025 01:46PM UTC coverage: 60.462% (+0.9%) from 59.535%
14335207249

push

github

web-flow
Merge pull request #2257 from alerque/lintery

98 of 147 new or added lines in 46 files covered. (66.67%)

1 existing line in 1 file now uncovered.

13061 of 21602 relevant lines covered (60.46%)

4611.17 hits per line

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

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

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

6
local lfs = require("lfs")
×
7

8
local applyConverter = function (source, converter)
9
   local extLen = string.len(converter.sourceExt)
×
10
   local targetFile = string.sub(source, 1, -extLen - 1) .. converter.targetExt
×
11

12
   local sourceTime = lfs.attributes(source, "modification")
×
13

14
   if sourceTime == nil then
×
15
      SU.debug("converters", "Source file not found", source)
×
16
      return nil -- source not found
×
17
   end
18

19
   local targetTime = lfs.attributes(targetFile, "modification")
×
20
   if (targetTime ~= nil) and (targetTime > sourceTime) then
×
21
      SU.debug("converters", "Source file already converted", source)
×
22
      return targetFile -- already converted
×
23
   end
24

25
   local command = string.gsub(converter.command, "%$(%w+)", {
×
26
      SOURCE = source,
27
      TARGET = targetFile,
28
   })
29

30
   local result = os.execute(command)
×
31
   if type(result) ~= "boolean" then
×
32
      result = (result == 0)
×
33
   end
34
   if result then
×
35
      SU.debug("converters", "Converted", source, "to", targetFile)
×
36
      return targetFile
×
37
   else
38
      return nil
×
39
   end
40
end
41

42
-- TODO Make this a standard utility function
43
local function extendCommand (name, func)
44
   -- Wrap an existing command
45
   local original = SILE.Commands[name]
×
46
   if original then
×
47
      SILE.Commands[name] = function (options, content)
×
48
         func(options, content, original)
×
49
      end
50
   else
51
      SU.debug("converters", "Can not extend command", name)
×
52
   end
53
end
54

NEW
55
function package:register (sourceExt, targetExt, command)
×
56
   table.insert(SILE.scratch.converters, {
×
57
      sourceExt = sourceExt,
58
      targetExt = targetExt,
59
      command = command,
60
   })
61
end
62

NEW
63
function package:checkConverters (source)
×
64
   local resolvedSrc = SILE.resolveFile(source) or SU.error("Couldn't find file " .. source)
×
65
   for _, converter in ipairs(SILE.scratch.converters) do
×
66
      local extLen = string.len(converter.sourceExt)
×
67
      if (string.len(resolvedSrc) > extLen) and (string.sub(resolvedSrc, -extLen) == converter.sourceExt) then
×
68
         return applyConverter(resolvedSrc, converter)
×
69
      end
70
   end
71
   return source -- No conversion needed.
×
72
end
73

74
function package:_init ()
×
75
   base._init(self)
×
76
   if not SILE.scratch.converters then
×
77
      SILE.scratch.converters = {}
×
78
   end
79
   extendCommand("include", function (options, content, original)
×
80
      local source = SU.required(options, "src", "include (converters)")
×
81
      local result = self:checkConverters(source)
×
82
      if result then
×
83
         options["src"] = result
×
84
         original(options, content)
×
85
      else
86
         SU.error("Conversion failure for include '" .. source .. '"')
×
87
      end
88
   end)
89
   extendCommand("img", function (options, content, original)
×
90
      local source = SU.required(options, "src", "img (converters)")
×
91
      local result = self:checkConverters(source)
×
92
      if result then
×
93
         options["src"] = result
×
94
         original(options, content)
×
95
      else
96
         SU.error("Conversion failure for image '" .. source .. '"')
×
97
      end
98
   end)
99
   self:deprecatedExport("register", self.register)
×
100
   self:deprecatedExport("checkConverters", self.checkConverters)
×
101
end
102

103
function package:registerCommands ()
×
104
   self:registerCommand("converters:register", function (options, _)
×
105
      self:register(options.from, options.to, options.command)
×
106
   end)
107

108
   self:registerCommand("converters:check", function (options, _)
×
109
      SU.deprecated("\\converters:check", nil, "0.14.10", "0.16.0")
×
110
      self:checkConverters(options.source)
×
111
   end)
112
end
113

114
package.documentation = [[
115
\begin{document}
116
The \autodoc:package{converters} package allows you to register additional handlers to process included files and images.
117
That sounds a bit abstract, so it’s best explained by example.
118
Suppose you have a GIF image that you would like to include in your document.
119
You read the documentation for the \autodoc:package{image} package and you discover that sadly GIF images are not supported.
120
The \autodoc:package{converters} package allows you to teach SILE how to get the GIF format into something that \em{is} supported.
121
We can use the ImageMagick toolkit to turn a GIF into a JPEG, and JPEGs are supported directly by SILE.
122

123
We do this by registering a converter with the \autodoc:command{\converters:register} command:
124

125
\begin[type=autodoc:codeblock]{raw}
126
\use[module=packages.converters]
127
\converters:register[from=.gif,to=.jpg,command=convert $SOURCE $TARGET]
128
\end{raw}
129

130
And now it just magically works:
131

132
\begin[type=autodoc:codeblock]{raw}
133
\img[src=hello.gif, width=50pt]
134
\end{raw}
135

136
This will execute the command \code{convert hello.gif hello.jpg} and include the converted \code{hello.jpg} file.
137

138
This trick also works for text files:
139

140
\begin[type=autodoc:codeblock]{raw}
141
\converters:register[from=.md, to=.sil, command=pandoc -o $TARGET $SOURCE]
142
\include[src=document.md]
143
\end{raw}
144
\end{document}
145
]]
×
146

147
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