Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add ArgumentSource as the projected value of arguments #128

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Examples/repeat/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ struct Repeat: ParsableCommand {
var includeCounter: Bool

@Argument(help: "The phrase to repeat.")
var phrase: String
var phrase: [String]

func run() throws {
let repeatCount = count ?? .max

dump($count)
dump($includeCounter)
dump($phrase)

for i in 1...repeatCount {
if includeCounter {
print("\(i): \(phrase)")
Expand Down
15 changes: 12 additions & 3 deletions Sources/ArgumentParser/Parsable Properties/Argument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,31 @@ public struct Argument<Value>:
public var wrappedValue: Value {
get {
switch _parsedValue {
case .value(let v):
case .value(let v, _):
return v
case .definition:
fatalError(directlyInitializedError)
}
}
set {
_parsedValue = .value(newValue)
_parsedValue = .value(newValue, _parsedValue.source ?? ArgumentSource(source: []))
}
}

public var projectedValue: ArgumentSource {
switch _parsedValue {
case .value(_, let source):
return source
case .definition:
fatalError(directlyInitializedError)
}
}
}

extension Argument: CustomStringConvertible {
public var description: String {
switch _parsedValue {
case .value(let v):
case .value(let v, _):
return String(describing: v)
case .definition:
return "Argument(*definition*)"
Expand Down
15 changes: 15 additions & 0 deletions Sources/ArgumentParser/Parsable Properties/ArgumentSource.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift Argument Parser open source project
//
// Copyright (c) 2020 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
//
//===----------------------------------------------------------------------===//

public struct ArgumentSource {
public var source: [(value: String, position: Int)]
}

15 changes: 12 additions & 3 deletions Sources/ArgumentParser/Parsable Properties/Flag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,31 @@ public struct Flag<Value>: Decodable, ParsedWrapper {
public var wrappedValue: Value {
get {
switch _parsedValue {
case .value(let v):
case .value(let v, _):
return v
case .definition:
fatalError(directlyInitializedError)
}
}
set {
_parsedValue = .value(newValue)
_parsedValue = .value(newValue, _parsedValue.source ?? ArgumentSource(source: []))
}
}

public var projectedValue: ArgumentSource {
switch _parsedValue {
case .value(_, let source):
return source
case .definition:
fatalError(directlyInitializedError)
}
}
}

extension Flag: CustomStringConvertible {
public var description: String {
switch _parsedValue {
case .value(let v):
case .value(let v, _):
return String(describing: v)
case .definition:
return "Flag(*definition*)"
Expand Down
15 changes: 12 additions & 3 deletions Sources/ArgumentParser/Parsable Properties/Option.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,31 @@ public struct Option<Value>: Decodable, ParsedWrapper {
public var wrappedValue: Value {
get {
switch _parsedValue {
case .value(let v):
case .value(let v, _):
return v
case .definition:
fatalError(directlyInitializedError)
}
}
set {
_parsedValue = .value(newValue)
_parsedValue = .value(newValue, _parsedValue.source ?? ArgumentSource(source: []))
}
}

public var projectedValue: ArgumentSource {
switch _parsedValue {
case .value(_, let source):
return source
case .definition:
fatalError(directlyInitializedError)
}
}
}

extension Option: CustomStringConvertible {
public var description: String {
switch _parsedValue {
case .value(let v):
case .value(let v, _):
return String(describing: v)
case .definition:
return "Option(*definition*)"
Expand Down
8 changes: 4 additions & 4 deletions Sources/ArgumentParser/Parsable Properties/OptionGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public struct OptionGroup<Value: ParsableArguments>: Decodable, ParsedWrapper {
if let d = decoder as? SingleValueDecoder,
let value = try? d.previousValue(Value.self)
{
self.init(_parsedValue: .value(value))
self.init(_parsedValue: .value(value, ArgumentSource(source: [])))
} else {
try self.init(_decoder: decoder)
if let d = decoder as? SingleValueDecoder {
Expand All @@ -63,22 +63,22 @@ public struct OptionGroup<Value: ParsableArguments>: Decodable, ParsedWrapper {
public var wrappedValue: Value {
get {
switch _parsedValue {
case .value(let v):
case .value(let v, _):
return v
case .definition:
fatalError(directlyInitializedError)
}
}
set {
_parsedValue = .value(newValue)
_parsedValue = .value(newValue, _parsedValue.source ?? ArgumentSource(source: []))
}
}
}

extension OptionGroup: CustomStringConvertible {
public var description: String {
switch _parsedValue {
case .value(let v):
case .value(let v, _):
return String(describing: v)
case .definition:
return "OptionGroup(*definition*)"
Expand Down
44 changes: 36 additions & 8 deletions Sources/ArgumentParser/Parsing/Parsed.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,26 @@ enum Parsed<Value> {
var makeSet: (InputKey) -> ArgumentSet
}

case value(Value)
case value(Value, ArgumentSource)
case definition(Definition)

internal init(_ makeSet: @escaping (InputKey) -> ArgumentSet) {
self = .definition(Definition(makeSet: makeSet))
}

var value: Value? {
switch self {
case .value(let v, _): return v
case .definition: return nil
}
}

var source: ArgumentSource? {
switch self {
case .value(_, let s): return s
case .definition: return nil
}
}
}

/// A type that wraps a `Parsed` instance to act as a property wrapper.
Expand Down Expand Up @@ -54,7 +68,14 @@ extension ParsedWrapper {
throw ParserError.noValue(forKey: d.parsedElement?.key ?? d.key)
}

self.init(_parsedValue: .value(value))
let sourceIndexes: [Int] = d.parsedElement!.inputOrigin.elements.compactMap { x -> Int? in
guard case .argumentIndex(let i) = x else { return nil }
return i.inputIndex.rawValue
}
let sourceValues = sourceIndexes.map { d.underlying.values.originalInput[$0] }
let source = ArgumentSource(source: Array(zip(sourceValues, sourceIndexes)))

self.init(_parsedValue: .value(value, source))
}

func argumentSet(for key: InputKey) -> ArgumentSet {
Expand All @@ -70,18 +91,25 @@ extension ParsedWrapper {
extension ParsedWrapper where Value: Decodable {
init(_decoder: Decoder) throws {
var value: Value
let source: ArgumentSource

do {
value = try Value.init(from: _decoder)
source = ArgumentSource(source: [])
} catch {
if let d = _decoder as? SingleValueDecoder,
let v = d.parsedElement?.value as? Value {
value = v
} else {
guard let d = _decoder as? SingleValueDecoder,
let v = d.parsedElement?.value as? Value else {
throw error
}
}
value = v

self.init(_parsedValue: .value(value))
let sourceIndexes: [Int] = d.parsedElement!.inputOrigin.elements.compactMap { x -> Int? in
guard case .argumentIndex(let i) = x else { return nil }
return i.inputIndex.rawValue
}
let sourceValues = sourceIndexes.map { d.underlying.values.originalInput[$0] }
source = ArgumentSource(source: Array(zip(sourceValues, sourceIndexes)))
}
self.init(_parsedValue: .value(value, source))
}
}
10 changes: 8 additions & 2 deletions Sources/ArgumentParser/Usage/HelpCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,17 @@ struct HelpCommand: ParsableCommand {

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self._subcommands = Argument(_parsedValue: .value(try container.decode([String].self, forKey: .subcommands)))
self._subcommands = Argument(
_parsedValue: .value(
try container.decode([String].self, forKey: .subcommands),
ArgumentSource(source: [])))
}

init(commandStack: [ParsableCommand.Type]) {
self.commandStack = commandStack
self._subcommands = Argument(_parsedValue: .value(commandStack.map { $0._commandName }))
self._subcommands = Argument(
_parsedValue: .value(
commandStack.map { $0._commandName },
ArgumentSource(source: [])))
}
}