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

Preserve Formatting of Symbol Declarations #204

Merged
merged 6 commits into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions Assets/css/all.css
Original file line number Diff line number Diff line change
Expand Up @@ -878,13 +878,12 @@ dd {
.highlight {
background: var(--secondary-system-background);
border-radius: 8px;
font-size: smaller;
font-size: 0.75em;
margin-bottom: 2em;
overflow-x: auto;
padding: 1em;
padding-left: 3em;
text-indent: -2em;
white-space: pre;
padding: 1em 1em 1em 3em;
white-space: pre-wrap;

& .p {
white-space: nowrap;
Expand Down
5 changes: 5 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed public extensions exposing nested code of all access levels.
#195 by @Tunous.

### Changed

- Changed display of code declarations in HTML.
#204 by @mattt.

## [1.0.0-beta.5] - 2020-09-29

### Added
Expand Down
8 changes: 4 additions & 4 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
"repositoryURL": "https://github.com/apple/swift-argument-parser.git",
"state": {
"branch": null,
"revision": "223d62adc52d51669ae2ee19bdb8b7d9fd6fcd9c",
"version": "0.0.6"
"revision": "92646c0cdbaca076c8d3d0207891785b3379cbff",
"version": "0.3.1"
}
},
{
Expand Down Expand Up @@ -104,8 +104,8 @@
"package": "SwiftSyntaxHighlighter",
"repositoryURL": "https://github.com/NSHipster/SwiftSyntaxHighlighter.git",
"state": {
"branch": "1.1.1",
"revision": "76bd23ae4b23f028a8e45f906c2bf98312fb9d33",
"branch": "1.1.3",
"revision": "b086ef5066b6f799f9c7d6d7fc1553581b55ef1e",
"version": null
}
}
Expand Down
7 changes: 4 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ let package = Package(
.package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .upToNextMinor(from: "0.1.2")),
.package(url: "https://github.com/NSHipster/HypertextLiteral.git", .upToNextMinor(from: "0.0.2")),
.package(url: "https://github.com/SwiftDocOrg/Markup.git", .upToNextMinor(from: "0.0.3")),
.package(url: "https://github.com/NSHipster/SwiftSyntaxHighlighter.git", .revision("1.1.1")),
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "0.0.6")),
.package(url: "https://github.com/NSHipster/SwiftSyntaxHighlighter.git", .revision("1.1.3")),
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "0.3.1")),
.package(url: "https://github.com/apple/swift-log.git", .upToNextMinor(from: "1.2.0")),
.package(name: "LoggingGitHubActions", url: "https://github.com/NSHipster/swift-log-github-actions.git", .upToNextMinor(from: "0.0.1")),
],
Expand Down Expand Up @@ -54,7 +54,8 @@ let package = Package(
dependencies: [
.product(name: "SwiftSyntax", package: "SwiftSyntax"),
.product(name: "SwiftSemantics", package: "SwiftSemantics"),
.product(name: "SwiftMarkup", package: "SwiftMarkup")
.product(name: "SwiftMarkup", package: "SwiftMarkup"),
.product(name: "SwiftSyntaxHighlighter", package: "SwiftSyntaxHighlighter")
]
),
.testTarget(
Expand Down
4 changes: 2 additions & 2 deletions Package@swift-5.2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ let package = Package(
.package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .upToNextMinor(from: "0.1.2")),
.package(url: "https://github.com/NSHipster/HypertextLiteral.git", .upToNextMinor(from: "0.0.2")),
.package(url: "https://github.com/SwiftDocOrg/Markup.git", .upToNextMinor(from: "0.0.3")),
.package(url: "https://github.com/NSHipster/SwiftSyntaxHighlighter.git", .revision("1.0.0")),
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "0.0.6")),
.package(url: "https://github.com/NSHipster/SwiftSyntaxHighlighter.git", .revision("1.0.2")),
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "0.3.1")),
.package(url: "https://github.com/apple/swift-log.git", .upToNextMinor(from: "1.2.0")),
.package(url: "https://github.com/NSHipster/swift-log-github-actions.git", .upToNextMinor(from: "0.0.1")),
],
Expand Down
2 changes: 1 addition & 1 deletion Resources/all.min.css

Large diffs are not rendered by default.

92 changes: 90 additions & 2 deletions Sources/SwiftDoc/Extensions/SwiftSyntax+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,94 @@ extension SourceLocation: Hashable {
}
}

// MARK: -

protocol SymbolDeclProtocol: SyntaxProtocol {
var declaration: Syntax { get }
}

extension AssociatedtypeDeclSyntax: SymbolDeclProtocol {}
extension ClassDeclSyntax: SymbolDeclProtocol {}
extension EnumDeclSyntax: SymbolDeclProtocol {}
extension EnumCaseDeclSyntax: SymbolDeclProtocol {}
extension FunctionDeclSyntax: SymbolDeclProtocol {}
extension InitializerDeclSyntax: SymbolDeclProtocol {}
extension OperatorDeclSyntax: SymbolDeclProtocol {}
extension PrecedenceGroupDeclSyntax: SymbolDeclProtocol {}
extension ProtocolDeclSyntax: SymbolDeclProtocol {}
extension StructDeclSyntax: SymbolDeclProtocol {}
extension SubscriptDeclSyntax: SymbolDeclProtocol {}
extension TypealiasDeclSyntax: SymbolDeclProtocol {}
extension VariableDeclSyntax: SymbolDeclProtocol {}

extension DeclGroupSyntax {
var declaration: Syntax {
Syntax(self.withoutTrailingTrivia()
.withoutLeadingTrivia()
.withMembers(SyntaxFactory.makeBlankMemberDeclBlock()))
}
}

extension EnumDeclSyntax {
var declaration: Syntax {
Syntax(self.withoutTrailingTrivia()
.withoutLeadingTrivia()
.withMembers(SyntaxFactory.makeBlankMemberDeclBlock()))
}
}

extension FunctionDeclSyntax {
var declaration: Syntax {
Syntax(self.withoutTrailingTrivia()
.withoutLeadingTrivia()
.withBody(SyntaxFactory.makeBlankCodeBlock()))
}
}

extension InitializerDeclSyntax {
var declaration: Syntax {
Syntax(self.withoutTrailingTrivia()
.withoutLeadingTrivia()
.withBody(SyntaxFactory.makeBlankCodeBlock()))
}
}

extension SubscriptDeclSyntax {
var declaration: Syntax {
Syntax(self.withoutTrailingTrivia()
.withoutLeadingTrivia()
.withAccessor(nil))
}
}

extension VariableDeclSyntax {
var declaration: Syntax {
let bindings = self.bindings.map { binding -> PatternBindingSyntax in
if let value = binding.initializer?.value,
value.is(ClosureExprSyntax.self) || value.is(FunctionCallExprSyntax.self)
{
return binding.withInitializer(nil)
.withAccessor(nil)
} else {
return binding.withAccessor(nil)
}
}

return Syntax(self.withoutTrailingTrivia()
.withoutLeadingTrivia()
.withBindings(SyntaxFactory.makePatternBindingList(bindings)))
}
}

extension SyntaxProtocol {
var declaration: Syntax {
Syntax(self.withoutLeadingTrivia()
.withoutTrailingTrivia())
}
}

// MARK: -

extension SyntaxProtocol {
var documentation: String? {
return leadingTrivia?.documentation
Expand Down Expand Up @@ -49,13 +137,13 @@ fileprivate extension TriviaPiece {
}
}

fileprivate extension String {
extension String {
var unindented: String {
let lines = split(separator: "\n", omittingEmptySubsequences: false)
guard lines.count > 1 else { return trimmingCharacters(in: .whitespaces) }

let indentation = lines.compactMap { $0.firstIndex(where: { !$0.isWhitespace })?.utf16Offset(in: $0) }
.min() ?? 0
.min() ?? 0

return lines.map {
guard $0.count > indentation else { return String($0) }
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDoc/Interface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public final class Interface {
for name in inheritedTypeNames {
let inheritedTypes = symbols.filter({ ($0.api is Class || $0.api is Protocol) && $0.id.description == name })
if inheritedTypes.isEmpty {
let inherited = Symbol(api: Unknown(name: name), context: [], declaration: nil, documentation: nil, sourceLocation: nil)
let inherited = Symbol(api: Unknown(name: name), context: [], declaration: [], documentation: nil, sourceLocation: nil)
relationships.insert(Relationship(subject: symbol, predicate: .conformsTo, object: inherited))
} else {
for inherited in inheritedTypes {
Expand Down
34 changes: 17 additions & 17 deletions Sources/SwiftDoc/SourceFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import SwiftMarkup
import SwiftSyntax
import SwiftSemantics
import struct SwiftSemantics.Protocol
import class SwiftSyntaxHighlighter.SwiftSyntaxHighlighter
import struct Highlighter.Token
import enum Xcode.Xcode

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

_ = walk(tree)
walk(tree)

assert(context.isEmpty)
}

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

func symbol<Node: SyntaxProtocol>(_ node: Node, api: API) -> Symbol? {
func symbol<Node: SymbolDeclProtocol>(_ node: Node, api: API) -> Symbol? {
guard let documentation = try? Documentation.parse(node.documentation) else { return nil }
let sourceLocation = sourceLocationConverter.location(for: node.position)
return Symbol(api: api, context: context, declaration: "\(api)", documentation: documentation, sourceLocation: sourceLocation)
return Symbol(api: api, context: context, declaration: declaration(for: node), documentation: documentation, sourceLocation: sourceLocation)
}

func declaration<Node: SymbolDeclProtocol>(for node: Node) -> [Token] {
let highlighter = SwiftSyntaxHighlighter(using: Xcode.self)
_ = highlighter.visitAny(Syntax(node.declaration))
return highlighter.tokens
}

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

override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {
let variables = node.bindings.compactMap { binding -> Variable? in
// Omit initializer expression if closure or function call
// to ensure reasonable declaration code blocks.
if let value = binding.initializer?.value,
value.is(ClosureExprSyntax.self) || value.is(FunctionCallExprSyntax.self)
{
return Variable(binding.withInitializer(nil))
} else {
return Variable(binding)
}
}

let variables = node.bindings.compactMap { Variable($0) }
for variable in variables {
push(symbol(node, api: variable))
}
Expand Down
11 changes: 6 additions & 5 deletions Sources/SwiftDoc/Symbol.swift
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import SwiftMarkup
import SwiftSyntax
import SwiftSemantics
import struct Highlighter.Token

public final class Symbol {
public typealias ID = Identifier

public let api: API
public let context: [Contextual]
public let declaration: String
public let declaration: [Token]
public let documentation: Documentation?
public let sourceLocation: SourceLocation?

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

init(api: API, context: [Contextual], declaration: String?, documentation: Documentation?, sourceLocation: SourceLocation?) {
init(api: API, context: [Contextual], declaration: [Token], documentation: Documentation?, sourceLocation: SourceLocation?) {
self.api = api
self.context = context
self.declaration = declaration ?? "\(api)"
self.declaration = declaration
self.documentation = documentation
self.sourceLocation = sourceLocation
}
Expand Down Expand Up @@ -241,11 +242,11 @@ extension Symbol: Codable {
throw DecodingError.dataCorrupted(context)
}

let declaration = try container.decodeIfPresent(String.self, forKey: .declaration)
let declaration = try container.decodeIfPresent([Token].self, forKey: .declaration)
let documentation = try container.decodeIfPresent(Documentation.self, forKey: .documentation)
let sourceLocation = try container.decodeIfPresent(SourceLocation.self, forKey: .sourceLocation)

self.init(api: api, context: [] /* TODO */, declaration: declaration, documentation: documentation, sourceLocation: sourceLocation)
self.init(api: api, context: [] /* TODO */, declaration: declaration ?? [], documentation: documentation, sourceLocation: sourceLocation)
}

public func encode(to encoder: Encoder) throws {
Expand Down
9 changes: 3 additions & 6 deletions Sources/swift-doc/Subcommands/Generate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,16 @@ extension SwiftDoc {
var moduleName: String

@Option(name: .shortAndLong,
default: ".build/documentation",
help: "The path for generated output")
var output: String
var output: String = ".build/documentation"

@Option(name: .shortAndLong,
default: .commonmark,
help: "The output format")
var format: Format
var format: Format = .commonmark

@Option(name: .customLong("base-url"),
default: "/",
help: "The base URL used for all relative URLs in generated documents.")
var baseURL: String
var baseURL: String = "/"
}

static var configuration = CommandConfiguration(abstract: "Generates Swift documentation")
Expand Down
14 changes: 9 additions & 5 deletions Sources/swift-doc/Supporting Types/Components/Declaration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import SwiftDoc
import SwiftMarkup
import SwiftSemantics
import HypertextLiteral
import SwiftSyntaxHighlighter
import Highlighter
import Xcode

struct Declaration: Component {
Expand All @@ -22,14 +22,18 @@ struct Declaration: Component {
var fragment: Fragment {
Fragment {
CodeBlock("swift") {
symbol.declaration.trimmingCharacters(in: .whitespacesAndNewlines)
symbol.declaration.map { $0.text }.joined()
}
}
}

var html: HypertextLiteral.HTML {
var html = try! SwiftSyntaxHighlighter.highlight(source: symbol.declaration, using: Xcode.self)
html = linkCodeElements(of: html, for: symbol, in: module, with: baseURL)
return HTML(html)
let code = symbol.declaration.map { $0.html }.joined()

return #"""
<div class="declaration">
<pre class="highlight"><code>\#(unsafeUnescaped: code)</code></pre>
</div>
"""#
}
}