Skip to content

Commit 59f39ec

Browse files
authored
Use the first long name in usage (#179)
* Use the first long name in usage (#167) Sorting names for option has been changed. * Usage will choose the first long name, if available, or otherwise the first short name * Help screen will show short names, then long names, in the order of their declaration. Solves (#167) * Fix adding same name more than once. Checkin long names in sort caused single dash long names to be treated as a short name. Fixed sort to check “short” instead of “long” Update current test to cover more cases. * Add isShort control to Name *Replace sortedNames with partitionedNames *Extract uniquifying logic into SequenceExtensions.swift * Refactor short test with computed property * Use pattern-matching instead of equality comparison
1 parent d9fc135 commit 59f39ec

File tree

6 files changed

+80
-24
lines changed

6 files changed

+80
-24
lines changed

Sources/ArgumentParser/Parsable Properties/NameSpecification.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ public struct NameSpecification: ExpressibleByArrayLiteral {
3838
/// Short labels can be combined into groups.
3939
case customShort(Character)
4040
}
41-
var elements: Set<Element>
41+
var elements: Array<Element>
4242

4343
public init<S>(_ sequence: S) where S : Sequence, Element == S.Element {
44-
self.elements = Set(sequence)
44+
self.elements = sequence.uniquified()
4545
}
4646

4747
public init(arrayLiteral elements: Element...) {

Sources/ArgumentParser/Parsing/Name.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ extension Name {
5353
return n
5454
}
5555
}
56+
57+
var isShort: Bool {
58+
switch self {
59+
case .short:
60+
return true
61+
default:
62+
return false
63+
}
64+
}
5665
}
5766

5867
// short argument names based on the synopsisString

Sources/ArgumentParser/Usage/UsageGenerator.swift

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ extension ArgumentDefinition {
6363

6464
switch kind {
6565
case .named:
66-
let joinedSynopsisString = sortedNames
66+
let joinedSynopsisString = partitionedNames
6767
.map { $0.synopsisString }
6868
.joined(separator: ", ")
6969

@@ -113,30 +113,12 @@ extension ArgumentDefinition {
113113
return unadornedSynopsis
114114
}
115115

116-
var sortedNames: [Name] {
117-
return names
118-
.sorted { (lhs, rhs) -> Bool in
119-
switch (lhs, rhs) {
120-
case let (.long(l), .long(r)):
121-
return l < r
122-
case (_, .long):
123-
return true
124-
case (.long, _):
125-
return false
126-
case let (.short(l), .short(r)):
127-
return l < r
128-
case (_, .short):
129-
return true
130-
case (.short, _):
131-
return false
132-
case let (.longWithSingleDash(l), .longWithSingleDash(r)):
133-
return l < r
134-
}
135-
}
116+
var partitionedNames: [Name] {
117+
return names.filter{ $0.isShort } + names.filter{ !$0.isShort }
136118
}
137119

138120
var preferredNameForSynopsis: Name? {
139-
sortedNames.last
121+
names.first{ !$0.isShort } ?? names.first
140122
}
141123

142124
var synopsisValueName: String? {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===----------------------------------------------------------*- swift -*-===//
2+
//
3+
// This source file is part of the Swift Argument Parser open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
extension Sequence where Element: Equatable {
13+
func uniquified() -> [Element] {
14+
var sequence = Array<Element>()
15+
for element in self {
16+
if !sequence.contains(element) {
17+
sequence.append(element)
18+
}
19+
}
20+
return sequence
21+
}
22+
}

Tests/ArgumentParserUnitTests/HelpGenerationTests.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,4 +358,23 @@ extension HelpGenerationTests {
358358
359359
""")
360360
}
361+
362+
struct L: ParsableArguments {
363+
@Option(
364+
name: [.short, .customLong("remote"), .customLong("remote"), .short, .customLong("when"), .long, .customLong("other", withSingleDash: true), .customLong("there"), .customShort("x"), .customShort("y")],
365+
help: "Help Message")
366+
var time: String?
367+
}
368+
369+
func testHelpWithMultipleCustomNames() {
370+
AssertHelp(for: L.self, equals: """
371+
USAGE: l [--remote <remote>]
372+
373+
OPTIONS:
374+
-t, -x, -y, --remote, --when, --time, -other, --there <remote>
375+
Help Message
376+
-h, --help Show help information.
377+
378+
""")
379+
}
361380
}

Tests/ArgumentParserUnitTests/UsageGenerationTests.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,28 @@ extension UsageGenerationTests {
149149
let help = UsageGenerator(toolName: "bar", parsable: J())
150150
XCTAssertEqual(help.synopsis, "bar --req <req> [--opt <opt>]")
151151
}
152+
153+
struct K: ParsableArguments {
154+
@Option(
155+
name: [.short, .customLong("remote"), .customLong("when"), .customLong("there")],
156+
help: "Help Message")
157+
var time: String?
158+
}
159+
160+
func testSynopsisWithMultipleCustomNames() {
161+
let help = UsageGenerator(toolName: "bar", parsable: K())
162+
XCTAssertEqual(help.synopsis, "bar [--remote <remote>]")
163+
}
164+
165+
struct L: ParsableArguments {
166+
@Option(
167+
name: [.short, .short, .customLong("remote", withSingleDash: true), .short, .customLong("remote", withSingleDash: true)],
168+
help: "Help Message")
169+
var time: String?
170+
}
171+
172+
func testSynopsisWithSingleDashLongNameFirst() {
173+
let help = UsageGenerator(toolName: "bar", parsable: L())
174+
XCTAssertEqual(help.synopsis, "bar [-remote <remote>]")
175+
}
152176
}

0 commit comments

Comments
 (0)