Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Commit adc3fc1

Browse files
authored
Preserve Formatting of Symbol Declarations (#204)
* Upgrade swift-argument-parser to 0.3.1 Upgrade SwiftSyntaxHighlighter to 1.1.3 * Preserve formatting of original code declarations * Adjust style of highlighted code blocks Decrease font size slightly and use white-space: pre-wrap * Add Changelog entry for #204 * Upgrade SwiftSyntaxHighlighter to 1.0.2 for Swift 5.2 * Upgrade swift-argument-parser to 0.3.1 for Swift 5.2
1 parent f2ec6cf commit adc3fc1

File tree

12 files changed

+145
-50
lines changed

12 files changed

+145
-50
lines changed

Assets/css/all.css

+3-4
Original file line numberDiff line numberDiff line change
@@ -878,13 +878,12 @@ dd {
878878
.highlight {
879879
background: var(--secondary-system-background);
880880
border-radius: 8px;
881-
font-size: smaller;
881+
font-size: 0.75em;
882882
margin-bottom: 2em;
883883
overflow-x: auto;
884-
padding: 1em;
885-
padding-left: 3em;
886884
text-indent: -2em;
887-
white-space: pre;
885+
padding: 1em 1em 1em 3em;
886+
white-space: pre-wrap;
888887

889888
& .p {
890889
white-space: nowrap;

Changelog.md

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
- Fixed public extensions exposing nested code of all access levels.
1818
#195 by @Tunous.
1919

20+
### Changed
21+
22+
- Changed display of code declarations in HTML.
23+
#204 by @mattt.
24+
2025
## [1.0.0-beta.5] - 2020-09-29
2126

2227
### Added

Package.resolved

+4-4
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
"repositoryURL": "https://github.com/apple/swift-argument-parser.git",
4343
"state": {
4444
"branch": null,
45-
"revision": "223d62adc52d51669ae2ee19bdb8b7d9fd6fcd9c",
46-
"version": "0.0.6"
45+
"revision": "92646c0cdbaca076c8d3d0207891785b3379cbff",
46+
"version": "0.3.1"
4747
}
4848
},
4949
{
@@ -104,8 +104,8 @@
104104
"package": "SwiftSyntaxHighlighter",
105105
"repositoryURL": "https://github.com/NSHipster/SwiftSyntaxHighlighter.git",
106106
"state": {
107-
"branch": "1.1.1",
108-
"revision": "76bd23ae4b23f028a8e45f906c2bf98312fb9d33",
107+
"branch": "1.1.3",
108+
"revision": "b086ef5066b6f799f9c7d6d7fc1553581b55ef1e",
109109
"version": null
110110
}
111111
}

Package.swift

+4-3
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ let package = Package(
2020
.package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .upToNextMinor(from: "0.1.2")),
2121
.package(url: "https://github.com/NSHipster/HypertextLiteral.git", .upToNextMinor(from: "0.0.2")),
2222
.package(url: "https://github.com/SwiftDocOrg/Markup.git", .upToNextMinor(from: "0.0.3")),
23-
.package(url: "https://github.com/NSHipster/SwiftSyntaxHighlighter.git", .revision("1.1.1")),
24-
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "0.0.6")),
23+
.package(url: "https://github.com/NSHipster/SwiftSyntaxHighlighter.git", .revision("1.1.3")),
24+
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "0.3.1")),
2525
.package(url: "https://github.com/apple/swift-log.git", .upToNextMinor(from: "1.2.0")),
2626
.package(name: "LoggingGitHubActions", url: "https://github.com/NSHipster/swift-log-github-actions.git", .upToNextMinor(from: "0.0.1")),
2727
],
@@ -54,7 +54,8 @@ let package = Package(
5454
dependencies: [
5555
.product(name: "SwiftSyntax", package: "SwiftSyntax"),
5656
.product(name: "SwiftSemantics", package: "SwiftSemantics"),
57-
.product(name: "SwiftMarkup", package: "SwiftMarkup")
57+
.product(name: "SwiftMarkup", package: "SwiftMarkup"),
58+
.product(name: "SwiftSyntaxHighlighter", package: "SwiftSyntaxHighlighter")
5859
]
5960
),
6061
.testTarget(

[email protected]

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ let package = Package(
1717
.package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .upToNextMinor(from: "0.1.2")),
1818
.package(url: "https://github.com/NSHipster/HypertextLiteral.git", .upToNextMinor(from: "0.0.2")),
1919
.package(url: "https://github.com/SwiftDocOrg/Markup.git", .upToNextMinor(from: "0.0.3")),
20-
.package(url: "https://github.com/NSHipster/SwiftSyntaxHighlighter.git", .revision("1.0.0")),
21-
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "0.0.6")),
20+
.package(url: "https://github.com/NSHipster/SwiftSyntaxHighlighter.git", .revision("1.0.2")),
21+
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "0.3.1")),
2222
.package(url: "https://github.com/apple/swift-log.git", .upToNextMinor(from: "1.2.0")),
2323
.package(url: "https://github.com/NSHipster/swift-log-github-actions.git", .upToNextMinor(from: "0.0.1")),
2424
],

Resources/all.min.css

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/SwiftDoc/Extensions/SwiftSyntax+Extensions.swift

+90-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,94 @@ extension SourceLocation: Hashable {
1919
}
2020
}
2121

22+
// MARK: -
23+
24+
protocol SymbolDeclProtocol: SyntaxProtocol {
25+
var declaration: Syntax { get }
26+
}
27+
28+
extension AssociatedtypeDeclSyntax: SymbolDeclProtocol {}
29+
extension ClassDeclSyntax: SymbolDeclProtocol {}
30+
extension EnumDeclSyntax: SymbolDeclProtocol {}
31+
extension EnumCaseDeclSyntax: SymbolDeclProtocol {}
32+
extension FunctionDeclSyntax: SymbolDeclProtocol {}
33+
extension InitializerDeclSyntax: SymbolDeclProtocol {}
34+
extension OperatorDeclSyntax: SymbolDeclProtocol {}
35+
extension PrecedenceGroupDeclSyntax: SymbolDeclProtocol {}
36+
extension ProtocolDeclSyntax: SymbolDeclProtocol {}
37+
extension StructDeclSyntax: SymbolDeclProtocol {}
38+
extension SubscriptDeclSyntax: SymbolDeclProtocol {}
39+
extension TypealiasDeclSyntax: SymbolDeclProtocol {}
40+
extension VariableDeclSyntax: SymbolDeclProtocol {}
41+
42+
extension DeclGroupSyntax {
43+
var declaration: Syntax {
44+
Syntax(self.withoutTrailingTrivia()
45+
.withoutLeadingTrivia()
46+
.withMembers(SyntaxFactory.makeBlankMemberDeclBlock()))
47+
}
48+
}
49+
50+
extension EnumDeclSyntax {
51+
var declaration: Syntax {
52+
Syntax(self.withoutTrailingTrivia()
53+
.withoutLeadingTrivia()
54+
.withMembers(SyntaxFactory.makeBlankMemberDeclBlock()))
55+
}
56+
}
57+
58+
extension FunctionDeclSyntax {
59+
var declaration: Syntax {
60+
Syntax(self.withoutTrailingTrivia()
61+
.withoutLeadingTrivia()
62+
.withBody(SyntaxFactory.makeBlankCodeBlock()))
63+
}
64+
}
65+
66+
extension InitializerDeclSyntax {
67+
var declaration: Syntax {
68+
Syntax(self.withoutTrailingTrivia()
69+
.withoutLeadingTrivia()
70+
.withBody(SyntaxFactory.makeBlankCodeBlock()))
71+
}
72+
}
73+
74+
extension SubscriptDeclSyntax {
75+
var declaration: Syntax {
76+
Syntax(self.withoutTrailingTrivia()
77+
.withoutLeadingTrivia()
78+
.withAccessor(nil))
79+
}
80+
}
81+
82+
extension VariableDeclSyntax {
83+
var declaration: Syntax {
84+
let bindings = self.bindings.map { binding -> PatternBindingSyntax in
85+
if let value = binding.initializer?.value,
86+
value.is(ClosureExprSyntax.self) || value.is(FunctionCallExprSyntax.self)
87+
{
88+
return binding.withInitializer(nil)
89+
.withAccessor(nil)
90+
} else {
91+
return binding.withAccessor(nil)
92+
}
93+
}
94+
95+
return Syntax(self.withoutTrailingTrivia()
96+
.withoutLeadingTrivia()
97+
.withBindings(SyntaxFactory.makePatternBindingList(bindings)))
98+
}
99+
}
100+
101+
extension SyntaxProtocol {
102+
var declaration: Syntax {
103+
Syntax(self.withoutLeadingTrivia()
104+
.withoutTrailingTrivia())
105+
}
106+
}
107+
108+
// MARK: -
109+
22110
extension SyntaxProtocol {
23111
var documentation: String? {
24112
return leadingTrivia?.documentation
@@ -49,13 +137,13 @@ fileprivate extension TriviaPiece {
49137
}
50138
}
51139

52-
fileprivate extension String {
140+
extension String {
53141
var unindented: String {
54142
let lines = split(separator: "\n", omittingEmptySubsequences: false)
55143
guard lines.count > 1 else { return trimmingCharacters(in: .whitespaces) }
56144

57145
let indentation = lines.compactMap { $0.firstIndex(where: { !$0.isWhitespace })?.utf16Offset(in: $0) }
58-
.min() ?? 0
146+
.min() ?? 0
59147

60148
return lines.map {
61149
guard $0.count > indentation else { return String($0) }

Sources/SwiftDoc/Interface.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public final class Interface {
6969
for name in inheritedTypeNames {
7070
let inheritedTypes = symbols.filter({ ($0.api is Class || $0.api is Protocol) && $0.id.description == name })
7171
if inheritedTypes.isEmpty {
72-
let inherited = Symbol(api: Unknown(name: name), context: [], declaration: nil, documentation: nil, sourceLocation: nil)
72+
let inherited = Symbol(api: Unknown(name: name), context: [], declaration: [], documentation: nil, sourceLocation: nil)
7373
relationships.insert(Relationship(subject: symbol, predicate: .conformsTo, object: inherited))
7474
} else {
7575
for inherited in inheritedTypes {

Sources/SwiftDoc/SourceFile.swift

+17-17
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import SwiftMarkup
33
import SwiftSyntax
44
import SwiftSemantics
55
import struct SwiftSemantics.Protocol
6+
import class SwiftSyntaxHighlighter.SwiftSyntaxHighlighter
7+
import struct Highlighter.Token
8+
import enum Xcode.Xcode
69

710
public protocol Contextual {}
811
extension Symbol: Contextual {}
@@ -45,20 +48,28 @@ public struct SourceFile: Hashable, Codable {
4548
sourceLocationConverter = SourceLocationConverter(file: url.path(relativeTo: directory), tree: tree)
4649
super.init()
4750

48-
_ = walk(tree)
51+
walk(tree)
4952

5053
assert(context.isEmpty)
5154
}
5255

53-
func symbol<Node, Declaration>(_ type: Declaration.Type, _ node: Node) -> Symbol? where Declaration: API & ExpressibleBySyntax, Node == Declaration.Syntax {
56+
func symbol<Node, Declaration>(_ type: Declaration.Type, _ node: Node) -> Symbol? where Declaration: API & ExpressibleBySyntax, Node == Declaration.Syntax, Node: SymbolDeclProtocol {
5457
guard let api = Declaration(node) else { return nil }
55-
return symbol(node, api: api)
58+
guard let documentation = try? Documentation.parse(node.documentation) else { return nil }
59+
let sourceLocation = sourceLocationConverter.location(for: node.position)
60+
return Symbol(api: api, context: context, declaration: declaration(for: node), documentation: documentation, sourceLocation: sourceLocation)
5661
}
5762

58-
func symbol<Node: SyntaxProtocol>(_ node: Node, api: API) -> Symbol? {
63+
func symbol<Node: SymbolDeclProtocol>(_ node: Node, api: API) -> Symbol? {
5964
guard let documentation = try? Documentation.parse(node.documentation) else { return nil }
6065
let sourceLocation = sourceLocationConverter.location(for: node.position)
61-
return Symbol(api: api, context: context, declaration: "\(api)", documentation: documentation, sourceLocation: sourceLocation)
66+
return Symbol(api: api, context: context, declaration: declaration(for: node), documentation: documentation, sourceLocation: sourceLocation)
67+
}
68+
69+
func declaration<Node: SymbolDeclProtocol>(for node: Node) -> [Token] {
70+
let highlighter = SwiftSyntaxHighlighter(using: Xcode.self)
71+
_ = highlighter.visitAny(Syntax(node.declaration))
72+
return highlighter.tokens
6273
}
6374

6475
func push(_ symbol: Symbol?) {
@@ -183,18 +194,7 @@ public struct SourceFile: Hashable, Codable {
183194
}
184195

185196
override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {
186-
let variables = node.bindings.compactMap { binding -> Variable? in
187-
// Omit initializer expression if closure or function call
188-
// to ensure reasonable declaration code blocks.
189-
if let value = binding.initializer?.value,
190-
value.is(ClosureExprSyntax.self) || value.is(FunctionCallExprSyntax.self)
191-
{
192-
return Variable(binding.withInitializer(nil))
193-
} else {
194-
return Variable(binding)
195-
}
196-
}
197-
197+
let variables = node.bindings.compactMap { Variable($0) }
198198
for variable in variables {
199199
push(symbol(node, api: variable))
200200
}

Sources/SwiftDoc/Symbol.swift

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
import SwiftMarkup
22
import SwiftSyntax
33
import SwiftSemantics
4+
import struct Highlighter.Token
45

56
public final class Symbol {
67
public typealias ID = Identifier
78

89
public let api: API
910
public let context: [Contextual]
10-
public let declaration: String
11+
public let declaration: [Token]
1112
public let documentation: Documentation?
1213
public let sourceLocation: SourceLocation?
1314

1415
public private(set) lazy var `extension`: Extension? = context.compactMap { $0 as? Extension }.first
1516
public private(set) lazy var conditions: [CompilationCondition] = context.compactMap { $0 as? CompilationCondition }
1617

17-
init(api: API, context: [Contextual], declaration: String?, documentation: Documentation?, sourceLocation: SourceLocation?) {
18+
init(api: API, context: [Contextual], declaration: [Token], documentation: Documentation?, sourceLocation: SourceLocation?) {
1819
self.api = api
1920
self.context = context
20-
self.declaration = declaration ?? "\(api)"
21+
self.declaration = declaration
2122
self.documentation = documentation
2223
self.sourceLocation = sourceLocation
2324
}
@@ -241,11 +242,11 @@ extension Symbol: Codable {
241242
throw DecodingError.dataCorrupted(context)
242243
}
243244

244-
let declaration = try container.decodeIfPresent(String.self, forKey: .declaration)
245+
let declaration = try container.decodeIfPresent([Token].self, forKey: .declaration)
245246
let documentation = try container.decodeIfPresent(Documentation.self, forKey: .documentation)
246247
let sourceLocation = try container.decodeIfPresent(SourceLocation.self, forKey: .sourceLocation)
247248

248-
self.init(api: api, context: [] /* TODO */, declaration: declaration, documentation: documentation, sourceLocation: sourceLocation)
249+
self.init(api: api, context: [] /* TODO */, declaration: declaration ?? [], documentation: documentation, sourceLocation: sourceLocation)
249250
}
250251

251252
public func encode(to encoder: Encoder) throws {

Sources/swift-doc/Subcommands/Generate.swift

+3-6
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,16 @@ extension SwiftDoc {
2525
var moduleName: String
2626

2727
@Option(name: .shortAndLong,
28-
default: ".build/documentation",
2928
help: "The path for generated output")
30-
var output: String
29+
var output: String = ".build/documentation"
3130

3231
@Option(name: .shortAndLong,
33-
default: .commonmark,
3432
help: "The output format")
35-
var format: Format
33+
var format: Format = .commonmark
3634

3735
@Option(name: .customLong("base-url"),
38-
default: "/",
3936
help: "The base URL used for all relative URLs in generated documents.")
40-
var baseURL: String
37+
var baseURL: String = "/"
4138
}
4239

4340
static var configuration = CommandConfiguration(abstract: "Generates Swift documentation")

Sources/swift-doc/Supporting Types/Components/Declaration.swift

+9-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import SwiftDoc
33
import SwiftMarkup
44
import SwiftSemantics
55
import HypertextLiteral
6-
import SwiftSyntaxHighlighter
6+
import Highlighter
77
import Xcode
88

99
struct Declaration: Component {
@@ -22,14 +22,18 @@ struct Declaration: Component {
2222
var fragment: Fragment {
2323
Fragment {
2424
CodeBlock("swift") {
25-
symbol.declaration.trimmingCharacters(in: .whitespacesAndNewlines)
25+
symbol.declaration.map { $0.text }.joined()
2626
}
2727
}
2828
}
2929

3030
var html: HypertextLiteral.HTML {
31-
var html = try! SwiftSyntaxHighlighter.highlight(source: symbol.declaration, using: Xcode.self)
32-
html = linkCodeElements(of: html, for: symbol, in: module, with: baseURL)
33-
return HTML(html)
31+
let code = symbol.declaration.map { $0.html }.joined()
32+
33+
return #"""
34+
<div class="declaration">
35+
<pre class="highlight"><code>\#(unsafeUnescaped: code)</code></pre>
36+
</div>
37+
"""#
3438
}
3539
}

0 commit comments

Comments
 (0)