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

Add API for titling an option group #492

Merged
merged 8 commits into from Sep 26, 2022

Conversation

natecook1000
Copy link
Member

@natecook1000 natecook1000 commented Sep 17, 2022

This change lets you provide a title for option groups, which is used when generating the help screen. Titled option groups, when they exist, are placed between the ARGUMENTS and OPTIONS section of the help. Multiple option groups with the same title are coalesced into a single group.

For example, this command declaration:

struct Extras: ParsableArguments {
    @Flag(help: "Print extra output while processing.")
    var verbose: Bool = false

    @Flag(help: "Include details no one asked for.")
    var oversharing: Bool = false
}

@main
struct Example: ParsableCommand {
    @OptionGroup(title: "Extras")
    var extras: Extras

    @Argument var name: String?
    @Option var title: String?
}

yields this help screen:

USAGE: example [--verbose] [--oversharing] [<name>] [--title <title>]

ARGUMENTS:
  <name>

EXTRAS:
  --verbose               Print extra output while processing.
  --oversharing           Include details no one asked for.

OPTIONS:
  --title <title>
  -h, --help              Show help information.

Resolves #267.

Checklist

  • I've added at least one test that validates that my change is working, if appropriate
  • I've followed the code style of the rest of the project
  • I've read the Contribution Guidelines
  • I've updated the documentation if necessary
    • API documentation
    • Articles

This change lets you provide a title for option groups, which is used
when generating the help screen. Titled option groups, when they exist,
are placed between the ARGUMENTS and OPTIONS section of the help.
Multiple option groups with the same title are coalesced into a single
group.

For example, this command declaration:

    struct Extras: ParsableArguments {
      @Flag(help: "Print extra output while processing.")
      var verbose: Bool = false

      @Flag(help: "Include details no one asked for.")
      var oversharing: Bool = false
    }

    @main
    struct Example: ParsableCommand {
      @OptionGroup(title: "Extras")
      var extras: Extras

      @argument var name: String?
      @option var title: String?
    }

yields this help screen:

    USAGE: example [--verbose] [--oversharing] [<name>] [--title <title>]

    ARGUMENTS:
      <name>

    EXTRAS:
      --verbose               Print extra output while processing.
      --oversharing           Include details no one asked for.

    OPTIONS:
      --title <title>
      -h, --help              Show help information.
@natecook1000
Copy link
Member Author

@rauhul I think we'll need an updated schema for the JSON help dump, and then we can update the man page generation to support this feature as well. Does that sound right?

Comment on lines +217 to +221
// Combine the compiled groups in this order:
// - arguments
// - named sections
// - options/flags
// - subcommands
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rauhul @ethan-kusters Does this seem like the correct order?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this makes sense to me!

Copy link
Contributor

@rauhul rauhul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I'm a little unsure if setting the title on every instance of an option group is the best api. It may be valuable to have an OptionGroupConfiguration so a default title could be provided by the type. This can always be added in the future, so theres no reason to stop this change.


extension OptionGroup {
@_disfavoredOverload
@available(*, deprecated, renamed: "init(title:visibility:)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this still, SAP isn't ABI stable and the above initializer is source compatible?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eh, well very very minimally source breaking if someone ever used a point free version of the function: OptionGroup.init(visibility:)I really doubt this is the case though.

@@ -136,6 +139,8 @@ internal struct HelpGenerator {

var positionalElements: [Section.Element] = []
var optionElements: [Section.Element] = []
var titledSections: [String: [Section.Element]] = [:]
var sectionTitles: [String] = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed? It seems like a duplicate of titledSections.keys

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NVM this is so they are sorted. A comment about this would be nice!

@natecook1000
Copy link
Member Author

LGTM, I'm a little unsure if setting the title on every instance of an option group is the best api. It may be valuable to have an OptionGroupConfiguration so a default title could be provided by the type. This can always be added in the future, so theres no reason to stop this change.

This is a really good point. I think since we'll want to be able to specify a title at the @OptionGroup site even if we have type-level customization (i.e. as an override), it's okay to continue with this first.

@natecook1000
Copy link
Member Author

@swift-ci Please test

@@ -239,4 +238,8 @@ extension StringProtocol where SubSequence == Substring {
guard lines.count == 2 else { return lines.joined(separator: "") }
return "\(lines[0])\n\(lines[1].indentingEachLine(by: n))"
}

var nilIfEmpty: Self? {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this is called nonEmpty in ArgumentParserToolInfo

@natecook1000
Copy link
Member Author

@swift-ci Please test

@natecook1000 natecook1000 merged commit b80fb05 into apple:main Sep 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Group and label option groups in the help screen
2 participants