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

Commit

Permalink
Preserve Formatting of Symbol Declarations (#204)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
mattt authored Oct 16, 2020
1 parent f2ec6cf commit adc3fc1
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 50 deletions.
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 [email protected]
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>
"""#
}
}

0 comments on commit adc3fc1

Please sign in to comment.