Skip to content

Commit

Permalink
SE-0356: Snippet slice parsing (swiftlang#20)
Browse files Browse the repository at this point in the history
Rewrite the snippet parser to support slicing.

See: https://github.com/apple/swift-evolution/blob/main/proposals/0356-swift-snippets.md#slices

Adopt SymbolKit model changes related to slicing.

Remove experimental guard flag for snippet functionality, but guard snippet
functionality on Swift 5.7.

rdar://95220356
  • Loading branch information
bitjammer authored Jul 28, 2022
1 parent 0fdcbf1 commit 00555b6
Show file tree
Hide file tree
Showing 14 changed files with 635 additions and 266 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors

// This snippet is in a subdirectory.

func foo() {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
// Create a foo.
import Library

// snippet.best
let best = BestStruct()
best.best()
// snippet.end

// snippet.hide

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
///
/// Is best.
public struct BestStruct {
public init() {}
public func best() {}
}
38 changes: 4 additions & 34 deletions IntegrationTests/Tests/SnippetDocumentationGenerationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import XCTest
final class SnippetDocumentationGenerationTests: XCTestCase {
func testGenerateDocumentationForPackageWithSnippets() throws {
let result = try swiftPackage(
"generate-documentation", "--enable-experimental-snippet-support",
"generate-documentation",
"--target", "Library",
workingDirectory: try setupTemporaryDirectoryForFixture(named: "PackageWithSnippets")
)

Expand All @@ -25,12 +26,9 @@ final class SnippetDocumentationGenerationTests: XCTestCase {
XCTAssertEqual(
Set(dataDirectoryContents.map(\.lastTwoPathComponents)),
[
// REMOVEME: "documentation/packagewithsnippets.json"
// should disappear once the fix for
// https://github.com/apple/swift-docc/pull/116 is available in CI.
"documentation/packagewithsnippets.json",
"documentation/library.json",
"library/beststruct.json",
"beststruct/init().json",
"beststruct/best().json",
]
)
Expand All @@ -49,34 +47,6 @@ final class SnippetDocumentationGenerationTests: XCTestCase {
)
}

func testGenerateDocumentationForPackageWithSnippetsWithoutExperimentalFlag() throws {
let result = try swiftPackage(
"generate-documentation",
workingDirectory: try setupTemporaryDirectoryForFixture(named: "PackageWithSnippets")
)

result.assertExitStatusEquals(0)
XCTAssertEqual(result.referencedDocCArchives.count, 1)

let doccArchiveURL = try XCTUnwrap(result.referencedDocCArchives.first)

let dataDirectoryContents = try filesIn(.dataSubdirectory, of: doccArchiveURL)

XCTAssertEqual(
Set(dataDirectoryContents.map(\.lastTwoPathComponents)),
[
"documentation/library.json",
"library/beststruct.json",
"beststruct/best().json",
]
)

XCTAssertFalse(
FileManager.default.fileExists(atPath: result.symbolGraphsDirectory.path),
"Unified symbol graph directory created when experimental snippet support flag was not passed."
)
}

func testPreviewDocumentationWithSnippets() throws {
let outputDirectory = try temporaryDirectory().appendingPathComponent("output")

Expand All @@ -87,9 +57,9 @@ final class SnippetDocumentationGenerationTests: XCTestCase {
"--disable-sandbox",
"--allow-writing-to-directory", outputDirectory.path,
"preview-documentation",
"--target", "Library",
"--port", port,
"--output-path", outputDirectory.path,
"--enable-experimental-snippet-support"
],
workingDirectory: try setupTemporaryDirectoryForFixture(named: "PackageWithSnippets")
)
Expand Down
24 changes: 10 additions & 14 deletions Plugins/Swift-DocC Convert/SwiftDocCConvert.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ import PackagePlugin

let verbose = argumentExtractor.extractFlag(named: "verbose") > 0

let experimentalSnippetSupportIsEnabled = argumentExtractor.extractFlag(
named: "enable-experimental-snippet-support"
) > 0

// Parse the given command-line arguments
let parsedArguments = ParsedArguments(argumentExtractor.remainingArguments)

Expand All @@ -50,16 +46,16 @@ import PackagePlugin
return
}

let snippetBuilder: SnippetBuilder?
if experimentalSnippetSupportIsEnabled {
let snippetBuildTool = try context.tool(named: "snippet-build")
snippetBuilder = SnippetBuilder(
snippetTool: URL(fileURLWithPath: snippetBuildTool.path.string, isDirectory: false),
workingDirectory: URL(fileURLWithPath: context.pluginWorkDirectory.string, isDirectory: true)
)
} else {
snippetBuilder = nil
}
#if swift(>=5.7)
let snippetBuildTool = try context.tool(named: "snippet-build")
let snippetBuilder = SnippetBuilder(
snippetTool: URL(fileURLWithPath: snippetBuildTool.path.string, isDirectory: false),
workingDirectory: URL(fileURLWithPath: context.pluginWorkDirectory.string, isDirectory: true)
)
#else
let snippetBuilder: SnippetBuilder? = nil
#endif


// Iterate over the Swift source module targets we were given.
for (index, target) in swiftSourceModuleTargets.enumerated() {
Expand Down
23 changes: 9 additions & 14 deletions Plugins/Swift-DocC Preview/SwiftDocCPreview.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ import PackagePlugin

let verbose = argumentExtractor.extractFlag(named: "verbose") > 0

let experimentalSnippetSupportIsEnabled = argumentExtractor.extractFlag(
named: "enable-experimental-snippet-support"
) > 0

// Parse the given command-line arguments
let parsedArguments = ParsedArguments(argumentExtractor.remainingArguments)

Expand Down Expand Up @@ -70,16 +66,15 @@ import PackagePlugin
return
}

let snippetBuilder: SnippetBuilder?
if experimentalSnippetSupportIsEnabled {
let snippetBuildTool = try context.tool(named: "snippet-build")
snippetBuilder = SnippetBuilder(
snippetTool: URL(fileURLWithPath: snippetBuildTool.path.string, isDirectory: false),
workingDirectory: URL(fileURLWithPath: context.pluginWorkDirectory.string, isDirectory: true)
)
} else {
snippetBuilder = nil
}
#if swift(>=5.7)
let snippetBuildTool = try context.tool(named: "snippet-build")
let snippetBuilder = SnippetBuilder(
snippetTool: URL(fileURLWithPath: snippetBuildTool.path.string, isDirectory: false),
workingDirectory: URL(fileURLWithPath: context.pluginWorkDirectory.string, isDirectory: true)
)
#else
let snippetBuilder: SnippetBuilder? = nil
#endif

let symbolGraphs = try packageManager.doccSymbolGraphs(
for: target,
Expand Down
29 changes: 20 additions & 9 deletions Sources/Snippets/Model/Snippet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,23 @@ public struct Snippet {

/// A short abstract explaining what the snippet does.
public var explanation: String

/// The ``presentationLines`` joined with a newline `"\n"` separator.
public var presentationCode: String {
return presentationLines.joined(separator: "\n")
}

/// The code to display as the snippet.
public var presentationCode: String

/// The identifier of the snippet.
public var identifier: String {
return sourceFile.deletingPathExtension().lastPathComponent
}
public var presentationLines: [String]

/// Named line ranges in the snippet.
public var slices: [String: Range<Int>]

init(parsing source: String, sourceFile: URL) {
let extractor = PlainTextSnippetExtractor(source: source)
self.explanation = extractor.explanation
self.presentationCode = extractor.presentationCode
let extractor = SnippetParser(source: source)
self.explanation = extractor.explanationLines.joined(separator: "\n")
self.presentationLines = extractor.presentationLines.map(String.init)
self.slices = extractor.slices
self.sourceFile = sourceFile
}

Expand All @@ -41,4 +45,11 @@ public struct Snippet {
let source = try String(contentsOf: sourceFile)
self.init(parsing: source, sourceFile: sourceFile)
}

subscript(sliceIdentifier: String) -> String? {
guard let slice = slices[sliceIdentifier] else {
return nil
}
return presentationLines[slice].joined(separator: "\n")
}
}
130 changes: 0 additions & 130 deletions Sources/Snippets/Parsing/PlainTextSnippetExtractor.swift

This file was deleted.

Loading

0 comments on commit 00555b6

Please sign in to comment.