From 875b1980e07ffba0d9f7e9bb3c2e4dc4abc2f10a Mon Sep 17 00:00:00 2001 From: Michael Housh Date: Mon, 9 Dec 2024 09:35:17 -0500 Subject: [PATCH] feat: Working on documentation --- Examples/README.md | 26 +++++++++++++++++++ .../CliDoc-Examples/CliDoc_Examples.swift | 3 ++- .../CliDoc-Examples/GroupCommand.swift | 21 +++++++++++++++ .../Documentation.docc/Resources/group.png | 3 +++ Sources/CliDocCore/Nodes/Group.swift | 17 ++++++++++++ Sources/CliDocCore/Nodes/HStack.swift | 4 +-- .../CliDocCore/Nodes/StackConfiguration.swift | 10 ++++--- Sources/CliDocCore/Nodes/VStack.swift | 4 +-- Tests/CliDocCoreTests/CliDocCoreTests.swift | 20 ++++++++++++++ 9 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 Examples/README.md create mode 100644 Examples/Sources/CliDoc-Examples/GroupCommand.swift create mode 100644 Sources/CliDocCore/Documentation.docc/Resources/group.png diff --git a/Examples/README.md b/Examples/README.md new file mode 100644 index 0000000..6339d8a --- /dev/null +++ b/Examples/README.md @@ -0,0 +1,26 @@ +# swift-cli-doc + +A tool for building rich documentation for command line applications using result builders and +syntax similar to `SwiftUI`. + +## Getting Started + +Add this as a package dependency to your command line application. + +```swift +let package = Package( + name: "my-tool" + ... + dependencies: [ + .package(url: "https://git.housh.dev/michael/swift-cli-doc", from: "0.1.0") + ], + targets: [ + .executableTarget( + name: "my-tool", + dependencies: [ + .product(name: "CliDoc", package: "swift-cli-doc") + ] + ) + ] +) +``` diff --git a/Examples/Sources/CliDoc-Examples/CliDoc_Examples.swift b/Examples/Sources/CliDoc-Examples/CliDoc_Examples.swift index 21748ee..299ba24 100644 --- a/Examples/Sources/CliDoc-Examples/CliDoc_Examples.swift +++ b/Examples/Sources/CliDoc-Examples/CliDoc_Examples.swift @@ -9,7 +9,8 @@ struct Application: ParsableCommand { subcommands: [ SectionCommand.self, VStackCommand.self, - HStackCommand.self + HStackCommand.self, + GroupCommand.self ] ) } diff --git a/Examples/Sources/CliDoc-Examples/GroupCommand.swift b/Examples/Sources/CliDoc-Examples/GroupCommand.swift new file mode 100644 index 0000000..c683e8b --- /dev/null +++ b/Examples/Sources/CliDoc-Examples/GroupCommand.swift @@ -0,0 +1,21 @@ +import ArgumentParser +import CliDocCore + +struct GroupCommand: ParsableCommand { + + static let configuration = CommandConfiguration(commandName: "group") + + func run() throws { + let group = Group { + "My headline." + "\n" + "Some content".color(.green) + "\n" + "Foo Bar".italic() + } + .color(.blue) + + print() + print("\(group.render())") + } +} diff --git a/Sources/CliDocCore/Documentation.docc/Resources/group.png b/Sources/CliDocCore/Documentation.docc/Resources/group.png new file mode 100644 index 0000000..53091cd --- /dev/null +++ b/Sources/CliDocCore/Documentation.docc/Resources/group.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ba5456762715d32c500c327945a975a79c4ca4a841422f15b2b45b542b462d1 +size 8637 diff --git a/Sources/CliDocCore/Nodes/Group.swift b/Sources/CliDocCore/Nodes/Group.swift index 575d036..29bd322 100644 --- a/Sources/CliDocCore/Nodes/Group.swift +++ b/Sources/CliDocCore/Nodes/Group.swift @@ -2,6 +2,23 @@ /// /// This allows you to group content together, which can optionally be /// styled. +/// +/// ### Example: +/// +/// ```swift +/// let group = Group { +/// "My headline." +/// "\n" +/// "Some content".color(.green) +/// "\n" +/// "Foo Bar".italic() +/// } +/// +/// print(group.render()) +/// ``` +/// +/// ![Group example](group.png) +/// public struct Group: TextNode { @usableFromInline diff --git a/Sources/CliDocCore/Nodes/HStack.swift b/Sources/CliDocCore/Nodes/HStack.swift index 87b57fe..2b2bc4f 100644 --- a/Sources/CliDocCore/Nodes/HStack.swift +++ b/Sources/CliDocCore/Nodes/HStack.swift @@ -59,7 +59,7 @@ public extension HStack { /// Style a ``HStack`` by creating a type that conforms to ``HStackStyle`` and use the /// style by calling the ``HStack/style(_:)`` method on your instance. /// -public protocol HStackStyle: TextModifier where Content == StackConfiguration {} +public protocol HStackStyle: TextModifier where Content == _StackConfiguration {} public extension HStackStyle where Self == HStackSeparatorStyle { /// Apply the given separator on a ``HStack``. @@ -88,7 +88,7 @@ public struct HStackSeparatorStyle: HStackStyle { } @inlinable - public func render(content: StackConfiguration) -> some TextNode { + public func render(content: _StackConfiguration) -> some TextNode { AnySeparatableStackNode(content: content, separator: separator) } } diff --git a/Sources/CliDocCore/Nodes/StackConfiguration.swift b/Sources/CliDocCore/Nodes/StackConfiguration.swift index 14ee7a5..3e98f80 100644 --- a/Sources/CliDocCore/Nodes/StackConfiguration.swift +++ b/Sources/CliDocCore/Nodes/StackConfiguration.swift @@ -1,10 +1,14 @@ +// swiftlint:disable type_name /// Represents the content of an ``HStack`` or a ``VStack``. /// -/// -public struct StackConfiguration { +/// This is an internal convenience type, but needs to remain public +/// for protcol conformances to work properly. +public struct _StackConfiguration { public let content: [any TextNode] } +// swiftlint:enable type_name + /// A helper type that removes empty text nodes, and applies a separtor between /// the array of text nodes. /// @@ -18,7 +22,7 @@ struct AnySeparatableStackNode: TextNode { let separator: Separator @usableFromInline - init(content: StackConfiguration, separator: Separator) { + init(content: _StackConfiguration, separator: Separator) { self.content = content.content self.separator = separator } diff --git a/Sources/CliDocCore/Nodes/VStack.swift b/Sources/CliDocCore/Nodes/VStack.swift index bf81636..e5764e9 100644 --- a/Sources/CliDocCore/Nodes/VStack.swift +++ b/Sources/CliDocCore/Nodes/VStack.swift @@ -62,7 +62,7 @@ public extension VStack { /// Style a ``VStack`` by creating a type that conforms to ``VStackStyle`` and use the /// style by calling the ``VStack/style(_:)`` method on your instance. /// -public protocol VStackStyle: TextModifier where Content == StackConfiguration {} +public protocol VStackStyle: TextModifier where Content == _StackConfiguration {} public extension VStackStyle where Self == VStackSeparatorStyle { @@ -92,7 +92,7 @@ public struct VStackSeparatorStyle: VStackStyle { } @inlinable - public func render(content: StackConfiguration) -> some TextNode { + public func render(content: _StackConfiguration) -> some TextNode { AnySeparatableStackNode(content: content, separator: separator) } } diff --git a/Tests/CliDocCoreTests/CliDocCoreTests.swift b/Tests/CliDocCoreTests/CliDocCoreTests.swift index 7b16c7d..349f0c2 100644 --- a/Tests/CliDocCoreTests/CliDocCoreTests.swift +++ b/Tests/CliDocCoreTests/CliDocCoreTests.swift @@ -22,6 +22,26 @@ struct CliDocCoreTests { } } #expect(group.render() == "foobar\("baz".blue)") + + let group2 = Group { + VStack { + "My headline." + "Some text." + } + "\n" + HStack { + "Foo" + "Bar" + } + } + .color(.green) + + print(group2.render()) + #expect(group2.render() == """ + My headline. + Some text. + Foo Bar + """.green) } @Test