Skip to content

Commit

Permalink
add merge function to command groups
Browse files Browse the repository at this point in the history
  • Loading branch information
marius-se committed Dec 1, 2023
1 parent 2e3e205 commit 611541a
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 14 deletions.
13 changes: 11 additions & 2 deletions Sources/ConsoleKit/Command/AnyCommand.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/// A type-erased `Command`.
public protocol AnyCommand: Sendable {
public protocol AnyCommand: Sendable, AnyAsyncCommand {
/// Text that will be displayed when `--help` is passed.
var help: String { get }

/// Runs the command against the supplied input.
func run(using context: inout CommandContext) throws
func outputAutoComplete(using context: inout CommandContext) throws
Expand All @@ -24,4 +24,13 @@ extension AnyCommand {
public func renderCompletionFunctions(using context: CommandContext, shell: Shell) -> String {
return ""
}

// we need to have a sync environment so the compiler uses the sync run method over the async version
private func syncRun(using context: inout CommandContext) throws {
try self.run(using: &context)
}

public func run(using context: inout CommandContext) async throws {
try self.syncRun(using: &context)
}
}
9 changes: 6 additions & 3 deletions Sources/ConsoleKit/Command/Async/AsyncCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
/// U ||----w |
/// || ||
///
public protocol AsyncCommand: AnyAsyncCommand {
public protocol AsyncCommand: Sendable, AnyAsyncCommand {
associatedtype Signature: CommandSignature
func run(using context: CommandContext, signature: Signature) async throws
}
Expand All @@ -90,7 +90,7 @@ extension AsyncCommand {
let input = context.input.arguments.joined(separator: " ")
throw ConsoleError.init(identifier: "unknownInput", reason: "Input not recognized: \(input)")
}
try await self.run(using: context, signature: signature)
try await self.run(using: context, signature: signature)
}

public func outputAutoComplete(using context: inout CommandContext) {
Expand All @@ -101,7 +101,10 @@ extension AsyncCommand {
}

public func outputHelp(using context: inout CommandContext) {
context.console.output("Usage: ".consoleText(.info) + context.input.executable.consoleText() + " ", newLine: false)
context.console.output(
"Usage: ".consoleText(.info) + context.input.executable.consoleText() + " ",
newLine: false
)
Signature.reference.outputHelp(help: self.help, using: &context)
}
}
34 changes: 32 additions & 2 deletions Sources/ConsoleKit/Command/Async/AsyncCommandGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,41 @@
public protocol AsyncCommandGroup: AnyAsyncCommand {
var commands: [String: any AnyAsyncCommand] { get }
var defaultCommand: (any AnyAsyncCommand)? { get }

/// Merges this group with another group.
/// - Parameters:
/// - group: The group to merge with.
/// - defaultCommand: The new default command to use.
/// - help: The help message to use for the merged group.
/// - Returns: A new `AsyncCommandGroup` with the merged commands.
func merge(
with group: any AsyncCommandGroup,
defaultCommand: (any AnyAsyncCommand)?,
help: String
) -> any AsyncCommandGroup
}

public struct MergedAsyncCommandGroup: AsyncCommandGroup {
public let commands: [String: any AnyAsyncCommand]
public let defaultCommand: (any AnyAsyncCommand)?
public var help: String
}

extension AsyncCommandGroup {
public var defaultCommand: (any AnyAsyncCommand)? {
return nil
public var defaultCommand: (any AnyAsyncCommand)? { nil }

public func merge(
with group: any AsyncCommandGroup,
defaultCommand: (any AnyAsyncCommand)?,
help: String
) -> any AsyncCommandGroup {
var mergedCommands = self.commands
mergedCommands.merge(group.commands, uniquingKeysWith: { (_, new) in new })
return MergedAsyncCommandGroup(
commands: mergedCommands,
defaultCommand: defaultCommand,
help: help
)
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/ConsoleKit/Command/Async/AsyncCommands.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// Represents a top-level group of configured commands. This is usually created by calling `resolve(for:)` on `AsyncCommands`.
public struct AsyncCommands {
public struct AsyncCommands: Sendable {
/// Top-level available commands, stored by unique name.
public var commands: [String: any AnyAsyncCommand]

Expand Down Expand Up @@ -38,7 +38,7 @@ public struct AsyncCommands {
self.defaultCommand = defaultCommand
self.enableAutocomplete = enableAutocomplete
}

/// Adds an `AsyncCommand` instance to the config.
///
/// var config = AsyncCommands()
Expand Down
8 changes: 4 additions & 4 deletions Sources/ConsoleKit/Command/CommandContext.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/// A type-erased `CommandContext`
public struct CommandContext {
public struct CommandContext: Sendable {
/// The `Console` this command was run on.
public var console: any Console

/// The parsed arguments (according to declared signature).
public var input: CommandInput

public var userInfo: [AnyHashable: Any]
public var userInfo: [AnySendableHashable: any Sendable]

/// Create a new `AnyCommandContext`.
public init(
console: any Console,
Expand Down
8 changes: 7 additions & 1 deletion Sources/ConsoleKit/Command/CommandGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/// try console.run(group, with: context)
///
/// You can create your own `CommandGroup` if you want to support custom `CommandOptions`.
public protocol CommandGroup: AnyCommand {
public protocol CommandGroup: AnyCommand, AsyncCommandGroup {
var commands: [String: any AnyCommand] { get }
var defaultCommand: (any AnyCommand)? { get }
}
Expand All @@ -22,6 +22,12 @@ extension CommandGroup {
public var defaultCommand: (any AnyCommand)? {
return nil
}

public var commands: [String: any AnyAsyncCommand] {
// make the compiler happy
let castedCommands: [String: any AnyCommand] = commands
return castedCommands
}
}

extension CommandGroup {
Expand Down

0 comments on commit 611541a

Please sign in to comment.