Skip to content

Commit 27c4e97

Browse files
committed
add pie chart breakdown for symbol and declaration count
1 parent 55f58a4 commit 27c4e97

File tree

14 files changed

+485
-18
lines changed

14 files changed

+485
-18
lines changed

Assets/css/Main.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/css/Main.css.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/HTMLDOM/SVG/SVG.Point.swift

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
#if canImport(Glibc)
2+
import func Glibc.cos
3+
import func Glibc.sin
4+
#elseif canImport(Darwin)
5+
import func Darwin.cos
6+
import func Darwin.sin
7+
#endif
18

29
extension SVG
310
{
@@ -26,22 +33,22 @@ extension SVG.Point:Hashable where Scalar:Hashable
2633
extension SVG.Point:Sendable where Scalar:Sendable
2734
{
2835
}
29-
// extension SVG.Point<Float>
30-
// {
31-
// @inlinable public
32-
// init(radians:Float, radius:Float = 1.0)
33-
// {
34-
// self.init(radius * _cos(radians), radius * -_sin(radians))
35-
// }
36-
// }
37-
// extension SVG.Point<Double>
38-
// {
39-
// @inlinable public
40-
// init(radians:Double, radius:Double = 1.0)
41-
// {
42-
// self.init(radius * _cos(radians), radius * -_sin(radians))
43-
// }
44-
// }
36+
extension SVG.Point<Float>
37+
{
38+
@inlinable public
39+
init(radians:Float, radius:Float = 1.0)
40+
{
41+
self.init(radius * _cos(radians), radius * -_sin(radians))
42+
}
43+
}
44+
extension SVG.Point<Double>
45+
{
46+
@inlinable public
47+
init(radians:Double, radius:Double = 1.0)
48+
{
49+
self.init(radius * _cos(radians), radius * -_sin(radians))
50+
}
51+
}
4552
extension SVG.Point:CustomStringConvertible
4653
{
4754
@inlinable public

Sources/HTMLStreaming/HTML/HTML.ContentEncoder (ext).swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,26 @@ extension HTML.ContentEncoder
3232
}
3333
}
3434
extension HTML.ContentEncoder
35+
{
36+
@inlinable public
37+
subscript<Renderable>(svg:SVG,
38+
attributes:(inout SVG.AttributeEncoder) -> () = { _ in }) -> Renderable?
39+
where Renderable:ScalableVectorOutputStreamable
40+
{
41+
get
42+
{
43+
nil
44+
}
45+
set(value)
46+
{
47+
if let value:Renderable
48+
{
49+
self[svg, attributes] { $0 += value }
50+
}
51+
}
52+
}
53+
}
54+
extension HTML.ContentEncoder
3555
{
3656
@inlinable public
3757
subscript<Renderable>(link target:String?,

Sources/UnidocPages/Templates/Site.Docs.Meta.swift

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,126 @@ extension Site.Docs.Meta:ApplicationPage
156156
}
157157
}
158158

159+
var breakdown:(unweighted:Pie, weighted:Pie) = ([], [])
160+
for (value, `class`, what):
161+
(KeyPath<Record.Master.Meta.Stats.Decl, Int>, String, String) in
162+
[
163+
(
164+
\.functions,
165+
"function",
166+
"free functions or variables"
167+
),
168+
(
169+
\.operators,
170+
"operator",
171+
"operators"
172+
),
173+
(
174+
\.constructors,
175+
"constructor",
176+
"initializers, type members, or enum cases"
177+
),
178+
(
179+
\.methods,
180+
"method",
181+
"instance methods"
182+
),
183+
(
184+
\.subscripts,
185+
"subscript",
186+
"instance subscripts"
187+
),
188+
(
189+
\.functors,
190+
"functor",
191+
"functors"
192+
),
193+
(
194+
\.protocols,
195+
"protocol",
196+
"protocols"
197+
),
198+
(
199+
\.requirements,
200+
"requirement",
201+
"protocol requirements"
202+
),
203+
(
204+
\.witnesses,
205+
"witness",
206+
"default implementations"
207+
),
208+
(
209+
\.actors,
210+
"actor",
211+
"actors"
212+
),
213+
(
214+
\.classes,
215+
"class",
216+
"classes"
217+
),
218+
(
219+
\.structures,
220+
"structure",
221+
"structs or enums"
222+
),
223+
(
224+
\.typealiases,
225+
"typealias",
226+
"typealiases"
227+
),
228+
]
229+
{
230+
@Sendable
231+
func percent(_ value:Double) -> String
232+
{
233+
let permille:Int = .init((value * 1000).rounded())
234+
let (percent, f):(Int, Int) = permille.quotientAndRemainder(
235+
dividingBy: 10)
236+
237+
return "\(percent).\(f) percent"
238+
}
239+
240+
let unweighted:Int = self.master.stats.decls[keyPath: value]
241+
let weighted:Int = unweighted +
242+
self.master.stats.firstPartyFeatures[keyPath: value] +
243+
self.master.stats.thirdPartyFeatures[keyPath: value]
244+
245+
if unweighted > 0
246+
{
247+
let value:Pie.Value = .init(weight: unweighted,
248+
class: `class`)
249+
{
250+
return """
251+
\(percent($0)) of the declarations in this package are \(what)
252+
"""
253+
}
254+
breakdown.unweighted.values.append(value)
255+
}
256+
if weighted > 0
257+
{
258+
let value:Pie.Value = .init(weight: weighted,
259+
class: `class`)
260+
{
261+
return """
262+
\(percent($0)) of the symbols in this package are \(what)
263+
"""
264+
}
265+
breakdown.weighted.values.append(value)
266+
}
267+
}
268+
269+
$0[.h2] = "Symbol Breakdown"
270+
271+
$0[.h3] = "Symbols"
272+
273+
$0 += breakdown.weighted
274+
275+
$0[.h3] = "Declarations"
276+
277+
$0 += breakdown.unweighted
278+
159279
$0[.h2] = "Snapshot Information"
160280

161281
$0[.dl]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import HTML
2+
3+
extension Pie.Slice
4+
{
5+
struct Title
6+
{
7+
let text:String
8+
9+
init(_ text:String)
10+
{
11+
self.text = text
12+
}
13+
}
14+
}
15+
extension Pie.Slice.Title:ScalableVectorOutputStreamable
16+
{
17+
static
18+
func += (svg:inout SVG.ContentEncoder, self:Self)
19+
{
20+
svg[.title] = self.text.isEmpty ? nil : self.text
21+
}
22+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import HTML
2+
3+
extension Pie
4+
{
5+
struct Slice
6+
{
7+
let share:Double
8+
let startArc:SVG.Point<Double>
9+
let endArc:SVG.Point<Double>
10+
/// The end of the slice, in radians.
11+
let end:Double
12+
13+
init(share:Double,
14+
startArc:SVG.Point<Double>,
15+
endArc:SVG.Point<Double>,
16+
end:Double)
17+
{
18+
self.share = share
19+
self.startArc = startArc
20+
self.endArc = endArc
21+
self.end = end
22+
}
23+
}
24+
}
25+
extension Pie.Slice
26+
{
27+
init(share:Double, from start:SVG.Point<Double>, to end:Double)
28+
{
29+
self.init(share: share,
30+
startArc: start,
31+
endArc: .init(radians: end),
32+
end: end)
33+
}
34+
}
35+
extension Pie.Slice
36+
{
37+
var d:String
38+
{
39+
var d:String = "M 0,0 L \(self.startArc)"
40+
switch self.share
41+
{
42+
case 0 ..< 0.375:
43+
d += " A 1,1 0 0 0 \(self.endArc)"
44+
45+
case 0.625 ... 1:
46+
d += " A 1,1 0 1 0 \(self.endArc)"
47+
48+
case _:
49+
// Near-semicircular arc; split into 2 segments to avoid degenerate behavior.
50+
let p:SVG.Point<Double> = .init(radians: self.end - 0.5 * Double.pi)
51+
d += " A 1,1 0 0 0 \(p) A 1,1 0 0 0 \(self.endArc)"
52+
}
53+
54+
if self.endArc.x >= 0,
55+
self.endArc.y == 0
56+
{
57+
d += " Z"
58+
}
59+
else if
60+
self.endArc.x >= 0,
61+
self.endArc.y >= 0
62+
{
63+
var fringe:SVG.Point<Double> = .init(radians: self.end + 0.1, radius: 0.5)
64+
fringe.y = max(fringe.y, 0)
65+
66+
d += " L \(fringe) Z"
67+
}
68+
else
69+
{
70+
let fringe:SVG.Point<Double> = .init(radians: self.end + 0.1, radius: 0.5)
71+
d += " L \(fringe) Z"
72+
}
73+
74+
return d
75+
}
76+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
extension Pie
2+
{
3+
@frozen public
4+
struct Value:Sendable
5+
{
6+
public
7+
var weight:Int
8+
public
9+
var label:(@Sendable (Double) -> String)?
10+
public
11+
var `class`:String
12+
13+
@inlinable public
14+
init(weight:Int,
15+
class:String = "",
16+
label:(@Sendable (Double) -> String)? = nil)
17+
{
18+
self.weight = weight
19+
self.class = `class`
20+
self.label = label
21+
}
22+
}
23+
}
24+
extension Pie.Value
25+
{
26+
func title(_ share:Double) -> Pie.Slice.Title
27+
{
28+
.init(self.label?(share) ?? "")
29+
}
30+
}

0 commit comments

Comments
 (0)