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

sile-typesetter / sile / 6713098919

31 Oct 2023 10:21PM UTC coverage: 52.831% (-21.8%) from 74.636%
6713098919

push

github

web-flow
Merge d0a2a1ee9 into b185d4972

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

8173 of 15470 relevant lines covered (52.83%)

6562.28 hits per line

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

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

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

6
local pdf
7

8
-- URL escape sequence, URL fragment:
9
local preferBreakBefore = "%#"
×
10
-- URL path elements, URL query arguments, acceptable extras:
11
local preferBreakAfter = ":/.;?&=!_-"
×
12
-- URL scheme:
13
local alwaysBreakAfter = ":" -- Must have only one character here!
×
14

15
local escapeRegExpMinimal = function (str)
16
  -- Minimalist = just what's needed for the above strings
17
  return string.gsub(str, '([%.%?%-%%])', '%%%1')
×
18
end
19

20
local breakPattern = "["..escapeRegExpMinimal(preferBreakBefore..preferBreakAfter..alwaysBreakAfter).."]"
×
21

22
function package:_init ()
×
23
  base._init(self)
×
24
  self:loadPackage("verbatim")
×
25
  self:loadPackage("inputfilter")
×
26
  pdf = SILE.outputter._name == "libtexpdf"
×
27
  if pdf then self:loadPackage("pdf") end
×
28
end
29

30
function package.declareSettings (_)
×
31

32
  SILE.settings:declare({
×
33
    parameter = "url.linebreak.primaryPenalty",
34
    type = "integer",
35
    default = 100,
36
    help = "Penalty for breaking lines in URLs at preferred breakpoints"
×
37
  })
38

39
  SILE.settings:declare({
×
40
    parameter = "url.linebreak.secondaryPenalty",
41
    type = "integer",
42
    default = 200,
43
    help = "Penalty for breaking lines in URLs at tolerable breakpoints (should be higher than url.linebreak.primaryPenalty)"
×
44
  })
45

46
end
47

48
function package:registerCommands ()
×
49

50
  self:registerCommand("href", function (options, content)
×
51
    if not pdf then
×
52
      if options.src then
×
53
        SILE.process(content)
×
54
      else
55
        SILE.call("url", { language = options.language }, content)
×
56
      end
57
      return -- DONE.
×
58
    end
59

60
    if options.src then
×
61
      SILE.call("pdf:link", { dest = options.src, external = true,
×
62
        borderwidth = options.borderwidth,
63
        borderstyle = options.borderstyle,
64
        bordercolor = options.bordercolor,
65
        borderoffset = options.borderoffset },
66
        content)
×
67
    else
68
      options.src = content[1]
×
69
      SILE.call("pdf:link", { dest = options.src, external = true,
×
70
        borderwidth = options.borderwidth,
71
        borderstyle = options.borderstyle,
72
        bordercolor = options.bordercolor,
73
        borderoffset = options.borderoffset },
74
        function (_, _)
75
          SILE.call("url", { language = options.language }, content)
×
76
        end)
77
    end
78
  end, "Inserts a PDF hyperlink.")
×
79

80
  local urlFilter = function (node, content, options)
81
    if type(node) == "table" then return node end
×
82
    local result = {}
×
83
    for token in SU.gtoke(node, breakPattern) do
×
84
      if token.string then
×
85
        result[#result+1] = token.string
×
86
      else
87
        if string.find(preferBreakBefore, escapeRegExpMinimal(token.separator)) then
×
88
          -- Accepts breaking before, and at the extreme worst after.
89
          result[#result+1] = self.class.packages.inputfilter:createCommand(
×
90
          content.pos, content.col, content.lno,
×
91
          "penalty", { penalty = options.primaryPenalty }
×
92
          )
93
          result[#result+1] = token.separator
×
94
          result[#result+1] = self.class.packages.inputfilter:createCommand(
×
95
          content.pos, content.col, content.lno,
×
96
          "penalty", { penalty = options.worsePenalty }
×
97
          )
98
        elseif token.separator == alwaysBreakAfter then
×
99
          -- Accept breaking after (only).
100
          result[#result+1] = token.separator
×
101
          result[#result+1] = self.class.packages.inputfilter:createCommand(
×
102
          content.pos, content.col, content.lno,
×
103
          "penalty", { penalty = options.primaryPenalty }
×
104
          )
105
        else
106
          -- Accept breaking after, but tolerate breaking before.
107
          result[#result+1] = self.class.packages.inputfilter:createCommand(
×
108
          content.pos, content.col, content.lno,
×
109
          "penalty", { penalty = options.secondaryPenalty }
×
110
          )
111
          result[#result+1] = token.separator
×
112
          result[#result+1] = self.class.packages.inputfilter:createCommand(
×
113
          content.pos, content.col, content.lno,
×
114
          "penalty", { penalty = options.primaryPenalty }
×
115
          )
116
        end
117
      end
118
    end
119
    return result
×
120
  end
121

122
  self:registerCommand("url", function (options, content)
×
123
    SILE.settings:temporarily(function ()
×
124
      local primaryPenalty = SILE.settings:get("url.linebreak.primaryPenalty")
×
125
      local secondaryPenalty = SILE.settings:get("url.linebreak.secondaryPenalty")
×
126
      local worsePenalty = primaryPenalty + secondaryPenalty
×
127

128
      if options.language then
×
129
        SILE.languageSupport.loadLanguage(options.language)
×
130
        if options.language == "fr" then
×
131
          -- Trick the engine by declaring a "fake"" language that doesn't apply
132
          -- the typographic rules for punctuations
133
          SILE.hyphenator.languages["_fr_noSpacingRules"] = SILE.hyphenator.languages.fr
×
134
          -- Not needed (the engine already defaults to SILE.nodeMakers.unicode if
135
          -- the language is not found):
136
          -- SILE.nodeMakers._fr_noSpacingRules = SILE.nodeMakers.unicode
137
          SILE.settings:set("document.language", "_fr_noSpacingRules")
×
138
        else
139
          SILE.settings:set("document.language", options.language)
×
140
        end
141
      else
142
        SILE.settings:set("document.language", 'und')
×
143
      end
144

145
      local result = self.class.packages.inputfilter:transformContent(content, urlFilter, {
×
146
        primaryPenalty = primaryPenalty,
147
        secondaryPenalty = secondaryPenalty,
148
        worsePenalty = worsePenalty
×
149
      })
150
      SILE.call("urlstyle", {}, result)
×
151
    end)
152
  end, "Inserts penalties in an URL so it can be broken over multiple lines at appropriate places.")
×
153

154
  self:registerCommand("urlstyle", function (options, content)
×
155
    SILE.call("code", options, content)
×
156
  end, "Hook that may be redefined to change the styling of URLs")
×
157

158
end
159

160
package.documentation = [[
161
\begin{document}
162
\use[module=packages.url]
163
This package enhances the typesetting of URLs in two ways.
164
First, it provides the \autodoc:command{\href[src=<url>]{<content>}} command which inserts PDF hyperlinks, \href[src=http://www.sile-typesetter.org/]{like this}.
165

166
The \autodoc:command{\href} command accepts the same \autodoc:parameter{borderwidth}, \autodoc:parameter{bordercolor}, \autodoc:parameter{borderstyle}, and \autodoc:parameter{borderoffset} styling options as the \autodoc:command[check=false]{\pdf:link} command from the \autodoc:package{pdf} package, for instance \href[src=http://www.sile-typesetter.org/, borderwidth=0.4pt, bordercolor=blue, borderstyle=underline]{like this}.
167

168
Nowadays, it is a common practice to have URLs in print articles (whether it is a good practice or not is yet \em{another} topic).
169
Therefore, the package also provides the \autodoc:command{\url} command, which will automatically insert breakpoints into unwieldy URLs like \url{https://github.com/sile-typesetter/sile-typesetter.github.io/tree/master/examples} so that they can be broken up over multiple lines.
170

171
It allows line breaks after the colon, and before or after appropriate segments of an URL (path elements, query parts, fragments, etc.).
172
By default, the \autodoc:command{\url} command ignores the current language, as one would not want hyphenation to occur in URL segments.
173
If you have no other choice, however, you can pass it a \autodoc:parameter{language} option to enforce a language to be applied.
174
Note that if French (\code{fr}) is selected, the special typographic rules applying to punctuations in this language are disabled.
175

176
To typeset a URL and also make it an active hyperlink, use the \autodoc:command{\href} command without the \autodoc:parameter{src} option,
177
but with the URL passed as argument.
178

179
The breaks are controlled by two penalty settings: \autodoc:setting{url.linebreak.primaryPenalty} for preferred breakpoints and, for less acceptable but still tolerable breakpoints, \autodoc:setting{url.linebreak.secondaryPenalty}—its value should logically be higher than the previous one.
180

181
The \autodoc:command{\urlstyle} command hook may be overridden to change the style of URLs.
182
By default, they are typeset as “code”.
183

184
\end{document}
185
]]
×
186

187
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