Skip to content

Commit 04319de

Browse files
author
Jesse Haigh
committed
WIP tests, WIP parsing for wrap and highlight
1 parent 4381935 commit 04319de

File tree

5 files changed

+151
-14
lines changed

5 files changed

+151
-14
lines changed

Sources/SwiftDocC/Checker/Checkers/InvalidCodeBlockOption.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public struct InvalidCodeBlockOption: Checker {
3434
let info = codeBlock.language?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
3535
guard !info.isEmpty else { return }
3636

37+
// TODO this will also fail on parsing highlight values with commas inside the array
3738
let tokens = info
3839
.split(separator: ",")
3940
.map { $0.trimmingCharacters(in: .whitespaces) }

Sources/SwiftDocC/Model/Rendering/Content/RenderBlockContent.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ public enum RenderBlockContent: Equatable {
130130

131131
public enum OptionName: String, CaseIterable {
132132
case nocopy
133+
case wrap
134+
case highlight
133135

134136
init?<S: StringProtocol>(caseInsensitive raw: S) {
135137
self.init(rawValue: raw.lowercased())

Sources/SwiftDocC/Model/Rendering/RenderContentCompiler.swift

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,27 @@ struct RenderContentCompiler: MarkupVisitor {
5050

5151
if FeatureFlags.current.isExperimentalCodeBlockEnabled {
5252

53-
func parseLanguageString(_ input: String?) -> (lang: String? , tokens: [RenderBlockContent.CodeListing.OptionName]) {
53+
func parseLanguageString(_ input: String?) -> (lang: String? , tokens: [(RenderBlockContent.CodeListing.OptionName, Substring?)]) {
5454
guard let input else { return (lang: nil, tokens: []) }
55+
// TODO this fails on parsing highlight values with commas inside the array
5556
let parts = input
5657
.split(separator: ",")
5758
.map { $0.trimmingCharacters(in: .whitespaces) }
5859
var lang: String? = nil
59-
var options: [RenderBlockContent.CodeListing.OptionName] = []
60+
var options: [(RenderBlockContent.CodeListing.OptionName, Substring?)] = []
6061

6162
for part in parts {
6263
if let eq = part.firstIndex(of: "=") {
6364
let name = part[..<eq].trimmingCharacters(in: .whitespaces)
64-
let _ = part[part.index(after: eq)...]
65-
if let opt = RenderBlockContent.CodeListing.OptionName(caseInsensitive: name) {
66-
options.append(opt)
65+
let value = part[part.index(after: eq)...]
66+
if let option = RenderBlockContent.CodeListing.OptionName(caseInsensitive: name) {
67+
options.append((option, value))
6768
} else if lang == nil {
6869
lang = String(part)
6970
}
7071
} else {
71-
if let opt = RenderBlockContent.CodeListing.OptionName(caseInsensitive: part) {
72-
options.append(opt)
72+
if let option = RenderBlockContent.CodeListing.OptionName(caseInsensitive: part) {
73+
options.append((option, nil))
7374
} else if lang == nil {
7475
lang = String(part)
7576
}
@@ -78,26 +79,41 @@ struct RenderContentCompiler: MarkupVisitor {
7879
return (lang, options)
7980
}
8081

82+
func parseHighlight(_ value: Substring?) -> [Int]? {
83+
guard var s = value.map(String.init) else { return nil }
84+
s = s.trimmingCharacters(in: .whitespaces)
85+
if s.hasPrefix("[") && s.hasSuffix("]") {
86+
s.removeFirst()
87+
s.removeLast()
88+
}
89+
let ints = s.split(separator: ",").compactMap{ Int($0.trimmingCharacters(in: .whitespaces)) }
90+
return ints.isEmpty ? nil : ints
91+
}
92+
8193
let options = parseLanguageString(codeBlock.language)
8294

8395
var listing = RenderBlockContent.CodeListing(
8496
syntax: options.lang ?? bundle.info.defaultCodeListingLanguage,
8597
code: codeBlock.code.splitByNewlines,
8698
metadata: nil,
8799
copyToClipboard: true, // default value
88-
wrap: 0,
89-
highlight: [Int]()
100+
wrap: 0, // default value
101+
highlight: [Int]() // default value
90102
)
91103

92104
// apply code block options
93-
for option in options.tokens {
105+
for (option, value) in options.tokens {
94106
switch option {
95107
case .nocopy:
96108
listing.copyToClipboard = false
97109
case .wrap:
98-
listing.wrap = 0 //placeholder
110+
if let value, let intValue = Int(value) {
111+
listing.wrap = intValue
112+
} else {
113+
listing.wrap = 0
114+
}
99115
case .highlight:
100-
listing.highlight = [Int]() //placeholder
116+
listing.highlight = parseHighlight(value) ?? []
101117
}
102118
}
103119

Tests/SwiftDocCTests/Checker/Checkers/InvalidCodeBlockOptionTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ let a = 1
2424
var checker = InvalidCodeBlockOption(sourceFile: nil)
2525
checker.visit(document)
2626
XCTAssertTrue(checker.problems.isEmpty)
27-
XCTAssertEqual(RenderBlockContent.CodeListing.knownOptions, ["nocopy"])
27+
XCTAssertEqual(RenderBlockContent.CodeListing.knownOptions, ["highlight", "nocopy", "wrap"])
2828
}
2929

3030
func testOption() {

Tests/SwiftDocCTests/Rendering/RenderContentCompilerTests.swift

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,6 @@ class RenderContentCompilerTests: XCTestCase {
282282
```
283283
"""#
284284
let document = Document(parsing: source)
285-
286285
let result = document.children.flatMap { compiler.visit($0) }
287286

288287
let renderCodeBlock = try XCTUnwrap(result[0] as? RenderBlockContent)
@@ -316,4 +315,123 @@ class RenderContentCompilerTests: XCTestCase {
316315
XCTAssertEqual(codeListing.syntax, "swift, nocopy")
317316
XCTAssertEqual(codeListing.copyToClipboard, false)
318317
}
318+
319+
func testWrapAndHighlight() async throws {
320+
enableFeatureFlag(\.isExperimentalCodeBlockEnabled)
321+
322+
let (bundle, context) = try await testBundleAndContext()
323+
var compiler = RenderContentCompiler(context: context, bundle: bundle, identifier: ResolvedTopicReference(bundleID: bundle.id, path: "/path", fragment: nil, sourceLanguage: .swift))
324+
325+
let source = #"""
326+
```swift, wrap=20, highlight=[2]
327+
let a = 1
328+
let b = 2
329+
let c = 3
330+
let d = 4
331+
let e = 5
332+
```
333+
"""#
334+
335+
let document = Document(parsing: source)
336+
337+
let result = document.children.flatMap { compiler.visit($0) }
338+
339+
let renderCodeBlock = try XCTUnwrap(result[0] as? RenderBlockContent)
340+
guard case let .codeListing(codeListing) = renderCodeBlock else {
341+
XCTFail("Expected RenderBlockContent.codeListing")
342+
return
343+
}
344+
345+
XCTAssertEqual(codeListing.syntax, "swift")
346+
XCTAssertEqual(codeListing.wrap, 20)
347+
XCTAssertEqual(codeListing.highlight, [2])
348+
}
349+
350+
func testHighlight() async throws {
351+
enableFeatureFlag(\.isExperimentalCodeBlockEnabled)
352+
353+
let (bundle, context) = try await testBundleAndContext()
354+
var compiler = RenderContentCompiler(context: context, bundle: bundle, identifier: ResolvedTopicReference(bundleID: bundle.id, path: "/path", fragment: nil, sourceLanguage: .swift))
355+
356+
let source = #"""
357+
```swift, highlight=[2]
358+
let a = 1
359+
let b = 2
360+
let c = 3
361+
let d = 4
362+
let e = 5
363+
```
364+
"""#
365+
366+
let document = Document(parsing: source)
367+
368+
let result = document.children.flatMap { compiler.visit($0) }
369+
370+
let renderCodeBlock = try XCTUnwrap(result[0] as? RenderBlockContent)
371+
guard case let .codeListing(codeListing) = renderCodeBlock else {
372+
XCTFail("Expected RenderBlockContent.codeListing")
373+
return
374+
}
375+
376+
XCTAssertEqual(codeListing.syntax, "swift")
377+
XCTAssertEqual(codeListing.highlight, [2])
378+
}
379+
380+
func testHighlightNoFeatureFlag() async throws {
381+
let (bundle, context) = try await testBundleAndContext()
382+
var compiler = RenderContentCompiler(context: context, bundle: bundle, identifier: ResolvedTopicReference(bundleID: bundle.id, path: "/path", fragment: nil, sourceLanguage: .swift))
383+
384+
let source = #"""
385+
```swift, highlight=[2]
386+
let a = 1
387+
let b = 2
388+
let c = 3
389+
let d = 4
390+
let e = 5
391+
```
392+
"""#
393+
394+
let document = Document(parsing: source)
395+
396+
let result = document.children.flatMap { compiler.visit($0) }
397+
398+
let renderCodeBlock = try XCTUnwrap(result[0] as? RenderBlockContent)
399+
guard case let .codeListing(codeListing) = renderCodeBlock else {
400+
XCTFail("Expected RenderBlockContent.codeListing")
401+
return
402+
}
403+
404+
XCTAssertEqual(codeListing.syntax, "swift, highlight=[2]")
405+
XCTAssertEqual(codeListing.highlight, [])
406+
}
407+
408+
func testMultipleHighlight() async throws {
409+
enableFeatureFlag(\.isExperimentalCodeBlockEnabled)
410+
411+
let (bundle, context) = try await testBundleAndContext()
412+
var compiler = RenderContentCompiler(context: context, bundle: bundle, identifier: ResolvedTopicReference(bundleID: bundle.id, path: "/path", fragment: nil, sourceLanguage: .swift))
413+
414+
let source = #"""
415+
```swift, highlight=[1, 2, 3]
416+
let a = 1
417+
let b = 2
418+
let c = 3
419+
let d = 4
420+
let e = 5
421+
```
422+
"""#
423+
424+
let document = Document(parsing: source)
425+
426+
let result = document.children.flatMap { compiler.visit($0) }
427+
428+
let renderCodeBlock = try XCTUnwrap(result[0] as? RenderBlockContent)
429+
guard case let .codeListing(codeListing) = renderCodeBlock else {
430+
XCTFail("Expected RenderBlockContent.codeListing")
431+
return
432+
}
433+
434+
XCTAssertEqual(codeListing.syntax, "swift")
435+
//XCTAssertEqual(codeListing.highlight, [1, 2, 3])
436+
}
319437
}

0 commit comments

Comments
 (0)